@pipsend/sdk 0.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/dist/index.js ADDED
@@ -0,0 +1,1030 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ AuthenticationError: () => AuthenticationError,
24
+ ConfigurationError: () => ConfigurationError,
25
+ PipsendClient: () => PipsendClient,
26
+ PipsendError: () => PipsendError,
27
+ WebSocketError: () => WebSocketError,
28
+ createClient: () => createClient,
29
+ default: () => index_default
30
+ });
31
+ module.exports = __toCommonJS(index_exports);
32
+
33
+ // src/types/index.ts
34
+ var PipsendError = class extends Error {
35
+ constructor(message, code, statusCode) {
36
+ super(message);
37
+ this.code = code;
38
+ this.statusCode = statusCode;
39
+ this.name = "PipsendError";
40
+ }
41
+ };
42
+ var AuthenticationError = class extends PipsendError {
43
+ constructor(message) {
44
+ super(message, "AUTH_ERROR", 401);
45
+ this.name = "AuthenticationError";
46
+ }
47
+ };
48
+ var ConfigurationError = class extends PipsendError {
49
+ constructor(message) {
50
+ super(message, "CONFIG_ERROR");
51
+ this.name = "ConfigurationError";
52
+ }
53
+ };
54
+ var WebSocketError = class extends PipsendError {
55
+ constructor(message) {
56
+ super(message, "WEBSOCKET_ERROR");
57
+ this.name = "WebSocketError";
58
+ }
59
+ };
60
+
61
+ // src/core/auth.ts
62
+ var AuthManager = class {
63
+ constructor(config) {
64
+ this.config = config;
65
+ const marginMinutes = config.refreshMarginMinutes ?? 5;
66
+ this.refreshMarginMs = marginMinutes * 60 * 1e3;
67
+ }
68
+ /**
69
+ * Checks if a valid token is available
70
+ */
71
+ isAuthenticated() {
72
+ return !!this.tokenInfo && !this.isTokenExpired();
73
+ }
74
+ /**
75
+ * Gets the current token (if it exists and is valid)
76
+ */
77
+ getToken() {
78
+ if (this.isAuthenticated()) {
79
+ return this.tokenInfo?.token;
80
+ }
81
+ return void 0;
82
+ }
83
+ /**
84
+ * Ensures a valid token exists, authenticating if necessary
85
+ */
86
+ async ensureAuthenticated() {
87
+ if (!this.isAuthenticated()) {
88
+ await this.authenticate();
89
+ }
90
+ return this.tokenInfo.token;
91
+ }
92
+ /**
93
+ * Performs authentication with the server
94
+ * TODO: Implement real API call when available
95
+ */
96
+ async authenticate() {
97
+ try {
98
+ const mockResponse = {
99
+ token: "mock_token_" + Date.now(),
100
+ expiresIn: 180 * 60
101
+ // 180 minutes in seconds
102
+ };
103
+ this.setTokenInfo(mockResponse);
104
+ console.log("\u2705 Authentication successful (mock)");
105
+ } catch (error) {
106
+ if (error instanceof AuthenticationError) {
107
+ throw error;
108
+ }
109
+ throw new AuthenticationError(
110
+ `Authentication error: ${error instanceof Error ? error.message : "Unknown error"}`
111
+ );
112
+ }
113
+ }
114
+ /**
115
+ * Forces a re-authentication
116
+ */
117
+ async refreshToken() {
118
+ this.tokenInfo = void 0;
119
+ await this.authenticate();
120
+ }
121
+ /**
122
+ * Clears the current token
123
+ */
124
+ clearToken() {
125
+ this.tokenInfo = void 0;
126
+ }
127
+ /**
128
+ * Checks if the token is expired or about to expire
129
+ */
130
+ isTokenExpired() {
131
+ if (!this.tokenInfo) return true;
132
+ const now = Date.now();
133
+ const expiryWithMargin = this.tokenInfo.expiresAt.getTime() - this.refreshMarginMs;
134
+ return now >= expiryWithMargin;
135
+ }
136
+ /**
137
+ * Stores the received token information
138
+ */
139
+ setTokenInfo(response) {
140
+ const now = /* @__PURE__ */ new Date();
141
+ const expiresAt = new Date(now.getTime() + response.expiresIn * 1e3);
142
+ this.tokenInfo = {
143
+ token: response.token,
144
+ issuedAt: now,
145
+ expiresAt
146
+ };
147
+ }
148
+ };
149
+
150
+ // src/core/websocket.ts
151
+ var WebSocketManager = class {
152
+ constructor(config, authManager) {
153
+ this.config = config;
154
+ this.authManager = authManager;
155
+ // WebSocket instance (browser or ws package)
156
+ this.reconnectAttempts = 0;
157
+ this.listeners = /* @__PURE__ */ new Map();
158
+ this.isConnected = false;
159
+ this.subscribedChannels = [];
160
+ this.isReconnecting = false;
161
+ }
162
+ /**
163
+ * Connects to the WebSocket server
164
+ */
165
+ async connect() {
166
+ if (this.isConnected) {
167
+ console.log("\u26A0\uFE0F WebSocket already connected");
168
+ return;
169
+ }
170
+ if (this.isReconnecting) {
171
+ console.log("\u26A0\uFE0F WebSocket reconnection in progress");
172
+ return;
173
+ }
174
+ const wsUrl = this.buildWebSocketUrl();
175
+ const token = await this.authManager.ensureAuthenticated();
176
+ return new Promise((resolve, reject) => {
177
+ try {
178
+ const WS = this.getWebSocketConstructor();
179
+ this.ws = new WS(wsUrl);
180
+ this.ws.onopen = () => {
181
+ console.log("\u2705 WebSocket connected");
182
+ this.isConnected = true;
183
+ this.isReconnecting = false;
184
+ this.reconnectAttempts = 0;
185
+ this.send({
186
+ type: "auth",
187
+ payload: { token },
188
+ timestamp: Date.now()
189
+ });
190
+ this.emit("connected", { timestamp: Date.now() });
191
+ if (this.subscribedChannels.length > 0) {
192
+ console.log("\u{1F504} Resubscribing to channels:", this.subscribedChannels);
193
+ this.subscribe(this.subscribedChannels);
194
+ }
195
+ this.startHeartbeat();
196
+ resolve();
197
+ };
198
+ this.ws.onmessage = (event) => {
199
+ try {
200
+ const data = JSON.parse(event.data);
201
+ this.handleMessage(data);
202
+ } catch (error) {
203
+ console.error("\u274C Failed to parse WebSocket message:", error);
204
+ }
205
+ };
206
+ this.ws.onerror = (error) => {
207
+ console.error("\u274C WebSocket error:", error);
208
+ this.emit("error", error);
209
+ if (!this.isConnected) {
210
+ reject(new WebSocketError("Failed to connect to WebSocket server"));
211
+ }
212
+ };
213
+ this.ws.onclose = (event) => {
214
+ console.log("WebSocket disconnected", event.code, event.reason);
215
+ this.isConnected = false;
216
+ this.stopHeartbeat();
217
+ this.emit("disconnected", {
218
+ code: event.code,
219
+ reason: event.reason,
220
+ timestamp: Date.now()
221
+ });
222
+ this.handleReconnect();
223
+ };
224
+ } catch (error) {
225
+ reject(new WebSocketError(
226
+ `Failed to create WebSocket: ${error instanceof Error ? error.message : "Unknown error"}`
227
+ ));
228
+ }
229
+ });
230
+ }
231
+ /**
232
+ * Subscribes to channels (symbols, events, etc.)
233
+ * TODO: Adjust message format according to real WebSocket API
234
+ */
235
+ subscribe(channels) {
236
+ if (!this.isConnected) {
237
+ throw new WebSocketError("WebSocket not connected. Call connect() first.");
238
+ }
239
+ this.subscribedChannels = [.../* @__PURE__ */ new Set([...this.subscribedChannels, ...channels])];
240
+ this.send({
241
+ type: "subscribe",
242
+ payload: { channels },
243
+ timestamp: Date.now()
244
+ });
245
+ console.log("\u{1F4E1} Subscribed to channels:", channels);
246
+ }
247
+ /**
248
+ * Unsubscribes from channels
249
+ * TODO: Adjust message format according to real WebSocket API
250
+ */
251
+ unsubscribe(channels) {
252
+ if (!this.isConnected) {
253
+ console.warn("WebSocket not connected, cannot unsubscribe");
254
+ return;
255
+ }
256
+ this.subscribedChannels = this.subscribedChannels.filter(
257
+ (ch) => !channels.includes(ch)
258
+ );
259
+ this.send({
260
+ type: "unsubscribe",
261
+ payload: { channels },
262
+ timestamp: Date.now()
263
+ });
264
+ console.log("\u{1F4E1} Unsubscribed from channels:", channels);
265
+ }
266
+ /**
267
+ * Registers an event listener
268
+ */
269
+ on(event, callback) {
270
+ if (!this.listeners.has(event)) {
271
+ this.listeners.set(event, /* @__PURE__ */ new Set());
272
+ }
273
+ this.listeners.get(event).add(callback);
274
+ }
275
+ /**
276
+ * Removes an event listener
277
+ */
278
+ off(event, callback) {
279
+ if (!callback) {
280
+ this.listeners.delete(event);
281
+ } else {
282
+ this.listeners.get(event)?.delete(callback);
283
+ }
284
+ }
285
+ /**
286
+ * Disconnects from WebSocket
287
+ */
288
+ disconnect() {
289
+ console.log("\u{1F44B} Disconnecting WebSocket...");
290
+ this.stopHeartbeat();
291
+ if (this.ws) {
292
+ this.ws.close();
293
+ this.ws = void 0;
294
+ }
295
+ this.isConnected = false;
296
+ this.isReconnecting = false;
297
+ this.subscribedChannels = [];
298
+ this.listeners.clear();
299
+ }
300
+ /**
301
+ * Checks if WebSocket is connected
302
+ */
303
+ isWebSocketConnected() {
304
+ return this.isConnected;
305
+ }
306
+ /**
307
+ * Gets list of subscribed channels
308
+ */
309
+ getSubscribedChannels() {
310
+ return [...this.subscribedChannels];
311
+ }
312
+ // Private methods
313
+ /**
314
+ * Builds WebSocket URL from HTTP(S) server URL
315
+ */
316
+ buildWebSocketUrl() {
317
+ try {
318
+ const url = new URL(this.config.server);
319
+ url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
320
+ const wsPath = this.config.websocket?.path || "/ws";
321
+ url.pathname = wsPath;
322
+ return url.toString();
323
+ } catch (error) {
324
+ throw new WebSocketError("Invalid server URL for WebSocket connection");
325
+ }
326
+ }
327
+ /**
328
+ * Gets WebSocket constructor (browser or Node.js)
329
+ */
330
+ getWebSocketConstructor() {
331
+ if (typeof WebSocket !== "undefined") {
332
+ return WebSocket;
333
+ }
334
+ try {
335
+ return require("ws");
336
+ } catch {
337
+ throw new WebSocketError(
338
+ 'WebSocket not available. Install "ws" package for Node.js: npm install ws'
339
+ );
340
+ }
341
+ }
342
+ /**
343
+ * Sends a message through WebSocket
344
+ */
345
+ send(message) {
346
+ if (!this.ws || !this.isConnected) {
347
+ console.warn("\u26A0\uFE0F WebSocket not ready, message not sent:", message.type);
348
+ return;
349
+ }
350
+ try {
351
+ const payload = JSON.stringify(message);
352
+ this.ws.send(payload);
353
+ } catch (error) {
354
+ console.error("\u274C Failed to send WebSocket message:", error);
355
+ }
356
+ }
357
+ /**
358
+ * Handles incoming WebSocket messages
359
+ * TODO: Adjust message handling according to real WebSocket API
360
+ */
361
+ handleMessage(data) {
362
+ if (data.type === "authenticated") {
363
+ console.log("\u2705 WebSocket authenticated");
364
+ this.emit("authenticated", data.payload || {});
365
+ return;
366
+ }
367
+ if (data.type === "pong") {
368
+ return;
369
+ }
370
+ const eventType = data.type;
371
+ this.emit(eventType, data.payload || data);
372
+ this.emit("*", data);
373
+ }
374
+ /**
375
+ * Emits an event to all registered listeners
376
+ */
377
+ emit(event, data) {
378
+ const listeners = this.listeners.get(event);
379
+ if (listeners && listeners.size > 0) {
380
+ listeners.forEach((callback) => {
381
+ try {
382
+ callback(data);
383
+ } catch (error) {
384
+ console.error(`\u274C Error in WebSocket listener for "${event}":`, error);
385
+ }
386
+ });
387
+ }
388
+ }
389
+ /**
390
+ * Handles reconnection logic with exponential backoff
391
+ */
392
+ handleReconnect() {
393
+ const autoReconnect = this.config.websocket?.autoReconnect ?? true;
394
+ const maxAttempts = this.config.websocket?.maxReconnectAttempts ?? 5;
395
+ if (!autoReconnect) {
396
+ console.log("Auto-reconnect disabled");
397
+ return;
398
+ }
399
+ if (this.reconnectAttempts >= maxAttempts) {
400
+ console.log(`\u274C Max reconnection attempts (${maxAttempts}) reached. Giving up.`);
401
+ this.emit("error", new WebSocketError("Max reconnection attempts reached"));
402
+ return;
403
+ }
404
+ const delay = Math.min(1e3 * Math.pow(2, this.reconnectAttempts), 3e4);
405
+ console.log(
406
+ `\u{1F504} Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts + 1}/${maxAttempts})...`
407
+ );
408
+ this.isReconnecting = true;
409
+ setTimeout(() => {
410
+ this.reconnectAttempts++;
411
+ this.connect().catch((error) => {
412
+ console.error("\u274C Reconnection failed:", error);
413
+ });
414
+ }, delay);
415
+ }
416
+ /**
417
+ * Starts heartbeat to keep connection alive
418
+ */
419
+ startHeartbeat() {
420
+ const interval = this.config.websocket?.heartbeatInterval || 3e4;
421
+ this.heartbeatTimer = setInterval(() => {
422
+ if (this.isConnected) {
423
+ this.send({
424
+ type: "ping",
425
+ timestamp: Date.now()
426
+ });
427
+ }
428
+ }, interval);
429
+ }
430
+ /**
431
+ * Stops heartbeat timer
432
+ */
433
+ stopHeartbeat() {
434
+ if (this.heartbeatTimer) {
435
+ clearInterval(this.heartbeatTimer);
436
+ this.heartbeatTimer = void 0;
437
+ }
438
+ }
439
+ };
440
+
441
+ // src/api/http-client.ts
442
+ var HttpClient = class {
443
+ constructor(baseUrl) {
444
+ this.baseUrl = baseUrl;
445
+ }
446
+ /**
447
+ * Makes an HTTP request
448
+ */
449
+ async request(endpoint, options = {}) {
450
+ const url = `${this.baseUrl}${endpoint}`;
451
+ try {
452
+ const response = await fetch(url, {
453
+ ...options,
454
+ headers: {
455
+ "Content-Type": "application/json",
456
+ ...options.headers
457
+ }
458
+ });
459
+ if (!response.ok) {
460
+ const errorText = await response.text();
461
+ throw new PipsendError(
462
+ `HTTP ${response.status}: ${errorText || response.statusText}`,
463
+ "HTTP_ERROR",
464
+ response.status
465
+ );
466
+ }
467
+ const text = await response.text();
468
+ if (!text) {
469
+ return {};
470
+ }
471
+ return JSON.parse(text);
472
+ } catch (error) {
473
+ if (error instanceof PipsendError) {
474
+ throw error;
475
+ }
476
+ throw new PipsendError(
477
+ `Request failed: ${error instanceof Error ? error.message : "Unknown error"}`,
478
+ "NETWORK_ERROR"
479
+ );
480
+ }
481
+ }
482
+ /**
483
+ * GET request
484
+ */
485
+ async get(endpoint, params) {
486
+ const queryString = params ? this.buildQueryString(params) : "";
487
+ const url = queryString ? `${endpoint}?${queryString}` : endpoint;
488
+ return this.request(url, { method: "GET" });
489
+ }
490
+ /**
491
+ * POST request
492
+ */
493
+ async post(endpoint, body) {
494
+ return this.request(endpoint, {
495
+ method: "POST",
496
+ body: body ? JSON.stringify(body) : void 0
497
+ });
498
+ }
499
+ /**
500
+ * PUT request
501
+ */
502
+ async put(endpoint, body) {
503
+ return this.request(endpoint, {
504
+ method: "PUT",
505
+ body: body ? JSON.stringify(body) : void 0
506
+ });
507
+ }
508
+ /**
509
+ * DELETE request
510
+ */
511
+ async delete(endpoint) {
512
+ return this.request(endpoint, { method: "DELETE" });
513
+ }
514
+ /**
515
+ * Builds query string from params object
516
+ */
517
+ buildQueryString(params) {
518
+ const filtered = Object.entries(params).filter(([_, value]) => value !== void 0 && value !== null && value !== "").map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
519
+ return filtered.join("&");
520
+ }
521
+ };
522
+
523
+ // src/api/accounts.ts
524
+ var AccountsAPI = class {
525
+ constructor(http) {
526
+ this.http = http;
527
+ }
528
+ /**
529
+ * List all accounts with optional filters and pagination
530
+ */
531
+ async list(params) {
532
+ return this.http.get("/api/v1/accounts", params);
533
+ }
534
+ /**
535
+ * Get all account logins
536
+ */
537
+ async getLogins() {
538
+ return this.http.get("/api/v1/accounts/logins");
539
+ }
540
+ /**
541
+ * Get account statistics with optional filters
542
+ */
543
+ async getStatistics(params) {
544
+ return this.http.get("/api/v1/accounts/statistics", params);
545
+ }
546
+ /**
547
+ * Change master password for an account
548
+ */
549
+ async changeMasterPassword(login, request) {
550
+ return this.http.put(`/api/v1/accounts/${login}/password/master`, request);
551
+ }
552
+ /**
553
+ * Change investor password for an account
554
+ */
555
+ async changeInvestorPassword(login, request) {
556
+ return this.http.put(`/api/v1/accounts/${login}/password/investor`, request);
557
+ }
558
+ /**
559
+ * Archive an account
560
+ */
561
+ async archive(login) {
562
+ return this.http.put(`/api/v1/accounts/${login}/archive`);
563
+ }
564
+ /**
565
+ * Unarchive an account
566
+ */
567
+ async unarchive(login) {
568
+ return this.http.put(`/api/v1/accounts/${login}/unarchive`);
569
+ }
570
+ };
571
+
572
+ // src/api/trading-groups.ts
573
+ var TradingGroupsAPI = class {
574
+ constructor(http) {
575
+ this.http = http;
576
+ }
577
+ /**
578
+ * List all trading groups with optional filters
579
+ */
580
+ async list(params) {
581
+ return this.http.get("/api/v1/trading-groups", params);
582
+ }
583
+ /**
584
+ * Get trading group by name
585
+ */
586
+ async getByName(name) {
587
+ return this.http.get(`/api/v1/trading-groups/${encodeURIComponent(name)}`);
588
+ }
589
+ /**
590
+ * Get all trading group names
591
+ */
592
+ async getNames() {
593
+ return this.http.get("/api/v1/trading-groups/names");
594
+ }
595
+ /**
596
+ * Get trading group statistics
597
+ */
598
+ async getStatistics(type) {
599
+ return this.http.get("/api/v1/trading-groups/statistics", type ? { type } : void 0);
600
+ }
601
+ };
602
+
603
+ // src/api/market-data.ts
604
+ var MarketDataAPI = class {
605
+ constructor(http) {
606
+ this.http = http;
607
+ }
608
+ /**
609
+ * Get historical OHLCV candles
610
+ *
611
+ * @param params - Candles parameters (symbol and timeframe are required)
612
+ * @returns Paginated candles or array of candles
613
+ *
614
+ * @example
615
+ * ```ts
616
+ * // Get last 100 candles
617
+ * const candles = await client.marketData.getCandles({
618
+ * symbol: 'BTCUSD',
619
+ * timeframe: '1m',
620
+ * limit: 100,
621
+ * order: 'desc'
622
+ * });
623
+ *
624
+ * // Get candles with time range
625
+ * const candles = await client.marketData.getCandles({
626
+ * symbol: 'BTCUSD,ETHUSD',
627
+ * timeframe: '1h',
628
+ * from: '2025-11-01T00:00:00Z',
629
+ * to: '2025-11-02T00:00:00Z'
630
+ * });
631
+ * ```
632
+ */
633
+ async getCandles(params) {
634
+ return this.http.get("/api/v1/candles", params);
635
+ }
636
+ /**
637
+ * Get available symbols with metadata
638
+ *
639
+ * @param params - Optional filters for symbols
640
+ * @returns Paginated symbols or array of symbols
641
+ *
642
+ * @example
643
+ * ```ts
644
+ * // Get all symbols
645
+ * const symbols = await client.marketData.getSymbols();
646
+ *
647
+ * // Filter by group
648
+ * const cryptoSymbols = await client.marketData.getSymbols({
649
+ * group: 'CRYPTO_MAJOR',
650
+ * has_data: true
651
+ * });
652
+ * ```
653
+ */
654
+ async getSymbols(params) {
655
+ return this.http.get("/api/v1/symbols", params);
656
+ }
657
+ /**
658
+ * Get symbol groups hierarchy
659
+ *
660
+ * Note: This endpoint never uses pagination
661
+ *
662
+ * @param params - Optional filters for groups
663
+ * @returns Array of groups
664
+ *
665
+ * @example
666
+ * ```ts
667
+ * // Get all groups
668
+ * const groups = await client.marketData.getGroups();
669
+ *
670
+ * // Get only root groups
671
+ * const rootGroups = await client.marketData.getGroups({
672
+ * root_only: true
673
+ * });
674
+ * ```
675
+ */
676
+ async getGroups(params) {
677
+ return this.http.get("/api/v1/groups", params);
678
+ }
679
+ };
680
+
681
+ // src/api/positions.ts
682
+ var PositionsAPI = class {
683
+ constructor(http) {
684
+ this.http = http;
685
+ }
686
+ /**
687
+ * List positions with optional filters and pagination
688
+ */
689
+ async list(params) {
690
+ return this.http.get("/api/v1/positions", params);
691
+ }
692
+ /**
693
+ * Get position statistics with optional filters and grouping
694
+ */
695
+ async getStats(params) {
696
+ return this.http.get("/api/v1/positions/stats", params);
697
+ }
698
+ /**
699
+ * Get position totals with dynamic grouping
700
+ */
701
+ async getTotals(params) {
702
+ return this.http.get("/api/v1/positions/totals", params);
703
+ }
704
+ /**
705
+ * Update position (modify SL/TP)
706
+ */
707
+ async update(id, request) {
708
+ return this.http.put(`/api/v1/positions/${id}`, request);
709
+ }
710
+ /**
711
+ * Delete (close) position
712
+ */
713
+ async delete(id, params) {
714
+ return this.http.delete(`/api/v1/positions/${id}?login=${params.login}`);
715
+ }
716
+ /**
717
+ * Check and recalculate positions
718
+ */
719
+ async check(request) {
720
+ return this.http.post("/api/v1/positions/check", request);
721
+ }
722
+ };
723
+
724
+ // src/api/orders.ts
725
+ var OrdersAPI = class {
726
+ constructor(http) {
727
+ this.http = http;
728
+ }
729
+ /**
730
+ * List orders with optional filters and pagination
731
+ */
732
+ async list(params) {
733
+ return this.http.get("/api/v1/orders", params);
734
+ }
735
+ /**
736
+ * Get order statistics with optional filters and grouping
737
+ */
738
+ async getStats(params) {
739
+ return this.http.get("/api/v1/orders/stats", params);
740
+ }
741
+ /**
742
+ * Get order totals with dynamic grouping
743
+ */
744
+ async getTotals(params) {
745
+ return this.http.get("/api/v1/orders/totals", params);
746
+ }
747
+ /**
748
+ * Update order (modify SL/TP)
749
+ */
750
+ async update(id, request) {
751
+ return this.http.put(`/api/v1/orders/${id}`, request);
752
+ }
753
+ /**
754
+ * Delete (cancel) order
755
+ */
756
+ async delete(id, params) {
757
+ return this.http.delete(`/api/v1/orders/${id}?login=${params.login}`);
758
+ }
759
+ /**
760
+ * Check and validate pending orders
761
+ */
762
+ async check(request) {
763
+ return this.http.post("/api/v1/orders/check", request);
764
+ }
765
+ };
766
+
767
+ // src/api/trades.ts
768
+ var TradesAPI = class {
769
+ constructor(http) {
770
+ this.http = http;
771
+ }
772
+ /**
773
+ * Open a new trade (market or pending order)
774
+ */
775
+ async open(request) {
776
+ return this.http.post("/api/v1/trades/open", request);
777
+ }
778
+ /**
779
+ * Close a trade (full or partial)
780
+ */
781
+ async close(request) {
782
+ return this.http.post("/api/v1/trades/close", request);
783
+ }
784
+ /**
785
+ * Modify trade Stop Loss and/or Take Profit
786
+ */
787
+ async modify(request) {
788
+ return this.http.put("/api/v1/trades/modify", request);
789
+ }
790
+ /**
791
+ * Check if there's sufficient margin for a trade
792
+ */
793
+ async checkMargin(request) {
794
+ return this.http.post("/api/v1/trades/check-margin", request);
795
+ }
796
+ /**
797
+ * Calculate potential profit for a trade
798
+ */
799
+ async calculateProfit(request) {
800
+ return this.http.post("/api/v1/trades/calc-profit", request);
801
+ }
802
+ };
803
+
804
+ // src/core/client.ts
805
+ var PipsendClient = class {
806
+ constructor(config) {
807
+ /**
808
+ * Authentication API
809
+ * TODO: Implement when authentication is available
810
+ */
811
+ this.auth = {
812
+ /**
813
+ * Forces a token refresh
814
+ */
815
+ refresh: async () => {
816
+ await this.authManager.refreshToken();
817
+ },
818
+ /**
819
+ * Checks if the client is authenticated
820
+ */
821
+ isAuthenticated: () => {
822
+ return this.authManager.isAuthenticated();
823
+ },
824
+ /**
825
+ * Gets the current token (if it exists)
826
+ */
827
+ getToken: () => {
828
+ return this.authManager.getToken();
829
+ },
830
+ /**
831
+ * Logs out by clearing the token
832
+ */
833
+ logout: () => {
834
+ this.authManager.clearToken();
835
+ }
836
+ };
837
+ /**
838
+ * WebSocket streaming API
839
+ * Provides real-time updates for prices, orders, positions, etc.
840
+ */
841
+ this.stream = {
842
+ /**
843
+ * Connects to WebSocket server
844
+ */
845
+ connect: async () => {
846
+ if (!this.wsManager) {
847
+ throw new WebSocketError(
848
+ "WebSocket not enabled. Set websocket.enabled: true in config"
849
+ );
850
+ }
851
+ await this.wsManager.connect();
852
+ },
853
+ /**
854
+ * Disconnects from WebSocket server
855
+ */
856
+ disconnect: () => {
857
+ this.wsManager?.disconnect();
858
+ },
859
+ /**
860
+ * Checks if WebSocket is connected
861
+ */
862
+ isConnected: () => {
863
+ return this.wsManager?.isWebSocketConnected() ?? false;
864
+ },
865
+ /**
866
+ * Subscribes to symbols or channels
867
+ * @example
868
+ * client.stream.subscribe(['EURUSD', 'GBPUSD']);
869
+ */
870
+ subscribe: (channels) => {
871
+ if (!this.wsManager) {
872
+ throw new WebSocketError("WebSocket not enabled");
873
+ }
874
+ this.wsManager.subscribe(channels);
875
+ },
876
+ /**
877
+ * Unsubscribes from symbols or channels
878
+ */
879
+ unsubscribe: (channels) => {
880
+ if (!this.wsManager) {
881
+ throw new WebSocketError("WebSocket not enabled");
882
+ }
883
+ this.wsManager.unsubscribe(channels);
884
+ },
885
+ /**
886
+ * Gets list of subscribed channels
887
+ */
888
+ getSubscriptions: () => {
889
+ return this.wsManager?.getSubscribedChannels() ?? [];
890
+ },
891
+ /**
892
+ * Listens to real-time price updates
893
+ */
894
+ onPriceUpdate: (callback) => {
895
+ if (!this.wsManager) {
896
+ throw new WebSocketError("WebSocket not enabled");
897
+ }
898
+ this.wsManager.on("price", callback);
899
+ },
900
+ /**
901
+ * Listens to real-time order updates
902
+ */
903
+ onOrderUpdate: (callback) => {
904
+ if (!this.wsManager) {
905
+ throw new WebSocketError("WebSocket not enabled");
906
+ }
907
+ this.wsManager.on("order", callback);
908
+ },
909
+ /**
910
+ * Listens to real-time position updates
911
+ */
912
+ onPositionUpdate: (callback) => {
913
+ if (!this.wsManager) {
914
+ throw new WebSocketError("WebSocket not enabled");
915
+ }
916
+ this.wsManager.on("position", callback);
917
+ },
918
+ /**
919
+ * Listens to real-time balance updates
920
+ */
921
+ onBalanceUpdate: (callback) => {
922
+ if (!this.wsManager) {
923
+ throw new WebSocketError("WebSocket not enabled");
924
+ }
925
+ this.wsManager.on("balance", callback);
926
+ },
927
+ /**
928
+ * Listens to connection events
929
+ */
930
+ onConnected: (callback) => {
931
+ if (!this.wsManager) {
932
+ throw new WebSocketError("WebSocket not enabled");
933
+ }
934
+ this.wsManager.on("connected", callback);
935
+ },
936
+ /**
937
+ * Listens to disconnection events
938
+ */
939
+ onDisconnected: (callback) => {
940
+ if (!this.wsManager) {
941
+ throw new WebSocketError("WebSocket not enabled");
942
+ }
943
+ this.wsManager.on("disconnected", callback);
944
+ },
945
+ /**
946
+ * Listens to error events
947
+ */
948
+ onError: (callback) => {
949
+ if (!this.wsManager) {
950
+ throw new WebSocketError("WebSocket not enabled");
951
+ }
952
+ this.wsManager.on("error", callback);
953
+ },
954
+ /**
955
+ * Removes event listener
956
+ */
957
+ off: (event, callback) => {
958
+ this.wsManager?.off(event, callback);
959
+ }
960
+ };
961
+ this.validateConfig(config);
962
+ this.config = {
963
+ ...config,
964
+ autoRefresh: config.autoRefresh ?? true,
965
+ refreshMarginMinutes: config.refreshMarginMinutes ?? 5,
966
+ timezone: config.timezone ?? "UTC"
967
+ };
968
+ this.authManager = new AuthManager(this.config);
969
+ this.http = new HttpClient(this.config.server);
970
+ this.accounts = new AccountsAPI(this.http);
971
+ this.tradingGroups = new TradingGroupsAPI(this.http);
972
+ this.marketData = new MarketDataAPI(this.http);
973
+ this.positions = new PositionsAPI(this.http);
974
+ this.orders = new OrdersAPI(this.http);
975
+ this.trades = new TradesAPI(this.http);
976
+ if (config.websocket?.enabled) {
977
+ this.wsManager = new WebSocketManager(this.config, this.authManager);
978
+ if (config.websocket.autoConnect) {
979
+ this.wsManager.connect().catch((error) => {
980
+ console.error("Failed to auto-connect WebSocket:", error);
981
+ });
982
+ }
983
+ }
984
+ }
985
+ /**
986
+ * Validates the initial configuration
987
+ */
988
+ validateConfig(config) {
989
+ if (!config.server) {
990
+ throw new ConfigurationError('The "server" parameter is required');
991
+ }
992
+ try {
993
+ new URL(config.server);
994
+ } catch {
995
+ throw new ConfigurationError('The "server" parameter must be a valid URL');
996
+ }
997
+ }
998
+ /**
999
+ * Health check
1000
+ */
1001
+ async ping() {
1002
+ return this.http.get("/ping");
1003
+ }
1004
+ /**
1005
+ * Client information
1006
+ */
1007
+ getConfig() {
1008
+ return { ...this.config };
1009
+ }
1010
+ };
1011
+
1012
+ // src/index.ts
1013
+ function createClient(config) {
1014
+ return new PipsendClient(config);
1015
+ }
1016
+ var sdk = {
1017
+ createClient,
1018
+ PipsendClient
1019
+ };
1020
+ var index_default = sdk;
1021
+ // Annotate the CommonJS export names for ESM import in node:
1022
+ 0 && (module.exports = {
1023
+ AuthenticationError,
1024
+ ConfigurationError,
1025
+ PipsendClient,
1026
+ PipsendError,
1027
+ WebSocketError,
1028
+ createClient
1029
+ });
1030
+ //# sourceMappingURL=index.js.map