GithubHelp home page GithubHelp logo

lukas-reining / eventsource Goto Github PK

View Code? Open in Web Editor NEW
32.0 32.0 3.0 332 KB

EventSource implementation that is fully compliant with the WHATWG Server-Sent Events specification but takes more arguments.

License: MIT License

JavaScript 19.51% TypeScript 80.49%
eventsource server-sent-events sse

eventsource's Issues

EventSource close()d during 'reconnect' comes alive again after retry timeout

When a working EventSource is failed (by the remote end closing the connection), reconnect() is called internally as expected.

reconnect() checks whether readyState has been set to CLOSED (it hasn't), and then queues a call to connect() after a timeout:

await this.connect(this.currentLastEventId);

Before the timeout expires, the consuming application calls close(), which changes the readyState to CLOSED.

Once the timeout expires, connect() resets readyState to CONNECTING:

this.readyState = this.CONNECTING;

.. and the previously closed EventSource begins emitting messages.

A quick fix might be to test readyState early in connect() or to store the timeoutID returned by reconnect()'s setTimeout() and call clearTimeout() during close().

Confusing warnings when retrying with disableRetry set to true

When setting disableRetry to true in the config and an event happens that would trigger a retry, the library still logs a warning to the console, although the retry will not happen due to the disableRetry option in the config.
This is a bit confusing. The warning tells the developer it will reconnect to the event-source, while actually not doing so.

I think it should not log the warning in this case. Or is this expected behaviour?

https://github.com/lukas-reining/eventsource/blob/ad8eb89b52cf6ae98338638af91faf6ceb20b247/src/eventsource.ts#L146C1-L153C1

Named export 'EventSource' not found (CJS)

Using "type": "module" in package.json, results in the following behavior. Hers's a minimally viable example:

Node version 18.19.1
extended-eventsource@^1.4.6

ESM

index.js

import { EventSource } from 'extended-eventsource';

const es = new EventSource(<MY_SSE_URL>, {
  withCredentials: true,
  disableLogger: true,
});

es.onopen = () => {
  console.log('EventSource connected');
};

Error (via node index.js)

import { EventSource } from 'extended-eventsource';
         ^^^^^^^^^^^
SyntaxError: Named export 'EventSource' not found. The requested module 'extended-eventsource' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from 'extended-eventsource';
const { EventSource } = pkg;

    at ModuleJob._instantiate (node:internal/modules/esm/module_job:123:21)
    at async ModuleJob.run (node:internal/modules/esm/module_job:191:5)
    at async ModuleLoader.import (node:internal/modules/esm/loader:336:24)
    at async loadESM (node:internal/process/esm_loader:34:7)
Node.js v18.19.1dleMainPromise (node:internal/modules/run_main:106:12)

The suggested "fix" from the error no effect, and result in the following:

Modified index.js

import pkg from 'extended-eventsource';
const { EventSource } = pkg;

const es = new EventSource('https://sdk.flagsync.com/events/sdk-updates', {
  withCredentials: true,
  disableLogger: true,
});

es.onopen = () => {
  console.log('EventSource connected');
};
export { CustomEventSource, CustomEventSource as EventSource };
^^^^^^

SyntaxError: Unexpected token 'export'
    at internalCompileFunction (node:internal/vm:73:18)
    at wrapSafe (node:internal/modules/cjs/loader:1274:20)
    at Module._compile (node:internal/modules/cjs/loader:1320:27)

Package.json

{
  "name": "modern",
  "version": "1.0.0",
  "description": "",
  "main": "index",
  "type": "module",
  "scripts": {
    "start": "node index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "extended-eventsource": "^1.4.6"
  }
}

CJS

Require

require does work as expected; must remove "type": "module" from package.json

index.js

const { EventSource } = require('extended-eventsource');

const es = new EventSource(<MY_SSE_URL>, {
  withCredentials: true,
  disableLogger: true,
});

es.onopen = () => {
  console.log('EventSource connected');
};
EventSource connected

package.json

{
  "name": "scripts",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "extended-eventsource": "^1.4.6"
  }
}

