@upbit-official/upbit-sdk 1.0.0 → 1.1.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/CHANGELOG.md +5 -0
- package/README.md +21 -0
- package/client.d.mts +10 -4
- package/client.d.mts.map +1 -1
- package/client.d.ts +10 -4
- package/client.d.ts.map +1 -1
- package/client.js +23 -5
- package/client.js.map +1 -1
- package/client.mjs +23 -5
- package/client.mjs.map +1 -1
- package/index.d.mts +3 -1
- package/index.d.mts.map +1 -1
- package/index.d.ts +3 -1
- package/index.d.ts.map +1 -1
- package/index.js +2 -1
- package/index.js.map +1 -1
- package/index.mjs +1 -1
- package/index.mjs.map +1 -1
- package/internal/ws-parser.d.mts +40 -0
- package/internal/ws-parser.d.mts.map +1 -0
- package/internal/ws-parser.d.ts +40 -0
- package/internal/ws-parser.d.ts.map +1 -0
- package/internal/ws-parser.js +125 -0
- package/internal/ws-parser.js.map +1 -0
- package/internal/ws-parser.mjs +118 -0
- package/internal/ws-parser.mjs.map +1 -0
- package/internal/ws-simple-types.d.mts +8 -0
- package/internal/ws-simple-types.d.mts.map +1 -0
- package/internal/ws-simple-types.d.ts +8 -0
- package/internal/ws-simple-types.d.ts.map +1 -0
- package/internal/ws-simple-types.js +3 -0
- package/internal/ws-simple-types.js.map +1 -0
- package/internal/ws-simple-types.mjs +2 -0
- package/internal/ws-simple-types.mjs.map +1 -0
- package/internal/ws.d.mts +1 -0
- package/internal/ws.d.mts.map +1 -1
- package/internal/ws.d.ts +1 -0
- package/internal/ws.d.ts.map +1 -1
- package/internal/ws.js.map +1 -1
- package/internal/ws.mjs.map +1 -1
- package/lib/index.d.mts +4 -2
- package/lib/index.d.mts.map +1 -1
- package/lib/index.d.ts +4 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -1
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +1 -1
- package/lib/index.mjs.map +1 -1
- package/lib/jsonParseFloat.d.mts +5 -5
- package/lib/jsonParseFloat.d.mts.map +1 -1
- package/lib/jsonParseFloat.d.ts +5 -5
- package/lib/jsonParseFloat.d.ts.map +1 -1
- package/lib/jsonParseFloat.js +30 -12
- package/lib/jsonParseFloat.js.map +1 -1
- package/lib/jsonParseFloat.mjs +30 -12
- package/lib/jsonParseFloat.mjs.map +1 -1
- package/lib/ws.d.mts +102 -15
- package/lib/ws.d.mts.map +1 -1
- package/lib/ws.d.ts +102 -15
- package/lib/ws.d.ts.map +1 -1
- package/lib/ws.js +208 -34
- package/lib/ws.js.map +1 -1
- package/lib/ws.mjs +204 -33
- package/lib/ws.mjs.map +1 -1
- package/package.json +1 -1
- package/resources/index.d.mts +3 -2
- package/resources/index.d.mts.map +1 -1
- package/resources/index.d.ts +3 -2
- package/resources/index.d.ts.map +1 -1
- package/resources/index.js +3 -1
- package/resources/index.js.map +1 -1
- package/resources/index.mjs +3 -2
- package/resources/index.mjs.map +1 -1
- package/resources/ws-info/index.d.mts +6 -0
- package/resources/ws-info/index.d.mts.map +1 -0
- package/resources/ws-info/index.d.ts +6 -0
- package/resources/ws-info/index.d.ts.map +1 -0
- package/resources/ws-info/index.js +6 -0
- package/resources/ws-info/index.js.map +1 -0
- package/resources/ws-info/index.mjs +2 -0
- package/resources/ws-info/index.mjs.map +1 -0
- package/resources/ws-info/internal-base.d.mts +63 -0
- package/resources/ws-info/internal-base.d.mts.map +1 -0
- package/resources/ws-info/internal-base.d.ts +63 -0
- package/resources/ws-info/internal-base.d.ts.map +1 -0
- package/resources/ws-info/internal-base.js +47 -0
- package/resources/ws-info/internal-base.js.map +1 -0
- package/resources/ws-info/internal-base.mjs +41 -0
- package/resources/ws-info/internal-base.mjs.map +1 -0
- package/resources/ws-info/ws-info.d.mts +1180 -0
- package/resources/ws-info/ws-info.d.mts.map +1 -0
- package/resources/ws-info/ws-info.d.ts +1180 -0
- package/resources/ws-info/ws-info.d.ts.map +1 -0
- package/resources/ws-info/ws-info.js +8 -0
- package/resources/ws-info/ws-info.js.map +1 -0
- package/resources/ws-info/ws-info.mjs +4 -0
- package/resources/ws-info/ws-info.mjs.map +1 -0
- package/resources/ws-info/ws.d.mts +91 -0
- package/resources/ws-info/ws.d.mts.map +1 -0
- package/resources/ws-info/ws.d.ts +91 -0
- package/resources/ws-info/ws.d.ts.map +1 -0
- package/resources/ws-info/ws.js +463 -0
- package/resources/ws-info/ws.js.map +1 -0
- package/resources/ws-info/ws.mjs +458 -0
- package/resources/ws-info/ws.mjs.map +1 -0
- package/resources/ws-info.d.mts +2 -0
- package/resources/ws-info.d.mts.map +1 -0
- package/resources/ws-info.d.ts +2 -0
- package/resources/ws-info.d.ts.map +1 -0
- package/resources/ws-info.js +5 -0
- package/resources/ws-info.js.map +1 -0
- package/resources/ws-info.mjs +2 -0
- package/resources/ws-info.mjs.map +1 -0
- package/resources/ws-private/index.d.mts +3 -1
- package/resources/ws-private/index.d.mts.map +1 -1
- package/resources/ws-private/index.d.ts +3 -1
- package/resources/ws-private/index.d.ts.map +1 -1
- package/resources/ws-private/index.js.map +1 -1
- package/resources/ws-private/index.mjs +1 -1
- package/resources/ws-private/index.mjs.map +1 -1
- package/resources/ws-private/internal-base.d.mts.map +1 -1
- package/resources/ws-private/internal-base.d.ts.map +1 -1
- package/resources/ws-private/internal-base.js.map +1 -1
- package/resources/ws-private/internal-base.mjs.map +1 -1
- package/resources/ws-private/ws-private.d.mts +301 -9
- package/resources/ws-private/ws-private.d.mts.map +1 -1
- package/resources/ws-private/ws-private.d.ts +301 -9
- package/resources/ws-private/ws-private.d.ts.map +1 -1
- package/resources/ws-private/ws-private.js.map +1 -1
- package/resources/ws-private/ws-private.mjs.map +1 -1
- package/resources/ws-private/ws.d.mts +2 -2
- package/resources/ws-private/ws.d.mts.map +1 -1
- package/resources/ws-private/ws.d.ts +2 -2
- package/resources/ws-private/ws.d.ts.map +1 -1
- package/resources/ws-private/ws.js +15 -20
- package/resources/ws-private/ws.js.map +1 -1
- package/resources/ws-private/ws.mjs +15 -20
- package/resources/ws-private/ws.mjs.map +1 -1
- package/resources/ws-public/index.d.mts +3 -1
- package/resources/ws-public/index.d.mts.map +1 -1
- package/resources/ws-public/index.d.ts +3 -1
- package/resources/ws-public/index.d.ts.map +1 -1
- package/resources/ws-public/index.js.map +1 -1
- package/resources/ws-public/index.mjs +1 -1
- package/resources/ws-public/index.mjs.map +1 -1
- package/resources/ws-public/internal-base.d.mts.map +1 -1
- package/resources/ws-public/internal-base.d.ts.map +1 -1
- package/resources/ws-public/internal-base.js.map +1 -1
- package/resources/ws-public/internal-base.mjs.map +1 -1
- package/resources/ws-public/ws-public.d.mts +355 -5
- package/resources/ws-public/ws-public.d.mts.map +1 -1
- package/resources/ws-public/ws-public.d.ts +355 -5
- package/resources/ws-public/ws-public.d.ts.map +1 -1
- package/resources/ws-public/ws.d.mts +2 -2
- package/resources/ws-public/ws.d.mts.map +1 -1
- package/resources/ws-public/ws.d.ts +2 -2
- package/resources/ws-public/ws.d.ts.map +1 -1
- package/resources/ws-public/ws.js +15 -20
- package/resources/ws-public/ws.js.map +1 -1
- package/resources/ws-public/ws.mjs +15 -20
- package/resources/ws-public/ws.mjs.map +1 -1
- package/src/client.ts +92 -5
- package/src/index.ts +24 -1
- package/src/internal/ws-parser.ts +164 -0
- package/src/internal/ws-simple-types.ts +34 -0
- package/src/internal/ws.ts +1 -0
- package/src/lib/index.ts +17 -2
- package/src/lib/jsonParseFloat.ts +37 -12
- package/src/lib/ws.ts +367 -55
- package/src/resources/index.ts +42 -2
- package/src/resources/ws-info/index.ts +44 -0
- package/src/resources/ws-info/internal-base.ts +96 -0
- package/src/resources/ws-info/ws-info.ts +1855 -0
- package/src/resources/ws-info/ws.ts +574 -0
- package/src/resources/ws-info.ts +1 -0
- package/src/resources/ws-private/index.ts +12 -1
- package/src/resources/ws-private/internal-base.ts +0 -1
- package/src/resources/ws-private/ws-private.ts +420 -18
- package/src/resources/ws-private/ws.ts +16 -23
- package/src/resources/ws-public/index.ts +16 -1
- package/src/resources/ws-public/internal-base.ts +0 -1
- package/src/resources/ws-public/ws-public.ts +459 -4
- package/src/resources/ws-public/ws.ts +16 -23
- package/src/version.ts +1 -1
- package/version.d.mts +1 -1
- package/version.d.ts +1 -1
- package/version.js +1 -1
- package/version.js.map +1 -1
- package/version.mjs +1 -1
- package/version.mjs.map +1 -1
package/src/lib/ws.ts
CHANGED
|
@@ -1,14 +1,31 @@
|
|
|
1
1
|
import * as WS from 'ws';
|
|
2
2
|
import { uuid4 } from '../internal/utils/uuid';
|
|
3
3
|
import { createJwtToken } from './jwtAuth';
|
|
4
|
-
import { jsonParseFloat } from './jsonParseFloat';
|
|
5
4
|
import { buildURL as buildPublicURL } from '../resources/ws-public/internal-base';
|
|
6
5
|
import { buildURL as buildPrivateURL } from '../resources/ws-private/internal-base';
|
|
6
|
+
import { buildURL as buildInfoURL } from '../resources/ws-info/internal-base';
|
|
7
7
|
import type { ConnectPublicServerEvent } from '../resources/ws-public/ws-public';
|
|
8
|
-
import type {
|
|
8
|
+
import type {
|
|
9
|
+
ListSubscriptionsResponse,
|
|
10
|
+
ListSubscriptionsServerResponse,
|
|
11
|
+
SimpleListSubscriptionsResponse,
|
|
12
|
+
} from '../resources/ws-public/ws-public';
|
|
13
|
+
import type { AnnouncementCategory, ConnectPrivateServerEvent } from '../resources/ws-private/ws-private';
|
|
14
|
+
import type { ConnectInfoServerEvent } from '../resources/ws-info/ws-info';
|
|
15
|
+
import type { ConnectInfoClientEvent } from '../resources/ws-info/ws-info';
|
|
16
|
+
import {
|
|
17
|
+
parseWebSocketValue,
|
|
18
|
+
isListSubscriptionsResponse,
|
|
19
|
+
type InfoWebSocketUnknownMessage,
|
|
20
|
+
type WebSocketMessage,
|
|
21
|
+
} from '../internal/ws-parser';
|
|
22
|
+
import type { SimpleWebSocketEvent } from '../internal/ws-simple-types';
|
|
23
|
+
import type { SimpleWebSocketEvent as ExtensibleSimpleEvent } from '../internal/ws-parser';
|
|
9
24
|
import type { Upbit } from '../client';
|
|
10
25
|
|
|
11
26
|
export interface WsStreamOptions {
|
|
27
|
+
/** Response format (default: DEFAULT). Preserved for queries and reconnects. */
|
|
28
|
+
format?: WsStreamFormat;
|
|
12
29
|
/** Maximum number of reconnection attempts (default: 5) */
|
|
13
30
|
maxRetries?: number;
|
|
14
31
|
/** Reconnection delay in ms (default: 1000) */
|
|
@@ -19,55 +36,220 @@ export interface WsStreamOptions {
|
|
|
19
36
|
onReconnect?: () => void;
|
|
20
37
|
}
|
|
21
38
|
|
|
39
|
+
export type WsStreamFormat = 'DEFAULT' | 'SIMPLE' | 'JSON_LIST' | 'SIMPLE_LIST';
|
|
40
|
+
|
|
41
|
+
export enum WsEndpoint {
|
|
42
|
+
Public = 'public',
|
|
43
|
+
Private = 'private',
|
|
44
|
+
Info = 'info',
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function requiresAuth(endpoint: WsEndpoint): boolean {
|
|
48
|
+
return endpoint !== WsEndpoint.Public;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export type WsDefaultListSubscriptionsResponse = ListSubscriptionsResponse;
|
|
52
|
+
|
|
53
|
+
export type WsSimpleListSubscriptionsResponse = SimpleListSubscriptionsResponse;
|
|
54
|
+
|
|
55
|
+
export type WsListSubscriptionsResponse = ListSubscriptionsServerResponse;
|
|
56
|
+
|
|
57
|
+
export interface WsAnnouncementOptions extends WsStreamOptions {
|
|
58
|
+
/** Response format (default: DEFAULT). */
|
|
59
|
+
format?: WsStreamFormat;
|
|
60
|
+
/** Announcement categories to receive. Omit to receive all categories. */
|
|
61
|
+
categories?: AnnouncementCategory[];
|
|
62
|
+
/** Whether to include the announcement body in stream messages. */
|
|
63
|
+
includeBody?: boolean;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export type WsIndicatorSubscription = Omit<Extract<InfoSubscription, { type: 'indicator' }>, 'type'>;
|
|
67
|
+
|
|
68
|
+
export interface WsIndicatorOptions extends Omit<WsIndicatorSubscription, 'codes'>, WsStreamOptions {
|
|
69
|
+
format?: WsStreamFormat;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export type WsIndicatorSignalSubscription = Omit<
|
|
73
|
+
Extract<InfoSubscription, { type: 'indicator_signal' }>,
|
|
74
|
+
'type'
|
|
75
|
+
>;
|
|
76
|
+
export interface WsIndicatorSignalOptions
|
|
77
|
+
extends Omit<WsIndicatorSignalSubscription, 'codes'>,
|
|
78
|
+
WsStreamOptions {
|
|
79
|
+
format?: WsStreamFormat;
|
|
80
|
+
}
|
|
81
|
+
|
|
22
82
|
type PublicSubscriptionType =
|
|
23
83
|
| { type: 'ticker'; codes: string[] }
|
|
24
84
|
| { type: 'trade'; codes: string[] }
|
|
25
85
|
| { type: 'orderbook'; codes: string[] }
|
|
26
86
|
| { type: string; codes: string[] }; // candle.{interval}
|
|
27
87
|
|
|
28
|
-
type
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
88
|
+
type AnnouncementSubscriptionType = {
|
|
89
|
+
type: 'announcement';
|
|
90
|
+
categories?: AnnouncementCategory[];
|
|
91
|
+
include_body?: boolean;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
type PrivateSubscriptionType =
|
|
95
|
+
| AnnouncementSubscriptionType
|
|
96
|
+
| { type: 'myOrder'; codes?: string[] }
|
|
97
|
+
| { type: 'myAsset' };
|
|
98
|
+
|
|
99
|
+
export type InfoSubscription = Extract<
|
|
100
|
+
ConnectInfoClientEvent[number],
|
|
101
|
+
{ type: 'indicator' | 'indicator_signal' }
|
|
102
|
+
>;
|
|
103
|
+
|
|
104
|
+
type AnySubscriptionType = PublicSubscriptionType | PrivateSubscriptionType | InfoSubscription;
|
|
105
|
+
type WsServerEvent =
|
|
106
|
+
| ConnectPublicServerEvent
|
|
107
|
+
| ConnectPrivateServerEvent
|
|
108
|
+
| ConnectInfoServerEvent
|
|
109
|
+
| InfoWebSocketUnknownMessage;
|
|
110
|
+
export type WsSimpleEvent = SimpleWebSocketEvent;
|
|
111
|
+
export type WsStreamEvent =
|
|
112
|
+
| WebSocketMessage<WsServerEvent | WsSimpleEvent | ExtensibleSimpleEvent>
|
|
113
|
+
| WsListSubscriptionsResponse
|
|
114
|
+
| Array<
|
|
115
|
+
WebSocketMessage<WsServerEvent | WsSimpleEvent | ExtensibleSimpleEvent> | WsListSubscriptionsResponse
|
|
116
|
+
>;
|
|
117
|
+
|
|
118
|
+
type PublicEvent<Type extends ConnectPublicServerEvent['type']> = Extract<
|
|
119
|
+
ConnectPublicServerEvent,
|
|
120
|
+
{ type: Type }
|
|
121
|
+
>;
|
|
122
|
+
type CandleEvent = Exclude<ConnectPublicServerEvent, PublicEvent<'ticker' | 'trade' | 'orderbook'>>;
|
|
123
|
+
type PrivateEvent<Type extends ConnectPrivateServerEvent['type']> = Extract<
|
|
124
|
+
ConnectPrivateServerEvent,
|
|
125
|
+
{ type: Type }
|
|
126
|
+
>;
|
|
127
|
+
type InfoEvent<Type extends ConnectInfoServerEvent['type']> = Extract<ConnectInfoServerEvent, { type: Type }>;
|
|
128
|
+
|
|
129
|
+
export function buildSubscriptionMessage(types: AnySubscriptionType[], format?: WsStreamFormat): string {
|
|
33
130
|
const fields: object[] = [{ ticket: uuid4() }];
|
|
34
131
|
for (const t of types) {
|
|
35
|
-
|
|
36
|
-
fields.push({ type: t.type, codes: t.codes });
|
|
37
|
-
} else {
|
|
38
|
-
fields.push({ type: t.type });
|
|
39
|
-
}
|
|
132
|
+
fields.push(t);
|
|
40
133
|
}
|
|
134
|
+
if (format !== undefined) fields.push({ format });
|
|
135
|
+
return JSON.stringify(fields);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function buildListSubscriptionsMessage(format?: WsStreamFormat): string {
|
|
139
|
+
const fields: object[] = [{ ticket: uuid4() }, { method: 'LIST_SUBSCRIPTIONS' }];
|
|
140
|
+
if (format !== undefined) fields.push({ format });
|
|
41
141
|
return JSON.stringify(fields);
|
|
42
142
|
}
|
|
43
143
|
|
|
144
|
+
export function parseWsMessage(data: string): unknown {
|
|
145
|
+
return parseWebSocketValue(data);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function buildAnnouncementSubscription(
|
|
149
|
+
categories?: AnnouncementCategory[],
|
|
150
|
+
includeBody?: boolean,
|
|
151
|
+
): AnnouncementSubscriptionType {
|
|
152
|
+
const subscription: AnnouncementSubscriptionType = { type: 'announcement' };
|
|
153
|
+
if (categories !== undefined) subscription.categories = categories;
|
|
154
|
+
if (includeBody !== undefined) subscription.include_body = includeBody;
|
|
155
|
+
return subscription;
|
|
156
|
+
}
|
|
157
|
+
|
|
44
158
|
/**
|
|
45
159
|
* Manages a WebSocket stream as an AsyncIterable.
|
|
46
160
|
*
|
|
47
161
|
* Use with `for await (const event of manager) { ... }`.
|
|
48
162
|
*/
|
|
49
|
-
export class WsStreamManager
|
|
163
|
+
export class WsStreamManager<Event = ConnectPublicServerEvent | ConnectPrivateServerEvent>
|
|
164
|
+
implements AsyncIterable<Event>
|
|
165
|
+
{
|
|
50
166
|
private readonly client: Upbit;
|
|
51
167
|
private readonly types: AnySubscriptionType[];
|
|
52
|
-
private readonly
|
|
168
|
+
private readonly endpoint: WsEndpoint;
|
|
169
|
+
private readonly format: WsStreamFormat | undefined;
|
|
53
170
|
private readonly maxRetries: number;
|
|
54
171
|
private readonly retryDelayMs: number;
|
|
55
172
|
private readonly onDisconnect: WsStreamOptions['onDisconnect'];
|
|
56
173
|
private readonly onReconnect: WsStreamOptions['onReconnect'];
|
|
57
174
|
private _currentWs: WS.WebSocket | null = null;
|
|
58
|
-
|
|
59
|
-
|
|
175
|
+
private _pendingListSubscriptions:
|
|
176
|
+
| {
|
|
177
|
+
resolve: (value: WsListSubscriptionsResponse) => void;
|
|
178
|
+
reject: (reason: Error) => void;
|
|
179
|
+
timer: ReturnType<typeof setTimeout>;
|
|
180
|
+
socket: WS.WebSocket;
|
|
181
|
+
ticket: string;
|
|
182
|
+
}
|
|
183
|
+
| undefined;
|
|
184
|
+
|
|
185
|
+
constructor(
|
|
186
|
+
client: Upbit,
|
|
187
|
+
types: AnySubscriptionType[],
|
|
188
|
+
privateConnection: boolean,
|
|
189
|
+
opts?: WsStreamOptions & { format?: WsStreamFormat },
|
|
190
|
+
);
|
|
191
|
+
constructor(
|
|
192
|
+
client: Upbit,
|
|
193
|
+
types: AnySubscriptionType[],
|
|
194
|
+
endpoint: WsEndpoint,
|
|
195
|
+
opts?: WsStreamOptions & { format?: WsStreamFormat },
|
|
196
|
+
);
|
|
197
|
+
constructor(
|
|
198
|
+
client: Upbit,
|
|
199
|
+
types: AnySubscriptionType[],
|
|
200
|
+
endpoint: WsEndpoint | boolean,
|
|
201
|
+
opts: WsStreamOptions & { format?: WsStreamFormat } = {},
|
|
202
|
+
) {
|
|
60
203
|
this.client = client;
|
|
61
204
|
this.types = types;
|
|
62
|
-
this.
|
|
205
|
+
this.endpoint =
|
|
206
|
+
typeof endpoint === 'boolean' ?
|
|
207
|
+
endpoint ? WsEndpoint.Private
|
|
208
|
+
: WsEndpoint.Public
|
|
209
|
+
: endpoint;
|
|
210
|
+
this.format = opts.format;
|
|
63
211
|
this.maxRetries = opts.maxRetries ?? 5;
|
|
64
212
|
this.retryDelayMs = opts.retryDelayMs ?? 1000;
|
|
65
213
|
if (opts.onDisconnect) this.onDisconnect = opts.onDisconnect;
|
|
66
214
|
if (opts.onReconnect) this.onReconnect = opts.onReconnect;
|
|
67
215
|
}
|
|
68
216
|
|
|
217
|
+
/**
|
|
218
|
+
* Returns subscriptions for this stream's currently open connection.
|
|
219
|
+
* Start consuming the iterator before calling; calls before connection reject.
|
|
220
|
+
* The response format is unchanged. Responses are matched by request ticket.
|
|
221
|
+
*/
|
|
222
|
+
listSubscriptions(timeoutMs = 5000): Promise<WsListSubscriptionsResponse> {
|
|
223
|
+
const ws = this._currentWs;
|
|
224
|
+
if (!ws || ws.readyState !== WS.WebSocket.OPEN) {
|
|
225
|
+
return Promise.reject(new Error('WebSocket connection is not open'));
|
|
226
|
+
}
|
|
227
|
+
if (this._pendingListSubscriptions) {
|
|
228
|
+
return Promise.reject(new Error('LIST_SUBSCRIPTIONS request is already pending'));
|
|
229
|
+
}
|
|
230
|
+
return new Promise((resolve, reject) => {
|
|
231
|
+
const message = buildListSubscriptionsMessage(this.format);
|
|
232
|
+
const ticket: string = JSON.parse(message)[0].ticket;
|
|
233
|
+
const timer = setTimeout(() => {
|
|
234
|
+
if (this._pendingListSubscriptions?.ticket === ticket) {
|
|
235
|
+
this._settlePendingListSubscriptions(
|
|
236
|
+
ws,
|
|
237
|
+
new Error('LIST_SUBSCRIPTIONS response not received within timeout'),
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
}, timeoutMs);
|
|
241
|
+
this._pendingListSubscriptions = { resolve, reject, timer, socket: ws, ticket };
|
|
242
|
+
try {
|
|
243
|
+
ws.send(message);
|
|
244
|
+
} catch (error) {
|
|
245
|
+
this._settlePendingListSubscriptions(ws, error instanceof Error ? error : new Error(String(error)));
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
69
250
|
/** Closes the current WebSocket connection. */
|
|
70
251
|
close(): void {
|
|
252
|
+
if (this._currentWs) this._settlePendingListSubscriptions(this._currentWs, new Error('WebSocket closed'));
|
|
71
253
|
if (
|
|
72
254
|
this._currentWs &&
|
|
73
255
|
(this._currentWs.readyState === WS.WebSocket.OPEN ||
|
|
@@ -77,47 +259,73 @@ export class WsStreamManager implements AsyncIterable<ConnectPublicServerEvent |
|
|
|
77
259
|
}
|
|
78
260
|
}
|
|
79
261
|
|
|
80
|
-
[Symbol.asyncIterator](): AsyncGenerator<
|
|
81
|
-
|
|
262
|
+
[Symbol.asyncIterator](): AsyncGenerator<Event> {
|
|
263
|
+
const iterator = this._iterate();
|
|
264
|
+
const finish = iterator.return.bind(iterator);
|
|
265
|
+
iterator.return = (value) => {
|
|
266
|
+
if (this._currentWs)
|
|
267
|
+
this._settlePendingListSubscriptions(this._currentWs, new Error('WebSocket iterator ended'));
|
|
268
|
+
this.close();
|
|
269
|
+
return finish(value);
|
|
270
|
+
};
|
|
271
|
+
return iterator;
|
|
82
272
|
}
|
|
83
273
|
|
|
84
|
-
private async *_iterate(): AsyncGenerator<
|
|
274
|
+
private async *_iterate(): AsyncGenerator<Event> {
|
|
85
275
|
let retries = 0;
|
|
86
276
|
|
|
87
277
|
while (true) {
|
|
88
|
-
const queue:
|
|
278
|
+
const queue: WsStreamEvent[] = [];
|
|
89
279
|
let resolve: (() => void) | null = null;
|
|
90
280
|
let reject: ((err: Error) => void) | null = null;
|
|
91
281
|
let done = false;
|
|
92
282
|
let closeCode = 1000;
|
|
93
283
|
let closeReason = '';
|
|
284
|
+
let pingTimer: ReturnType<typeof setInterval> | undefined;
|
|
94
285
|
|
|
95
286
|
const ws = await this._connect();
|
|
96
287
|
this._currentWs = ws;
|
|
97
288
|
|
|
98
289
|
ws.on('message', (data: WS.RawData) => {
|
|
290
|
+
let parsed: unknown;
|
|
99
291
|
try {
|
|
100
|
-
|
|
101
|
-
| ConnectPublicServerEvent
|
|
102
|
-
| ConnectPrivateServerEvent;
|
|
103
|
-
queue.push(parsed);
|
|
104
|
-
resolve?.();
|
|
105
|
-
resolve = null;
|
|
292
|
+
parsed = parseWebSocketValue(data);
|
|
106
293
|
} catch {
|
|
107
|
-
//
|
|
294
|
+
return; // Preserve the stream's existing handling of malformed JSON.
|
|
108
295
|
}
|
|
296
|
+
const items = Array.isArray(parsed) ? parsed : [parsed];
|
|
297
|
+
const remaining = items.filter((item) => {
|
|
298
|
+
if (!isListSubscriptionsResponse(item)) return true;
|
|
299
|
+
return !this._settlePendingListSubscriptions(ws, item);
|
|
300
|
+
});
|
|
301
|
+
if (remaining.length > 0 || (Array.isArray(parsed) && parsed.length === 0)) {
|
|
302
|
+
// Preserve the single versus list envelope for every endpoint.
|
|
303
|
+
queue.push((Array.isArray(parsed) ? remaining : remaining[0]) as WsStreamEvent);
|
|
304
|
+
}
|
|
305
|
+
resolve?.();
|
|
306
|
+
resolve = null;
|
|
109
307
|
});
|
|
110
308
|
|
|
309
|
+
if (this.endpoint === WsEndpoint.Info) {
|
|
310
|
+
pingTimer = setInterval(() => {
|
|
311
|
+
if (ws.readyState === WS.WebSocket.OPEN) ws.ping();
|
|
312
|
+
}, 30_000);
|
|
313
|
+
}
|
|
314
|
+
|
|
111
315
|
ws.on('close', (code: number, reason: Buffer) => {
|
|
316
|
+
if (pingTimer !== undefined) clearInterval(pingTimer);
|
|
112
317
|
done = true;
|
|
113
318
|
closeCode = code;
|
|
114
319
|
closeReason = reason.toString();
|
|
320
|
+
this._settlePendingListSubscriptions(ws, new Error(`WebSocket disconnected (code=${code})`));
|
|
115
321
|
resolve?.();
|
|
116
322
|
resolve = null;
|
|
117
323
|
});
|
|
118
324
|
|
|
119
325
|
ws.on('error', (err: Error) => {
|
|
326
|
+
if (pingTimer !== undefined) clearInterval(pingTimer);
|
|
120
327
|
done = true;
|
|
328
|
+
this._settlePendingListSubscriptions(ws, err);
|
|
121
329
|
reject?.(err);
|
|
122
330
|
reject = null;
|
|
123
331
|
resolve?.();
|
|
@@ -133,11 +341,13 @@ export class WsStreamManager implements AsyncIterable<ConnectPublicServerEvent |
|
|
|
133
341
|
});
|
|
134
342
|
}
|
|
135
343
|
while (queue.length > 0) {
|
|
136
|
-
yield queue.shift()
|
|
344
|
+
yield queue.shift()! as Event;
|
|
137
345
|
}
|
|
138
346
|
}
|
|
139
347
|
} finally {
|
|
140
|
-
|
|
348
|
+
if (pingTimer !== undefined) clearInterval(pingTimer);
|
|
349
|
+
this._settlePendingListSubscriptions(ws, new Error('WebSocket iterator ended'));
|
|
350
|
+
if (this._currentWs === ws) this._currentWs = null;
|
|
141
351
|
if (ws.readyState === WS.WebSocket.OPEN || ws.readyState === WS.WebSocket.CONNECTING) {
|
|
142
352
|
ws.close();
|
|
143
353
|
}
|
|
@@ -165,25 +375,30 @@ export class WsStreamManager implements AsyncIterable<ConnectPublicServerEvent |
|
|
|
165
375
|
}
|
|
166
376
|
|
|
167
377
|
private async _connect(): Promise<WS.WebSocket> {
|
|
168
|
-
const url =
|
|
378
|
+
const url =
|
|
379
|
+
this.endpoint === WsEndpoint.Info ? buildInfoURL(this.client)
|
|
380
|
+
: this.endpoint === WsEndpoint.Private ? buildPrivateURL(this.client)
|
|
381
|
+
: buildPublicURL(this.client);
|
|
169
382
|
|
|
170
|
-
|
|
383
|
+
let authHeaders: Record<string, string> | undefined;
|
|
171
384
|
|
|
172
|
-
if (this.
|
|
385
|
+
if (requiresAuth(this.endpoint)) {
|
|
173
386
|
const { accessKey, secretKey } = this.client;
|
|
174
387
|
if (!accessKey || !secretKey) {
|
|
175
|
-
throw new Error(
|
|
388
|
+
throw new Error(`${this.endpoint} WebSocket requires accessKey and secretKey`);
|
|
176
389
|
}
|
|
177
390
|
const token = createJwtToken(accessKey, secretKey);
|
|
178
|
-
|
|
391
|
+
authHeaders = { Authorization: `Bearer ${token}` };
|
|
179
392
|
}
|
|
180
393
|
|
|
394
|
+
const headers = this.client._buildWebSocketHandshakeHeaders(authHeaders);
|
|
395
|
+
|
|
181
396
|
return new Promise<WS.WebSocket>((resolve, reject) => {
|
|
182
397
|
const ws = new WS.WebSocket(url.toString(), { headers });
|
|
183
398
|
|
|
184
399
|
const onOpen = () => {
|
|
185
400
|
ws.removeListener('error', onError);
|
|
186
|
-
ws.send(buildSubscriptionMessage(this.types));
|
|
401
|
+
ws.send(buildSubscriptionMessage(this.types, this.format));
|
|
187
402
|
resolve(ws);
|
|
188
403
|
};
|
|
189
404
|
|
|
@@ -196,6 +411,23 @@ export class WsStreamManager implements AsyncIterable<ConnectPublicServerEvent |
|
|
|
196
411
|
ws.once('error', onError);
|
|
197
412
|
});
|
|
198
413
|
}
|
|
414
|
+
|
|
415
|
+
private _settlePendingListSubscriptions(
|
|
416
|
+
ws: WS.WebSocket,
|
|
417
|
+
result: Error | WsListSubscriptionsResponse,
|
|
418
|
+
): boolean {
|
|
419
|
+
const pending = this._pendingListSubscriptions;
|
|
420
|
+
if (!pending || pending.socket !== ws) return false;
|
|
421
|
+
if (!(result instanceof Error)) {
|
|
422
|
+
const ticket = 'ticket' in result ? result.ticket : result.tckt;
|
|
423
|
+
if (pending.ticket !== ticket) return false;
|
|
424
|
+
}
|
|
425
|
+
this._pendingListSubscriptions = undefined;
|
|
426
|
+
clearTimeout(pending.timer);
|
|
427
|
+
if (result instanceof Error) pending.reject(result);
|
|
428
|
+
else pending.resolve(result);
|
|
429
|
+
return true;
|
|
430
|
+
}
|
|
199
431
|
}
|
|
200
432
|
|
|
201
433
|
/**
|
|
@@ -208,34 +440,67 @@ export class WsStream {
|
|
|
208
440
|
constructor(private readonly client: Upbit) {}
|
|
209
441
|
|
|
210
442
|
/** Subscribe to the ticker (current price) stream. */
|
|
211
|
-
ticker(codes: string[], opts?: WsStreamOptions): WsStreamManager {
|
|
212
|
-
return new WsStreamManager(this.client, [{ type: 'ticker', codes }],
|
|
443
|
+
ticker(codes: string[], opts?: WsStreamOptions): WsStreamManager<PublicEvent<'ticker'>> {
|
|
444
|
+
return new WsStreamManager(this.client, [{ type: 'ticker', codes }], WsEndpoint.Public, opts);
|
|
213
445
|
}
|
|
214
446
|
|
|
215
447
|
/** Subscribe to the trade (executed order) stream. */
|
|
216
|
-
trade(codes: string[], opts?: WsStreamOptions): WsStreamManager {
|
|
217
|
-
return new WsStreamManager(this.client, [{ type: 'trade', codes }],
|
|
448
|
+
trade(codes: string[], opts?: WsStreamOptions): WsStreamManager<PublicEvent<'trade'>> {
|
|
449
|
+
return new WsStreamManager(this.client, [{ type: 'trade', codes }], WsEndpoint.Public, opts);
|
|
218
450
|
}
|
|
219
451
|
|
|
220
452
|
/** Subscribe to the orderbook stream. */
|
|
221
|
-
orderbook(codes: string[], opts?: WsStreamOptions): WsStreamManager {
|
|
222
|
-
return new WsStreamManager(this.client, [{ type: 'orderbook', codes }],
|
|
453
|
+
orderbook(codes: string[], opts?: WsStreamOptions): WsStreamManager<PublicEvent<'orderbook'>> {
|
|
454
|
+
return new WsStreamManager(this.client, [{ type: 'orderbook', codes }], WsEndpoint.Public, opts);
|
|
223
455
|
}
|
|
224
456
|
|
|
225
457
|
/** Subscribe to the candle stream. */
|
|
226
|
-
candle(codes: string[], opts?: { interval?: string } & WsStreamOptions): WsStreamManager {
|
|
458
|
+
candle(codes: string[], opts?: { interval?: string } & WsStreamOptions): WsStreamManager<CandleEvent> {
|
|
227
459
|
const { interval = '1m', ...streamOpts } = opts ?? {};
|
|
228
|
-
return new WsStreamManager(
|
|
460
|
+
return new WsStreamManager(
|
|
461
|
+
this.client,
|
|
462
|
+
[{ type: `candle.${interval}`, codes }],
|
|
463
|
+
WsEndpoint.Public,
|
|
464
|
+
streamOpts,
|
|
465
|
+
);
|
|
229
466
|
}
|
|
230
467
|
|
|
231
468
|
/** Subscribe to the myOrder (my orders) stream. Requires authentication. */
|
|
232
|
-
myOrder(codes: string[], opts?: WsStreamOptions): WsStreamManager {
|
|
233
|
-
return new WsStreamManager(this.client, [{ type: 'myOrder', codes }],
|
|
469
|
+
myOrder(codes: string[], opts?: WsStreamOptions): WsStreamManager<PrivateEvent<'myOrder'>> {
|
|
470
|
+
return new WsStreamManager(this.client, [{ type: 'myOrder', codes }], WsEndpoint.Private, opts);
|
|
234
471
|
}
|
|
235
472
|
|
|
236
473
|
/** Subscribe to the myAsset (my assets) stream. Requires authentication. */
|
|
237
|
-
myAsset(opts?: WsStreamOptions): WsStreamManager {
|
|
238
|
-
return new WsStreamManager(this.client, [{ type: 'myAsset' }],
|
|
474
|
+
myAsset(opts?: WsStreamOptions): WsStreamManager<PrivateEvent<'myAsset'>> {
|
|
475
|
+
return new WsStreamManager(this.client, [{ type: 'myAsset' }], WsEndpoint.Private, opts);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/** Subscribe to the announcement stream. Requires authentication. */
|
|
479
|
+
announcement(opts?: WsAnnouncementOptions): WsStreamManager<PrivateEvent<'announcement'>> {
|
|
480
|
+
const { categories, includeBody, ...streamOpts } = opts ?? {};
|
|
481
|
+
return new WsStreamManager(
|
|
482
|
+
this.client,
|
|
483
|
+
[buildAnnouncementSubscription(categories, includeBody)],
|
|
484
|
+
WsEndpoint.Private,
|
|
485
|
+
streamOpts,
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/** Subscribe to calculated indicator values. Requires authentication. */
|
|
490
|
+
indicator(codes: string[], opts: WsIndicatorOptions): WsStreamManager<InfoEvent<'indicator'>> {
|
|
491
|
+
const { timeframe, indicators, format = 'DEFAULT', ...streamOpts } = opts;
|
|
492
|
+
const subscription: InfoSubscription = { type: 'indicator', codes, timeframe, indicators };
|
|
493
|
+
return new WsStreamManager(this.client, [subscription], WsEndpoint.Info, { ...streamOpts, format });
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/** Subscribe to technical indicator condition transitions. Requires authentication. */
|
|
497
|
+
indicatorSignal(
|
|
498
|
+
codes: string[],
|
|
499
|
+
opts: WsIndicatorSignalOptions,
|
|
500
|
+
): WsStreamManager<InfoEvent<'indicator_signal'>> {
|
|
501
|
+
const { timeframe, indicators, format = 'DEFAULT', ...streamOpts } = opts;
|
|
502
|
+
const subscription: InfoSubscription = { type: 'indicator_signal', codes, timeframe, indicators };
|
|
503
|
+
return new WsStreamManager(this.client, [subscription], WsEndpoint.Info, { ...streamOpts, format });
|
|
239
504
|
}
|
|
240
505
|
|
|
241
506
|
/** Subscribe to multiple public streams at once. */
|
|
@@ -246,37 +511,84 @@ export class WsStream {
|
|
|
246
511
|
orderbook?: string[];
|
|
247
512
|
candle?: { codes: string[]; interval?: string };
|
|
248
513
|
} & WsStreamOptions,
|
|
249
|
-
): WsStreamManager {
|
|
250
|
-
const { ticker, trade, orderbook, candle, maxRetries, retryDelayMs, onDisconnect, onReconnect } =
|
|
514
|
+
): WsStreamManager<ConnectPublicServerEvent> {
|
|
515
|
+
const { ticker, trade, orderbook, candle, format, maxRetries, retryDelayMs, onDisconnect, onReconnect } =
|
|
516
|
+
opts;
|
|
251
517
|
const types: AnySubscriptionType[] = [];
|
|
252
518
|
if (ticker) types.push({ type: 'ticker', codes: ticker });
|
|
253
519
|
if (trade) types.push({ type: 'trade', codes: trade });
|
|
254
520
|
if (orderbook) types.push({ type: 'orderbook', codes: orderbook });
|
|
255
521
|
if (candle) types.push({ type: `candle.${candle.interval ?? '1m'}`, codes: candle.codes });
|
|
256
522
|
const streamOpts: WsStreamOptions = {};
|
|
523
|
+
if (format !== undefined) streamOpts.format = format;
|
|
257
524
|
if (maxRetries !== undefined) streamOpts.maxRetries = maxRetries;
|
|
258
525
|
if (retryDelayMs !== undefined) streamOpts.retryDelayMs = retryDelayMs;
|
|
259
526
|
if (onDisconnect) streamOpts.onDisconnect = onDisconnect;
|
|
260
527
|
if (onReconnect) streamOpts.onReconnect = onReconnect;
|
|
261
|
-
return new WsStreamManager(this.client, types,
|
|
528
|
+
return new WsStreamManager(this.client, types, WsEndpoint.Public, streamOpts);
|
|
262
529
|
}
|
|
263
530
|
|
|
264
531
|
/** Subscribe to multiple private streams at once. Requires authentication. */
|
|
265
532
|
subscribePrivate(
|
|
266
533
|
opts: {
|
|
534
|
+
announcement?: boolean | Pick<WsAnnouncementOptions, 'categories' | 'includeBody'>;
|
|
267
535
|
myOrder?: string[];
|
|
268
536
|
myAsset?: boolean;
|
|
269
537
|
} & WsStreamOptions,
|
|
270
|
-
): WsStreamManager {
|
|
271
|
-
const { myOrder, myAsset, maxRetries, retryDelayMs, onDisconnect, onReconnect } =
|
|
538
|
+
): WsStreamManager<ConnectPrivateServerEvent> {
|
|
539
|
+
const { announcement, myOrder, myAsset, format, maxRetries, retryDelayMs, onDisconnect, onReconnect } =
|
|
540
|
+
opts;
|
|
272
541
|
const types: AnySubscriptionType[] = [];
|
|
542
|
+
if (announcement) {
|
|
543
|
+
types.push(
|
|
544
|
+
buildAnnouncementSubscription(
|
|
545
|
+
announcement === true ? undefined : announcement.categories,
|
|
546
|
+
announcement === true ? undefined : announcement.includeBody,
|
|
547
|
+
),
|
|
548
|
+
);
|
|
549
|
+
}
|
|
273
550
|
if (myOrder) types.push({ type: 'myOrder', codes: myOrder });
|
|
274
551
|
if (myAsset) types.push({ type: 'myAsset' });
|
|
275
|
-
const streamOpts: WsStreamOptions = {};
|
|
552
|
+
const streamOpts: WsStreamOptions & { format?: WsStreamFormat } = {};
|
|
553
|
+
if (format !== undefined) streamOpts.format = format;
|
|
554
|
+
if (maxRetries !== undefined) streamOpts.maxRetries = maxRetries;
|
|
555
|
+
if (retryDelayMs !== undefined) streamOpts.retryDelayMs = retryDelayMs;
|
|
556
|
+
if (onDisconnect) streamOpts.onDisconnect = onDisconnect;
|
|
557
|
+
if (onReconnect) streamOpts.onReconnect = onReconnect;
|
|
558
|
+
return new WsStreamManager(this.client, types, WsEndpoint.Private, streamOpts);
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/** Subscribe to multiple info streams at once. Requires authentication. */
|
|
562
|
+
subscribeInfo(
|
|
563
|
+
opts: {
|
|
564
|
+
indicator?: WsIndicatorSubscription | WsIndicatorSubscription[];
|
|
565
|
+
indicatorSignal?: WsIndicatorSignalSubscription | WsIndicatorSignalSubscription[];
|
|
566
|
+
} & WsStreamOptions,
|
|
567
|
+
): WsStreamManager<ConnectInfoServerEvent> {
|
|
568
|
+
const { indicator, indicatorSignal, format, maxRetries, retryDelayMs, onDisconnect, onReconnect } = opts;
|
|
569
|
+
const subscriptions: InfoSubscription[] = [
|
|
570
|
+
...(indicator ?
|
|
571
|
+
Array.isArray(indicator) ?
|
|
572
|
+
indicator
|
|
573
|
+
: [indicator]
|
|
574
|
+
: []
|
|
575
|
+
).map((item): InfoSubscription => ({ ...item, type: 'indicator' })),
|
|
576
|
+
...(indicatorSignal ?
|
|
577
|
+
Array.isArray(indicatorSignal) ?
|
|
578
|
+
indicatorSignal
|
|
579
|
+
: [indicatorSignal]
|
|
580
|
+
: []
|
|
581
|
+
).map((item): InfoSubscription => ({ ...item, type: 'indicator_signal' })),
|
|
582
|
+
];
|
|
583
|
+
if (subscriptions.length === 0) {
|
|
584
|
+
throw new Error('At least one subscription type must be specified');
|
|
585
|
+
}
|
|
586
|
+
const streamOpts: WsStreamOptions & { format?: WsStreamFormat } = {};
|
|
587
|
+
if (format !== undefined) streamOpts.format = format;
|
|
276
588
|
if (maxRetries !== undefined) streamOpts.maxRetries = maxRetries;
|
|
277
589
|
if (retryDelayMs !== undefined) streamOpts.retryDelayMs = retryDelayMs;
|
|
278
590
|
if (onDisconnect) streamOpts.onDisconnect = onDisconnect;
|
|
279
591
|
if (onReconnect) streamOpts.onReconnect = onReconnect;
|
|
280
|
-
return new WsStreamManager(this.client,
|
|
592
|
+
return new WsStreamManager(this.client, subscriptions, WsEndpoint.Info, streamOpts);
|
|
281
593
|
}
|
|
282
594
|
}
|
package/src/resources/index.ts
CHANGED
|
@@ -120,5 +120,45 @@ export {
|
|
|
120
120
|
type WithdrawRetrieveChanceParams,
|
|
121
121
|
type WithdrawsUuidCursorIDPage,
|
|
122
122
|
} from './withdraws';
|
|
123
|
-
export {
|
|
124
|
-
|
|
123
|
+
export {
|
|
124
|
+
WsInfo,
|
|
125
|
+
type BollingerBandsIndicator,
|
|
126
|
+
type BollingerBandsIndicatorSignal,
|
|
127
|
+
type Indicator,
|
|
128
|
+
type IndicatorSignal,
|
|
129
|
+
type IndicatorTimeframe,
|
|
130
|
+
type IndicatorType,
|
|
131
|
+
type MaCrossoverIndicator,
|
|
132
|
+
type MaCrossoverIndicatorSignal,
|
|
133
|
+
type MacdIndicator,
|
|
134
|
+
type MacdIndicatorSignal,
|
|
135
|
+
type MovingAverageIndicator,
|
|
136
|
+
type MovingAverageIndicatorSignal,
|
|
137
|
+
type RsiIndicator,
|
|
138
|
+
type RsiIndicatorSignal,
|
|
139
|
+
type RsiOverboughtIndicatorSignal,
|
|
140
|
+
type RsiOverboughtIndicatorSignalRequest,
|
|
141
|
+
type RsiOversoldIndicatorSignal,
|
|
142
|
+
type RsiOversoldIndicatorSignalRequest,
|
|
143
|
+
type VolumeIndicator,
|
|
144
|
+
type VolumeIndicatorSignal,
|
|
145
|
+
type ConnectInfoClientEvent,
|
|
146
|
+
type ConnectInfoServerEvent,
|
|
147
|
+
} from './ws-info';
|
|
148
|
+
export {
|
|
149
|
+
WsPrivate,
|
|
150
|
+
type Announcement,
|
|
151
|
+
type AnnouncementCategory,
|
|
152
|
+
type AnnouncementEventType,
|
|
153
|
+
type ConnectPrivateClientEvent,
|
|
154
|
+
type ConnectPrivateServerEvent,
|
|
155
|
+
type ConnectPrivateServerMessage,
|
|
156
|
+
} from './ws-private';
|
|
157
|
+
export {
|
|
158
|
+
WsPublic,
|
|
159
|
+
type ConnectPublicClientEvent,
|
|
160
|
+
type ConnectPublicServerEvent,
|
|
161
|
+
type ListSubscriptionsResponse,
|
|
162
|
+
type ListSubscriptionsServerResponse,
|
|
163
|
+
type SimpleListSubscriptionsResponse,
|
|
164
|
+
} from './ws-public';
|