@socket-mesh/client 18.1.5 → 19.0.0
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/dist/client-auth-engine.d.ts +7 -7
- package/dist/client-auth-engine.js +15 -12
- package/dist/client-channels.d.ts +13 -12
- package/dist/client-channels.js +80 -75
- package/dist/client-socket-options.d.ts +17 -15
- package/dist/client-socket-options.js +13 -1
- package/dist/client-socket.d.ts +56 -11
- package/dist/client-socket.js +35 -18
- package/dist/client-transport.d.ts +18 -28
- package/dist/client-transport.js +74 -66
- package/dist/handlers/index.d.ts +4 -4
- package/dist/handlers/index.js +4 -4
- package/dist/handlers/kickout.d.ts +6 -7
- package/dist/handlers/kickout.js +1 -3
- package/dist/handlers/publish.d.ts +5 -7
- package/dist/handlers/publish.js +1 -1
- package/dist/handlers/remove-auth-token.d.ts +1 -1
- package/dist/handlers/set-auth-token.d.ts +3 -3
- package/dist/handlers/set-auth-token.js +1 -1
- package/dist/index.d.ts +8 -8
- package/dist/index.js +8 -8
- package/dist/maps/client-map.d.ts +8 -8
- package/dist/maps/index.d.ts +2 -2
- package/dist/maps/index.js +2 -2
- package/dist/maps/server-map.d.ts +11 -11
- package/dist/plugins/batching-plugin.d.ts +20 -22
- package/dist/plugins/batching-plugin.js +41 -22
- package/dist/plugins/in-order-plugin.d.ts +6 -6
- package/dist/plugins/in-order-plugin.js +31 -28
- package/dist/plugins/index.d.ts +3 -3
- package/dist/plugins/index.js +3 -3
- package/dist/plugins/offline-plugin.d.ts +7 -7
- package/dist/plugins/offline-plugin.js +29 -23
- package/package.json +30 -28
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import { SignedAuthToken } from
|
|
1
|
+
import { SignedAuthToken } from '@socket-mesh/auth';
|
|
2
2
|
export interface ClientAuthEngine {
|
|
3
|
+
loadToken(): Promise<null | SignedAuthToken>;
|
|
4
|
+
removeToken(): Promise<null | SignedAuthToken>;
|
|
3
5
|
saveToken(token: SignedAuthToken, options?: {
|
|
4
6
|
[key: string]: any;
|
|
5
7
|
}): Promise<SignedAuthToken>;
|
|
6
|
-
removeToken(): Promise<SignedAuthToken>;
|
|
7
|
-
loadToken(): Promise<SignedAuthToken | null>;
|
|
8
8
|
}
|
|
9
|
-
export declare function isAuthEngine(auth: ClientAuthEngine | LocalStorageAuthEngineOptions): auth is ClientAuthEngine;
|
|
10
9
|
export interface LocalStorageAuthEngineOptions {
|
|
11
10
|
authTokenName?: string;
|
|
12
11
|
}
|
|
12
|
+
export declare function isAuthEngine(auth?: ClientAuthEngine | LocalStorageAuthEngineOptions | null): auth is ClientAuthEngine;
|
|
13
13
|
export declare class LocalStorageAuthEngine implements ClientAuthEngine {
|
|
14
14
|
private readonly _authTokenName;
|
|
15
15
|
private readonly _internalStorage;
|
|
16
16
|
readonly isLocalStorageEnabled: boolean;
|
|
17
17
|
constructor({ authTokenName }?: LocalStorageAuthEngineOptions);
|
|
18
|
-
private
|
|
18
|
+
private checkLocalStorageEnabled;
|
|
19
|
+
loadToken(): Promise<null | SignedAuthToken>;
|
|
20
|
+
removeToken(): Promise<null | SignedAuthToken>;
|
|
19
21
|
saveToken(token: string): Promise<SignedAuthToken>;
|
|
20
|
-
removeToken(): Promise<SignedAuthToken>;
|
|
21
|
-
loadToken(): Promise<SignedAuthToken>;
|
|
22
22
|
}
|
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
export function isAuthEngine(auth) {
|
|
2
|
-
return (typeof auth === 'object' && 'saveToken' in auth && 'removeToken' in auth && 'loadToken' in auth);
|
|
2
|
+
return (!!auth && typeof auth === 'object' && 'saveToken' in auth && 'removeToken' in auth && 'loadToken' in auth);
|
|
3
3
|
}
|
|
4
4
|
export class LocalStorageAuthEngine {
|
|
5
|
+
_authTokenName;
|
|
6
|
+
_internalStorage;
|
|
7
|
+
isLocalStorageEnabled;
|
|
5
8
|
constructor({ authTokenName } = {}) {
|
|
6
9
|
this._internalStorage = {};
|
|
7
|
-
this.isLocalStorageEnabled = this.
|
|
10
|
+
this.isLocalStorageEnabled = this.checkLocalStorageEnabled();
|
|
8
11
|
this._authTokenName = authTokenName ?? 'socketmesh.authToken';
|
|
9
12
|
}
|
|
10
|
-
|
|
13
|
+
checkLocalStorageEnabled() {
|
|
11
14
|
let err;
|
|
12
15
|
try {
|
|
13
16
|
// Safari, in Private Browsing Mode, looks like it supports localStorage but all calls to setItem
|
|
14
17
|
// throw QuotaExceededError. We're going to detect this and avoid hard to debug edge cases.
|
|
15
|
-
localStorage.setItem('__localStorageTest',
|
|
18
|
+
localStorage.setItem('__localStorageTest', '1');
|
|
16
19
|
localStorage.removeItem('__localStorageTest');
|
|
17
20
|
}
|
|
18
21
|
catch (e) {
|
|
@@ -20,17 +23,18 @@ export class LocalStorageAuthEngine {
|
|
|
20
23
|
}
|
|
21
24
|
return !err;
|
|
22
25
|
}
|
|
23
|
-
async
|
|
26
|
+
async loadToken() {
|
|
27
|
+
let token;
|
|
24
28
|
if (this.isLocalStorageEnabled) {
|
|
25
|
-
localStorage.
|
|
29
|
+
token = localStorage.getItem(this._authTokenName);
|
|
26
30
|
}
|
|
27
31
|
else {
|
|
28
|
-
this._internalStorage[this._authTokenName]
|
|
32
|
+
token = this._internalStorage[this._authTokenName] || null;
|
|
29
33
|
}
|
|
30
34
|
return token;
|
|
31
35
|
}
|
|
32
36
|
async removeToken() {
|
|
33
|
-
|
|
37
|
+
const loadPromise = this.loadToken();
|
|
34
38
|
if (this.isLocalStorageEnabled) {
|
|
35
39
|
localStorage.removeItem(this._authTokenName);
|
|
36
40
|
}
|
|
@@ -39,13 +43,12 @@ export class LocalStorageAuthEngine {
|
|
|
39
43
|
}
|
|
40
44
|
return loadPromise;
|
|
41
45
|
}
|
|
42
|
-
async
|
|
43
|
-
let token;
|
|
46
|
+
async saveToken(token) {
|
|
44
47
|
if (this.isLocalStorageEnabled) {
|
|
45
|
-
|
|
48
|
+
localStorage.setItem(this._authTokenName, token);
|
|
46
49
|
}
|
|
47
50
|
else {
|
|
48
|
-
|
|
51
|
+
this._internalStorage[this._authTokenName] = token;
|
|
49
52
|
}
|
|
50
53
|
return token;
|
|
51
54
|
}
|
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
import { ChannelDetails, ChannelMap, Channels, ChannelsOptions } from
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { ChannelDetails, ChannelMap, Channels, ChannelsOptions } from '@socket-mesh/channels';
|
|
2
|
+
import { SocketTransport } from '@socket-mesh/core';
|
|
3
|
+
import { ClientTransport } from './client-transport.js';
|
|
4
|
+
import { ServerPrivateMap } from './maps/server-map.js';
|
|
4
5
|
export interface ClientChannelsOptions extends ChannelsOptions {
|
|
5
6
|
autoSubscribeOnConnect?: boolean;
|
|
6
7
|
}
|
|
7
|
-
export declare class ClientChannels<TChannel extends ChannelMap,
|
|
8
|
-
autoSubscribeOnConnect: boolean;
|
|
9
|
-
protected readonly _transport: ClientTransport<TIncoming, TService, TOutgoing, TPrivateOutgoing, TState>;
|
|
8
|
+
export declare class ClientChannels<TChannel extends ChannelMap, TState extends object = {}> extends Channels<TChannel> {
|
|
10
9
|
protected _preparingPendingSubscriptions: boolean;
|
|
11
|
-
|
|
10
|
+
protected readonly _transport: SocketTransport<{}, {}, TState, {}, {}, ServerPrivateMap>;
|
|
11
|
+
autoSubscribeOnConnect: boolean;
|
|
12
|
+
constructor(transport: ClientTransport<TState>, options?: ClientChannelsOptions);
|
|
13
|
+
invokePublish<U extends keyof TChannel & string>(channelName: keyof TChannel & string, data: TChannel[U]): Promise<void>;
|
|
14
|
+
private processPendingSubscriptions;
|
|
12
15
|
private suspendSubscriptions;
|
|
16
|
+
transmitPublish<U extends keyof TChannel & string>(channelName: U, data: TChannel[U]): Promise<void>;
|
|
17
|
+
private triggerChannelSubscribeFail;
|
|
13
18
|
protected trySubscribe(channel: ChannelDetails): void;
|
|
14
|
-
private processPendingSubscriptions;
|
|
15
|
-
unsubscribe(channelName: keyof TChannel & string): void;
|
|
16
19
|
protected tryUnsubscribe(channel: ChannelDetails): void;
|
|
17
|
-
|
|
18
|
-
transmitPublish<U extends keyof TChannel & string>(channelName: U, data: TChannel[U]): Promise<void>;
|
|
19
|
-
invokePublish<U extends keyof TChannel & string>(channelName: keyof TChannel & string, data: TChannel[U]): Promise<void>;
|
|
20
|
+
unsubscribe(channelName: keyof TChannel & string): void;
|
|
20
21
|
}
|
package/dist/client-channels.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
import { Channels } from
|
|
1
|
+
import { Channels } from '@socket-mesh/channels';
|
|
2
|
+
import { toError } from '@socket-mesh/core';
|
|
2
3
|
export class ClientChannels extends Channels {
|
|
4
|
+
_preparingPendingSubscriptions;
|
|
5
|
+
_transport;
|
|
6
|
+
autoSubscribeOnConnect;
|
|
3
7
|
constructor(transport, options) {
|
|
4
8
|
if (!options) {
|
|
5
9
|
options = {};
|
|
@@ -9,20 +13,51 @@ export class ClientChannels extends Channels {
|
|
|
9
13
|
this._transport = transport;
|
|
10
14
|
this._preparingPendingSubscriptions = false;
|
|
11
15
|
this._transport.plugins.push({
|
|
12
|
-
type: 'channels',
|
|
13
16
|
onAuthenticated: () => {
|
|
14
17
|
if (!this._preparingPendingSubscriptions) {
|
|
15
18
|
this.processPendingSubscriptions();
|
|
16
19
|
}
|
|
17
20
|
},
|
|
21
|
+
onClose: () => {
|
|
22
|
+
this.suspendSubscriptions();
|
|
23
|
+
},
|
|
18
24
|
onReady: () => {
|
|
19
25
|
if (this.autoSubscribeOnConnect) {
|
|
20
26
|
this.processPendingSubscriptions();
|
|
21
27
|
}
|
|
22
28
|
},
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
29
|
+
type: 'channels'
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
invokePublish(channelName, data) {
|
|
33
|
+
const pubData = {
|
|
34
|
+
channel: this.decorateChannelName(channelName),
|
|
35
|
+
data
|
|
36
|
+
};
|
|
37
|
+
return this._transport.invoke('#publish', pubData)[0];
|
|
38
|
+
}
|
|
39
|
+
processPendingSubscriptions() {
|
|
40
|
+
this._preparingPendingSubscriptions = false;
|
|
41
|
+
const pendingChannels = [];
|
|
42
|
+
Object.keys(this._channelMap).forEach((channelName) => {
|
|
43
|
+
const channel = this._channelMap[channelName];
|
|
44
|
+
if (channel.state === 'pending') {
|
|
45
|
+
pendingChannels.push(channel);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
pendingChannels.sort((a, b) => {
|
|
49
|
+
const ap = a.options.priority || 0;
|
|
50
|
+
const bp = b.options.priority || 0;
|
|
51
|
+
if (ap > bp) {
|
|
52
|
+
return -1;
|
|
53
|
+
}
|
|
54
|
+
if (ap < bp) {
|
|
55
|
+
return 1;
|
|
56
|
+
}
|
|
57
|
+
return 0;
|
|
58
|
+
});
|
|
59
|
+
pendingChannels.forEach((channel) => {
|
|
60
|
+
this.trySubscribe(channel);
|
|
26
61
|
});
|
|
27
62
|
}
|
|
28
63
|
suspendSubscriptions() {
|
|
@@ -30,13 +65,37 @@ export class ClientChannels extends Channels {
|
|
|
30
65
|
this.triggerChannelUnsubscribe(this._channelMap[channel], true);
|
|
31
66
|
}
|
|
32
67
|
}
|
|
68
|
+
transmitPublish(channelName, data) {
|
|
69
|
+
const pubData = {
|
|
70
|
+
channel: this.decorateChannelName(channelName),
|
|
71
|
+
data
|
|
72
|
+
};
|
|
73
|
+
return this._transport.transmit('#publish', pubData);
|
|
74
|
+
}
|
|
75
|
+
triggerChannelSubscribeFail(err, channel, options) {
|
|
76
|
+
const hasAuthRequirements = !channel.options.waitForAuth || !!this._transport.signedAuthToken;
|
|
77
|
+
const hasChannel = !!this._channelMap[channel.name];
|
|
78
|
+
if (hasChannel && hasAuthRequirements) {
|
|
79
|
+
delete this._channelMap[channel.name];
|
|
80
|
+
this._channelEventDemux.write(`${channel.name}/subscribeFail`, {
|
|
81
|
+
channel: channel.name,
|
|
82
|
+
error: err,
|
|
83
|
+
options
|
|
84
|
+
});
|
|
85
|
+
this.emit('subscribeFail', {
|
|
86
|
+
channel: channel.name,
|
|
87
|
+
error: err,
|
|
88
|
+
options
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
33
92
|
trySubscribe(channel) {
|
|
34
|
-
const
|
|
93
|
+
const hasAuthRequirements = !channel.options.waitForAuth || !!this._transport.signedAuthToken;
|
|
35
94
|
// We can only ever have one pending subscribe action at any given time on a channel
|
|
36
|
-
if (this._transport.status === 'ready'
|
|
37
|
-
!this._preparingPendingSubscriptions
|
|
38
|
-
!channel.subscribePromise
|
|
39
|
-
|
|
95
|
+
if (this._transport.status === 'ready'
|
|
96
|
+
&& !this._preparingPendingSubscriptions
|
|
97
|
+
&& !channel.subscribePromise
|
|
98
|
+
&& hasAuthRequirements) {
|
|
40
99
|
const subscriptionOptions = {};
|
|
41
100
|
if (channel.options.waitForAuth) {
|
|
42
101
|
subscriptionOptions.waitForAuth = true;
|
|
@@ -44,7 +103,7 @@ export class ClientChannels extends Channels {
|
|
|
44
103
|
if (channel.options.data) {
|
|
45
104
|
subscriptionOptions.data = channel.options.data;
|
|
46
105
|
}
|
|
47
|
-
[channel.subscribePromise, channel.subscribeAbort] = this._transport.invoke({ method: '#subscribe'
|
|
106
|
+
[channel.subscribePromise, channel.subscribeAbort] = this._transport.invoke({ ackTimeoutMs: false, method: '#subscribe' }, {
|
|
48
107
|
channel: this.decorateChannelName(channel.name),
|
|
49
108
|
...subscriptionOptions
|
|
50
109
|
});
|
|
@@ -52,14 +111,15 @@ export class ClientChannels extends Channels {
|
|
|
52
111
|
delete channel.subscribePromise;
|
|
53
112
|
delete channel.subscribeAbort;
|
|
54
113
|
this.triggerChannelSubscribe(channel, subscriptionOptions);
|
|
55
|
-
}).catch(err => {
|
|
56
|
-
|
|
114
|
+
}).catch((err) => {
|
|
115
|
+
const error = toError(err);
|
|
116
|
+
if (error.name === 'BadConnectionError') {
|
|
57
117
|
// In case of a failed connection, keep the subscription
|
|
58
118
|
// as pending; it will try again on reconnect.
|
|
59
119
|
return;
|
|
60
120
|
}
|
|
61
|
-
if (
|
|
62
|
-
this.triggerChannelSubscribeFail(
|
|
121
|
+
if (error.name !== 'AbortError') {
|
|
122
|
+
this.triggerChannelSubscribeFail(error, channel, subscriptionOptions);
|
|
63
123
|
}
|
|
64
124
|
delete channel.subscribePromise;
|
|
65
125
|
delete channel.subscribeAbort;
|
|
@@ -70,36 +130,6 @@ export class ClientChannels extends Channels {
|
|
|
70
130
|
});
|
|
71
131
|
}
|
|
72
132
|
}
|
|
73
|
-
processPendingSubscriptions() {
|
|
74
|
-
this._preparingPendingSubscriptions = false;
|
|
75
|
-
const pendingChannels = [];
|
|
76
|
-
Object.keys(this._channelMap).forEach((channelName) => {
|
|
77
|
-
const channel = this._channelMap[channelName];
|
|
78
|
-
if (channel.state === 'pending') {
|
|
79
|
-
pendingChannels.push(channel);
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
pendingChannels.sort((a, b) => {
|
|
83
|
-
const ap = a.options.priority || 0;
|
|
84
|
-
const bp = b.options.priority || 0;
|
|
85
|
-
if (ap > bp) {
|
|
86
|
-
return -1;
|
|
87
|
-
}
|
|
88
|
-
if (ap < bp) {
|
|
89
|
-
return 1;
|
|
90
|
-
}
|
|
91
|
-
return 0;
|
|
92
|
-
});
|
|
93
|
-
pendingChannels.forEach((channel) => {
|
|
94
|
-
this.trySubscribe(channel);
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
unsubscribe(channelName) {
|
|
98
|
-
const channel = this._channelMap[channelName];
|
|
99
|
-
if (channel) {
|
|
100
|
-
this.tryUnsubscribe(channel);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
133
|
tryUnsubscribe(channel) {
|
|
104
134
|
this.triggerChannelUnsubscribe(channel);
|
|
105
135
|
if (this._transport.status === 'ready') {
|
|
@@ -112,38 +142,13 @@ export class ClientChannels extends Channels {
|
|
|
112
142
|
// the operation on the server side.
|
|
113
143
|
this._transport
|
|
114
144
|
.transmit('#unsubscribe', decoratedChannelName)
|
|
115
|
-
.catch(
|
|
145
|
+
.catch((_) => { });
|
|
116
146
|
}
|
|
117
147
|
}
|
|
118
|
-
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
delete this._channelMap[channel.name];
|
|
123
|
-
this._channelEventDemux.write(`${channel.name}/subscribeFail`, {
|
|
124
|
-
channel: channel.name,
|
|
125
|
-
error: err,
|
|
126
|
-
options
|
|
127
|
-
});
|
|
128
|
-
this.emit('subscribeFail', {
|
|
129
|
-
error: err,
|
|
130
|
-
channel: channel.name,
|
|
131
|
-
options
|
|
132
|
-
});
|
|
148
|
+
unsubscribe(channelName) {
|
|
149
|
+
const channel = this._channelMap[channelName];
|
|
150
|
+
if (channel) {
|
|
151
|
+
this.tryUnsubscribe(channel);
|
|
133
152
|
}
|
|
134
153
|
}
|
|
135
|
-
transmitPublish(channelName, data) {
|
|
136
|
-
const pubData = {
|
|
137
|
-
channel: this.decorateChannelName(channelName),
|
|
138
|
-
data
|
|
139
|
-
};
|
|
140
|
-
return this._transport.transmit('#publish', pubData);
|
|
141
|
-
}
|
|
142
|
-
invokePublish(channelName, data) {
|
|
143
|
-
const pubData = {
|
|
144
|
-
channel: this.decorateChannelName(channelName),
|
|
145
|
-
data
|
|
146
|
-
};
|
|
147
|
-
return this._transport.invoke('#publish', pubData)[0];
|
|
148
|
-
}
|
|
149
154
|
}
|
|
@@ -1,24 +1,26 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import { ClientAuthEngine, LocalStorageAuthEngineOptions } from
|
|
4
|
-
import { ClientPrivateMap } from "./maps/client-map.js";
|
|
5
|
-
import { ServerPrivateMap } from "./maps/server-map.js";
|
|
1
|
+
import { BaseSocketOptions } from '@socket-mesh/core';
|
|
2
|
+
import ws from 'isomorphic-ws';
|
|
3
|
+
import { ClientAuthEngine, LocalStorageAuthEngineOptions } from './client-auth-engine.js';
|
|
6
4
|
export interface AutoReconnectOptions {
|
|
7
5
|
initialDelay: number;
|
|
8
|
-
randomness: number;
|
|
9
|
-
multiplier: number;
|
|
10
6
|
maxDelayMs: number;
|
|
7
|
+
multiplier: number;
|
|
8
|
+
randomness: number;
|
|
9
|
+
}
|
|
10
|
+
export interface ClientSocketOptions<TState extends object = {}> extends BaseSocketOptions<TState> {
|
|
11
|
+
address: string | URL;
|
|
12
|
+
authEngine?: ClientAuthEngine | LocalStorageAuthEngineOptions | null;
|
|
13
|
+
autoConnect?: boolean;
|
|
14
|
+
autoReconnect?: boolean | Partial<AutoReconnectOptions>;
|
|
15
|
+
autoSubscribeOnConnect?: boolean;
|
|
16
|
+
channelPrefix?: string;
|
|
17
|
+
connectTimeoutMs?: number;
|
|
18
|
+
wsOptions?: ws.ClientOptions;
|
|
11
19
|
}
|
|
12
20
|
export interface ConnectOptions {
|
|
13
21
|
address?: string | URL;
|
|
14
22
|
connectTimeoutMs?: number;
|
|
15
23
|
wsOptions?: ws.ClientOptions;
|
|
16
24
|
}
|
|
17
|
-
export
|
|
18
|
-
|
|
19
|
-
authEngine?: ClientAuthEngine | LocalStorageAuthEngineOptions | null;
|
|
20
|
-
autoReconnect?: Partial<AutoReconnectOptions> | boolean;
|
|
21
|
-
autoSubscribeOnConnect?: boolean;
|
|
22
|
-
channelPrefix?: string;
|
|
23
|
-
}
|
|
24
|
-
export declare function parseClientOptions<TIncoming extends MethodMap, TService extends ServiceMap, TOutgoing extends PublicMethodMap, TPrivateOutgoing extends PrivateMethodMap, TState extends object>(options: ClientSocketOptions<TOutgoing, TService, TIncoming, TPrivateOutgoing, TState> | string | URL): ClientSocketOptions<TOutgoing, TService, TIncoming, TPrivateOutgoing, TState>;
|
|
25
|
+
export declare function parseAutoReconnectOptions(value?: boolean | Partial<AutoReconnectOptions>): AutoReconnectOptions | false;
|
|
26
|
+
export declare function parseClientOptions<TState extends object>(options: ClientSocketOptions<TState> | string | URL): ClientSocketOptions<TState>;
|
|
@@ -1,6 +1,18 @@
|
|
|
1
|
+
export function parseAutoReconnectOptions(value) {
|
|
2
|
+
if (value) {
|
|
3
|
+
return {
|
|
4
|
+
initialDelay: 10000,
|
|
5
|
+
maxDelayMs: 60000,
|
|
6
|
+
multiplier: 1.5,
|
|
7
|
+
randomness: 10000,
|
|
8
|
+
...(value === true ? {} : value)
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
1
13
|
export function parseClientOptions(options) {
|
|
2
14
|
if (typeof options === 'string' || 'pathname' in options) {
|
|
3
15
|
options = { address: options };
|
|
4
16
|
}
|
|
5
|
-
return
|
|
17
|
+
return { ...options };
|
|
6
18
|
}
|
package/dist/client-socket.d.ts
CHANGED
|
@@ -1,27 +1,72 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
1
|
+
import { SignedAuthToken } from '@socket-mesh/auth';
|
|
2
|
+
import { ChannelMap } from '@socket-mesh/channels';
|
|
3
|
+
import { AuthenticateEvent, AuthStateChangeEvent, BadAuthTokenEvent, BaseSocket, CloseEvent, ConnectEvent, ConnectingEvent, DeauthenticateEvent, DisconnectEvent, ErrorEvent, FunctionReturnType, InvokeMethodOptions, InvokeServiceOptions, MessageEvent, PingEvent, PongEvent, PrivateMethodMap, PublicMethodMap, RemoveAuthTokenEvent, RequestEvent, ResponseEvent, ServiceMap, ServiceMethodName, ServiceName, Socket, TypedRequestEvent, TypedResponseEvent, TypedSocketEvent } from '@socket-mesh/core';
|
|
4
|
+
import { DemuxedConsumableStream, StreamEvent } from '@socket-mesh/stream-demux';
|
|
5
|
+
import { ClientChannels } from './client-channels.js';
|
|
6
|
+
import { AutoReconnectOptions, ClientSocketOptions, ConnectOptions } from './client-socket-options.js';
|
|
7
|
+
import { ClientPrivateMap } from './maps/client-map.js';
|
|
8
|
+
import { ServerPrivateMap } from './maps/server-map.js';
|
|
9
|
+
export declare class ClientSocket<TIncoming extends PublicMethodMap = {}, TOutgoing extends PublicMethodMap = {}, TChannel extends ChannelMap = ChannelMap, TService extends ServiceMap = {}, TState extends object = {}, TPrivateOutgoing extends PrivateMethodMap = {}> extends BaseSocket<TState> implements Socket<TIncoming & ClientPrivateMap, TOutgoing, TState, TService, {}, TPrivateOutgoing & ServerPrivateMap> {
|
|
9
10
|
private readonly _clientTransport;
|
|
10
|
-
readonly channels: ClientChannels<TChannel,
|
|
11
|
+
readonly channels: ClientChannels<TChannel, TState>;
|
|
11
12
|
constructor(address: string | URL);
|
|
12
|
-
constructor(options: ClientSocketOptions<
|
|
13
|
+
constructor(options: ClientSocketOptions<TState>);
|
|
13
14
|
authenticate(signedAuthToken: SignedAuthToken): Promise<void>;
|
|
14
15
|
get autoReconnect(): AutoReconnectOptions | false;
|
|
15
|
-
set autoReconnect(value: Partial<AutoReconnectOptions>
|
|
16
|
+
set autoReconnect(value: boolean | Partial<AutoReconnectOptions>);
|
|
16
17
|
connect(options?: ConnectOptions): void;
|
|
17
18
|
get connectTimeoutMs(): number;
|
|
18
19
|
set connectTimeoutMs(timeoutMs: number);
|
|
19
20
|
deauthenticate(): Promise<boolean>;
|
|
21
|
+
emit(event: 'request', data: TypedRequestEvent<TIncoming & ClientPrivateMap, TService>): void;
|
|
22
|
+
emit(event: 'response', data: TypedResponseEvent<TOutgoing, TPrivateOutgoing & ServerPrivateMap, TService>): void;
|
|
23
|
+
emit(event: 'authStateChange', data: AuthStateChangeEvent): void;
|
|
24
|
+
emit(event: 'authenticate', data: AuthenticateEvent): void;
|
|
25
|
+
emit(event: 'badAuthToken', data: BadAuthTokenEvent): void;
|
|
26
|
+
emit(event: 'close', data: CloseEvent): void;
|
|
27
|
+
emit(event: 'connect', data: ConnectEvent): void;
|
|
28
|
+
emit(event: 'connectAbort', data: DisconnectEvent): void;
|
|
29
|
+
emit(event: 'connecting', data: ConnectingEvent): void;
|
|
30
|
+
emit(event: 'deauthenticate', data: DeauthenticateEvent): void;
|
|
31
|
+
emit(event: 'disconnect', data: DisconnectEvent): void;
|
|
32
|
+
emit(event: 'end'): void;
|
|
33
|
+
emit(event: 'error', data: ErrorEvent): void;
|
|
34
|
+
emit(event: 'message', data: MessageEvent): void;
|
|
35
|
+
emit(event: 'ping', data: PingEvent): void;
|
|
36
|
+
emit(event: 'pong', data: PongEvent): void;
|
|
37
|
+
emit(event: 'removeAuthToken', data: RemoveAuthTokenEvent): void;
|
|
38
|
+
emit(event: 'request', data: RequestEvent): void;
|
|
39
|
+
emit(event: 'response', data: ResponseEvent): void;
|
|
40
|
+
invoke<TMethod extends keyof TOutgoing & string>(method: TMethod, arg?: Parameters<TOutgoing[TMethod]>[0]): Promise<FunctionReturnType<TOutgoing[TMethod]>>;
|
|
41
|
+
invoke<TServiceName extends ServiceName<TService>, TMethod extends ServiceMethodName<TService, TServiceName>>(options: [TServiceName, TMethod, (false | number)?], arg?: Parameters<TService[TServiceName][TMethod]>[0]): Promise<FunctionReturnType<TService[TServiceName][TMethod]>>;
|
|
42
|
+
invoke<TServiceName extends ServiceName<TService>, TMethod extends ServiceMethodName<TService, TServiceName>>(options: InvokeServiceOptions<TService, TServiceName, TMethod>, arg?: Parameters<TService[TServiceName][TMethod]>[0]): Promise<FunctionReturnType<TService[TServiceName][TMethod]>>;
|
|
43
|
+
invoke<TMethod extends keyof TOutgoing & string>(options: InvokeMethodOptions<TOutgoing, TMethod>, arg?: Parameters<TOutgoing[TMethod]>[0]): Promise<FunctionReturnType<TOutgoing[TMethod]>>;
|
|
20
44
|
get isPingTimeoutDisabled(): boolean;
|
|
21
45
|
set isPingTimeoutDisabled(isDisabled: boolean);
|
|
46
|
+
listen(): DemuxedConsumableStream<StreamEvent<TypedSocketEvent<TIncoming & ClientPrivateMap, TOutgoing, TPrivateOutgoing & ServerPrivateMap, TService>>>;
|
|
47
|
+
listen(event: 'authStateChange'): DemuxedConsumableStream<AuthStateChangeEvent>;
|
|
48
|
+
listen(event: 'authenticate'): DemuxedConsumableStream<AuthenticateEvent>;
|
|
49
|
+
listen(event: 'badAuthToken'): DemuxedConsumableStream<BadAuthTokenEvent>;
|
|
50
|
+
listen(event: 'close'): DemuxedConsumableStream<CloseEvent>;
|
|
51
|
+
listen(event: 'connect'): DemuxedConsumableStream<ConnectEvent>;
|
|
52
|
+
listen(event: 'connectAbort'): DemuxedConsumableStream<DisconnectEvent>;
|
|
53
|
+
listen(event: 'connecting'): DemuxedConsumableStream<ConnectingEvent>;
|
|
54
|
+
listen(event: 'deauthenticate'): DemuxedConsumableStream<DeauthenticateEvent>;
|
|
55
|
+
listen(event: 'disconnect'): DemuxedConsumableStream<DisconnectEvent>;
|
|
56
|
+
listen(event: 'end'): DemuxedConsumableStream<void>;
|
|
57
|
+
listen(event: 'error'): DemuxedConsumableStream<ErrorEvent>;
|
|
58
|
+
listen(event: 'message'): DemuxedConsumableStream<MessageEvent>;
|
|
59
|
+
listen(event: 'ping'): DemuxedConsumableStream<PingEvent>;
|
|
60
|
+
listen(event: 'pong'): DemuxedConsumableStream<PongEvent>;
|
|
61
|
+
listen(event: 'removeAuthToken'): DemuxedConsumableStream<RemoveAuthTokenEvent>;
|
|
62
|
+
listen(event: 'request'): DemuxedConsumableStream<TypedRequestEvent<TIncoming & ClientPrivateMap, TService>>;
|
|
63
|
+
listen(event: 'response'): DemuxedConsumableStream<TypedResponseEvent<TOutgoing, TPrivateOutgoing & ServerPrivateMap, TService>>;
|
|
64
|
+
listen<U extends TypedSocketEvent<TIncoming & ClientPrivateMap, TOutgoing, TPrivateOutgoing & ServerPrivateMap, TService>, V = U>(event: string): DemuxedConsumableStream<V>;
|
|
22
65
|
get pingTimeoutMs(): number;
|
|
23
66
|
set pingTimeoutMs(timeoutMs: number);
|
|
24
67
|
reconnect(code?: number, reason?: string): void;
|
|
68
|
+
transmit<TMethod extends keyof TOutgoing & string>(method: TMethod, arg?: Parameters<TOutgoing[TMethod]>[0]): Promise<void>;
|
|
69
|
+
transmit<TServiceName extends ServiceName<TService>, TMethod extends ServiceMethodName<TService, TServiceName>>(options: [TServiceName, TMethod], arg?: Parameters<TService[TServiceName][TMethod]>[0]): Promise<void>;
|
|
25
70
|
get type(): 'client';
|
|
26
71
|
get uri(): URL;
|
|
27
72
|
}
|
package/dist/client-socket.js
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
export class ClientSocket extends
|
|
1
|
+
import { BaseSocket, toError, wait } from '@socket-mesh/core';
|
|
2
|
+
import { hydrateError } from '@socket-mesh/errors';
|
|
3
|
+
import { ClientChannels } from './client-channels.js';
|
|
4
|
+
import { parseClientOptions } from './client-socket-options.js';
|
|
5
|
+
import { ClientTransport } from './client-transport.js';
|
|
6
|
+
import { kickOutHandler } from './handlers/kickout.js';
|
|
7
|
+
import { publishHandler } from './handlers/publish.js';
|
|
8
|
+
import { removeAuthTokenHandler } from './handlers/remove-auth-token.js';
|
|
9
|
+
import { setAuthTokenHandler } from './handlers/set-auth-token.js';
|
|
10
|
+
export class ClientSocket extends BaseSocket {
|
|
11
|
+
_clientTransport;
|
|
12
|
+
channels;
|
|
11
13
|
constructor(options) {
|
|
12
14
|
options = parseClientOptions(options);
|
|
13
15
|
options.handlers =
|
|
14
16
|
Object.assign({
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
'#kickOut': kickOutHandler,
|
|
18
|
+
'#publish': publishHandler,
|
|
19
|
+
'#removeAuthToken': removeAuthTokenHandler,
|
|
20
|
+
'#setAuthToken': setAuthTokenHandler
|
|
19
21
|
}, options.handlers);
|
|
20
22
|
const clientTransport = new ClientTransport(options);
|
|
21
23
|
super(clientTransport, options);
|
|
@@ -33,14 +35,15 @@ export class ClientSocket extends Socket {
|
|
|
33
35
|
await wait(0);
|
|
34
36
|
}
|
|
35
37
|
catch (err) {
|
|
36
|
-
|
|
38
|
+
const error = toError(err);
|
|
39
|
+
if (error.name !== 'BadConnectionError' && error.name !== 'TimeoutError') {
|
|
37
40
|
// In case of a bad/closed connection or a timeout, we maintain the last
|
|
38
41
|
// known auth state since those errors don't mean that the token is invalid.
|
|
39
42
|
await this._clientTransport.changeToUnauthenticatedState();
|
|
40
43
|
// In order for the events to trigger we need to wait for the next tick.
|
|
41
44
|
await wait(0);
|
|
42
45
|
}
|
|
43
|
-
throw hydrateError(
|
|
46
|
+
throw hydrateError(error);
|
|
44
47
|
}
|
|
45
48
|
}
|
|
46
49
|
get autoReconnect() {
|
|
@@ -65,22 +68,33 @@ export class ClientSocket extends Socket {
|
|
|
65
68
|
oldAuthToken = await this._clientTransport.authEngine.removeToken();
|
|
66
69
|
}
|
|
67
70
|
catch (err) {
|
|
68
|
-
this._clientTransport.onError(err);
|
|
71
|
+
this._clientTransport.onError(toError(err));
|
|
69
72
|
return;
|
|
70
73
|
}
|
|
71
|
-
|
|
74
|
+
if (oldAuthToken) {
|
|
75
|
+
this.emit('removeAuthToken', { oldAuthToken });
|
|
76
|
+
}
|
|
72
77
|
})();
|
|
73
78
|
if (this.status !== 'closed') {
|
|
74
79
|
await this._clientTransport.transmit('#removeAuthToken');
|
|
75
80
|
}
|
|
76
81
|
return await super.deauthenticate();
|
|
77
82
|
}
|
|
83
|
+
emit(event, data) {
|
|
84
|
+
super.emit(event, data);
|
|
85
|
+
}
|
|
86
|
+
invoke(methodOptions, arg) {
|
|
87
|
+
return super.invoke(methodOptions, arg);
|
|
88
|
+
}
|
|
78
89
|
get isPingTimeoutDisabled() {
|
|
79
90
|
return this._clientTransport.isPingTimeoutDisabled;
|
|
80
91
|
}
|
|
81
92
|
set isPingTimeoutDisabled(isDisabled) {
|
|
82
93
|
this._clientTransport.isPingTimeoutDisabled = isDisabled;
|
|
83
94
|
}
|
|
95
|
+
listen(event) {
|
|
96
|
+
return super.listen(event ?? '');
|
|
97
|
+
}
|
|
84
98
|
get pingTimeoutMs() {
|
|
85
99
|
return this._clientTransport.pingTimeoutMs;
|
|
86
100
|
}
|
|
@@ -91,6 +105,9 @@ export class ClientSocket extends Socket {
|
|
|
91
105
|
this.disconnect(code, reason);
|
|
92
106
|
this.connect();
|
|
93
107
|
}
|
|
108
|
+
transmit(serviceAndMethod, arg) {
|
|
109
|
+
return super.transmit(serviceAndMethod, arg);
|
|
110
|
+
}
|
|
94
111
|
get type() {
|
|
95
112
|
return this._clientTransport.type;
|
|
96
113
|
}
|