@pipsend/sdk 0.1.0 → 0.1.2
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/README.md +259 -32
- package/dist/index.d.mts +328 -29
- package/dist/index.d.ts +328 -29
- package/dist/index.js +313 -74
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +313 -74
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -32,11 +32,30 @@ module.exports = __toCommonJS(index_exports);
|
|
|
32
32
|
|
|
33
33
|
// src/types/index.ts
|
|
34
34
|
var PipsendError = class extends Error {
|
|
35
|
-
constructor(message, code, statusCode) {
|
|
35
|
+
constructor(message, code, statusCode, errors, response) {
|
|
36
36
|
super(message);
|
|
37
37
|
this.code = code;
|
|
38
38
|
this.statusCode = statusCode;
|
|
39
39
|
this.name = "PipsendError";
|
|
40
|
+
this.errors = errors;
|
|
41
|
+
this.response = response;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Get formatted error message with validation details
|
|
45
|
+
*/
|
|
46
|
+
getDetailedMessage() {
|
|
47
|
+
if (!this.errors || this.errors.length === 0) {
|
|
48
|
+
return this.message;
|
|
49
|
+
}
|
|
50
|
+
const errorDetails = this.errors.map((err) => ` - ${err.field}: ${err.message}`).join("\n");
|
|
51
|
+
return `${this.message}
|
|
52
|
+
${errorDetails}`;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Check if this is a validation error
|
|
56
|
+
*/
|
|
57
|
+
isValidationError() {
|
|
58
|
+
return this.statusCode === 422 || this.code === "VALIDATION_ERROR";
|
|
40
59
|
}
|
|
41
60
|
};
|
|
42
61
|
var AuthenticationError = class extends PipsendError {
|
|
@@ -91,17 +110,35 @@ var AuthManager = class {
|
|
|
91
110
|
}
|
|
92
111
|
/**
|
|
93
112
|
* Performs authentication with the server
|
|
94
|
-
* TODO: Implement real API call when available
|
|
95
113
|
*/
|
|
96
114
|
async authenticate() {
|
|
115
|
+
if (!this.config.login || !this.config.password) {
|
|
116
|
+
throw new AuthenticationError(
|
|
117
|
+
"Login and password are required for authentication. Please provide them in the config."
|
|
118
|
+
);
|
|
119
|
+
}
|
|
97
120
|
try {
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
121
|
+
const response = await fetch(`${this.config.server}/api/v1/auth/login`, {
|
|
122
|
+
method: "POST",
|
|
123
|
+
headers: { "Content-Type": "application/json" },
|
|
124
|
+
body: JSON.stringify({
|
|
125
|
+
login: this.config.login,
|
|
126
|
+
password: this.config.password
|
|
127
|
+
})
|
|
128
|
+
});
|
|
129
|
+
if (!response.ok) {
|
|
130
|
+
const errorData = await response.json().catch(() => ({}));
|
|
131
|
+
throw new AuthenticationError(
|
|
132
|
+
errorData.message || `Authentication failed: ${response.status} ${response.statusText}`
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
const data = await response.json();
|
|
136
|
+
this.setTokenInfo(data);
|
|
137
|
+
console.log("\u2705 Authentication successful");
|
|
138
|
+
console.log(` User: ${data.user.first_name} ${data.user.last_name} (${data.user.email})`);
|
|
139
|
+
console.log(` Login: ${data.user.login}`);
|
|
140
|
+
console.log(` Balance: $${data.user.balance.toFixed(2)}`);
|
|
141
|
+
console.log(` Logged with: ${data.logged_with}`);
|
|
105
142
|
} catch (error) {
|
|
106
143
|
if (error instanceof AuthenticationError) {
|
|
107
144
|
throw error;
|
|
@@ -112,11 +149,45 @@ var AuthManager = class {
|
|
|
112
149
|
}
|
|
113
150
|
}
|
|
114
151
|
/**
|
|
115
|
-
*
|
|
152
|
+
* Refreshes the access token using the refresh token
|
|
116
153
|
*/
|
|
117
154
|
async refreshToken() {
|
|
118
|
-
this.tokenInfo
|
|
119
|
-
|
|
155
|
+
if (!this.tokenInfo?.refreshToken) {
|
|
156
|
+
console.log("\u26A0\uFE0F No refresh token available, performing full authentication");
|
|
157
|
+
this.tokenInfo = void 0;
|
|
158
|
+
await this.authenticate();
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
try {
|
|
162
|
+
const response = await fetch(`${this.config.server}/api/v1/auth/refresh`, {
|
|
163
|
+
method: "POST",
|
|
164
|
+
headers: { "Content-Type": "application/json" },
|
|
165
|
+
body: JSON.stringify({
|
|
166
|
+
refresh_token: this.tokenInfo.refreshToken
|
|
167
|
+
})
|
|
168
|
+
});
|
|
169
|
+
if (!response.ok) {
|
|
170
|
+
console.log("\u26A0\uFE0F Refresh token failed, performing full authentication");
|
|
171
|
+
this.tokenInfo = void 0;
|
|
172
|
+
await this.authenticate();
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const data = await response.json();
|
|
176
|
+
const now = /* @__PURE__ */ new Date();
|
|
177
|
+
const expiresAt = new Date(now.getTime() + data.expires_in * 1e3);
|
|
178
|
+
this.tokenInfo = {
|
|
179
|
+
token: data.access_token,
|
|
180
|
+
refreshToken: this.tokenInfo.refreshToken,
|
|
181
|
+
// Keep the same refresh token
|
|
182
|
+
issuedAt: now,
|
|
183
|
+
expiresAt
|
|
184
|
+
};
|
|
185
|
+
console.log("\u2705 Token refreshed successfully");
|
|
186
|
+
} catch (error) {
|
|
187
|
+
console.error("\u274C Error refreshing token:", error);
|
|
188
|
+
this.tokenInfo = void 0;
|
|
189
|
+
await this.authenticate();
|
|
190
|
+
}
|
|
120
191
|
}
|
|
121
192
|
/**
|
|
122
193
|
* Clears the current token
|
|
@@ -138,9 +209,10 @@ var AuthManager = class {
|
|
|
138
209
|
*/
|
|
139
210
|
setTokenInfo(response) {
|
|
140
211
|
const now = /* @__PURE__ */ new Date();
|
|
141
|
-
const expiresAt = new Date(now.getTime() + response.
|
|
212
|
+
const expiresAt = new Date(now.getTime() + response.expires_in * 1e3);
|
|
142
213
|
this.tokenInfo = {
|
|
143
|
-
token: response.
|
|
214
|
+
token: response.access_token,
|
|
215
|
+
refreshToken: response.refresh_token,
|
|
144
216
|
issuedAt: now,
|
|
145
217
|
expiresAt
|
|
146
218
|
};
|
|
@@ -171,8 +243,9 @@ var WebSocketManager = class {
|
|
|
171
243
|
console.log("\u26A0\uFE0F WebSocket reconnection in progress");
|
|
172
244
|
return;
|
|
173
245
|
}
|
|
174
|
-
const wsUrl = this.buildWebSocketUrl();
|
|
175
246
|
const token = await this.authManager.ensureAuthenticated();
|
|
247
|
+
const baseWsUrl = this.buildWebSocketUrl();
|
|
248
|
+
const wsUrl = `${baseWsUrl}${baseWsUrl.includes("?") ? "&" : "?"}token=${encodeURIComponent(token)}`;
|
|
176
249
|
return new Promise((resolve, reject) => {
|
|
177
250
|
try {
|
|
178
251
|
const WS = this.getWebSocketConstructor();
|
|
@@ -182,11 +255,6 @@ var WebSocketManager = class {
|
|
|
182
255
|
this.isConnected = true;
|
|
183
256
|
this.isReconnecting = false;
|
|
184
257
|
this.reconnectAttempts = 0;
|
|
185
|
-
this.send({
|
|
186
|
-
type: "auth",
|
|
187
|
-
payload: { token },
|
|
188
|
-
timestamp: Date.now()
|
|
189
|
-
});
|
|
190
258
|
this.emit("connected", { timestamp: Date.now() });
|
|
191
259
|
if (this.subscribedChannels.length > 0) {
|
|
192
260
|
console.log("\u{1F504} Resubscribing to channels:", this.subscribedChannels);
|
|
@@ -229,24 +297,22 @@ var WebSocketManager = class {
|
|
|
229
297
|
});
|
|
230
298
|
}
|
|
231
299
|
/**
|
|
232
|
-
* Subscribes to channels
|
|
233
|
-
* TODO: Adjust message format according to real WebSocket API
|
|
300
|
+
* Subscribes to WebSocket channels
|
|
234
301
|
*/
|
|
235
302
|
subscribe(channels) {
|
|
236
303
|
if (!this.isConnected) {
|
|
237
304
|
throw new WebSocketError("WebSocket not connected. Call connect() first.");
|
|
238
305
|
}
|
|
239
306
|
this.subscribedChannels = [.../* @__PURE__ */ new Set([...this.subscribedChannels, ...channels])];
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
307
|
+
const message = {
|
|
308
|
+
action: "subscribe",
|
|
309
|
+
channels
|
|
310
|
+
};
|
|
311
|
+
this.sendAction(message);
|
|
245
312
|
console.log("\u{1F4E1} Subscribed to channels:", channels);
|
|
246
313
|
}
|
|
247
314
|
/**
|
|
248
|
-
* Unsubscribes from channels
|
|
249
|
-
* TODO: Adjust message format according to real WebSocket API
|
|
315
|
+
* Unsubscribes from WebSocket channels
|
|
250
316
|
*/
|
|
251
317
|
unsubscribe(channels) {
|
|
252
318
|
if (!this.isConnected) {
|
|
@@ -256,11 +322,11 @@ var WebSocketManager = class {
|
|
|
256
322
|
this.subscribedChannels = this.subscribedChannels.filter(
|
|
257
323
|
(ch) => !channels.includes(ch)
|
|
258
324
|
);
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
325
|
+
const message = {
|
|
326
|
+
action: "unsubscribe",
|
|
327
|
+
channels
|
|
328
|
+
};
|
|
329
|
+
this.sendAction(message);
|
|
264
330
|
console.log("\u{1F4E1} Unsubscribed from channels:", channels);
|
|
265
331
|
}
|
|
266
332
|
/**
|
|
@@ -317,7 +383,7 @@ var WebSocketManager = class {
|
|
|
317
383
|
try {
|
|
318
384
|
const url = new URL(this.config.server);
|
|
319
385
|
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
320
|
-
const wsPath = this.config.websocket?.path || "/ws";
|
|
386
|
+
const wsPath = this.config.websocket?.path || "/api/v1/ws";
|
|
321
387
|
url.pathname = wsPath;
|
|
322
388
|
return url.toString();
|
|
323
389
|
} catch (error) {
|
|
@@ -340,11 +406,11 @@ var WebSocketManager = class {
|
|
|
340
406
|
}
|
|
341
407
|
}
|
|
342
408
|
/**
|
|
343
|
-
* Sends
|
|
409
|
+
* Sends an action message through WebSocket
|
|
344
410
|
*/
|
|
345
|
-
|
|
411
|
+
sendAction(message) {
|
|
346
412
|
if (!this.ws || !this.isConnected) {
|
|
347
|
-
console.warn("\u26A0\uFE0F WebSocket not ready, message not sent:", message.
|
|
413
|
+
console.warn("\u26A0\uFE0F WebSocket not ready, message not sent:", message.action);
|
|
348
414
|
return;
|
|
349
415
|
}
|
|
350
416
|
try {
|
|
@@ -355,21 +421,99 @@ var WebSocketManager = class {
|
|
|
355
421
|
}
|
|
356
422
|
}
|
|
357
423
|
/**
|
|
358
|
-
*
|
|
359
|
-
* TODO: Adjust message handling according to real WebSocket API
|
|
424
|
+
* Sends a ping message (for heartbeat)
|
|
360
425
|
*/
|
|
361
|
-
|
|
362
|
-
if (
|
|
363
|
-
console.log("\u2705 WebSocket authenticated");
|
|
364
|
-
this.emit("authenticated", data.payload || {});
|
|
426
|
+
sendPing() {
|
|
427
|
+
if (!this.ws || !this.isConnected) {
|
|
365
428
|
return;
|
|
366
429
|
}
|
|
367
|
-
|
|
368
|
-
|
|
430
|
+
try {
|
|
431
|
+
this.ws.send(JSON.stringify({ action: "ping" }));
|
|
432
|
+
} catch (error) {
|
|
433
|
+
console.error("\u274C Failed to send ping:", error);
|
|
369
434
|
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Handles incoming WebSocket messages
|
|
438
|
+
*/
|
|
439
|
+
handleMessage(message) {
|
|
440
|
+
switch (message.op) {
|
|
441
|
+
case "connected":
|
|
442
|
+
this.handleConnected(message);
|
|
443
|
+
break;
|
|
444
|
+
case "subscription_success":
|
|
445
|
+
this.handleSubscriptionSuccess(message);
|
|
446
|
+
break;
|
|
447
|
+
case "unsubscription_success":
|
|
448
|
+
this.handleUnsubscriptionSuccess(message);
|
|
449
|
+
break;
|
|
450
|
+
case "push":
|
|
451
|
+
this.handlePushEvent(message);
|
|
452
|
+
break;
|
|
453
|
+
case "error":
|
|
454
|
+
this.handleError(message);
|
|
455
|
+
break;
|
|
456
|
+
default:
|
|
457
|
+
console.warn(message.op);
|
|
458
|
+
}
|
|
459
|
+
this.emit("*", message);
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Handles connected message from server
|
|
463
|
+
*/
|
|
464
|
+
handleConnected(message) {
|
|
465
|
+
console.log("\u2705 WebSocket connected:", message.data.message);
|
|
466
|
+
console.log(" Available channels:", message.data.available_channels);
|
|
467
|
+
this.emit("connected", message.data);
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Handles subscription success
|
|
471
|
+
*/
|
|
472
|
+
handleSubscriptionSuccess(message) {
|
|
473
|
+
console.log("\u2705 Subscription successful:", message.data.subscribed);
|
|
474
|
+
this.emit("subscription_success", message.data);
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Handles unsubscription success
|
|
478
|
+
*/
|
|
479
|
+
handleUnsubscriptionSuccess(message) {
|
|
480
|
+
console.log("\u2705 Unsubscription successful:", message.data.unsubscribed);
|
|
481
|
+
this.emit("unsubscription_success", message.data);
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Handles push events (actual data events)
|
|
485
|
+
*/
|
|
486
|
+
handlePushEvent(message) {
|
|
487
|
+
const eventData = message.data;
|
|
488
|
+
const eventType = eventData.type;
|
|
489
|
+
switch (eventType) {
|
|
490
|
+
case "position.opened":
|
|
491
|
+
this.emit("position:opened", eventData);
|
|
492
|
+
break;
|
|
493
|
+
case "position.closed":
|
|
494
|
+
case "position.partially_closed":
|
|
495
|
+
this.emit("position:closed", eventData);
|
|
496
|
+
break;
|
|
497
|
+
case "position.updated":
|
|
498
|
+
this.emit("position:updated", eventData);
|
|
499
|
+
break;
|
|
500
|
+
default:
|
|
501
|
+
if (message.topic?.startsWith("balance:")) {
|
|
502
|
+
this.emit("balance:updated", eventData);
|
|
503
|
+
} else {
|
|
504
|
+
console.warn("Unknown event type:", eventType);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Handles error messages from server
|
|
510
|
+
*/
|
|
511
|
+
handleError(message) {
|
|
512
|
+
console.error("\u274C WebSocket error:", message.data.message);
|
|
513
|
+
if (message.data.error) {
|
|
514
|
+
console.error(" Error details:", message.data.error);
|
|
515
|
+
}
|
|
516
|
+
this.emit("error", message.data);
|
|
373
517
|
}
|
|
374
518
|
/**
|
|
375
519
|
* Emits an event to all registered listeners
|
|
@@ -420,10 +564,7 @@ var WebSocketManager = class {
|
|
|
420
564
|
const interval = this.config.websocket?.heartbeatInterval || 3e4;
|
|
421
565
|
this.heartbeatTimer = setInterval(() => {
|
|
422
566
|
if (this.isConnected) {
|
|
423
|
-
this.
|
|
424
|
-
type: "ping",
|
|
425
|
-
timestamp: Date.now()
|
|
426
|
-
});
|
|
567
|
+
this.sendPing();
|
|
427
568
|
}
|
|
428
569
|
}, interval);
|
|
429
570
|
}
|
|
@@ -440,28 +581,59 @@ var WebSocketManager = class {
|
|
|
440
581
|
|
|
441
582
|
// src/api/http-client.ts
|
|
442
583
|
var HttpClient = class {
|
|
443
|
-
constructor(baseUrl) {
|
|
584
|
+
constructor(baseUrl, authManager) {
|
|
444
585
|
this.baseUrl = baseUrl;
|
|
586
|
+
this.authManager = authManager;
|
|
445
587
|
}
|
|
446
588
|
/**
|
|
447
589
|
* Makes an HTTP request
|
|
448
590
|
*/
|
|
449
|
-
async request(endpoint, options = {}) {
|
|
591
|
+
async request(endpoint, options = {}, retryOn401 = true) {
|
|
450
592
|
const url = `${this.baseUrl}${endpoint}`;
|
|
451
593
|
try {
|
|
594
|
+
const headers = {
|
|
595
|
+
"Content-Type": "application/json",
|
|
596
|
+
...options.headers || {}
|
|
597
|
+
};
|
|
598
|
+
if (this.authManager) {
|
|
599
|
+
const token = await this.authManager.ensureAuthenticated();
|
|
600
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
601
|
+
}
|
|
452
602
|
const response = await fetch(url, {
|
|
453
603
|
...options,
|
|
454
|
-
headers
|
|
455
|
-
"Content-Type": "application/json",
|
|
456
|
-
...options.headers
|
|
457
|
-
}
|
|
604
|
+
headers
|
|
458
605
|
});
|
|
606
|
+
if (response.status === 401 && this.authManager && retryOn401) {
|
|
607
|
+
console.log("\u26A0\uFE0F Received 401, attempting to refresh token...");
|
|
608
|
+
await this.authManager.refreshToken();
|
|
609
|
+
return this.request(endpoint, options, false);
|
|
610
|
+
}
|
|
459
611
|
if (!response.ok) {
|
|
460
612
|
const errorText = await response.text();
|
|
613
|
+
let errorMessage = `HTTP ${response.status}: ${errorText || response.statusText}`;
|
|
614
|
+
let errorCode = "HTTP_ERROR";
|
|
615
|
+
let validationErrors;
|
|
616
|
+
let errorResponse;
|
|
617
|
+
try {
|
|
618
|
+
const errorJson = JSON.parse(errorText);
|
|
619
|
+
errorResponse = errorJson;
|
|
620
|
+
if (errorJson.message) {
|
|
621
|
+
errorMessage = errorJson.message;
|
|
622
|
+
}
|
|
623
|
+
if (errorJson.status_code) {
|
|
624
|
+
errorCode = errorJson.status_code;
|
|
625
|
+
}
|
|
626
|
+
if (errorJson.errors && Array.isArray(errorJson.errors)) {
|
|
627
|
+
validationErrors = errorJson.errors;
|
|
628
|
+
}
|
|
629
|
+
} catch {
|
|
630
|
+
}
|
|
461
631
|
throw new PipsendError(
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
response.status
|
|
632
|
+
errorMessage,
|
|
633
|
+
errorCode,
|
|
634
|
+
response.status,
|
|
635
|
+
validationErrors,
|
|
636
|
+
errorResponse
|
|
465
637
|
);
|
|
466
638
|
}
|
|
467
639
|
const text = await response.text();
|
|
@@ -525,6 +697,12 @@ var AccountsAPI = class {
|
|
|
525
697
|
constructor(http) {
|
|
526
698
|
this.http = http;
|
|
527
699
|
}
|
|
700
|
+
/**
|
|
701
|
+
* Create a new trading account
|
|
702
|
+
*/
|
|
703
|
+
async create(request) {
|
|
704
|
+
return this.http.post("/api/v1/accounts", request);
|
|
705
|
+
}
|
|
528
706
|
/**
|
|
529
707
|
* List all accounts with optional filters and pagination
|
|
530
708
|
*/
|
|
@@ -537,6 +715,12 @@ var AccountsAPI = class {
|
|
|
537
715
|
async getLogins() {
|
|
538
716
|
return this.http.get("/api/v1/accounts/logins");
|
|
539
717
|
}
|
|
718
|
+
/**
|
|
719
|
+
* Get account status/metrics (balance, equity, credit, margin)
|
|
720
|
+
*/
|
|
721
|
+
async getStatus(login) {
|
|
722
|
+
return this.http.get(`/api/v1/accounts/${login}/status`);
|
|
723
|
+
}
|
|
540
724
|
/**
|
|
541
725
|
* Get account statistics with optional filters
|
|
542
726
|
*/
|
|
@@ -567,6 +751,20 @@ var AccountsAPI = class {
|
|
|
567
751
|
async unarchive(login) {
|
|
568
752
|
return this.http.put(`/api/v1/accounts/${login}/unarchive`);
|
|
569
753
|
}
|
|
754
|
+
/**
|
|
755
|
+
* Update account information (partial update)
|
|
756
|
+
* All fields are optional, only send the ones you want to update
|
|
757
|
+
*/
|
|
758
|
+
async update(login, request) {
|
|
759
|
+
return this.http.put(`/api/v1/accounts/${login}`, request);
|
|
760
|
+
}
|
|
761
|
+
/**
|
|
762
|
+
* Adjust balance or credit for an account
|
|
763
|
+
* The adjustment is relative: amount is added or subtracted from current value
|
|
764
|
+
*/
|
|
765
|
+
async balance(login, request) {
|
|
766
|
+
return this.http.put(`/api/v1/accounts/${login}/adjust`, request);
|
|
767
|
+
}
|
|
570
768
|
};
|
|
571
769
|
|
|
572
770
|
// src/api/trading-groups.ts
|
|
@@ -863,9 +1061,9 @@ var PipsendClient = class {
|
|
|
863
1061
|
return this.wsManager?.isWebSocketConnected() ?? false;
|
|
864
1062
|
},
|
|
865
1063
|
/**
|
|
866
|
-
* Subscribes to
|
|
1064
|
+
* Subscribes to WebSocket channels
|
|
867
1065
|
* @example
|
|
868
|
-
* client.stream.subscribe(['
|
|
1066
|
+
* client.stream.subscribe(['positions:new', 'positions:closed']);
|
|
869
1067
|
*/
|
|
870
1068
|
subscribe: (channels) => {
|
|
871
1069
|
if (!this.wsManager) {
|
|
@@ -874,7 +1072,7 @@ var PipsendClient = class {
|
|
|
874
1072
|
this.wsManager.subscribe(channels);
|
|
875
1073
|
},
|
|
876
1074
|
/**
|
|
877
|
-
* Unsubscribes from
|
|
1075
|
+
* Unsubscribes from WebSocket channels
|
|
878
1076
|
*/
|
|
879
1077
|
unsubscribe: (channels) => {
|
|
880
1078
|
if (!this.wsManager) {
|
|
@@ -889,40 +1087,81 @@ var PipsendClient = class {
|
|
|
889
1087
|
return this.wsManager?.getSubscribedChannels() ?? [];
|
|
890
1088
|
},
|
|
891
1089
|
/**
|
|
892
|
-
* Listens to
|
|
1090
|
+
* Listens to position opened events
|
|
1091
|
+
*/
|
|
1092
|
+
onPositionOpened: (callback) => {
|
|
1093
|
+
if (!this.wsManager) {
|
|
1094
|
+
throw new WebSocketError("WebSocket not enabled");
|
|
1095
|
+
}
|
|
1096
|
+
this.wsManager.on("position:opened", callback);
|
|
1097
|
+
},
|
|
1098
|
+
/**
|
|
1099
|
+
* Listens to position closed events (includes partial closes)
|
|
1100
|
+
*/
|
|
1101
|
+
onPositionClosed: (callback) => {
|
|
1102
|
+
if (!this.wsManager) {
|
|
1103
|
+
throw new WebSocketError("WebSocket not enabled");
|
|
1104
|
+
}
|
|
1105
|
+
this.wsManager.on("position:closed", callback);
|
|
1106
|
+
},
|
|
1107
|
+
/**
|
|
1108
|
+
* Listens to position updated events (throttled to max 1 per 2 seconds)
|
|
1109
|
+
*/
|
|
1110
|
+
onPositionUpdated: (callback) => {
|
|
1111
|
+
if (!this.wsManager) {
|
|
1112
|
+
throw new WebSocketError("WebSocket not enabled");
|
|
1113
|
+
}
|
|
1114
|
+
this.wsManager.on("position:updated", callback);
|
|
1115
|
+
},
|
|
1116
|
+
/**
|
|
1117
|
+
* Listens to balance updated events
|
|
1118
|
+
*/
|
|
1119
|
+
onBalanceUpdated: (callback) => {
|
|
1120
|
+
if (!this.wsManager) {
|
|
1121
|
+
throw new WebSocketError("WebSocket not enabled");
|
|
1122
|
+
}
|
|
1123
|
+
this.wsManager.on("balance:updated", callback);
|
|
1124
|
+
},
|
|
1125
|
+
// Legacy methods (deprecated but kept for compatibility)
|
|
1126
|
+
/**
|
|
1127
|
+
* @deprecated Use onPositionUpdated instead
|
|
893
1128
|
*/
|
|
894
1129
|
onPriceUpdate: (callback) => {
|
|
1130
|
+
console.warn("\u26A0\uFE0F onPriceUpdate is deprecated. Use onPositionUpdated instead.");
|
|
895
1131
|
if (!this.wsManager) {
|
|
896
1132
|
throw new WebSocketError("WebSocket not enabled");
|
|
897
1133
|
}
|
|
898
|
-
this.wsManager.on("
|
|
1134
|
+
this.wsManager.on("position:updated", callback);
|
|
899
1135
|
},
|
|
900
1136
|
/**
|
|
901
|
-
*
|
|
1137
|
+
* @deprecated Use onPositionOpened/onPositionClosed instead
|
|
902
1138
|
*/
|
|
903
1139
|
onOrderUpdate: (callback) => {
|
|
1140
|
+
console.warn("\u26A0\uFE0F onOrderUpdate is deprecated. Use onPositionOpened/onPositionClosed instead.");
|
|
904
1141
|
if (!this.wsManager) {
|
|
905
1142
|
throw new WebSocketError("WebSocket not enabled");
|
|
906
1143
|
}
|
|
907
|
-
this.wsManager.on("
|
|
1144
|
+
this.wsManager.on("position:opened", callback);
|
|
908
1145
|
},
|
|
909
1146
|
/**
|
|
910
|
-
*
|
|
1147
|
+
* @deprecated Use onPositionUpdated instead
|
|
911
1148
|
*/
|
|
912
1149
|
onPositionUpdate: (callback) => {
|
|
1150
|
+
console.warn("\u26A0\uFE0F onPositionUpdate is deprecated. Use onPositionUpdated instead.");
|
|
913
1151
|
if (!this.wsManager) {
|
|
914
1152
|
throw new WebSocketError("WebSocket not enabled");
|
|
915
1153
|
}
|
|
916
|
-
this.wsManager.on("position", callback);
|
|
1154
|
+
this.wsManager.on("position:updated", callback);
|
|
917
1155
|
},
|
|
918
1156
|
/**
|
|
919
|
-
*
|
|
1157
|
+
* @deprecated Use onBalanceUpdated instead
|
|
920
1158
|
*/
|
|
921
1159
|
onBalanceUpdate: (callback) => {
|
|
1160
|
+
console.warn("\u26A0\uFE0F onBalanceUpdate is deprecated. Use onBalanceUpdated instead.");
|
|
922
1161
|
if (!this.wsManager) {
|
|
923
1162
|
throw new WebSocketError("WebSocket not enabled");
|
|
924
1163
|
}
|
|
925
|
-
this.wsManager.on("balance", callback);
|
|
1164
|
+
this.wsManager.on("balance:updated", callback);
|
|
926
1165
|
},
|
|
927
1166
|
/**
|
|
928
1167
|
* Listens to connection events
|
|
@@ -966,7 +1205,7 @@ var PipsendClient = class {
|
|
|
966
1205
|
timezone: config.timezone ?? "UTC"
|
|
967
1206
|
};
|
|
968
1207
|
this.authManager = new AuthManager(this.config);
|
|
969
|
-
this.http = new HttpClient(this.config.server);
|
|
1208
|
+
this.http = new HttpClient(this.config.server, this.authManager);
|
|
970
1209
|
this.accounts = new AccountsAPI(this.http);
|
|
971
1210
|
this.tradingGroups = new TradingGroupsAPI(this.http);
|
|
972
1211
|
this.marketData = new MarketDataAPI(this.http);
|