laravel-echo-api-gateway 0.5.8 → 0.5.9
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/.eslintrc.js +1 -0
- package/.github/workflows/ci.yml +49 -45
- package/README.md +93 -17
- package/dist/Channel.d.ts +89 -0
- package/dist/Connector.d.ts +92 -0
- package/dist/EventFormatter.d.ts +10 -0
- package/dist/Websocket.d.ts +78 -0
- package/dist/laravel-echo-api-gateway.common.js +403 -762
- package/dist/laravel-echo-api-gateway.iife.js +487 -846
- package/dist/laravel-echo-api-gateway.js +401 -760
- package/jest.config.js +3 -7
- package/js-src/Channel.ts +74 -62
- package/js-src/Connector.ts +100 -40
- package/js-src/EventFormatter.ts +24 -0
- package/js-src/Websocket.ts +217 -168
- package/js-tests/Connector.test.ts +295 -60
- package/js-tests/EchoCompatibility.test.ts +96 -0
- package/js-tests/helpers.ts +37 -0
- package/package.json +23 -30
- package/phpstan.neon.dist +3 -12
- package/phpunit.xml +2 -2
- package/rollup.config.mjs +14 -0
- package/tsconfig.json +6 -6
- package/dist/js-src/Channel.d.ts +0 -68
- package/dist/js-src/Connector.d.ts +0 -49
- package/dist/js-src/Websocket.d.ts +0 -38
- package/rollup.config.js +0 -31
package/.eslintrc.js
CHANGED
package/.github/workflows/ci.yml
CHANGED
|
@@ -8,10 +8,25 @@ jobs:
|
|
|
8
8
|
pest:
|
|
9
9
|
runs-on: ubuntu-latest
|
|
10
10
|
strategy:
|
|
11
|
-
fail-fast:
|
|
11
|
+
fail-fast: false
|
|
12
12
|
matrix:
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
include:
|
|
14
|
+
- php: '8.1'
|
|
15
|
+
laravel: '^10.0'
|
|
16
|
+
testbench: '^8.0'
|
|
17
|
+
- php: '8.2'
|
|
18
|
+
laravel: '^11.0'
|
|
19
|
+
testbench: '^9.0'
|
|
20
|
+
- php: '8.3'
|
|
21
|
+
laravel: '^12.0'
|
|
22
|
+
testbench: '^10.0'
|
|
23
|
+
- php: '8.4'
|
|
24
|
+
laravel: '^12.0'
|
|
25
|
+
testbench: '^10.0'
|
|
26
|
+
- php: '8.5'
|
|
27
|
+
laravel: '^13.0'
|
|
28
|
+
testbench: '^11.0'
|
|
29
|
+
name: Pest - PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }}
|
|
15
30
|
steps:
|
|
16
31
|
- uses: actions/checkout@v4
|
|
17
32
|
- uses: shivammathur/setup-php@v2
|
|
@@ -19,35 +34,35 @@ jobs:
|
|
|
19
34
|
php-version: ${{ matrix.php }}
|
|
20
35
|
extensions: dom, mbstring, soap, bcmath, pdo_sqlite, intl
|
|
21
36
|
coverage: pcov
|
|
22
|
-
-
|
|
23
|
-
|
|
24
|
-
composer-
|
|
37
|
+
- name: Install dependencies
|
|
38
|
+
run: |
|
|
39
|
+
composer update --no-interaction --prefer-dist --with-all-dependencies \
|
|
40
|
+
--with "laravel/framework:${{ matrix.laravel }}" \
|
|
41
|
+
--with "orchestra/testbench:${{ matrix.testbench }}"
|
|
25
42
|
- name: Run PestPHP
|
|
26
|
-
run: vendor/bin/pest --coverage
|
|
43
|
+
run: vendor/bin/pest --coverage-clover test-results/pest.xml
|
|
27
44
|
env:
|
|
28
45
|
AWS_ACCESS_KEY_ID: fake
|
|
29
46
|
AWS_SECRET_ACCESS_KEY: fake
|
|
30
47
|
AWS_SESSION_TOKEN: fake
|
|
31
48
|
- name: Upload coverage to Codecov
|
|
32
49
|
if: always()
|
|
33
|
-
uses: codecov/codecov-action@
|
|
50
|
+
uses: codecov/codecov-action@v4
|
|
34
51
|
with:
|
|
35
52
|
token: ${{ secrets.CODECOV_TOKEN }}
|
|
36
53
|
flags: pest-${{ matrix.php }}
|
|
37
|
-
|
|
54
|
+
files: test-results/pest.xml
|
|
38
55
|
|
|
39
56
|
larastan:
|
|
40
57
|
runs-on: ubuntu-latest
|
|
41
58
|
name: Larastan
|
|
42
59
|
steps:
|
|
43
|
-
- uses: actions/checkout@
|
|
60
|
+
- uses: actions/checkout@v4
|
|
44
61
|
- uses: shivammathur/setup-php@v2
|
|
45
62
|
with:
|
|
46
|
-
php-version:
|
|
63
|
+
php-version: '8.4'
|
|
47
64
|
extensions: soap, bcmath, pdo_sqlite, intl
|
|
48
|
-
- uses: ramsey/composer-install@
|
|
49
|
-
with:
|
|
50
|
-
composer-options: "--prefer-dist --optimize-autoloader --ignore-platform-reqs"
|
|
65
|
+
- uses: ramsey/composer-install@v3
|
|
51
66
|
- name: Run Larastan
|
|
52
67
|
run: vendor/bin/phpstan analyse --no-progress
|
|
53
68
|
|
|
@@ -55,49 +70,38 @@ jobs:
|
|
|
55
70
|
runs-on: ubuntu-latest
|
|
56
71
|
name: ESLint
|
|
57
72
|
steps:
|
|
58
|
-
- uses: actions/checkout@
|
|
73
|
+
- uses: actions/checkout@v4
|
|
74
|
+
- uses: actions/setup-node@v4
|
|
75
|
+
with:
|
|
76
|
+
node-version: '22'
|
|
59
77
|
- name: Install dependencies
|
|
60
|
-
run: npm
|
|
78
|
+
run: npm ci
|
|
61
79
|
- name: Run ESLint
|
|
62
80
|
run: npm run lint
|
|
63
81
|
|
|
64
82
|
jest:
|
|
65
83
|
runs-on: ubuntu-latest
|
|
66
|
-
|
|
84
|
+
strategy:
|
|
85
|
+
fail-fast: false
|
|
86
|
+
matrix:
|
|
87
|
+
node: ['18', '20', '22']
|
|
88
|
+
# The suite runs every test against laravel-echo v1 (aliased as laravel-echo-v1) and v2.
|
|
89
|
+
name: Jest - Node ${{ matrix.node }}
|
|
67
90
|
steps:
|
|
68
|
-
- uses: actions/checkout@
|
|
69
|
-
- uses: actions/setup-node@
|
|
91
|
+
- uses: actions/checkout@v4
|
|
92
|
+
- uses: actions/setup-node@v4
|
|
70
93
|
with:
|
|
71
|
-
node-version:
|
|
94
|
+
node-version: ${{ matrix.node }}
|
|
72
95
|
- name: Install dependencies
|
|
73
|
-
run: npm
|
|
96
|
+
run: npm ci
|
|
97
|
+
- name: Build
|
|
98
|
+
run: npm run build
|
|
74
99
|
- name: Run Jest
|
|
75
|
-
run: npm
|
|
100
|
+
run: npm test -- --coverage --coverageDirectory=test-results/jest
|
|
76
101
|
- name: Upload coverage to Codecov
|
|
77
102
|
if: always()
|
|
78
|
-
uses: codecov/codecov-action@
|
|
103
|
+
uses: codecov/codecov-action@v4
|
|
79
104
|
with:
|
|
80
105
|
token: ${{ secrets.CODECOV_TOKEN }}
|
|
81
106
|
flags: jest
|
|
82
|
-
|
|
83
|
-
# phpcs:
|
|
84
|
-
# runs-on: ubuntu-latest
|
|
85
|
-
# name: PHP Style Fixer
|
|
86
|
-
# steps:
|
|
87
|
-
# - uses: actions/checkout@v2
|
|
88
|
-
# - uses: shivammathur/setup-php@v2
|
|
89
|
-
# with:
|
|
90
|
-
# php-version: '7.4'
|
|
91
|
-
# extensions: soap, bcmath, pdo_sqlite
|
|
92
|
-
# - name: Get Composer Cache Directory
|
|
93
|
-
# id: composer-cache
|
|
94
|
-
# run: echo "::set-output name=dir::$(composer config cache-files-dir)"
|
|
95
|
-
# - uses: actions/cache@v2
|
|
96
|
-
# with:
|
|
97
|
-
# path: ${{ steps.composer-cache.outputs.dir }}
|
|
98
|
-
# key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
|
|
99
|
-
# restore-keys: ${{ runner.os }}-composer-
|
|
100
|
-
# - name: Install Composer dependencies
|
|
101
|
-
# run: composer install --no-interaction --no-progress --prefer-dist --optimize-autoloader --ignore-platform-reqs
|
|
102
|
-
# - name: Run PHP-CS-Fixer
|
|
103
|
-
# run: vendor/bin/php-cs-fixer fix --dry-run --diff --allow-risky=yes
|
|
107
|
+
files: test-results/jest/clover.xml
|
package/README.md
CHANGED
|
@@ -18,10 +18,11 @@ though the latter one involves some manual set-up.
|
|
|
18
18
|
In order to use this package, your project needs to meet the following criteria:
|
|
19
19
|
|
|
20
20
|
- PHP 8.x
|
|
21
|
-
- Laravel 6 to
|
|
21
|
+
- Laravel 6 to 13
|
|
22
22
|
- Uses either [bref](https://bref.sh) or [Laravel Vapor](https://vapor.laravel.com) to deploy to AWS
|
|
23
23
|
- Has a working queue
|
|
24
|
-
- Uses
|
|
24
|
+
- Uses [laravel-echo](https://github.com/laravel/echo) v1.10+ or v2 on the client
|
|
25
|
+
- Uses Vite, Laravel Mix or any other tool to bundle your assets (or Node.js 18+ for non-browser clients)
|
|
25
26
|
|
|
26
27
|
## Installation
|
|
27
28
|
|
|
@@ -32,11 +33,11 @@ First we have to install both the composer and npm package:
|
|
|
32
33
|
```shell
|
|
33
34
|
composer require georgeboot/laravel-echo-api-gateway
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
# or
|
|
37
|
-
npm install --save-dev laravel-echo-api-gateway
|
|
36
|
+
npm install --save-dev laravel-echo laravel-echo-api-gateway
|
|
38
37
|
```
|
|
39
38
|
|
|
39
|
+
`laravel-echo` is a peer dependency: the package works with the version your app already uses (v1.10+ or v2).
|
|
40
|
+
|
|
40
41
|
### Platform-specific instructions
|
|
41
42
|
|
|
42
43
|
#### A. When using Bref
|
|
@@ -51,8 +52,7 @@ functions:
|
|
|
51
52
|
# Add this function
|
|
52
53
|
websocket:
|
|
53
54
|
handler: handlers/websocket.php
|
|
54
|
-
|
|
55
|
-
- ${bref:layer.php-80}
|
|
55
|
+
runtime: php-83
|
|
56
56
|
events:
|
|
57
57
|
- websocket: $disconnect
|
|
58
58
|
- websocket: $default
|
|
@@ -122,6 +122,8 @@ provider:
|
|
|
122
122
|
LARAVEL_ECHO_API_GATEWAY_DYNAMODB_TABLE: !Ref ConnectionsTable
|
|
123
123
|
LARAVEL_ECHO_API_GATEWAY_API_ID: !Ref WebsocketsApi
|
|
124
124
|
LARAVEL_ECHO_API_GATEWAY_API_STAGE: "${self:provider.stage}"
|
|
125
|
+
# Optional, see "Signing secret" below
|
|
126
|
+
LARAVEL_ECHO_API_GATEWAY_SECRET: ${ssm:/my-app/echo-api-gateway-secret}
|
|
125
127
|
```
|
|
126
128
|
|
|
127
129
|
Next, create the PHP handler file in `handlers/websocket.php`
|
|
@@ -180,38 +182,112 @@ BROADCAST_DRIVER=laravel-echo-api-gateway
|
|
|
180
182
|
LARAVEL_ECHO_API_GATEWAY_DYNAMODB_TABLE=the-table-name-you-entered-when-creating-it
|
|
181
183
|
LARAVEL_ECHO_API_GATEWAY_API_ID=your-websocket-api-id
|
|
182
184
|
LARAVEL_ECHO_API_GATEWAY_API_STAGE=your-api-stage-name
|
|
185
|
+
# Optional, see "Signing secret" below
|
|
186
|
+
LARAVEL_ECHO_API_GATEWAY_SECRET=a-long-random-string
|
|
183
187
|
```
|
|
184
188
|
|
|
189
|
+
### Signing secret
|
|
190
|
+
|
|
191
|
+
Private and presence channels are authorized by your app (`/broadcasting/auth`), which signs the socket id and channel
|
|
192
|
+
name. The websocket handler verifies that signature before subscribing the connection. By default both use your
|
|
193
|
+
`APP_KEY`. If the websocket handler runs as a separate app, set the same `LARAVEL_ECHO_API_GATEWAY_SECRET` on both
|
|
194
|
+
instead of sharing your `APP_KEY`.
|
|
195
|
+
|
|
185
196
|
### Generate front-end code
|
|
186
197
|
|
|
187
198
|
Add to your javascript file:
|
|
188
199
|
|
|
189
200
|
```js
|
|
190
201
|
import Echo from 'laravel-echo';
|
|
191
|
-
import {
|
|
202
|
+
import { Connector } from 'laravel-echo-api-gateway';
|
|
192
203
|
|
|
193
204
|
window.Echo = new Echo({
|
|
194
|
-
broadcaster,
|
|
205
|
+
broadcaster: Connector,
|
|
195
206
|
// replace the placeholders
|
|
196
|
-
host: 'wss://{api-
|
|
207
|
+
host: 'wss://{api-id}.execute-api.{region}.amazonaws.com/{stage}',
|
|
197
208
|
authEndpoint: '{auth-url}/broadcasting/auth', // Optional: Use if you have a separate authentication endpoint
|
|
198
209
|
bearerToken: '{token}', // Optional: Use if you need a Bearer Token for authentication
|
|
199
210
|
});
|
|
200
211
|
```
|
|
201
212
|
|
|
202
|
-
|
|
213
|
+
The `broadcaster` export from previous versions keeps working: `new Echo({ broadcaster, ... })`.
|
|
214
|
+
|
|
215
|
+
With TypeScript and laravel-echo v2, its typings do not accept custom connector classes yet, so cast the option:
|
|
216
|
+
`broadcaster: Connector as any`.
|
|
217
|
+
|
|
218
|
+
#### Using `@laravel/echo-react` or `@laravel/echo-vue`
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
import { configureEcho } from '@laravel/echo-react';
|
|
222
|
+
import { Connector } from 'laravel-echo-api-gateway';
|
|
223
|
+
|
|
224
|
+
configureEcho({
|
|
225
|
+
broadcaster: Connector as any,
|
|
226
|
+
host: import.meta.env.VITE_ECHO_API_GATEWAY_HOST,
|
|
227
|
+
});
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
#### Using it outside the browser (Node.js, Electron)
|
|
231
|
+
|
|
232
|
+
The connector only needs the global `WebSocket` and `fetch`, available in Node.js 22+ (or 18+ with a `WebSocket`
|
|
233
|
+
polyfill such as [ws](https://github.com/websockets/ws) assigned to `globalThis.WebSocket`).
|
|
234
|
+
|
|
235
|
+
To authorize private channels with your own logic, pass a custom handler. It receives the socket id and channel name
|
|
236
|
+
and must call back with the response of your `/broadcasting/auth` endpoint:
|
|
237
|
+
|
|
203
238
|
```js
|
|
204
|
-
|
|
205
|
-
|
|
239
|
+
const echo = new Echo({
|
|
240
|
+
broadcaster: Connector,
|
|
241
|
+
host: 'wss://{api-id}.execute-api.{region}.amazonaws.com/{stage}',
|
|
242
|
+
channelAuthorization: {
|
|
243
|
+
customHandler: ({ socketId, channelName }, callback) => {
|
|
244
|
+
fetch('https://my-app.test/api/broadcasting/auth', {
|
|
245
|
+
method: 'POST',
|
|
246
|
+
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
|
|
247
|
+
body: JSON.stringify({ socket_id: socketId, channel_name: channelName }),
|
|
248
|
+
})
|
|
249
|
+
.then((response) => response.json())
|
|
250
|
+
.then((data) => callback(null, data))
|
|
251
|
+
.catch((error) => callback(error, null));
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
});
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
You can also pass `channelAuthorization: { endpoint, headers }` to only change the endpoint or add headers.
|
|
258
|
+
Authorization failures and rejected subscriptions are reported to `channel.error(callback)`.
|
|
259
|
+
|
|
260
|
+
#### Options
|
|
206
261
|
|
|
262
|
+
| Option | Default | Description |
|
|
263
|
+
| --- | --- | --- |
|
|
264
|
+
| `host` | | The websocket URL of your API Gateway stage. |
|
|
265
|
+
| `authEndpoint` | `/broadcasting/auth` | Endpoint used to authorize private and presence channels. |
|
|
266
|
+
| `bearerToken` | | Sent as `Authorization: Bearer ...` to the auth endpoint. |
|
|
267
|
+
| `auth.headers` | `{}` | Extra headers sent to the auth endpoint. |
|
|
268
|
+
| `channelAuthorization` | | `{ endpoint, headers, customHandler }`, see above. |
|
|
269
|
+
| `pingInterval` | `60000` | Milliseconds between keep-alive pings. API Gateway closes idle connections after 10 minutes. |
|
|
270
|
+
| `reconnectDelay` | `1000` | Milliseconds before the first reconnect attempt. Later attempts back off exponentially. |
|
|
271
|
+
| `maxReconnectDelay` | `30000` | Upper bound for the reconnect delay. |
|
|
272
|
+
| `debug` | `false` | Log connection activity to the console. |
|
|
273
|
+
|
|
274
|
+
API Gateway closes every websocket connection after 2 hours. The connector reconnects automatically and subscribes
|
|
275
|
+
again to every channel you joined, so your listeners keep receiving events.
|
|
276
|
+
|
|
277
|
+
You can also enable console output by passing a `debug: true` option to your Echo initializer:
|
|
278
|
+
|
|
279
|
+
```js
|
|
207
280
|
window.Echo = new Echo({
|
|
208
|
-
broadcaster,
|
|
209
|
-
|
|
210
|
-
host: 'wss://{api-ip}.execute-api.{region}.amazonaws.com/{stage}',
|
|
281
|
+
broadcaster: Connector,
|
|
282
|
+
host: 'wss://{api-id}.execute-api.{region}.amazonaws.com/{stage}',
|
|
211
283
|
debug: true
|
|
212
284
|
});
|
|
213
285
|
```
|
|
214
286
|
|
|
287
|
+
Lastly, build your assets (for example with Vite or Laravel Mix). After this step, you should be up and running.
|
|
215
288
|
|
|
289
|
+
### Limitations
|
|
216
290
|
|
|
217
|
-
|
|
291
|
+
- Presence channels can be joined, but member tracking (`here`, `joining`, `leaving`) is not implemented yet.
|
|
292
|
+
- Client events (whispers) can only be sent by connections subscribed to the private or presence channel, like Pusher.
|
|
293
|
+
- Encrypted private channels are not supported.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { EventFormatter } from "./EventFormatter";
|
|
2
|
+
import { Websocket } from "./Websocket";
|
|
3
|
+
import type { Options } from "./Websocket";
|
|
4
|
+
/**
|
|
5
|
+
* A channel on the API Gateway websocket. It implements the public, private and presence channel
|
|
6
|
+
* interfaces of laravel-echo (v1 and v2) without extending its internal classes.
|
|
7
|
+
*/
|
|
8
|
+
export declare class Channel {
|
|
9
|
+
/**
|
|
10
|
+
* The websocket connection.
|
|
11
|
+
*/
|
|
12
|
+
socket: Websocket;
|
|
13
|
+
/**
|
|
14
|
+
* The name of the channel.
|
|
15
|
+
*/
|
|
16
|
+
name: string;
|
|
17
|
+
/**
|
|
18
|
+
* Channel options.
|
|
19
|
+
*/
|
|
20
|
+
options: Options;
|
|
21
|
+
/**
|
|
22
|
+
* The event formatter.
|
|
23
|
+
*/
|
|
24
|
+
eventFormatter: EventFormatter;
|
|
25
|
+
/**
|
|
26
|
+
* Create a new class instance.
|
|
27
|
+
*/
|
|
28
|
+
constructor(socket: Websocket, name: string, options: Options);
|
|
29
|
+
/**
|
|
30
|
+
* Subscribe to the channel.
|
|
31
|
+
*/
|
|
32
|
+
subscribe(): void;
|
|
33
|
+
/**
|
|
34
|
+
* Unsubscribe from the channel.
|
|
35
|
+
*/
|
|
36
|
+
unsubscribe(): void;
|
|
37
|
+
/**
|
|
38
|
+
* Listen for an event on the channel instance.
|
|
39
|
+
*/
|
|
40
|
+
listen(event: string, callback: Function): this;
|
|
41
|
+
/**
|
|
42
|
+
* Stop listening for an event on the channel instance. Without a callback, every listener of the event is removed.
|
|
43
|
+
*/
|
|
44
|
+
stopListening(event: string, callback?: Function): this;
|
|
45
|
+
/**
|
|
46
|
+
* Listen for a whisper event on the channel instance.
|
|
47
|
+
*/
|
|
48
|
+
listenForWhisper(event: string, callback: Function): this;
|
|
49
|
+
/**
|
|
50
|
+
* Stop listening for a whisper event on the channel instance.
|
|
51
|
+
*/
|
|
52
|
+
stopListeningForWhisper(event: string, callback?: Function): this;
|
|
53
|
+
/**
|
|
54
|
+
* Listen for an event on the channel instance.
|
|
55
|
+
*/
|
|
56
|
+
notification(callback: Function): this;
|
|
57
|
+
/**
|
|
58
|
+
* Stop listening for notification events on the channel instance.
|
|
59
|
+
*/
|
|
60
|
+
stopListeningForNotification(callback?: Function): this;
|
|
61
|
+
/**
|
|
62
|
+
* Register a callback to be called anytime a subscription succeeds.
|
|
63
|
+
*/
|
|
64
|
+
subscribed(callback: Function): this;
|
|
65
|
+
/**
|
|
66
|
+
* Register a callback to be called anytime a subscription or authorization error occurs.
|
|
67
|
+
*/
|
|
68
|
+
error(callback: Function): this;
|
|
69
|
+
/**
|
|
70
|
+
* Bind a channel to an event.
|
|
71
|
+
*/
|
|
72
|
+
on(event: string, callback: Function): this;
|
|
73
|
+
/**
|
|
74
|
+
* Send a client event to the other members of the channel.
|
|
75
|
+
*/
|
|
76
|
+
whisper(event: string, data: unknown): this;
|
|
77
|
+
/**
|
|
78
|
+
* Presence channels are not supported yet: member tracking is not implemented on the server.
|
|
79
|
+
*/
|
|
80
|
+
here(_callback: Function): this;
|
|
81
|
+
/**
|
|
82
|
+
* Presence channels are not supported yet: member tracking is not implemented on the server.
|
|
83
|
+
*/
|
|
84
|
+
joining(_callback: Function): this;
|
|
85
|
+
/**
|
|
86
|
+
* Presence channels are not supported yet: member tracking is not implemented on the server.
|
|
87
|
+
*/
|
|
88
|
+
leaving(_callback: Function): this;
|
|
89
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { Websocket } from "./Websocket";
|
|
2
|
+
import type { Options } from "./Websocket";
|
|
3
|
+
import { Channel } from "./Channel";
|
|
4
|
+
export { Channel };
|
|
5
|
+
export { EventFormatter } from "./EventFormatter";
|
|
6
|
+
export type { AuthorizationData, AuthorizationError, ChannelAuthorization, Options } from "./Websocket";
|
|
7
|
+
/**
|
|
8
|
+
* Laravel Echo connector for API Gateway websockets.
|
|
9
|
+
*
|
|
10
|
+
* It does not extend laravel-echo's internal classes, so it works with laravel-echo v1 and v2:
|
|
11
|
+
* both create custom connectors with `new options.broadcaster(options)`.
|
|
12
|
+
*/
|
|
13
|
+
export declare class Connector {
|
|
14
|
+
/**
|
|
15
|
+
* Default connector options, matching laravel-echo's defaults.
|
|
16
|
+
*/
|
|
17
|
+
static readonly _defaultOptions: {
|
|
18
|
+
auth: {
|
|
19
|
+
headers: {};
|
|
20
|
+
};
|
|
21
|
+
authEndpoint: string;
|
|
22
|
+
csrfToken: any;
|
|
23
|
+
bearerToken: any;
|
|
24
|
+
host: any;
|
|
25
|
+
namespace: string;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Connector options.
|
|
29
|
+
*/
|
|
30
|
+
options: Options;
|
|
31
|
+
socket: Websocket;
|
|
32
|
+
/**
|
|
33
|
+
* All of the subscribed channel names.
|
|
34
|
+
*/
|
|
35
|
+
channels: {
|
|
36
|
+
[name: string]: Channel;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Create a new class instance. Without a host no connection is opened, which keeps
|
|
40
|
+
* laravel-echo v2's `new broadcaster()` capability check free of side effects.
|
|
41
|
+
*/
|
|
42
|
+
constructor(options?: Options);
|
|
43
|
+
/**
|
|
44
|
+
* Merge the custom options with the defaults and add the CSRF and bearer token headers.
|
|
45
|
+
*/
|
|
46
|
+
protected setOptions(options: Options): void;
|
|
47
|
+
/**
|
|
48
|
+
* Extract the CSRF token from the page.
|
|
49
|
+
*/
|
|
50
|
+
protected csrfToken(): string | null;
|
|
51
|
+
/**
|
|
52
|
+
* Create a fresh websocket connection.
|
|
53
|
+
*/
|
|
54
|
+
connect(): void;
|
|
55
|
+
/**
|
|
56
|
+
* Listen for an event on a channel instance.
|
|
57
|
+
*/
|
|
58
|
+
listen(name: string, event: string, callback: Function): Channel;
|
|
59
|
+
/**
|
|
60
|
+
* Get a channel instance by name.
|
|
61
|
+
*/
|
|
62
|
+
channel(name: string): Channel;
|
|
63
|
+
/**
|
|
64
|
+
* Get a private channel instance by name.
|
|
65
|
+
*/
|
|
66
|
+
privateChannel(name: string): Channel;
|
|
67
|
+
/**
|
|
68
|
+
* Get a presence channel instance by name.
|
|
69
|
+
*/
|
|
70
|
+
presenceChannel(name: string): Channel;
|
|
71
|
+
/**
|
|
72
|
+
* Leave the given channel, as well as its private and presence variants.
|
|
73
|
+
*/
|
|
74
|
+
leave(name: string): void;
|
|
75
|
+
/**
|
|
76
|
+
* Leave the given channel.
|
|
77
|
+
*/
|
|
78
|
+
leaveChannel(name: string): void;
|
|
79
|
+
/**
|
|
80
|
+
* Get the socket ID for the connection.
|
|
81
|
+
*/
|
|
82
|
+
socketId(): string | undefined;
|
|
83
|
+
/**
|
|
84
|
+
* Disconnect socket connection.
|
|
85
|
+
*/
|
|
86
|
+
disconnect(): void;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Kept for backwards compatibility: `new Echo({ broadcaster })`. A function declaration (not an arrow
|
|
90
|
+
* function) so laravel-echo can call it with `new`.
|
|
91
|
+
*/
|
|
92
|
+
export declare function broadcaster(options?: Options): Connector;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formats event names the same way laravel-echo does, so `listen('OrderCreated')` matches
|
|
3
|
+
* `App\Events\OrderCreated` and `listen('.custom-name')` matches `custom-name`.
|
|
4
|
+
*/
|
|
5
|
+
export declare class EventFormatter {
|
|
6
|
+
private namespace;
|
|
7
|
+
constructor(namespace: string | false);
|
|
8
|
+
format(event: string): string;
|
|
9
|
+
setNamespace(namespace: string | false): void;
|
|
10
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { Channel } from "./Channel";
|
|
2
|
+
export type ChannelAuthorizationCallback = (error: unknown, data: AuthorizationData | null) => void;
|
|
3
|
+
export type ChannelAuthorization = {
|
|
4
|
+
endpoint?: string;
|
|
5
|
+
headers?: Record<string, string>;
|
|
6
|
+
customHandler?: (params: {
|
|
7
|
+
socketId: string;
|
|
8
|
+
channelName: string;
|
|
9
|
+
}, callback: ChannelAuthorizationCallback) => void;
|
|
10
|
+
};
|
|
11
|
+
export type Options = {
|
|
12
|
+
host?: string;
|
|
13
|
+
authEndpoint?: string;
|
|
14
|
+
auth?: {
|
|
15
|
+
headers: Record<string, string>;
|
|
16
|
+
};
|
|
17
|
+
channelAuthorization?: ChannelAuthorization;
|
|
18
|
+
bearerToken?: string | null;
|
|
19
|
+
csrfToken?: string | null;
|
|
20
|
+
namespace?: string | false;
|
|
21
|
+
debug?: boolean;
|
|
22
|
+
/** Milliseconds between keep-alive pings. API Gateway closes idle connections after 10 minutes. */
|
|
23
|
+
pingInterval?: number;
|
|
24
|
+
/** Milliseconds to wait before the first reconnect attempt. Later attempts back off exponentially. */
|
|
25
|
+
reconnectDelay?: number;
|
|
26
|
+
/** Upper bound for the reconnect delay, in milliseconds. */
|
|
27
|
+
maxReconnectDelay?: number;
|
|
28
|
+
[key: string]: any;
|
|
29
|
+
};
|
|
30
|
+
export type MessageBody = {
|
|
31
|
+
event: string;
|
|
32
|
+
channel?: string;
|
|
33
|
+
data?: any;
|
|
34
|
+
};
|
|
35
|
+
export type AuthorizationData = {
|
|
36
|
+
auth: string;
|
|
37
|
+
channel_data?: string;
|
|
38
|
+
};
|
|
39
|
+
export type AuthorizationError = {
|
|
40
|
+
type: 'AuthError';
|
|
41
|
+
status: number | null;
|
|
42
|
+
error: unknown;
|
|
43
|
+
};
|
|
44
|
+
export declare class Websocket {
|
|
45
|
+
options: Options;
|
|
46
|
+
websocket: WebSocket | undefined;
|
|
47
|
+
private buffer;
|
|
48
|
+
/**
|
|
49
|
+
* Every channel that should be subscribed, re-subscribed each time a new connection is identified.
|
|
50
|
+
*/
|
|
51
|
+
private channels;
|
|
52
|
+
private listeners;
|
|
53
|
+
private socketId;
|
|
54
|
+
private closing;
|
|
55
|
+
private reconnectAttempts;
|
|
56
|
+
private reconnectTimer;
|
|
57
|
+
private pingTimer;
|
|
58
|
+
constructor(options: Options);
|
|
59
|
+
private connect;
|
|
60
|
+
private scheduleReconnect;
|
|
61
|
+
private startPing;
|
|
62
|
+
private stopPing;
|
|
63
|
+
private handleMessage;
|
|
64
|
+
private dispatch;
|
|
65
|
+
protected parseMessage(body: string): MessageBody | undefined;
|
|
66
|
+
getSocketId(): string | undefined;
|
|
67
|
+
private socketIsReady;
|
|
68
|
+
send(message: MessageBody): void;
|
|
69
|
+
close(): void;
|
|
70
|
+
subscribe(channel: Channel): void;
|
|
71
|
+
private actuallySubscribe;
|
|
72
|
+
private authorize;
|
|
73
|
+
private authorizationError;
|
|
74
|
+
unsubscribe(channel: Channel): void;
|
|
75
|
+
bind(channel: Channel, event: string, callback: Function): void;
|
|
76
|
+
unbind(channel: Channel, event: string, callback?: Function): void;
|
|
77
|
+
private debug;
|
|
78
|
+
}
|