laravel-echo-api-gateway 0.5.1 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/js-src/Channel.ts CHANGED
@@ -3,6 +3,8 @@ import { Channel as BaseChannel } from 'laravel-echo/src/channel/channel';
3
3
  import { PresenceChannel } from "laravel-echo/src/channel";
4
4
  import { Websocket } from "./Websocket";
5
5
 
6
+ const LOG_PREFIX = '[LE-AG-Channel]';
7
+
6
8
  /**
7
9
  * This class represents a Pusher channel.
8
10
  */
@@ -45,6 +47,8 @@ export class Channel extends BaseChannel implements PresenceChannel {
45
47
  * Subscribe to a Pusher channel.
46
48
  */
47
49
  subscribe(): any {
50
+ this.options["debug"] && console.log(`${LOG_PREFIX} subscribe for channel ${this.name} ...`);
51
+
48
52
  this.socket.subscribe(this)
49
53
  }
50
54
 
@@ -52,13 +56,17 @@ export class Channel extends BaseChannel implements PresenceChannel {
52
56
  * Unsubscribe from a Pusher channel.
53
57
  */
54
58
  unsubscribe(): void {
59
+ this.options["debug"] && console.log(`${LOG_PREFIX} unsubscribe for channel ${this.name} ...`);
60
+
55
61
  this.socket.unsubscribe(this);
56
62
  }
57
63
 
58
64
  /**
59
65
  * Listen for an event on the channel instance.
60
66
  */
61
- listen(event: string, callback: Function): Channel {
67
+ listen(event: string, callback: Function): this {
68
+ this.options["debug"] && console.log(`${LOG_PREFIX} listen to ${event} for channel ${this.name} ...`);
69
+
62
70
  this.on(this.eventFormatter.format(event), callback);
63
71
 
64
72
  return this;
@@ -67,7 +75,9 @@ export class Channel extends BaseChannel implements PresenceChannel {
67
75
  /**
68
76
  * Stop listening for an event on the channel instance.
69
77
  */
70
- stopListening(event: string, callback?: Function): Channel {
78
+ stopListening(event: string, callback?: Function): this {
79
+ this.options["debug"] && console.log(`${LOG_PREFIX} stop listening to ${event} for channel ${this.name} ...`);
80
+
71
81
  this.socket.unbindEvent(this, event, callback)
72
82
 
73
83
  return this;
@@ -76,7 +86,9 @@ export class Channel extends BaseChannel implements PresenceChannel {
76
86
  /**
77
87
  * Register a callback to be called anytime a subscription succeeds.
78
88
  */
79
- subscribed(callback: Function): Channel {
89
+ subscribed(callback: Function): this {
90
+ this.options["debug"] && console.log(`${LOG_PREFIX} subscribed for channel ${this.name} ...`);
91
+
80
92
  this.on('subscription_succeeded', () => {
81
93
  callback();
82
94
  });
@@ -87,7 +99,9 @@ export class Channel extends BaseChannel implements PresenceChannel {
87
99
  /**
88
100
  * Register a callback to be called anytime a subscription error occurs.
89
101
  */
90
- error(callback: Function): Channel {
102
+ error(callback: Function): this {
103
+ this.options["debug"] && console.log(`${LOG_PREFIX} error for channel ${this.name} ...`);
104
+
91
105
  this.on('error', (status) => {
92
106
  callback(status);
93
107
  });
@@ -99,12 +113,14 @@ export class Channel extends BaseChannel implements PresenceChannel {
99
113
  * Bind a channel to an event.
100
114
  */
101
115
  on(event: string, callback: Function): Channel {
116
+ this.options["debug"] && console.log(`${LOG_PREFIX} on ${event} for channel ${this.name} ...`);
117
+
102
118
  this.socket.bind(this, event, callback)
103
119
 
104
120
  return this;
105
121
  }
106
122
 
107
- whisper(event: string, data: object): Channel {
123
+ whisper(event: string, data: object): this {
108
124
  let channel = this.name;
109
125
  let formattedEvent = "client-" + event;
110
126
  this.socket.send({
@@ -116,7 +132,7 @@ export class Channel extends BaseChannel implements PresenceChannel {
116
132
  return this;
117
133
  }
118
134
 
119
- here(callback: Function): Channel {
135
+ here(callback: Function): this {
120
136
  // TODO: implement
121
137
 
122
138
  return this
@@ -125,7 +141,7 @@ export class Channel extends BaseChannel implements PresenceChannel {
125
141
  /**
126
142
  * Listen for someone joining the channel.
127
143
  */
128
- joining(callback: Function): Channel {
144
+ joining(callback: Function): this {
129
145
  // TODO: implement
130
146
 
131
147
  return this
@@ -134,9 +150,11 @@ export class Channel extends BaseChannel implements PresenceChannel {
134
150
  /**
135
151
  * Listen for someone leaving the channel.
136
152
  */
137
- leaving(callback: Function): Channel {
153
+ leaving(callback: Function): this {
138
154
  // TODO: implement
139
155
 
140
156
  return this
141
157
  }
142
158
  }
159
+
160
+ export { PresenceChannel };
@@ -4,10 +4,10 @@ import {Channel} from "./Channel";
4
4
 
5
5
  export const broadcaster = (options: object): Connector => new Connector(options);
6
6
 
7
+ const LOG_PREFIX = '[LE-AG-Connector]';
8
+
7
9
  export class Connector extends BaseConnector {
8
- /**
9
- * The Socket.io connection instance.
10
- */
10
+
11
11
  socket: Websocket;
12
12
 
13
13
  /**
@@ -15,10 +15,19 @@ export class Connector extends BaseConnector {
15
15
  */
16
16
  channels: { [name: string]: Channel } = {};
17
17
 
18
+ /**
19
+ * Create a new class instance.
20
+ */
21
+ constructor(options: any) {
22
+ super(options);
23
+ }
24
+
18
25
  /**
19
26
  * Create a fresh Socket.io connection.
20
27
  */
21
28
  connect(): void {
29
+ this.options.debug && console.log(LOG_PREFIX + 'Connect ...' );
30
+
22
31
  this.socket = new Websocket(this.options);
23
32
 
24
33
  return;
@@ -103,6 +112,8 @@ export class Connector extends BaseConnector {
103
112
  * Disconnect socket connection.
104
113
  */
105
114
  disconnect(): void {
115
+ this.options.debug && console.log(LOG_PREFIX + 'Disconnect ...' );
116
+
106
117
  this.socket.close();
107
118
  }
108
119
  }
@@ -1,10 +1,13 @@
1
1
  import { AxiosResponse } from "axios";
2
2
  import { Channel } from "./Channel";
3
+ import axios from 'axios';
3
4
 
4
5
  export type Options = { authEndpoint: string, host: string, bearerToken: string, auth: any, debug: boolean };
5
6
 
6
7
  export type MessageBody = { event: string, channel?: string, data: object };
7
8
 
9
+ const LOG_PREFIX = '[LE-AG-Websocket]';
10
+
8
11
  export class Websocket {
9
12
  buffer: Array<object> = [];
10
13
 
@@ -12,7 +15,7 @@ export class Websocket {
12
15
 
13
16
  websocket: WebSocket;
14
17
 
15
- private listeners: { [channelName: string]: { [eventName: string]: Function } } = {}
18
+ private listeners: { [channelName: string]: { [eventName: string]: Function } } = {};
16
19
 
17
20
  private internalListeners: { [eventName: string]: Function } = {};
18
21
 
@@ -21,145 +24,176 @@ export class Websocket {
21
24
  private socketId: string;
22
25
 
23
26
  private closing = false;
27
+ private hasConnected = false;
24
28
 
25
29
  private pingInterval: NodeJS.Timeout;
26
30
 
31
+ constructor(options: Options) {
32
+ this.options = options;
33
+
34
+ this.connect(this.options.host);
35
+
36
+ return this;
37
+ }
38
+
27
39
  private connect(host: string): void {
28
- this.options.debug && console.log('Connecting');
29
40
 
30
- this.websocket = new WebSocket(host)
41
+ if (!host) {
42
+ this.options.debug && console.error(LOG_PREFIX + `Cannont connect without host !`);
43
+
44
+ return;
45
+ }
46
+
47
+ this.options.debug && console.log(LOG_PREFIX + `Trying to connect to ${host}...` );
48
+
49
+ this.websocket = new WebSocket(host);
50
+
51
+ this.websocket.onerror = () => {
52
+
53
+ if (!this.hasConnected) {
54
+
55
+ setTimeout(() => {
56
+ this.socketId = undefined;
57
+ this.connect(host);
58
+ }, 3000);
59
+ }
60
+ };
31
61
 
32
62
  this.websocket.onopen = () => {
63
+ this.options.debug && console.log(LOG_PREFIX + ' Connected !');
64
+ this.hasConnected = true;
65
+
33
66
  this.send({
34
67
  event: 'whoami',
35
- })
68
+ });
36
69
 
37
70
  while (this.buffer.length) {
38
- const message = this.buffer[0]
71
+ const message = this.buffer[0];
39
72
 
40
- this.send(message)
73
+ this.send(message);
41
74
 
42
- this.buffer.splice(0, 1)
75
+ this.buffer.splice(0, 1);
43
76
  }
44
- }
45
-
46
- this.websocket.onmessage = (messageEvent: MessageEvent) => {
47
- const message = this.parseMessage(messageEvent.data)
48
77
 
49
- if (!message) {
50
- return
51
- }
78
+ // Register events only once connected, or they won't be registered if connection failed/lost
52
79
 
53
- if (message.channel) {
54
- this.options.debug && console.log(`Received event ${message.event} on channel ${message.channel}`)
80
+ this.websocket.onmessage = (messageEvent: MessageEvent) => {
81
+ const message = this.parseMessage(messageEvent.data);
82
+ this.options.debug && console.log(LOG_PREFIX + ' onmessage', messageEvent.data);
55
83
 
56
- if (this.listeners[message.channel] && this.listeners[message.channel][message.event]) {
57
- this.listeners[message.channel][message.event](message.data)
84
+ if (!message) {
85
+ return;
58
86
  }
59
87
 
60
- return
61
- }
62
-
63
- if (this.internalListeners[message.event]) {
64
- this.internalListeners[message.event](message.data)
65
- }
88
+ if (message.channel) {
89
+ this.options.debug && console.log(`${LOG_PREFIX} Received event ${message.event} on channel ${message.channel}`);
66
90
 
67
- }
91
+ if (this.listeners[message.channel] && this.listeners[message.channel][message.event]) {
92
+ this.listeners[message.channel][message.event](message.data);
93
+ }
68
94
 
95
+ return;
96
+ }
69
97
 
70
- this.websocket.onclose = () => {
71
- if (this.socketId && !this.closing || !this.socketId) {
72
- this.options.debug && console.info('Connection lost, reconnecting...');
73
- setTimeout(() => {
74
- this.socketId = undefined
75
- this.connect(host)
76
- }, 1000);
98
+ if (this.internalListeners[message.event]) {
99
+ this.internalListeners[message.event](message.data);
100
+ }
77
101
  }
78
- };
79
102
 
80
- this.on('whoami', ({ socket_id: socketId }) => {
81
- this.socketId = socketId
82
103
 
83
- this.options.debug && console.log(`just set socketId to ${socketId}`)
104
+ // send ping every 60 seconds to keep connection alive
105
+ this.pingInterval = setInterval(() => {
106
+ if (this.websocket.readyState === this.websocket.OPEN) {
107
+ this.options.debug && console.log(LOG_PREFIX + ' Sending ping');
108
+
109
+ this.send({
110
+ event: 'ping',
111
+ });
112
+ }
113
+ }, 60 * 1000);
114
+ }
84
115
 
85
- while (this.channelBacklog.length) {
86
- const channel = this.channelBacklog[0]
87
116
 
88
- this.actuallySubscribe(channel)
117
+ this.websocket.onclose = () => {
118
+ this.options.debug && console.info('Connection closed.');
89
119
 
90
- this.channelBacklog.splice(0, 1)
120
+ if (this.closing){
121
+ return;
91
122
  }
92
- })
93
123
 
124
+ this.hasConnected = false;
125
+ this.options.debug && console.info('Connection lost, reconnecting...');
94
126
 
95
- // send ping every 60 seconds to keep connection alive
96
- this.pingInterval = setInterval(() => {
97
- if (this.websocket.readyState === this.websocket.OPEN) {
98
- this.options.debug && console.log('Sending ping')
99
- this.send({
100
- event: 'ping',
101
- })
102
- }
103
- }, 60 * 1000)
127
+ setTimeout(() => {
128
+ this.socketId = undefined;
129
+ this.connect(host);
130
+ }, 1000);
131
+ };
104
132
 
105
- }
133
+ this.on('whoami', ({ socket_id: socketId }) => {
134
+ this.socketId = socketId;
106
135
 
107
- constructor(options: Options) {
108
- this.options = options;
136
+ this.options.debug && console.log(`${LOG_PREFIX} Just set socketId to ${socketId}`);
109
137
 
110
- this.connect(this.options.host);
138
+ // Handle the backlog and don't empty it, we'll need it if we lose connection
139
+ let channel: Channel;
111
140
 
112
- return this
141
+ for(channel of this.channelBacklog){
142
+ this.actuallySubscribe(channel);
143
+ }
144
+ });
113
145
  }
114
146
 
115
147
  protected parseMessage(body: string): MessageBody {
116
148
  try {
117
- return JSON.parse(body)
149
+ return JSON.parse(body);
118
150
  } catch (error) {
119
- this.options.debug && console.error(error)
151
+ this.options.debug && console.error(error);
120
152
 
121
- return undefined
153
+ return undefined;
122
154
  }
123
155
  }
124
156
 
125
157
  getSocketId(): string {
126
- return this.socketId
158
+ return this.socketId;
127
159
  }
128
160
 
129
161
  private socketIsReady(): boolean {
130
- return this.websocket.readyState === this.websocket.OPEN
162
+ return this.websocket.readyState === this.websocket.OPEN;
131
163
  }
132
164
 
133
165
  send(message: object): void {
134
166
  if (this.socketIsReady()) {
135
- this.websocket.send(JSON.stringify(message))
136
- return
167
+ this.websocket.send(JSON.stringify(message));
168
+ return;
137
169
  }
138
170
 
139
- this.buffer.push(message)
171
+ this.buffer.push(message);
140
172
  }
141
173
 
142
174
  close(): void {
143
- this.closing = true
144
- this.internalListeners = {}
175
+ this.closing = true;
176
+ this.internalListeners = {};
145
177
 
146
- clearInterval(this.pingInterval)
147
- this.pingInterval = undefined
178
+ clearInterval(this.pingInterval);
179
+ this.pingInterval = undefined;
148
180
 
149
- this.websocket.close()
181
+ this.websocket.close();
150
182
  }
151
183
 
152
184
  subscribe(channel: Channel): void {
153
185
  if (this.getSocketId()) {
154
- this.actuallySubscribe(channel)
186
+ this.actuallySubscribe(channel);
155
187
  } else {
156
- this.channelBacklog.push(channel)
188
+ this.options.debug && console.log(`${LOG_PREFIX} subscribe - push channel backlog for channel ${channel.name}`);
189
+
190
+ this.channelBacklog.push(channel);
157
191
  }
158
192
  }
159
193
 
160
194
  private actuallySubscribe(channel: Channel): void {
161
195
  if (channel.name.startsWith('private-') || channel.name.startsWith('presence-')) {
162
- this.options.debug && console.log(`Sending auth request for channel ${channel.name}`)
196
+ this.options.debug && console.log(`${LOG_PREFIX} Sending auth request for channel ${channel.name}`);
163
197
 
164
198
  if (this.options.bearerToken) {
165
199
  this.options.auth.headers['Authorization'] = 'Bearer ' + this.options.bearerToken;
@@ -171,7 +205,7 @@ export class Websocket {
171
205
  }, {
172
206
  headers: this.options.auth.headers || {}
173
207
  }).then((response: AxiosResponse) => {
174
- this.options.debug && console.log(`Subscribing to channels ${channel.name}`)
208
+ this.options.debug && console.log(`${LOG_PREFIX} Subscribing to private channel ${channel.name}`);
175
209
 
176
210
  this.send({
177
211
  event: 'subscribe',
@@ -179,51 +213,59 @@ export class Websocket {
179
213
  channel: channel.name,
180
214
  ...response.data
181
215
  },
182
- })
216
+ });
183
217
  }).catch((error) => {
184
- this.options.debug && console.log(`Auth request for channel ${channel.name} failed`)
185
- this.options.debug && console.error(error)
218
+ this.options.debug && console.log(`${LOG_PREFIX} Auth request for channel ${channel.name} failed`);
219
+ this.options.debug && console.error(error);
186
220
  })
187
221
  } else {
188
- this.options.debug && console.log(`Subscribing to channels ${channel.name}`)
222
+ this.options.debug && console.log(`${LOG_PREFIX} Subscribing to channel ${channel.name}`);
189
223
 
190
224
  this.send({
191
225
  event: 'subscribe',
192
226
  data: {
193
227
  channel: channel.name,
194
228
  },
195
- })
229
+ });
196
230
  }
197
231
  }
198
232
 
199
233
  unsubscribe(channel: Channel): void {
234
+ this.options.debug && console.log(`${LOG_PREFIX} unsubscribe for channel ${channel.name}`);
235
+
200
236
  this.send({
201
237
  event: 'unsubscribe',
202
238
  data: {
203
239
  channel: channel.name,
204
240
  },
205
- })
241
+ });
206
242
 
207
243
  if (this.listeners[channel.name]) {
208
- delete this.listeners[channel.name]
244
+ delete this.listeners[channel.name];
209
245
  }
210
246
  }
211
247
 
212
248
  on(event: string, callback: Function = null): void {
213
- this.internalListeners[event] = callback
249
+ this.options.debug && console.log(`${LOG_PREFIX} on event ${event} ...`);
250
+
251
+ this.internalListeners[event] = callback;
214
252
  }
215
253
 
216
254
  bind(channel: Channel, event: string, callback: Function): void {
255
+ this.options.debug && console.log(`${LOG_PREFIX} bind event ${event} for channel ${channel.name} ...`);
256
+
217
257
  if (!this.listeners[channel.name]) {
218
- this.listeners[channel.name] = {}
258
+ this.listeners[channel.name] = {};
219
259
  }
220
260
 
221
- this.listeners[channel.name][event] = callback
261
+ this.listeners[channel.name][event] = callback;
222
262
  }
223
263
 
224
264
  unbindEvent(channel: Channel, event: string, callback: Function = null): void {
265
+ this.options.debug && console.log(`${LOG_PREFIX} unbind event ${event} for channel ${channel.name} ...`);
266
+
225
267
  if (this.internalListeners[event] && (callback === null || this.internalListeners[event] === callback)) {
226
- delete this.internalListeners[event]
268
+ delete this.internalListeners[event];
227
269
  }
228
270
  }
229
271
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "laravel-echo-api-gateway",
3
- "version": "0.5.1",
3
+ "version": "0.5.3",
4
4
  "description": "Use Laravel Echo with API Gateway Websockets",
5
5
  "keywords": [
6
6
  "laravel",
@@ -40,6 +40,7 @@
40
40
  "@babel/plugin-transform-object-assign": "^7.8.3",
41
41
  "@babel/preset-env": "^7.9.6",
42
42
  "@rollup/plugin-babel": "^5.0.0",
43
+ "@types/babel__traverse": "^7.20.6",
43
44
  "@types/jest": "^24.0.18",
44
45
  "@types/node": "^12.7.5",
45
46
  "@typescript-eslint/eslint-plugin": "^3.7.0",
@@ -48,14 +49,17 @@
48
49
  "eslint": "^7.5.0",
49
50
  "jest": "^24.9.0",
50
51
  "jest-websocket-mock": "^2.2.0",
51
- "laravel-echo": "^1.10.0",
52
+ "laravel-echo": "1.10.0",
52
53
  "mock-socket": "^9.0.3",
53
54
  "rollup": "^2.10.2",
55
+ "rollup-plugin-commonjs": "^10.1.0",
56
+ "rollup-plugin-json": "^4.0.0",
57
+ "rollup-plugin-node-resolve": "^5.2.0",
54
58
  "rollup-plugin-typescript2": "^0.27.1",
55
59
  "standard-version": "^8.0.1",
56
60
  "ts-jest": "^24.1.0",
57
61
  "tslib": "^1.10.0",
58
- "typescript": "^3.6.3"
62
+ "typescript": "^5.7.2"
59
63
  },
60
64
  "engines": {
61
65
  "node": ">=10"
package/rollup.config.js CHANGED
@@ -9,7 +9,10 @@ export default {
9
9
  { file: './dist/laravel-echo-api-gateway.iife.js', format: 'iife', name: 'LaravelEchoApiGateway' },
10
10
  ],
11
11
  plugins: [
12
- typescript(),
12
+ typescript({
13
+ tsconfig: './tsconfig.json', // Chemin explicite vers votre fichier TypeScript
14
+ useTsconfigDeclarationDir: true, // Respecte les options `outDir` et `declarationDir`
15
+ }),
13
16
  babel({
14
17
  babelHelpers: 'bundled',
15
18
  exclude: 'node_modules/**',