Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@twurple/eventsub-ws

Package Overview
Dependencies
Maintainers
1
Versions
74
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@twurple/eventsub-ws - npm Package Compare versions

Comparing version 5.3.0-pre.2 to 5.3.0-pre.3

18

lib/EventSubWsListener.d.ts

@@ -5,2 +5,13 @@ import type { HelixEventSubWebSocketTransportOptions } from '@twurple/api';

/**
* Configuration for an EventSub WebSocket listener.
*/
export interface EventSubWsConfig extends EventSubBaseConfig {
/**
* The URL to connect to initially.
*
* Can be used to connect to a test server, for example one created by the Twitch CLI.
*/
url?: string;
}
/**
* A WebSocket listener for the Twitch EventSub event distribution mechanism.

@@ -18,2 +29,5 @@ *

private _welcomeCallback?;
private readonly _initialUrl;
private _connecting;
private _reconnectInProgress;
/**

@@ -26,3 +40,3 @@ * Creates a new EventSub HTTP listener.

*/
constructor(config: EventSubBaseConfig);
constructor(config: EventSubWsConfig);
start(): Promise<void>;

@@ -36,3 +50,5 @@ stop(): Promise<void>;

private _connectTo;
private _disconnect;
private _reconnect;
}
//# sourceMappingURL=EventSubWsListener.d.ts.map

175

lib/EventSubWsListener.js

@@ -7,2 +7,3 @@ "use strict";

const shared_utils_1 = require("@d-fischer/shared-utils");
const api_1 = require("@twurple/api");
const auth_1 = require("@twurple/auth");

@@ -29,2 +30,3 @@ const common_1 = require("@twurple/common");