Remove unused `core-js` dependency

The eventsource repository currently lists core-js as a dependency, but it seems to be unused throughout the codebase. I suggest removing this dependency to streamline the project.

Empty string as the first response data

Thanks for creating such a wonderful package, @lukas-reining
I was trying to use sse in my angular app, but couldn't set Authorization header for request, and I found this package, really helpful.
By the way, why does it send empty string "" as the first data?
Of course, this is not a big issue, but as I was trying to send json string from backend and parse it on frontend, I encountered this, which caught me for some time.
Of course I added validation logic to avoid error, but I just want this package to be perfect.

Doens't work in production

This is working fine on local development, when I run angular app on localhost:4200,
However, once I deploy the app to the vercel, it returns error.

main-6FYVCRR5.js:7 ERROR TypeError: (void 0) is not a constructor
    at e.getEventSource (main-6FYVCRR5.js:18:4128)
    at i._subscribe (main-6FYVCRR5.js:18:3856)
    at i._trySubscribe (main-6FYVCRR5.js:3:4428)
    at main-6FYVCRR5.js:3:4373
    at Ua (main-6FYVCRR5.js:3:2222)
    at i.subscribe (main-6FYVCRR5.js:3:4289)
    at e.<anonymous> (main-6FYVCRR5.js:18:11341)
    at Generator.next (<anonymous>)
    at chunk-2WQGNY7Y.js:1:1640
    at new t (polyfills-LZBJRJJE.js:2:2128)
 this is the compiled source which I can see in devtools
            getEventSource(t) {
            return new (void 0)(t,{
                headers: {
                    Authorization: "Bearer " + this.token
                },
                retry: 3e3
            })
        }
    here's my source code 
import { Injectable, NgZone, inject } from '@angular/core';
import { Observable } from 'rxjs';
import { apiUrl } from '../../environment';
import { AuthRegularService } from '../services/auth-regular.service';
import { EventSource as CustomEventSource } from 'extended-eventsource';

@Injectable({
 providedIn: 'root',
})
export class SseService {
 token = inject(AuthRegularService).getToken();
 constructor(private _zone: NgZone) {}
 getServerSentEvent(url: string): Observable<any> {
   return Observable.create((observer: any) => {
     const eventSource = this.getEventSource(url);
     eventSource.onmessage = (event) => {
       this._zone.run(() => {
         // console.log("SSE event data received: ", event.data)
         if (!event.data) {
           console.log('False data received', event.data);
           // do not forward as this causes an error, "", false, undefined, null
         } else if (JSON.parse(event.data).msg === 'PROCESS_ENDED') {
           eventSource.close();
           observer.next(event);
         } else {
           observer.next(event);
         }
       });
     };
     eventSource.onerror = (error: any) => {
       console.log('Getting server sent event error:', error);
       eventSource.close();
       return;
       // this._zone.run(() => {
       //   observer.error(error);
       // });
     };
   });
 }

 private getEventSource(url: string): EventSource {
   return new CustomEventSource(url, {
     headers: {
       Authorization: 'Bearer ' + this.token,
     },
     retry: 3000,
   });
 }
}

`extended-eventsource` writes directly to stdout (and this behavior isn't configurable)

In several places this package uses console methods to write directly to standard output. This can be problematic when used from a CLI program where I want to have full control over my program's output. Currently I'm seeing messages like Connection established in my output which I have no straightforward way of preventing.

Would you consider accepting a pull request which removes all usages of console.*? Or if not, perhaps a new option to allow some mechanism to disable them?

Is it normal that onmessage never fires?

I can do this:

eventSource.addEventListener('specific-event-type', msg => { ... });

And it'll fire, but

eventSource.onmessage = msg => { .... }

Will never fire.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.