@logux/server 0.12.2 → 0.12.4

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.
@@ -1,172 +1,185 @@
1
- import {
1
+ import type {
2
+ AbstractActionCreator,
3
+ LoguxSubscribeAction,
4
+ LoguxUnsubscribeAction
5
+ } from '@logux/actions'
6
+ import type {
2
7
  Action,
3
8
  AnyAction,
4
9
  ID,
5
10
  Log,
11
+ LogStore,
6
12
  Meta,
7
13
  ServerConnection,
8
- LogStore,
9
14
  TestTime
10
15
  } from '@logux/core'
11
- import { Server as HTTPServer, ServerResponse, IncomingMessage } from 'http'
12
- import {
13
- LoguxUnsubscribeAction,
14
- AbstractActionCreator,
15
- LoguxSubscribeAction
16
- } from '@logux/actions'
17
- import { Unsubscribe } from 'nanoevents'
18
- import { LogFn } from 'pino'
16
+ import type { Server as HTTPServer, IncomingMessage, ServerResponse } from 'http'
17
+ import type { Unsubscribe } from 'nanoevents'
18
+ import type { LogFn } from 'pino'
19
19
 
20
- import { Context, ChannelContext } from '../context/index.js'
21
- import { ServerClient } from '../server-client/index.js'
20
+ import type { ChannelContext, Context } from '../context/index.js'
21
+ import type { ServerClient } from '../server-client/index.js'
22
22
 
23
23
  export interface ServerMeta extends Meta {
24
24
  /**
25
- * Action processing status
25
+ * All nodes subscribed to channel will receive the action.
26
26
  */
27
- status?: 'waiting' | 'processed' | 'error'
27
+ channel?: string
28
28
 
29
29
  /**
30
- * Node ID of the server received the action.
30
+ * All nodes subscribed to listed channels will receive the action.
31
31
  */
32
- server: string
32
+ channels?: string[]
33
33
 
34
34
  /**
35
- * All nodes subscribed to listed channels will receive the action.
35
+ * All nodes with listed client ID will receive the action.
36
36
  */
37
- channels?: string[]
37
+ client?: string
38
38
 
39
39
  /**
40
- * All nodes subscribed to channel will receive the action.
40
+ * All nodes with listed client IDs will receive the action.
41
41
  */
42
- channel?: string
42
+ clients?: string[]
43
43
 
44
44
  /**
45
- * All nodes with listed user IDs will receive the action.
45
+ * Client IDs, which will not receive the action.
46
46
  */
47
- users?: string[]
47
+ excludeClients?: string[]
48
48
 
49
49
  /**
50
- * All nodes with listed user ID will receive the action.
50
+ * Node with listed node ID will receive the action.
51
51
  */
52
- user?: string
52
+ node?: string
53
53
 
54
54
  /**
55
- * All nodes with listed client IDs will receive the action.
55
+ * All nodes with listed node IDs will receive the action.
56
56
  */
57
- clients?: string[]
57
+ nodes?: string[]
58
58
 
59
59
  /**
60
- * All nodes with listed client ID will receive the action.
60
+ * Node ID of the server received the action.
61
61
  */
62
- client?: string
62
+ server: string
63
63
 
64
64
  /**
65
- * All nodes with listed node IDs will receive the action.
65
+ * Action processing status
66
66
  */
67
- nodes?: string[]
67
+ status?: 'error' | 'processed' | 'waiting'
68
68
 
69
69
  /**
70
- * Node with listed node ID will receive the action.
70
+ * All nodes with listed user ID will receive the action.
71
71
  */
72
- node?: string
72
+ user?: string
73
73
 
74
74
  /**
75
- * Client IDs, which will not receive the action.
75
+ * All nodes with listed user IDs will receive the action.
76
76
  */
77
- excludeClients?: string[]
77
+ users?: string[]
78
78
  }
79
79
 
80
80
  export interface BaseServerOptions {
81
81
  /**
82
- * Server current application subprotocol version in SemVer format.
82
+ * URL to PHP, Ruby on Rails, or other backend to process actions and
83
+ * authentication.
83
84
  */
84
- subprotocol?: string
85
+ backend?: string
85
86
 
86
87
  /**
87
- * npm’s version requirements for client subprotocol version.
88
+ * SSL certificate or path to it. Path could be relative from server
89
+ * root. It is required in production mode, because WSS is highly
90
+ * recommended.
88
91
  */
89
- supports?: string
92
+ cert?: string
90
93
 
91
94
  /**
92
- * Application root to load files and show errors.
93
- * Default is `process.cwd()`.
95
+ * Regular expression which should be cleaned from error message and stack.
94
96
  *
95
- * ```js
96
- * root: __dirname
97
- * ```
97
+ * By default it cleans `Bearer [^\s"]+`.
98
98
  */
99
- root?: string
99
+ cleanFromLog?: RegExp
100
100
 
101
101
  /**
102
- * URL of main JS file in the root dir. Shortcut to set `root` in ES modules
103
- * without `fileURLToPath`.
104
- *
105
- * ```
106
- * fileUrl: import.meta.url
107
- * ```
102
+ * CIDR masks for IP address, where control requests could came from.
108
103
  */
109
- fileUrl?: string
104
+ controlMask?: string
110
105
 
111
106
  /**
112
- * Timeout in milliseconds to disconnect connection.
113
- * Default is `20000`.
107
+ * Secret to control the server.
114
108
  */
115
- timeout?: number
109
+ controlSecret?: string
116
110
 
117
111
  /**
118
- * Milliseconds since last message to test connection by sending ping.
119
- * Default is `10000`.
112
+ * Disable health check endpoint, control HTTP API, {@link Server#http}.
113
+ *
114
+ * The server will process only WebSocket connection and ignore all other
115
+ * HTTP request (so they can be processed by other HTTP server).
120
116
  */
121
- ping?: number
117
+ disableHttpServer?: boolean
122
118
 
123
119
  /**
124
- * URL to PHP, Ruby on Rails, or other backend to process actions and
125
- * authentication.
120
+ * Development or production server mode. By default,
121
+ * it will be taken from `NODE_ENV` environment variable.
122
+ * On empty `NODE_ENV` it will be `'development'`.
126
123
  */
127
- backend?: string
124
+ env?: 'development' | 'production'
128
125
 
129
126
  /**
130
- * URL to Redis for Logux Server Pro scaling.
127
+ * URL of main JS file in the root dir. Shortcut to set `root` in ES modules
128
+ * without `fileURLToPath`.
129
+ *
130
+ * ```
131
+ * fileUrl: import.meta.url
132
+ * ```
131
133
  */
132
- redis?: string
134
+ fileUrl?: string
133
135
 
134
136
  /**
135
- * Secret to control the server.
137
+ * IP-address to bind server. Default is `127.0.0.1`.
136
138
  */
137
- controlSecret?: string
139
+ host?: string
138
140
 
139
141
  /**
140
- * CIDR masks for IP address, where control requests could came from.
142
+ * Custom random ID to be used in node ID.
141
143
  */
142
- controlMask?: string
144
+ id?: string
143
145
 
144
146
  /**
145
- * Store to save log. Will be {@link @logux/core:MemoryStore}, by default.
147
+ * SSL key or path to it. Path could be relative from server root.
148
+ * It is required in production mode, because WSS is highly recommended.
146
149
  */
147
- store?: LogStore
150
+ key?: { pem: string } | string
148
151
 
149
152
  /**
150
- * Test time to test server.
153
+ * Process ID, to display in logs.
151
154
  */
152
- time?: TestTime
155
+ pid?: number
153
156
 
154
157
  /**
155
- * Custom random ID to be used in node ID.
158
+ * Milliseconds since last message to test connection by sending ping.
159
+ * Default is `20000`.
156
160
  */
157
- id?: string
161
+ ping?: number
158
162
 
159
163
  /**
160
- * Development or production server mode. By default,
161
- * it will be taken from `NODE_ENV` environment variable.
162
- * On empty `NODE_ENV` it will be `'development'`.
164
+ * Port to bind server. It will create HTTP server manually to connect
165
+ * WebSocket server to it. Default is `31337`.
163
166
  */
164
- env?: 'production' | 'development'
167
+ port?: number
165
168
 
166
169
  /**
167
- * Process ID, to display in logs.
170
+ * URL to Redis for Logux Server Pro scaling.
168
171
  */
169
- pid?: number
172
+ redis?: string
173
+
174
+ /**
175
+ * Application root to load files and show errors.
176
+ * Default is `process.cwd()`.
177
+ *
178
+ * ```js
179
+ * root: __dirname
180
+ * ```
181
+ */
182
+ root?: string
170
183
 
171
184
  /**
172
185
  * HTTP server to serve Logux’s WebSocket and HTTP requests.
@@ -177,58 +190,45 @@ export interface BaseServerOptions {
177
190
  server?: HTTPServer
178
191
 
179
192
  /**
180
- * Port to bind server. It will create HTTP server manually to connect
181
- * WebSocket server to it. Default is `31337`.
182
- */
183
- port?: number
184
-
185
- /**
186
- * IP-address to bind server. Default is `127.0.0.1`.
193
+ * Store to save log. Will be {@link @logux/core:MemoryStore}, by default.
187
194
  */
188
- host?: string
195
+ store?: LogStore
189
196
 
190
197
  /**
191
- * SSL key or path to it. Path could be relative from server root.
192
- * It is required in production mode, because WSS is highly recommended.
198
+ * Server current application subprotocol version in SemVer format.
193
199
  */
194
- key?: string | { pem: string }
200
+ subprotocol?: string
195
201
 
196
202
  /**
197
- * SSL certificate or path to it. Path could be relative from server
198
- * root. It is required in production mode, because WSS is highly
199
- * recommended.
203
+ * npm’s version requirements for client subprotocol version.
200
204
  */
201
- cert?: string
205
+ supports?: string
202
206
 
203
207
  /**
204
- * Regular expression which should be cleaned from error message and stack.
205
- *
206
- * By default it cleans `Bearer [^\s"]+`.
208
+ * Test time to test server.
207
209
  */
208
- cleanFromLog?: RegExp
210
+ time?: TestTime
209
211
 
210
212
  /**
211
- * Disable health check endpoint, control HTTP API, {@link Server#http}.
212
- *
213
- * The server will process only WebSocket connection and ignore all other
214
- * HTTP request (so they can be processed by other HTTP server).
213
+ * Timeout in milliseconds to disconnect connection.
214
+ * Default is `70000`.
215
215
  */
216
- disableHttpServer?: boolean
216
+ timeout?: number
217
217
  }
218
218
 
219
219
  export interface AuthenticatorOptions<Headers extends object> {
220
- headers: Headers
221
220
  client: ServerClient
222
- userId: string
223
221
  cookie: Record<string, string>
222
+ headers: Headers
224
223
  token: string
224
+ userId: string
225
225
  }
226
226
 
227
227
  export type SendBackActions =
228
- | void
228
+ | [Action, Partial<Meta>][]
229
229
  | Action
230
230
  | Action[]
231
- | [Action, Partial<Meta>][]
231
+ | void
232
232
 
233
233
  /**
234
234
  * The authentication callback.
@@ -279,7 +279,7 @@ interface Resender<
279
279
  ctx: Context<Data, Headers>,
280
280
  action: Readonly<TypeAction>,
281
281
  meta: Readonly<ServerMeta>
282
- ): Resend | Promise<Resend>
282
+ ): Promise<Resend> | Resend
283
283
  }
284
284
 
285
285
  /**
@@ -299,7 +299,7 @@ interface Processor<
299
299
  ctx: Context<Data, Headers>,
300
300
  action: Readonly<TypeAction>,
301
301
  meta: Readonly<ServerMeta>
302
- ): void | Promise<void>
302
+ ): Promise<void> | void
303
303
  }
304
304
 
305
305
  /**
@@ -377,7 +377,7 @@ interface FilterCreator<
377
377
  ctx: ChannelContext<Data, ChannelParams, Headers>,
378
378
  action: Readonly<SubscribeAction>,
379
379
  meta: Readonly<ServerMeta>
380
- ): Promise<ChannelFilter<Headers>> | ChannelFilter<Headers> | void
380
+ ): ChannelFilter<Headers> | Promise<ChannelFilter<Headers>> | void
381
381
  }
382
382
 
383
383
  /**
@@ -398,7 +398,7 @@ interface ChannelLoader<
398
398
  ctx: ChannelContext<Data, ChannelParams, Headers>,
399
399
  action: Readonly<SubscribeAction>,
400
400
  meta: Readonly<ServerMeta>
401
- ): SendBackActions | Promise<SendBackActions>
401
+ ): Promise<SendBackActions> | SendBackActions
402
402
  }
403
403
 
404
404
  /**
@@ -455,8 +455,8 @@ type ActionCallbacks<
455
455
  accessAndProcess: Processor<TypeAction, Data, Headers>
456
456
  }
457
457
  ) & {
458
- resend?: Resender<TypeAction, Data, Headers>
459
458
  finally?: ActionFinally<TypeAction, Data, Headers>
459
+ resend?: Resender<TypeAction, Data, Headers>
460
460
  }
461
461
 
462
462
  type ChannelCallbacks<
@@ -499,67 +499,67 @@ interface CleanReporter {
499
499
 
500
500
  interface AuthenticationReporter {
501
501
  connectionId: string
502
- subprotocol: string
503
502
  nodeId: string
503
+ subprotocol: string
504
504
  }
505
505
 
506
506
  interface ReportersArguments {
507
507
  add: ActionReporter
508
- useless: ActionReporter
508
+ authenticated: AuthenticationReporter
509
509
  clean: CleanReporter
510
- error: {
511
- err: Error
512
- fatal?: true
513
- actionId?: ID
514
- nodeId?: string
515
- connectionId?: string
516
- }
517
510
  clientError: {
511
+ connectionId?: string
518
512
  err: Error
519
513
  nodeId?: string
520
- connectionId?: string
521
514
  }
522
515
  connect: {
523
516
  connectionId: string
524
517
  ipAddress: string
525
518
  }
519
+ denied: CleanReporter
520
+ destroy: void
526
521
  disconnect: {
522
+ connectionId?: string
527
523
  nodeId?: string
524
+ }
525
+ error: {
526
+ actionId?: ID
528
527
  connectionId?: string
528
+ err: Error
529
+ fatal?: true
530
+ nodeId?: string
529
531
  }
530
- destroy: void
531
- unknownType: {
532
- type: string
533
- actionId: ID
532
+ listen: {
533
+ backend: string
534
+ cert: boolean
535
+ controlMask: string
536
+ controlSecret: string
537
+ environment: 'development' | 'production'
538
+ host: string
539
+ loguxServer: string
540
+ nodeId: string
541
+ notes: object
542
+ port: string
543
+ redis: string
544
+ server: boolean
545
+ subprotocol: string
546
+ supports: string
534
547
  }
535
- wrongChannel: SubscriptionReporter
536
548
  processed: {
537
549
  actionId: ID
538
550
  latency: number
539
551
  }
540
552
  subscribed: SubscriptionReporter
541
- unsubscribed: SubscriptionReporter
542
- denied: CleanReporter
543
- authenticated: AuthenticationReporter
544
553
  unauthenticated: AuthenticationReporter
545
- zombie: {
546
- nodeId: string
554
+ unknownType: {
555
+ actionId: ID
556
+ type: string
547
557
  }
548
- listen: {
549
- controlSecret: string
550
- controlMask: string
551
- loguxServer: string
552
- environment: 'production' | 'development'
553
- subprotocol: string
554
- supports: string
555
- backend: string
556
- server: boolean
558
+ unsubscribed: SubscriptionReporter
559
+ useless: ActionReporter
560
+ wrongChannel: SubscriptionReporter
561
+ zombie: {
557
562
  nodeId: string
558
- redis: string
559
- notes: object
560
- cert: boolean
561
- host: string
562
- port: string
563
563
  }
564
564
  }
565
565
 
@@ -571,42 +571,42 @@ export interface Reporter {
571
571
  }
572
572
 
573
573
  export type Resend =
574
- | string
575
- | string[]
576
574
  | {
577
575
  channel?: string
578
576
  channels?: string[]
579
- user?: string
580
- users?: string[]
581
577
  client?: string
582
578
  clients?: string[]
579
+ excludeClients?: string[]
583
580
  node?: string
584
581
  nodes?: string[]
585
- excludeClients?: string[]
582
+ user?: string
583
+ users?: string[]
586
584
  }
585
+ | string
586
+ | string[]
587
587
 
588
588
  export interface Logger {
589
- info(details: object, message: string): void
590
- warn(details: object, message: string): void
591
589
  error(details: object, message: string): void
592
590
  fatal(details: object, message: string): void
591
+ info(details: object, message: string): void
592
+ warn(details: object, message: string): void
593
593
  }
594
594
 
595
595
  interface Response {
596
+ body: string
596
597
  header?: {
597
598
  [name: string]: string
598
599
  }
599
- body: string
600
600
  }
601
601
 
602
602
  interface GetProcessor {
603
+ request(request: object): Promise<Response> | Response
603
604
  safe?: boolean
604
- request(request: object): Response | Promise<Response>
605
605
  }
606
606
 
607
607
  interface PostProcessor {
608
- isValid(command: object): boolean
609
608
  command(command: object, request: object): Promise<void>
609
+ isValid(command: object): boolean
610
610
  }
611
611
 
612
612
  /**
@@ -634,18 +634,30 @@ export class BaseServer<
634
634
  ServerLog extends Log = Log<ServerMeta>
635
635
  > {
636
636
  /**
637
- * @param opts Server options.
637
+ * Connected client by client ID.
638
+ *
639
+ * Do not rely on this data, when you have multiple Logux servers.
640
+ * Each server will have a different list.
638
641
  */
639
- constructor(opts: BaseServerOptions)
642
+ clientIds: Map<string, ServerClient>
640
643
 
641
644
  /**
642
- * Server options.
645
+ * Connected clients.
643
646
  *
644
647
  * ```js
645
- * console.log('Server options', server.options.subprotocol)
648
+ * for (let client of server.connected.values()) {
649
+ * console.log(client.remoteAddress)
650
+ * }
646
651
  * ```
647
652
  */
648
- options: BaseServerOptions
653
+ connected: Map<string, ServerClient>
654
+
655
+ /**
656
+ * Add callback to internal HTTP server.
657
+ */
658
+ controls: {
659
+ [path: string]: GetProcessor | PostProcessor
660
+ }
649
661
 
650
662
  /**
651
663
  * Production or development mode.
@@ -656,16 +668,7 @@ export class BaseServer<
656
668
  * }
657
669
  * ```
658
670
  */
659
- env: 'production' | 'development'
660
-
661
- /**
662
- * Server unique ID.
663
- *
664
- * ```js
665
- * console.log('Error was raised on ' + server.nodeId)
666
- * ```
667
- */
668
- nodeId: string
671
+ env: 'development' | 'production'
669
672
 
670
673
  /**
671
674
  * Server actions log.
@@ -677,23 +680,33 @@ export class BaseServer<
677
680
  log: ServerLog
678
681
 
679
682
  /**
680
- * Connected clients.
683
+ * Console for custom log records. It uses `pino` API.
681
684
  *
682
685
  * ```js
683
- * for (let client of server.connected.values()) {
684
- * console.log(client.remoteAddress)
685
- * }
686
+ * server.on('connected', client => {
687
+ * server.logger.info(
688
+ * { domain: client.httpHeaders.domain },
689
+ * 'Client domain'
690
+ * )
691
+ * })
686
692
  * ```
687
693
  */
688
- connected: Map<string, ServerClient>
694
+ logger: {
695
+ debug: LogFn
696
+ error: LogFn
697
+ fatal: LogFn
698
+ info: LogFn
699
+ warn: LogFn
700
+ }
689
701
 
690
702
  /**
691
- * Connected client by client ID.
703
+ * Server unique ID.
692
704
  *
693
- * Do not rely on this data, when you have multiple Logux servers.
694
- * Each server will have a different list.
705
+ * ```js
706
+ * console.log('Error was raised on ' + server.nodeId)
707
+ * ```
695
708
  */
696
- clientIds: Map<string, ServerClient>
709
+ nodeId: string
697
710
 
698
711
  /**
699
712
  * Connected client by node ID.
@@ -704,12 +717,13 @@ export class BaseServer<
704
717
  nodeIds: Map<string, ServerClient>
705
718
 
706
719
  /**
707
- * Connected client by user ID.
720
+ * Server options.
708
721
  *
709
- * Do not rely on this data, when you have multiple Logux servers.
710
- * Each server will have a different list.
722
+ * ```js
723
+ * console.log('Server options', server.options.subprotocol)
724
+ * ```
711
725
  */
712
- userIds: Map<string, ServerClient[]>
726
+ options: BaseServerOptions
713
727
 
714
728
  /**
715
729
  * Clients subscribed to some channel.
@@ -720,38 +734,37 @@ export class BaseServer<
720
734
  subscribers: {
721
735
  [channel: string]: {
722
736
  [nodeId: string]: {
723
- filter: ChannelFilter<{}> | true
737
+ filters: Record<string, ChannelFilter<{}> | true>
724
738
  unsubscribe?: (action: LoguxUnsubscribeAction, meta: ServerMeta) => void
725
739
  }
726
740
  }
727
741
  }
728
742
 
729
743
  /**
730
- * Add callback to internal HTTP server.
744
+ * Connected client by user ID.
745
+ *
746
+ * Do not rely on this data, when you have multiple Logux servers.
747
+ * Each server will have a different list.
731
748
  */
732
- controls: {
733
- [path: string]: GetProcessor | PostProcessor
734
- }
749
+ userIds: Map<string, ServerClient[]>
735
750
 
736
751
  /**
737
- * Console for custom log records. It uses `pino` API.
752
+ * @param opts Server options.
753
+ */
754
+ constructor(opts: BaseServerOptions)
755
+
756
+ /**
757
+ * Add new client for server. You should call this method manually
758
+ * mostly for test purposes.
738
759
  *
739
760
  * ```js
740
- * server.on('connected', client => {
741
- * server.logger.info(
742
- * { domain: client.httpHeaders.domain },
743
- * 'Client domain'
744
- * )
745
- * })
761
+ * server.addClient(test.right)
746
762
  * ```
763
+ *
764
+ * @param connection Logux connection to client.
765
+ * @returns Client ID.
747
766
  */
748
- logger: {
749
- fatal: LogFn
750
- error: LogFn
751
- warn: LogFn
752
- info: LogFn
753
- debug: LogFn
754
- }
767
+ addClient(connection: ServerConnection): number
755
768
 
756
769
  /**
757
770
  * Set authenticate function. It will receive client credentials
@@ -769,11 +782,75 @@ export class BaseServer<
769
782
  auth(authenticator: Authenticator<Headers>): void
770
783
 
771
784
  /**
772
- * Start WebSocket server and listen for clients.
785
+ * Define the channel.
773
786
  *
774
- * @returns When the server has been bound.
787
+ * ```js
788
+ * server.channel('user/:id', {
789
+ * access (ctx, action, meta) {
790
+ * return ctx.params.id === ctx.userId
791
+ * }
792
+ * filter (ctx, action, meta) {
793
+ * return (otherCtx, otherAction, otherMeta) => {
794
+ * return !action.hidden
795
+ * }
796
+ * }
797
+ * async load (ctx, action, meta) {
798
+ * const user = await db.loadUser(ctx.params.id)
799
+ * ctx.sendBack({ type: 'USER_NAME', name: user.name })
800
+ * }
801
+ * })
802
+ * ```
803
+ *
804
+ * @param pattern Pattern for channel name.
805
+ * @param callbacks Callback during subscription process.
775
806
  */
776
- listen(): Promise<void>
807
+ channel<
808
+ ChannelParams extends object = {},
809
+ Data extends object = {},
810
+ SubscribeAction extends LoguxSubscribeAction = LoguxSubscribeAction
811
+ >(
812
+ pattern: string,
813
+ callbacks: ChannelCallbacks<SubscribeAction, Data, ChannelParams, Headers>
814
+ ): void
815
+
816
+ /**
817
+ * @param pattern Regular expression for channel name.
818
+ * @param callbacks Callback during subscription process.
819
+ */
820
+ channel<
821
+ ChannelParams extends string[] = string[],
822
+ Data extends object = {},
823
+ SubscribeAction extends LoguxSubscribeAction = LoguxSubscribeAction
824
+ >(
825
+ pattern: RegExp,
826
+ callbacks: ChannelCallbacks<SubscribeAction, Data, ChannelParams, Headers>
827
+ ): void
828
+
829
+ /**
830
+ * Send runtime error stacktrace to all clients.
831
+ *
832
+ * ```js
833
+ * process.on('uncaughtException', e => {
834
+ * server.debugError(e)
835
+ * })
836
+ * ```
837
+ *
838
+ * @param error Runtime error instance.
839
+ */
840
+ debugError(error: Error): void
841
+
842
+ /**
843
+ * Stop server and unbind all listeners.
844
+ *
845
+ * ```js
846
+ * afterEach(() => {
847
+ * testServer.destroy()
848
+ * })
849
+ * ```
850
+ *
851
+ * @returns Promise when all listeners will be removed.
852
+ */
853
+ destroy(): Promise<void>
777
854
 
778
855
  /**
779
856
  * Add non-WebSocket HTTP request processor.
@@ -795,6 +872,59 @@ export class BaseServer<
795
872
  */
796
873
  http(listener: (req: IncomingMessage, res: ServerResponse) => void): void
797
874
 
875
+ /**
876
+ * Start WebSocket server and listen for clients.
877
+ *
878
+ * @returns When the server has been bound.
879
+ */
880
+ listen(): Promise<void>
881
+
882
+ /**
883
+ * @param event The event name.
884
+ * @param listener Event listener.
885
+ */
886
+ on(event: 'subscriptionCancelled', listener: () => void): Unsubscribe
887
+
888
+ /**
889
+ * @param event The event name.
890
+ * @param listener Subscription listener.
891
+ */
892
+ on(
893
+ event: 'subscribing',
894
+ listener: (action: LoguxSubscribeAction, meta: Readonly<ServerMeta>) => void
895
+ ): Unsubscribe
896
+
897
+ /**
898
+ * @param event The event name.
899
+ * @param listener Processing listener.
900
+ */
901
+ on(
902
+ event: 'backendGranted' | 'backendProcessed' | 'processed',
903
+ listener: (
904
+ action: Action,
905
+ meta: Readonly<ServerMeta>,
906
+ latencyMilliseconds: number
907
+ ) => void
908
+ ): Unsubscribe
909
+
910
+ /**
911
+ * @param event The event name.
912
+ * @param listener Action listener.
913
+ */
914
+ on(
915
+ event: 'add' | 'backendSent' | 'clean',
916
+ listener: (action: Action, meta: Readonly<ServerMeta>) => void
917
+ ): Unsubscribe
918
+
919
+ /**
920
+ * @param event The event name.
921
+ * @param listener Client listener.
922
+ */
923
+ on(
924
+ event: 'connected' | 'disconnected',
925
+ listener: (client: ServerClient) => void
926
+ ): Unsubscribe
927
+
798
928
  /**
799
929
  * Subscribe for synchronization events. It implements nanoevents API.
800
930
  * Supported events:
@@ -827,7 +957,7 @@ export class BaseServer<
827
957
  * @returns Unbind listener from event.
828
958
  */
829
959
  on(
830
- event: 'fatal' | 'clientError',
960
+ event: 'clientError' | 'fatal',
831
961
  listener: (err: Error) => void
832
962
  ): Unsubscribe
833
963
 
@@ -840,15 +970,6 @@ export class BaseServer<
840
970
  listener: (err: Error, action: Action, meta: Readonly<ServerMeta>) => void
841
971
  ): Unsubscribe
842
972
 
843
- /**
844
- * @param event The event name.
845
- * @param listener Client listener.
846
- */
847
- on(
848
- event: 'connected' | 'disconnected',
849
- listener: (client: ServerClient) => void
850
- ): Unsubscribe
851
-
852
973
  /**
853
974
  * @param event The event name.
854
975
  * @param listener Client listener.
@@ -858,15 +979,6 @@ export class BaseServer<
858
979
  listener: (client: ServerClient, latencyMilliseconds: number) => void
859
980
  ): Unsubscribe
860
981
 
861
- /**
862
- * @param event The event name.
863
- * @param listener Action listener.
864
- */
865
- on(
866
- event: 'add' | 'clean' | 'backendSent',
867
- listener: (action: Action, meta: Readonly<ServerMeta>) => void
868
- ): Unsubscribe
869
-
870
982
  /**
871
983
  * @param event The event name.
872
984
  * @param listener Action listener.
@@ -876,19 +988,6 @@ export class BaseServer<
876
988
  listener: (action: Action, meta: ServerMeta) => void
877
989
  ): Unsubscribe
878
990
 
879
- /**
880
- * @param event The event name.
881
- * @param listener Processing listener.
882
- */
883
- on(
884
- event: 'processed' | 'backendGranted' | 'backendProcessed',
885
- listener: (
886
- action: Action,
887
- meta: Readonly<ServerMeta>,
888
- latencyMilliseconds: number
889
- ) => void
890
- ): Unsubscribe
891
-
892
991
  /**
893
992
  * @param event The event name.
894
993
  * @param listener Subscription listener.
@@ -902,15 +1001,6 @@ export class BaseServer<
902
1001
  ) => void
903
1002
  ): Unsubscribe
904
1003
 
905
- /**
906
- * @param event The event name.
907
- * @param listener Subscription listener.
908
- */
909
- on(
910
- event: 'subscribing',
911
- listener: (action: LoguxSubscribeAction, meta: Readonly<ServerMeta>) => void
912
- ): Unsubscribe
913
-
914
1004
  /**
915
1005
  * @param event The event name.
916
1006
  * @param listener Subscription listener.
@@ -923,12 +1013,6 @@ export class BaseServer<
923
1013
  ) => void
924
1014
  ): Unsubscribe
925
1015
 
926
- /**
927
- * @param event The event name.
928
- * @param listener Event listener.
929
- */
930
- on(event: 'subscriptionCancelled', listener: () => void): Unsubscribe
931
-
932
1016
  /**
933
1017
  * @param event The event name.
934
1018
  * @param listener Report listener.
@@ -936,52 +1020,26 @@ export class BaseServer<
936
1020
  on(event: 'report', listener: Reporter): Unsubscribe
937
1021
 
938
1022
  /**
939
- * Stop server and unbind all listeners.
940
- *
941
- * ```js
942
- * afterEach(() => {
943
- * testServer.destroy()
944
- * })
945
- * ```
946
- *
947
- * @returns Promise when all listeners will be removed.
948
- */
949
- destroy(): Promise<void>
950
-
951
- /**
952
- * Define action type’s callbacks.
1023
+ * Set callbacks for unknown channel subscription.
953
1024
  *
954
- * ```js
955
- * server.type('CHANGE_NAME', {
956
- * access (ctx, action, meta) {
957
- * return action.user === ctx.userId
958
- * },
959
- * resend (ctx, action) {
960
- * return `user/${ action.user }`
961
- * }
962
- * process (ctx, action, meta) {
963
- * if (isFirstOlder(lastNameChange(action.user), meta)) {
964
- * return db.changeUserName({ id: action.user, name: action.name })
1025
+ *```js
1026
+ * server.otherChannel({
1027
+ * async access (ctx, action, meta) {
1028
+ * const res = await phpBackend.checkChannel(ctx.params[0], ctx.userId)
1029
+ * if (res.code === 404) {
1030
+ * this.wrongChannel(action, meta)
1031
+ * return false
1032
+ * } else {
1033
+ * return response.body === 'granted'
965
1034
  * }
966
1035
  * }
967
1036
  * })
968
1037
  * ```
969
1038
  *
970
- * @param name The action’s type or action’s type matching rule as RegExp..
971
- * @param callbacks Callbacks for actions with this type.
972
- */
973
- type<TypeAction extends Action = AnyAction, Data extends object = {}>(
974
- name: TypeAction['type'] | RegExp,
975
- callbacks: ActionCallbacks<TypeAction, Data, Headers>
976
- ): void
977
-
978
- /**
979
- * @param actionCreator Action creator function.
980
- * @param callbacks Callbacks for action created by creator.
1039
+ * @param callbacks Callback during subscription process.
981
1040
  */
982
- type<Creator extends AbstractActionCreator, Data extends object = {}>(
983
- actionCreator: Creator,
984
- callbacks: ActionCallbacks<ReturnType<Creator>, Data, Headers>
1041
+ otherChannel<Data extends object = {}>(
1042
+ callbacks: ChannelCallbacks<LoguxSubscribeAction, Data, [string], Headers>
985
1043
  ): void
986
1044
 
987
1045
  /**
@@ -1014,74 +1072,6 @@ export class BaseServer<
1014
1072
  callbacks: ActionCallbacks<Action, Data, Headers>
1015
1073
  ): void
1016
1074
 
1017
- /**
1018
- * Define the channel.
1019
- *
1020
- * ```js
1021
- * server.channel('user/:id', {
1022
- * access (ctx, action, meta) {
1023
- * return ctx.params.id === ctx.userId
1024
- * }
1025
- * filter (ctx, action, meta) {
1026
- * return (otherCtx, otherAction, otherMeta) => {
1027
- * return !action.hidden
1028
- * }
1029
- * }
1030
- * async load (ctx, action, meta) {
1031
- * const user = await db.loadUser(ctx.params.id)
1032
- * ctx.sendBack({ type: 'USER_NAME', name: user.name })
1033
- * }
1034
- * })
1035
- * ```
1036
- *
1037
- * @param pattern Pattern for channel name.
1038
- * @param callbacks Callback during subscription process.
1039
- */
1040
- channel<
1041
- ChannelParams extends object = {},
1042
- Data extends object = {},
1043
- SubscribeAction extends LoguxSubscribeAction = LoguxSubscribeAction
1044
- >(
1045
- pattern: string,
1046
- callbacks: ChannelCallbacks<SubscribeAction, Data, ChannelParams, Headers>
1047
- ): void
1048
-
1049
- /**
1050
- * @param pattern Regular expression for channel name.
1051
- * @param callbacks Callback during subscription process.
1052
- */
1053
- channel<
1054
- ChannelParams extends string[] = string[],
1055
- Data extends object = {},
1056
- SubscribeAction extends LoguxSubscribeAction = LoguxSubscribeAction
1057
- >(
1058
- pattern: RegExp,
1059
- callbacks: ChannelCallbacks<SubscribeAction, Data, ChannelParams, Headers>
1060
- ): void
1061
-
1062
- /**
1063
- * Set callbacks for unknown channel subscription.
1064
- *
1065
- *```js
1066
- * server.otherChannel({
1067
- * async access (ctx, action, meta) {
1068
- * const res = await phpBackend.checkChannel(ctx.params[0], ctx.userId)
1069
- * if (res.code === 404) {
1070
- * this.wrongChannel(action, meta)
1071
- * return false
1072
- * } else {
1073
- * return response.body === 'granted'
1074
- * }
1075
- * }
1076
- * })
1077
- * ```
1078
- *
1079
- * @param callbacks Callback during subscription process.
1080
- */
1081
- otherChannel<Data extends object = {}>(
1082
- callbacks: ChannelCallbacks<LoguxSubscribeAction, Data, [string], Headers>
1083
- ): void
1084
-
1085
1075
  /**
1086
1076
  * Add new action to the server and return the Promise until it will be
1087
1077
  * resend to clients and processed.
@@ -1095,41 +1085,6 @@ export class BaseServer<
1095
1085
  meta?: Partial<ServerMeta>
1096
1086
  ): Promise<Readonly<ServerMeta>>
1097
1087
 
1098
- /**
1099
- * Undo action from client.
1100
- *
1101
- * ```js
1102
- * if (couldNotFixConflict(action, meta)) {
1103
- * server.undo(action, meta)
1104
- * }
1105
- * ```
1106
- *
1107
- * @param action The original action to undo.
1108
- * @param meta The action’s metadata.
1109
- * @param reason Optional code for reason. Default is `'error'`.
1110
- * @param extra Extra fields to `logux/undo` action.
1111
- * @returns When action was saved to the log.
1112
- */
1113
- undo(
1114
- action: Action,
1115
- meta: ServerMeta,
1116
- reason?: string,
1117
- extra?: object
1118
- ): Promise<void>
1119
-
1120
- /**
1121
- * Send runtime error stacktrace to all clients.
1122
- *
1123
- * ```js
1124
- * process.on('uncaughtException', e => {
1125
- * server.debugError(e)
1126
- * })
1127
- * ```
1128
- *
1129
- * @param error Runtime error instance.
1130
- */
1131
- debugError(error: Error): void
1132
-
1133
1088
  /**
1134
1089
  * Send action, received by other server, to all clients of current server.
1135
1090
  * This method is for multi-server configuration only.
@@ -1148,7 +1103,7 @@ export class BaseServer<
1148
1103
  * @param action New action.
1149
1104
  * @param meta Action’s metadata.
1150
1105
  */
1151
- sendAction(action: Action, meta: ServerMeta): void | Promise<void>
1106
+ sendAction(action: Action, meta: ServerMeta): Promise<void> | void
1152
1107
 
1153
1108
  /**
1154
1109
  * Send `logux/subscribed` if client was not already subscribed.
@@ -1163,17 +1118,62 @@ export class BaseServer<
1163
1118
  subscribe(nodeId: string, channel: string): void
1164
1119
 
1165
1120
  /**
1166
- * Add new client for server. You should call this method manually
1167
- * mostly for test purposes.
1121
+ * @param actionCreator Action creator function.
1122
+ * @param callbacks Callbacks for action created by creator.
1123
+ */
1124
+ type<Creator extends AbstractActionCreator, Data extends object = {}>(
1125
+ actionCreator: Creator,
1126
+ callbacks: ActionCallbacks<ReturnType<Creator>, Data, Headers>
1127
+ ): void
1128
+
1129
+ /**
1130
+ * Define action type’s callbacks.
1168
1131
  *
1169
1132
  * ```js
1170
- * server.addClient(test.right)
1133
+ * server.type('CHANGE_NAME', {
1134
+ * access (ctx, action, meta) {
1135
+ * return action.user === ctx.userId
1136
+ * },
1137
+ * resend (ctx, action) {
1138
+ * return `user/${ action.user }`
1139
+ * }
1140
+ * process (ctx, action, meta) {
1141
+ * if (isFirstOlder(lastNameChange(action.user), meta)) {
1142
+ * return db.changeUserName({ id: action.user, name: action.name })
1143
+ * }
1144
+ * }
1145
+ * })
1171
1146
  * ```
1172
1147
  *
1173
- * @param connection Logux connection to client.
1174
- * @returns Client ID.
1148
+ * @param name The action’s type or action’s type matching rule as RegExp..
1149
+ * @param callbacks Callbacks for actions with this type.
1175
1150
  */
1176
- addClient(connection: ServerConnection): number
1151
+ type<TypeAction extends Action = AnyAction, Data extends object = {}>(
1152
+ name: RegExp | TypeAction['type'],
1153
+ callbacks: ActionCallbacks<TypeAction, Data, Headers>
1154
+ ): void
1155
+
1156
+ /**
1157
+ * Undo action from client.
1158
+ *
1159
+ * ```js
1160
+ * if (couldNotFixConflict(action, meta)) {
1161
+ * server.undo(action, meta)
1162
+ * }
1163
+ * ```
1164
+ *
1165
+ * @param action The original action to undo.
1166
+ * @param meta The action’s metadata.
1167
+ * @param reason Optional code for reason. Default is `'error'`.
1168
+ * @param extra Extra fields to `logux/undo` action.
1169
+ * @returns When action was saved to the log.
1170
+ */
1171
+ undo(
1172
+ action: Action,
1173
+ meta: ServerMeta,
1174
+ reason?: string,
1175
+ extra?: object
1176
+ ): Promise<void>
1177
1177
 
1178
1178
  /**
1179
1179
  * If you receive action with unknown type, this method will mark this action