constructor(config) {
var _a;
if (config.apiClient._authProvider.tokenType !== 'user') {

@@ -34,2 +36,5 @@ throw new auth_1.InvalidTokenTypeError('EventSub over WebSockets requires user access tokens to work.');

super(config);
this._initialUrl = (_a = config.url) !== null && _a !== void 0 ? _a : 'wss://eventsub-beta.wss.twitch.tv/ws';
this._connecting = false;
this._reconnectInProgress = false;
}

@@ -54,3 +59,3 @@ async start() {

if (!this._sessionId) {
throw new Error('Listener is not connected or does not have a session ID yet (this is a bug, please report it)');
throw new api_1.HellFreezesOverError('Listener is not connected or does not have a session ID yet');
}

@@ -63,3 +68,3 @@ return {

async _connect() {
await this._connectTo('wss://eventsub-beta.wss.twitch.tv/ws');
await this._connectTo(this._initialUrl);
}

@@ -71,64 +76,126 @@ async _connectTo(url) {

}
this._connection = new connection_1.WebSocketConnection({ url });
this._connection.onConnect(() => {
// TODO reset backoff
});
this._connection.onDisconnect(async (manually) => {
this._readyToSubscribe = false;
this._connection = undefined;
if (!manually) {
await this._connect(); // TODO backoff failures, re-register subscriptions on successful reconnect (at welcome?)
}
});
this._connection.onReceive(async (data) => {
var _a, _b;
const { metadata, payload } = JSON.parse(data);
switch (metadata.message_type) {
case 'session_welcome': {
this._sessionId = payload.session.id;
this._readyToSubscribe = true;
(_a = this._welcomeCallback) === null || _a === void 0 ? void 0 : _a.call(this);
this._welcomeCallback = undefined;
// TODO subscribe to all resting subscription objects
break;
this._connecting = true;
const retryTimerGenerator = (0, shared_utils_1.fibWithLimit)(120);
while (true) {
const newConnection = (this._connection = new connection_1.WebSocketConnection({ url }, { logger: this._logger }));
newConnection.onDisconnect(async (manually, reason) => {
this._readyToSubscribe = false;
if (manually) {
if (this._reconnectInProgress) {
this._logger.debug('Reconnect: old connection cleaned up');
}
else {
this._logger.info('Disconnected');
}
void newConnection.disconnect();
if (this._connection === newConnection) {
this._connection = undefined;
}
}
case 'session_keepalive': {
// TODO reset keepalive timeout
break;
else {
if (reason) {
this._logger.warn(`Disconnected unexpectedly: ${reason.message}; trying to reconnect`);
}
else {
this._logger.warn('Disconnected unexpectedly; trying to reconnect');
}
if (!this._connecting) {
void this._reconnect();
}
}
case 'notification': {
const id = payload.subscription.id;
const subscription = this._getCorrectSubscriptionByTwitchId(id);
if (!subscription) {
this._logger.error(`Notification from unknown event received: ${id}`);
});
this._connection.onReceive(async (data) => {
var _a;
this._logger.debug(`Received data: ${data.trim()}`);
const { metadata, payload } = JSON.parse(data);
switch (metadata.message_type) {
case 'session_welcome': {
this._logger.info(this._reconnectInProgress
? 'Reconnect: new connection established'
: 'Connection established');
this._sessionId = payload.session.id;
this._readyToSubscribe = true;
const welcomeCallbackPromise = (_a = this._welcomeCallback) === null || _a === void 0 ? void 0 : _a.call(this);
this._welcomeCallback = undefined;
await welcomeCallbackPromise;
this._reconnectInProgress = false;
// TODO subscribe to all resting subscription objects
break;
}
subscription._handleData(payload.event);
break;
}
case 'reconnect': {
await ((_b = this._connection) === null || _b === void 0 ? void 0 : _b.disconnect());
await this._connectTo(payload.session.reconnect_url);
break;
}
case 'revocation': {
const id = payload.subscription.id;
const subscription = this._getCorrectSubscriptionByTwitchId(id);
if (!subscription) {
this._logger.error(`Revocation from unknown event received: ${id}`);
case 'session_keepalive': {
// TODO implement keepalive timeout
break;
}
this._dropSubscription(subscription.id);
this._dropTwitchSubscription(subscription.id);
this.emit(this.onRevoke, subscription);
this._logger.debug(`Subscription revoked by Twitch for event: ${id}`);
break;
case 'session_reconnect': {
this._logger.info('Reconnect message received; initiating new connection');
this._reconnectInProgress = true;
const oldConnection = this._connection;
this._connection = undefined;
this._welcomeCallback = async () => await oldConnection.disconnect();
await this._connectTo(payload.session.reconnect_url);
break;
}
case 'notification': {
const id = payload.subscription.id;
const subscription = this._getCorrectSubscriptionByTwitchId(id);
if (!subscription) {
this._logger.error(`Notification from unknown event received: ${id}`);
break;
}
subscription._handleData(payload.event);
break;
}
case 'revocation': {
const id = payload.subscription.id;
const subscription = this._getCorrectSubscriptionByTwitchId(id);
if (!subscription) {
this._logger.error(`Revocation from unknown event received: ${id}`);
break;
}
this._dropSubscription(subscription.id);
this._dropTwitchSubscription(subscription.id);
this.emit(this.onRevoke, subscription);
this._logger.debug(`Subscription revoked by Twitch for event: ${id}`);
break;
}
default: {
this._logger.warn(`Unknown message type encountered: ${metadata.message_type}`);
}
}
default: {
this._logger.warn(`Unknown message type encountered: ${metadata.message_type}`);
});
try {
await this._connection.connect();
this._connecting = false;
return;
}
catch (e) {
if (!this._connecting) {
return;
}
this._logger.debug(`Connection error caught: ${e.message}`);
const secs = retryTimerGenerator.next().value;
if (secs !== 0) {
this._logger.info(`Retrying in ${secs} seconds`);
}
await (0, shared_utils_1.delay)(secs * 1000);
this._logger.info('Trying to reconnect');
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (!this._connecting) {
return;
}
}
});
await this._connection.connect();
}
}
async _disconnect() {
this._connecting = false;
if (this._connection) {
const lastConnection = this._connection;
this._connection = undefined;
await lastConnection.disconnect();
}
}
async _reconnect() {
void this._disconnect().catch((e) => this._logger.error(`Error while disconnecting for the reconnect: ${e.message}`));
await this._connect();
}
};

@@ -135,0 +202,0 @@ tslib_1.__decorate([

{
"name": "@twurple/eventsub-ws",
"version": "5.3.0-pre.2",
"version": "5.3.0-pre.3",
"publishConfig": {

@@ -38,14 +38,14 @@ "access": "public"

"@d-fischer/logger": "^4.0.0",
"@d-fischer/shared-utils": "^3.2.0",
"@d-fischer/shared-utils": "^3.4.0",
"@d-fischer/typed-event-emitter": "^3.3.0",
"@twurple/auth": "5.3.0-pre.2",
"@twurple/common": "5.3.0-pre.2",
"@twurple/eventsub-base": "5.3.0-pre.2",
"@twurple/auth": "5.3.0-pre.3",
"@twurple/common": "5.3.0-pre.3",
"@twurple/eventsub-base": "5.3.0-pre.3",
"tslib": "^2.0.3"
},
"devDependencies": {
"@twurple/api": "5.3.0-pre.2"
"@twurple/api": "5.3.0-pre.3"
},
"peerDependencies": {
"@twurple/api": "5.3.0-pre.2"
"@twurple/api": "5.3.0-pre.3"
},

@@ -52,0 +52,0 @@ "files": [

@@ -1,7 +0,24 @@

# Twurple - EventSub base
# Twurple - EventSub WebSocket listener
A base package for the HTTP and WS EventSub listeners. Don't use this directly.
[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/twurple/twurple/blob/main/LICENSE)
[![npm version](https://img.shields.io/npm/v/@twurple/eventsub-ws.svg?style=flat)](https://www.npmjs.com/package/@twurple/eventsub-ws)
![PRs welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)
Listen to events on Twitch via their EventSub API using WebSockets.
## Installation
yarn add @twurple/api @twurple/eventsub-ws
or using npm:
npm install @twurple/api @twurple/eventsub-ws
## Documentation
A good place to start with this library is the [documentation](https://twurple.js.org)
which also includes a complete reference of all classes and interfaces, as well as changes and deprecations between major versions.
## If you're getting stuck...
You can join the [Twitch API Libraries Discord Server](https://discord.gg/b9ZqMfz) and ask in `#twurple` for support.

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc