ctrader-ts 0.1.10 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/README.md +259 -91
  2. package/dist/bin/auth.js +8 -8
  3. package/dist/bin/auth.js.map +1 -1
  4. package/dist/cli/index.js +169 -26
  5. package/dist/cli/index.js.map +1 -1
  6. package/dist/src/{client.d.ts → core/client.d.ts} +57 -15
  7. package/dist/src/core/client.d.ts.map +1 -0
  8. package/dist/src/{client.js → core/client.js} +306 -49
  9. package/dist/src/core/client.js.map +1 -0
  10. package/dist/src/core/config.d.ts.map +1 -0
  11. package/dist/src/{config.js → core/config.js} +13 -13
  12. package/dist/src/core/config.js.map +1 -0
  13. package/dist/src/{connect.d.ts → core/connect.d.ts} +3 -3
  14. package/dist/src/core/connect.d.ts.map +1 -0
  15. package/dist/src/{connect.js → core/connect.js} +4 -6
  16. package/dist/src/core/connect.js.map +1 -0
  17. package/dist/src/{connection.d.ts → core/connection.d.ts} +53 -4
  18. package/dist/src/core/connection.d.ts.map +1 -0
  19. package/dist/src/{connection.js → core/connection.js} +152 -18
  20. package/dist/src/core/connection.js.map +1 -0
  21. package/dist/src/{errors.d.ts → core/errors.d.ts} +5 -0
  22. package/dist/src/core/errors.d.ts.map +1 -0
  23. package/dist/src/core/errors.js +85 -0
  24. package/dist/src/core/errors.js.map +1 -0
  25. package/dist/src/{helpers.d.ts → core/helpers.d.ts} +3 -3
  26. package/dist/src/core/helpers.d.ts.map +1 -0
  27. package/dist/src/{helpers.js → core/helpers.js} +9 -7
  28. package/dist/src/core/helpers.js.map +1 -0
  29. package/dist/src/{symbol-cache.d.ts → core/symbol-cache.d.ts} +2 -2
  30. package/dist/src/core/symbol-cache.d.ts.map +1 -0
  31. package/dist/src/core/symbol-cache.js.map +1 -0
  32. package/dist/src/index.d.ts +26 -11
  33. package/dist/src/index.d.ts.map +1 -1
  34. package/dist/src/index.js +24 -9
  35. package/dist/src/index.js.map +1 -1
  36. package/dist/src/modules/account.d.ts +68 -2
  37. package/dist/src/modules/account.d.ts.map +1 -1
  38. package/dist/src/modules/account.js +91 -34
  39. package/dist/src/modules/account.js.map +1 -1
  40. package/dist/src/modules/auth.d.ts +29 -2
  41. package/dist/src/modules/auth.d.ts.map +1 -1
  42. package/dist/src/modules/auth.js +42 -10
  43. package/dist/src/modules/auth.js.map +1 -1
  44. package/dist/src/modules/market.d.ts +51 -3
  45. package/dist/src/modules/market.d.ts.map +1 -1
  46. package/dist/src/modules/market.js +57 -16
  47. package/dist/src/modules/market.js.map +1 -1
  48. package/dist/src/modules/trading.d.ts +69 -3
  49. package/dist/src/modules/trading.d.ts.map +1 -1
  50. package/dist/src/modules/trading.js +74 -35
  51. package/dist/src/modules/trading.js.map +1 -1
  52. package/dist/src/protocol/codec.d.ts.map +1 -0
  53. package/dist/src/{codec.js → protocol/codec.js} +2 -2
  54. package/dist/src/protocol/codec.js.map +1 -0
  55. package/dist/src/{enums.d.ts → protocol/enums.d.ts} +177 -0
  56. package/dist/src/protocol/enums.d.ts.map +1 -0
  57. package/dist/src/{enums.js → protocol/enums.js} +177 -0
  58. package/dist/src/protocol/enums.js.map +1 -0
  59. package/dist/src/protocol/proto/messages.d.ts +7496 -0
  60. package/dist/src/protocol/proto/messages.js +21525 -0
  61. package/dist/src/protocol/proto/proto/messages.d.ts +7496 -0
  62. package/dist/src/protocol/proto/proto/messages.js +21525 -0
  63. package/dist/src/{types.d.ts → protocol/types.d.ts} +151 -3
  64. package/dist/src/protocol/types.d.ts.map +1 -0
  65. package/dist/src/{types.js.map → protocol/types.js.map} +1 -1
  66. package/llms.txt +280 -0
  67. package/package.json +89 -61
  68. package/dist/src/client.d.ts.map +0 -1
  69. package/dist/src/client.js.map +0 -1
  70. package/dist/src/codec.d.ts.map +0 -1
  71. package/dist/src/codec.js.map +0 -1
  72. package/dist/src/config.d.ts.map +0 -1
  73. package/dist/src/config.js.map +0 -1
  74. package/dist/src/connect.d.ts.map +0 -1
  75. package/dist/src/connect.js.map +0 -1
  76. package/dist/src/connection.d.ts.map +0 -1
  77. package/dist/src/connection.js.map +0 -1
  78. package/dist/src/enums.d.ts.map +0 -1
  79. package/dist/src/enums.js.map +0 -1
  80. package/dist/src/errors.d.ts.map +0 -1
  81. package/dist/src/errors.js +0 -47
  82. package/dist/src/errors.js.map +0 -1
  83. package/dist/src/helpers.d.ts.map +0 -1
  84. package/dist/src/helpers.js.map +0 -1
  85. package/dist/src/proto/messages.d.ts +0 -7076
  86. package/dist/src/proto/messages.js +0 -23289
  87. package/dist/src/proto/proto/messages.d.ts +0 -7076
  88. package/dist/src/proto/proto/messages.js +0 -23289
  89. package/dist/src/symbol-cache.d.ts.map +0 -1
  90. package/dist/src/symbol-cache.js.map +0 -1
  91. package/dist/src/types.d.ts.map +0 -1
  92. /package/dist/src/{config.d.ts → core/config.d.ts} +0 -0
  93. /package/dist/src/{symbol-cache.js → core/symbol-cache.js} +0 -0
  94. /package/dist/src/{codec.d.ts → protocol/codec.d.ts} +0 -0
  95. /package/dist/src/{types.js → protocol/types.js} +0 -0
@@ -9,20 +9,29 @@
9
9
  * - When a heartbeat is received from the server, immediately echo one back
10
10
  * - If no heartbeat received from server for HEARTBEAT_TIMEOUT_MS, close
11
11
  */
12
- import type { ConnectionState } from "./types.js";
12
+ import type { ConnectionState } from "../protocol/types.js";
13
13
  type PayloadHandler = (payload: Record<string, unknown>) => void;
14
14
  export type ConnectionEvent = "stateChange" | "error" | "message";
15
15
  type ConnectionEventHandler = (data: unknown) => void;
16
16
  export interface CTraderConnectionConfig {
17
- /** Hostname, e.g. "demo.ctraderapi.com" */
17
+ /** Hostname or IP address, e.g., "demo.ctraderapi.com" */
18
18
  host: string;
19
- /** Port — default 5035 */
19
+ /** Port number — default 5035 for cTrader Open API over TLS/TCP */
20
20
  port?: number;
21
+ /** Maximum number of reconnection attempts (0 = unlimited) */
21
22
  maxReconnectAttempts?: number;
23
+ /** Timeout in milliseconds for individual requests (default 15000ms) */
22
24
  requestTimeoutMs?: number;
23
- /** Called after TCP reconnects (not initial connect). Use for re-auth + subscription restore. */
25
+ /** Called after TLS/TCP reconnects (not initial connect). Use for re-auth + subscription restore. */
24
26
  onReconnect?: () => Promise<void>;
25
27
  }
28
+ /**
29
+ * Low-level TLS/TCP connection to the cTrader Open API (port 5035).
30
+ * Handles connect/disconnect, heartbeat, automatic reconnection,
31
+ * request/response matching, and payload-based event dispatch.
32
+ *
33
+ * Most users should use {@link CTrader} (via `connect()`) instead of this class directly.
34
+ */
26
35
  export declare class CTraderConnection {
27
36
  private socket;
28
37
  private readonly host;
@@ -44,16 +53,56 @@ export declare class CTraderConnection {
44
53
  private readonly pending;
45
54
  private readonly payloadHandlers;
46
55
  private readonly eventHandlers;
56
+ /** Request throttle queue */
57
+ private readonly requestQueue;
58
+ private inFlightRequests;
59
+ private lastRequestSentAt;
47
60
  constructor(config: CTraderConnectionConfig);
61
+ /** Current connection lifecycle state. */
48
62
  get state(): ConnectionState;
63
+ /** True when the TLS/TCP socket is established and ready for messages. */
49
64
  get isConnected(): boolean;
65
+ /**
66
+ * Establish a TLS/TCP connection to the cTrader API.
67
+ * Resolves when the connection is established, rejects on failure.
68
+ */
50
69
  connect(): Promise<void>;
70
+ /**
71
+ * Close the TLS/TCP connection and stop automatic reconnection.
72
+ * All pending requests are rejected.
73
+ */
51
74
  disconnect(): void;
75
+ /**
76
+ * Send a one-way message (fire-and-forget) over the TLS/TCP connection.
77
+ * Returns the generated clientMsgId for tracking.
78
+ */
52
79
  send(payloadType: number, payload?: Record<string, unknown>): string;
80
+ private static readonly MAX_RETRIES;
81
+ private static readonly INITIAL_RETRY_DELAY_MS;
82
+ /**
83
+ * Send a request and wait for the matching response.
84
+ * Automatically retries on rate-limit errors with exponential backoff.
85
+ * Rejects on timeout, non-retryable API error, or max retries exceeded.
86
+ */
53
87
  request(payloadType: number, payload: Record<string, unknown>): Promise<Record<string, unknown>>;
88
+ /**
89
+ * Internal: send a single request without retry.
90
+ */
91
+ private requestOnce;
92
+ private drainQueue;
93
+ /**
94
+ * Subscribe to a specific payload type.
95
+ * Returns an unsubscribe function.
96
+ */
54
97
  on(payloadType: number, handler: PayloadHandler): () => void;
98
+ /** Remove a specific handler for a payload type. */
55
99
  off(payloadType: number, handler: PayloadHandler): void;
100
+ /**
101
+ * Subscribe to connection lifecycle events (stateChange, error, message).
102
+ * Returns an unsubscribe function.
103
+ */
56
104
  onEvent(event: ConnectionEvent, handler: ConnectionEventHandler): () => void;
105
+ /** Remove a specific connection event handler. */
57
106
  offEvent(event: ConnectionEvent, handler: ConnectionEventHandler): void;
58
107
  private handleData;
59
108
  private handleMessage;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../../src/core/connection.ts"],"names":[],"mappings":"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"}
@@ -10,15 +10,29 @@
10
10
  * - If no heartbeat received from server for HEARTBEAT_TIMEOUT_MS, close
11
11
  */
12
12
  import * as tls from "node:tls";
13
- import { CTraderError, NotConnectedError, RequestTimeoutError, } from "./errors.js";
14
- import { PayloadType } from "./enums.js";
15
- import { encodeMessage, encodeHeartbeat, decodeMessage, } from "./codec.js";
13
+ import { decodeMessage, encodeHeartbeat, encodeMessage, } from "../protocol/codec.js";
14
+ import { PayloadType } from "../protocol/enums.js";
15
+ import { CTraderError, NotConnectedError, RequestTimeoutError } from "./errors.js";
16
16
  const REQUEST_TIMEOUT_MS = 15_000;
17
17
  const HEARTBEAT_CHECK_MS = 1_000;
18
18
  const HEARTBEAT_IDLE_MS = 10_000;
19
19
  const HEARTBEAT_TIMEOUT_MS = 60_000;
20
20
  const INITIAL_RECONNECT_DELAY_MS = 2_000;
21
21
  const MAX_RECONNECT_DELAY_MS = 60_000;
22
+ /**
23
+ * Throttle settings to avoid REQUEST_FREQUENCY_EXCEEDED errors.
24
+ * The cTrader Open API has an undocumented rate limit (~50 req/s).
25
+ * We limit concurrency and add a small gap between sends.
26
+ */
27
+ const MAX_CONCURRENT_REQUESTS = 5;
28
+ const REQUEST_GAP_MS = 50;
29
+ /**
30
+ * Low-level TLS/TCP connection to the cTrader Open API (port 5035).
31
+ * Handles connect/disconnect, heartbeat, automatic reconnection,
32
+ * request/response matching, and payload-based event dispatch.
33
+ *
34
+ * Most users should use {@link CTrader} (via `connect()`) instead of this class directly.
35
+ */
22
36
  export class CTraderConnection {
23
37
  socket = null;
24
38
  host;
@@ -40,6 +54,10 @@ export class CTraderConnection {
40
54
  pending = new Map();
41
55
  payloadHandlers = new Map();
42
56
  eventHandlers = new Map();
57
+ /** Request throttle queue */
58
+ requestQueue = [];
59
+ inFlightRequests = 0;
60
+ lastRequestSentAt = 0;
43
61
  constructor(config) {
44
62
  this.host = config.host;
45
63
  this.port = config.port ?? 5035;
@@ -47,17 +65,22 @@ export class CTraderConnection {
47
65
  this.requestTimeoutMs = config.requestTimeoutMs ?? REQUEST_TIMEOUT_MS;
48
66
  this.onReconnect = config.onReconnect;
49
67
  }
68
+ /** Current connection lifecycle state. */
50
69
  get state() {
51
70
  return this._state;
52
71
  }
72
+ /** True when the TLS/TCP socket is established and ready for messages. */
53
73
  get isConnected() {
54
74
  return this._state.status === "connected" || this._state.status === "ready";
55
75
  }
56
76
  // ─── Connect ────────────────────────────────────────────────────────────
77
+ /**
78
+ * Establish a TLS/TCP connection to the cTrader API.
79
+ * Resolves when the connection is established, rejects on failure.
80
+ */
57
81
  connect() {
58
82
  return new Promise((resolve, reject) => {
59
- if (this._state.status === "connected" ||
60
- this._state.status === "ready") {
83
+ if (this._state.status === "connected" || this._state.status === "ready") {
61
84
  resolve();
62
85
  return;
63
86
  }
@@ -97,6 +120,10 @@ export class CTraderConnection {
97
120
  });
98
121
  });
99
122
  }
123
+ /**
124
+ * Close the TLS/TCP connection and stop automatic reconnection.
125
+ * All pending requests are rejected.
126
+ */
100
127
  disconnect() {
101
128
  this.shouldReconnect = false;
102
129
  if (this.reconnectTimer !== null) {
@@ -112,6 +139,10 @@ export class CTraderConnection {
112
139
  this.setState({ status: "disconnected" });
113
140
  }
114
141
  // ─── Send ───────────────────────────────────────────────────────────────
142
+ /**
143
+ * Send a one-way message (fire-and-forget) over the TLS/TCP connection.
144
+ * Returns the generated clientMsgId for tracking.
145
+ */
115
146
  send(payloadType, payload) {
116
147
  if (this.socket === null || this.socket.destroyed) {
117
148
  throw new NotConnectedError();
@@ -122,17 +153,105 @@ export class CTraderConnection {
122
153
  this.lastSendAt = Date.now();
123
154
  return clientMsgId;
124
155
  }
125
- request(payloadType, payload) {
156
+ static MAX_RETRIES = 3;
157
+ static INITIAL_RETRY_DELAY_MS = 1_000;
158
+ /**
159
+ * Send a request and wait for the matching response.
160
+ * Automatically retries on rate-limit errors with exponential backoff.
161
+ * Rejects on timeout, non-retryable API error, or max retries exceeded.
162
+ */
163
+ async request(payloadType, payload) {
164
+ let lastError;
165
+ for (let attempt = 0; attempt <= CTraderConnection.MAX_RETRIES; attempt++) {
166
+ try {
167
+ return await this.requestOnce(payloadType, payload);
168
+ }
169
+ catch (err) {
170
+ if (err instanceof CTraderError &&
171
+ err.isRateLimit &&
172
+ attempt < CTraderConnection.MAX_RETRIES) {
173
+ lastError = err;
174
+ const delay = err.retryAfter ?? CTraderConnection.INITIAL_RETRY_DELAY_MS * 2 ** attempt;
175
+ await new Promise((r) => setTimeout(r, delay));
176
+ continue;
177
+ }
178
+ throw err;
179
+ }
180
+ }
181
+ throw lastError ?? new Error("Max retries exceeded");
182
+ }
183
+ /**
184
+ * Internal: send a single request without retry.
185
+ */
186
+ requestOnce(payloadType, payload) {
126
187
  return new Promise((resolve, reject) => {
127
- const clientMsgId = this.send(payloadType, payload);
128
- const timeout = setTimeout(() => {
129
- this.pending.delete(clientMsgId);
130
- reject(new RequestTimeoutError(payloadType, clientMsgId, this.requestTimeoutMs));
131
- }, this.requestTimeoutMs);
132
- this.pending.set(clientMsgId, { resolve, reject, timeout });
188
+ const execute = () => {
189
+ this.inFlightRequests++;
190
+ this.lastRequestSentAt = Date.now();
191
+ let clientMsgId;
192
+ try {
193
+ clientMsgId = this.send(payloadType, payload);
194
+ }
195
+ catch (err) {
196
+ this.inFlightRequests--;
197
+ this.drainQueue();
198
+ reject(err instanceof Error ? err : new Error(String(err)));
199
+ return;
200
+ }
201
+ const onComplete = () => {
202
+ this.inFlightRequests--;
203
+ this.drainQueue();
204
+ };
205
+ const timeout = setTimeout(() => {
206
+ this.pending.delete(clientMsgId);
207
+ onComplete();
208
+ reject(new RequestTimeoutError(payloadType, clientMsgId, this.requestTimeoutMs));
209
+ }, this.requestTimeoutMs);
210
+ this.pending.set(clientMsgId, {
211
+ resolve: (result) => {
212
+ onComplete();
213
+ resolve(result);
214
+ },
215
+ reject: (err) => {
216
+ onComplete();
217
+ reject(err);
218
+ },
219
+ timeout,
220
+ });
221
+ };
222
+ // Queue if at concurrency limit or need gap between sends
223
+ if (this.inFlightRequests >= MAX_CONCURRENT_REQUESTS) {
224
+ this.requestQueue.push(execute);
225
+ }
226
+ else {
227
+ const elapsed = Date.now() - this.lastRequestSentAt;
228
+ if (elapsed < REQUEST_GAP_MS) {
229
+ setTimeout(execute, REQUEST_GAP_MS - elapsed);
230
+ }
231
+ else {
232
+ execute();
233
+ }
234
+ }
133
235
  });
134
236
  }
237
+ drainQueue() {
238
+ if (this.requestQueue.length === 0 || this.inFlightRequests >= MAX_CONCURRENT_REQUESTS) {
239
+ return;
240
+ }
241
+ const next = this.requestQueue.shift();
242
+ const elapsed = Date.now() - this.lastRequestSentAt;
243
+ if (elapsed < REQUEST_GAP_MS) {
244
+ setTimeout(next, REQUEST_GAP_MS - elapsed);
245
+ }
246
+ else {
247
+ next();
248
+ }
249
+ }
135
250
  // ─── Event handlers ─────────────────────────────────────────────────────
251
+ /**
252
+ * Subscribe to a specific payload type.
253
+ * Returns an unsubscribe function.
254
+ */
136
255
  on(payloadType, handler) {
137
256
  let handlers = this.payloadHandlers.get(payloadType);
138
257
  if (handlers === undefined) {
@@ -142,9 +261,14 @@ export class CTraderConnection {
142
261
  handlers.add(handler);
143
262
  return () => this.off(payloadType, handler);
144
263
  }
264
+ /** Remove a specific handler for a payload type. */
145
265
  off(payloadType, handler) {
146
266
  this.payloadHandlers.get(payloadType)?.delete(handler);
147
267
  }
268
+ /**
269
+ * Subscribe to connection lifecycle events (stateChange, error, message).
270
+ * Returns an unsubscribe function.
271
+ */
148
272
  onEvent(event, handler) {
149
273
  let handlers = this.eventHandlers.get(event);
150
274
  if (handlers === undefined) {
@@ -154,6 +278,7 @@ export class CTraderConnection {
154
278
  handlers.add(handler);
155
279
  return () => this.offEvent(event, handler);
156
280
  }
281
+ /** Remove a specific connection event handler. */
157
282
  offEvent(event, handler) {
158
283
  this.eventHandlers.get(event)?.delete(handler);
159
284
  }
@@ -194,8 +319,7 @@ export class CTraderConnection {
194
319
  const req = this.pending.get(clientMsgId);
195
320
  this.pending.delete(clientMsgId);
196
321
  clearTimeout(req.timeout);
197
- if (payloadType === PayloadType.ERROR_RES ||
198
- payloadType === PayloadType.OA_ERROR_RES) {
322
+ if (payloadType === PayloadType.ERROR_RES || payloadType === PayloadType.OA_ERROR_RES) {
199
323
  req.reject(this.makeError(payload));
200
324
  return;
201
325
  }
@@ -203,8 +327,7 @@ export class CTraderConnection {
203
327
  return;
204
328
  }
205
329
  // Unsolicited error
206
- if (payloadType === PayloadType.ERROR_RES ||
207
- payloadType === PayloadType.OA_ERROR_RES) {
330
+ if (payloadType === PayloadType.ERROR_RES || payloadType === PayloadType.OA_ERROR_RES) {
208
331
  this.emit("error", this.makeError(payload));
209
332
  return;
210
333
  }
@@ -264,8 +387,7 @@ export class CTraderConnection {
264
387
  if (!this.shouldReconnect)
265
388
  return;
266
389
  this.reconnectAttempt++;
267
- if (this.maxReconnectAttempts > 0 &&
268
- this.reconnectAttempt > this.maxReconnectAttempts) {
390
+ if (this.maxReconnectAttempts > 0 && this.reconnectAttempt > this.maxReconnectAttempts) {
269
391
  this.setState({ status: "disconnected" });
270
392
  return;
271
393
  }
@@ -329,6 +451,18 @@ export class CTraderConnection {
329
451
  req.reject(error);
330
452
  }
331
453
  this.pending.clear();
454
+ // Reset throttle state — all in-flight requests are now dead
455
+ this.inFlightRequests = 0;
456
+ // Reject queued requests too — they'll fail on a dead socket
457
+ const queued = this.requestQueue.splice(0);
458
+ for (const fn of queued) {
459
+ try {
460
+ fn();
461
+ }
462
+ catch {
463
+ // Will throw NotConnectedError — caught by caller
464
+ }
465
+ }
332
466
  }
333
467
  makeError(err) {
334
468
  const opts = {
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.js","sourceRoot":"","sources":["../../../src/core/connection.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ /** Error returned by the cTrader Open API — includes a machine-readable code and human description. */
1
2
  export declare class CTraderError extends Error {
2
3
  readonly code: string;
3
4
  readonly description: string;
@@ -9,15 +10,19 @@ export declare class CTraderError extends Error {
9
10
  retryAfter?: number;
10
11
  maintenanceEndTimestamp?: number;
11
12
  });
13
+ /** Actionable recovery hint for this error, or undefined for unknown error codes */
14
+ get hint(): string | undefined;
12
15
  get isAuthError(): boolean;
13
16
  get isRateLimit(): boolean;
14
17
  get isMaintenance(): boolean;
15
18
  }
19
+ /** Thrown when a request does not receive a response within the configured timeout. */
16
20
  export declare class RequestTimeoutError extends Error {
17
21
  readonly payloadType: number;
18
22
  readonly clientMsgId: string;
19
23
  constructor(payloadType: number, clientMsgId: string, timeoutMs: number);
20
24
  }
25
+ /** Thrown when an operation is attempted while the WebSocket is not connected. */
21
26
  export declare class NotConnectedError extends Error {
22
27
  constructor();
23
28
  }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/core/errors.ts"],"names":[],"mappings":"AA6CA,uGAAuG;AACvG,qBAAa,YAAa,SAAQ,KAAK;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,uBAAuB,CAAC,EAAE,MAAM,CAAC;gBAE9B,IAAI,EAAE;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,uBAAuB,CAAC,EAAE,MAAM,CAAC;KACjC;IAcD,oFAAoF;IACpF,IAAI,IAAI,IAAI,MAAM,GAAG,SAAS,CAE7B;IAED,IAAI,WAAW,IAAI,OAAO,CASzB;IAED,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED,IAAI,aAAa,IAAI,OAAO,CAE3B;CACD;AAED,uFAAuF;AACvF,qBAAa,mBAAoB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;gBAEjB,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;CAQvE;AAED,kFAAkF;AAClF,qBAAa,iBAAkB,SAAQ,KAAK;;CAO3C"}
@@ -0,0 +1,85 @@
1
+ /** Actionable hint map: maps error codes to user-friendly recovery instructions */
2
+ const ERROR_HINTS = {
3
+ // Auth errors
4
+ OA_AUTH_TOKEN_EXPIRED: "Your access token has expired. Run `ctrader-ts auth` to re-authenticate.",
5
+ ACCOUNT_NOT_AUTHORIZED: "This account isn't authorized. Run `ctrader-ts auth` and select the correct account.",
6
+ CH_CLIENT_AUTH_FAILURE: "Client authentication failed. Check your clientId and clientSecret in config.",
7
+ CH_CLIENT_NOT_AUTHENTICATED: "You must authenticate before making requests. Call connect() which handles this automatically.",
8
+ CH_ACCESS_TOKEN_INVALID: "Invalid access token. Run `ctrader-ts auth` to get a fresh token.",
9
+ OAUTH_TOKEN_INVALIDATED: "Token was invalidated (possibly revoked or used from another location). Run `ctrader-ts auth`.",
10
+ // Rate limiting
11
+ REQUEST_FREQUENCY_EXCEEDED: "Too many requests. Wait and retry — consider adding delays between rapid API calls.",
12
+ BLOCKED_PAYLOAD_TYPE: "This request type is temporarily blocked due to rate limiting. Wait before retrying.",
13
+ // Maintenance
14
+ SERVER_IS_UNDER_MAINTENANCE: "Server is under maintenance. Check maintenanceEndTimestamp for expected end time.",
15
+ // Trading errors
16
+ NOT_ENOUGH_MONEY: "Insufficient free margin. Reduce position size or close existing positions to free up margin.",
17
+ SYMBOL_NOT_FOUND: "Symbol not found. Check available symbols with getSymbols() or `ctrader-ts symbols`.",
18
+ INVALID_VOLUME: "Invalid volume. Ensure lots >= minVolume and is a multiple of stepVolume. Use getSymbolInfo() to check limits.",
19
+ MARKET_CLOSED: "Market is closed for this symbol. Check trading hours with getSymbolInfo().",
20
+ TRADING_BAD_VOLUME: "Volume out of range. Use getSymbolInfo() to check minVolume, maxVolume, and stepVolume.",
21
+ TRADING_BAD_STOPS: "Invalid SL/TP distance. Some brokers require minimum distances — use getSymbolInfo() to check slDistance/tpDistance.",
22
+ POSITION_NOT_FOUND: "Position not found. It may have been closed or the ID is incorrect.",
23
+ ORDER_NOT_FOUND: "Order not found. It may have been filled, expired, or cancelled.",
24
+ NO_MORE_ACCOUNTS_AVAILABLE: "No more accounts available. Check your cTrader ID has linked broker accounts.",
25
+ CONNECTIONS_LIMIT_EXCEEDED: "Too many connections from this app. Close other sessions or wait for them to expire.",
26
+ TRADING_DISABLED: "Trading is disabled on this account. Contact your broker.",
27
+ };
28
+ /** Error returned by the cTrader Open API — includes a machine-readable code and human description. */
29
+ export class CTraderError extends Error {
30
+ code;
31
+ description;
32
+ retryAfter;
33
+ maintenanceEndTimestamp;
34
+ constructor(opts) {
35
+ const hint = ERROR_HINTS[opts.code];
36
+ const message = hint
37
+ ? `[${opts.code}] ${opts.description} — ${hint}`
38
+ : `[${opts.code}] ${opts.description}`;
39
+ super(message);
40
+ this.name = "CTraderError";
41
+ this.code = opts.code;
42
+ this.description = opts.description;
43
+ if (opts.retryAfter !== undefined)
44
+ this.retryAfter = opts.retryAfter;
45
+ if (opts.maintenanceEndTimestamp !== undefined)
46
+ this.maintenanceEndTimestamp = opts.maintenanceEndTimestamp;
47
+ }
48
+ /** Actionable recovery hint for this error, or undefined for unknown error codes */
49
+ get hint() {
50
+ return ERROR_HINTS[this.code];
51
+ }
52
+ get isAuthError() {
53
+ return (this.code === "OA_AUTH_TOKEN_EXPIRED" ||
54
+ this.code === "ACCOUNT_NOT_AUTHORIZED" ||
55
+ this.code === "CH_CLIENT_AUTH_FAILURE" ||
56
+ this.code === "CH_CLIENT_NOT_AUTHENTICATED" ||
57
+ this.code === "CH_ACCESS_TOKEN_INVALID" ||
58
+ this.code === "OAUTH_TOKEN_INVALIDATED");
59
+ }
60
+ get isRateLimit() {
61
+ return this.code === "REQUEST_FREQUENCY_EXCEEDED" || this.code === "BLOCKED_PAYLOAD_TYPE";
62
+ }
63
+ get isMaintenance() {
64
+ return this.code === "SERVER_IS_UNDER_MAINTENANCE";
65
+ }
66
+ }
67
+ /** Thrown when a request does not receive a response within the configured timeout. */
68
+ export class RequestTimeoutError extends Error {
69
+ payloadType;
70
+ clientMsgId;
71
+ constructor(payloadType, clientMsgId, timeoutMs) {
72
+ super(`Request timed out after ${timeoutMs}ms (payloadType: ${payloadType}, id: ${clientMsgId}). Check your network connection or try increasing requestTimeoutMs.`);
73
+ this.name = "RequestTimeoutError";
74
+ this.payloadType = payloadType;
75
+ this.clientMsgId = clientMsgId;
76
+ }
77
+ }
78
+ /** Thrown when an operation is attempted while the WebSocket is not connected. */
79
+ export class NotConnectedError extends Error {
80
+ constructor() {
81
+ super("Not connected to cTrader API. Call connect() first, or check that the connection hasn't been dropped.");
82
+ this.name = "NotConnectedError";
83
+ }
84
+ }
85
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/core/errors.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
- import type { CTraderAccount } from "./modules/account.js";
2
- import type { CTraderMarket } from "./modules/market.js";
1
+ import type { CTraderAccount } from "../modules/account.js";
2
+ import type { CTraderMarket } from "../modules/market.js";
3
+ import type { SlTpSpec } from "../protocol/types.js";
3
4
  import type { SymbolCache } from "./symbol-cache.js";
4
- import type { SlTpSpec } from "./types.js";
5
5
  export type { SlTpSpec };
6
6
  interface SlTpContext {
7
7
  account: CTraderAccount;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/core/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAc,QAAQ,EAAa,MAAM,sBAAsB,CAAC;AAC5E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,YAAY,EAAE,QAAQ,EAAE,CAAC;AAEzB,UAAU,WAAW;IACpB,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,WAAW,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACtB;AAED,UAAU,YAAY;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,SAAI,GAAG,MAAM,CAEpE;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAChC,GAAG,EAAE,WAAW,EAChB,EAAE,EAAE,QAAQ,GAAG,SAAS,EACxB,EAAE,EAAE,QAAQ,GAAG,SAAS,GACtB,OAAO,CAAC,YAAY,CAAC,CAmBvB"}
@@ -3,7 +3,7 @@
3
3
  * Formula: pips * 10^(5 - pipPosition)
4
4
  */
5
5
  export function pipsToRelative(pips, pipPosition = 4) {
6
- return Math.round(pips * Math.pow(10, 5 - pipPosition));
6
+ return Math.round(pips * 10 ** (5 - pipPosition));
7
7
  }
8
8
  /**
9
9
  * Resolve human-friendly SlTpSpec (pips / dollars / equity) into protocol-level
@@ -31,7 +31,7 @@ async function specToPips(cache, spec, volumeInUnits) {
31
31
  if ("pips" in spec)
32
32
  return spec.pips;
33
33
  const sym = await cache.getSymbolDetails();
34
- const pipSize = Math.pow(10, -sym.pipPosition);
34
+ const pipSize = 10 ** -sym.pipPosition;
35
35
  const lotSize = sym.lotSize ?? 100_000;
36
36
  const lots = volumeInUnits / 100_000;
37
37
  // pipValue = pipSize * lotSize * quoteToAccountRate (assumed 1:1 for USD accounts)
@@ -63,9 +63,7 @@ class RequestCache {
63
63
  }
64
64
  getSymbolDetails() {
65
65
  if (this.symbolPromise === null) {
66
- this.symbolPromise = this.ctx.market
67
- .getSymbolsById([this.ctx.symbolId])
68
- .then((symbols) => {
66
+ this.symbolPromise = this.ctx.market.getSymbolsById([this.ctx.symbolId]).then((symbols) => {
69
67
  const sym = symbols[0];
70
68
  if (sym === undefined) {
71
69
  throw new Error(`Symbol details not found for id ${this.ctx.symbolId}`);
@@ -91,14 +89,18 @@ class RequestCache {
91
89
  return new Promise((resolve, reject) => {
92
90
  const timeout = setTimeout(() => {
93
91
  unsub();
94
- void this.ctx.market.unsubscribeSpots([this.ctx.symbolId]).catch(() => { });
92
+ void this.ctx.market.unsubscribeSpots([this.ctx.symbolId]).catch(() => {
93
+ /* fire-and-forget cleanup */
94
+ });
95
95
  reject(new Error(`Timed out waiting for spot price on symbol ${this.ctx.symbolId}`));
96
96
  }, 10_000);
97
97
  const unsub = this.ctx.market.onSpot((event) => {
98
98
  if (event.symbolId === this.ctx.symbolId) {
99
99
  clearTimeout(timeout);
100
100
  unsub();
101
- void this.ctx.market.unsubscribeSpots([this.ctx.symbolId]).catch(() => { });
101
+ void this.ctx.market.unsubscribeSpots([this.ctx.symbolId]).catch(() => {
102
+ /* fire-and-forget cleanup */
103
+ });
102
104
  resolve(event);
103
105
  }
104
106
  });
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../../src/core/helpers.ts"],"names":[],"mappings":"AAoBA;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,WAAW,GAAG,CAAC;IAC3D,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,EAAE,IAAI,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC;AACnD,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAChC,GAAgB,EAChB,EAAwB,EACxB,EAAwB;IAExB,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,IAAI,EAAE,KAAK,SAAS,IAAI,EAAE,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IAExD,MAAM,KAAK,GAAG,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC;IAEpC,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,KAAK,EAAE,EAAE,EAAE,GAAG,CAAC,aAAa,CAAC,CAAC;QAC5D,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,gBAAgB,EAAE,CAAC;QAC3C,MAAM,CAAC,gBAAgB,GAAG,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC;IACjE,CAAC;IAED,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,KAAK,EAAE,EAAE,EAAE,GAAG,CAAC,aAAa,CAAC,CAAC;QAC5D,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,gBAAgB,EAAE,CAAC;QAC3C,MAAM,CAAC,kBAAkB,GAAG,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC;IACnE,CAAC;IAED,OAAO,MAAM,CAAC;AACf,CAAC;AAED,KAAK,UAAU,UAAU,CACxB,KAAmB,EACnB,IAAc,EACd,aAAqB;IAErB,IAAI,MAAM,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC,IAAI,CAAC;IAErC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,gBAAgB,EAAE,CAAC;IAC3C,MAAM,OAAO,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC;IACvC,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC;IACvC,MAAM,IAAI,GAAG,aAAa,GAAG,OAAO,CAAC;IAErC,mFAAmF;IACnF,MAAM,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,CAAC,CAAC;IAEvC,IAAI,OAAe,CAAC;IACpB,IAAI,SAAS,IAAI,IAAI,EAAE,CAAC;QACvB,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IACxB,CAAC;SAAM,CAAC;QACP,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,EAAE,CAAC;QACvC,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC;QAC9B,OAAO,GAAG,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IAChC,CAAC;IAED,6CAA6C;IAC7C,MAAM,YAAY,GAAG,OAAO,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IACjD,OAAO,YAAY,CAAC;AACrB,CAAC;AAED;;;GAGG;AACH,MAAM,YAAY;IACA,GAAG,CAAc;IAC1B,aAAa,GAA+B,IAAI,CAAC;IACjD,aAAa,GAAwC,IAAI,CAAC;IAC1D,WAAW,GAA8B,IAAI,CAAC;IAEtD,YAAY,GAAgB;QAC3B,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IAChB,CAAC;IAED,gBAAgB;QACf,IAAI,IAAI,CAAC,aAAa,KAAK,IAAI,EAAE,CAAC;YACjC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE;gBACzF,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;gBACvB,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;oBACvB,MAAM,IAAI,KAAK,CAAC,mCAAmC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;gBACzE,CAAC;gBACD,OAAO,GAAG,CAAC;YACZ,CAAC,CAAC,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC,aAAa,CAAC;IAC3B,CAAC;IAED,SAAS;QACR,IAAI,IAAI,CAAC,aAAa,KAAK,IAAI,EAAE,CAAC;YACjC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;QACnD,CAAC;QACD,OAAO,IAAI,CAAC,aAAa,CAAC;IAC3B,CAAC;IAED,YAAY;QACX,IAAI,IAAI,CAAC,WAAW,KAAK,IAAI,EAAE,CAAC;YAC/B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QACxC,CAAC;QACD,OAAO,IAAI,CAAC,WAAW,CAAC;IACzB,CAAC;IAEO,YAAY;QACnB,OAAO,IAAI,OAAO,CAAY,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACjD,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC/B,KAAK,EAAE,CAAC;gBACR,KAAK,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;oBACrE,6BAA6B;gBAC9B,CAAC,CAAC,CAAC;gBACH,MAAM,CAAC,IAAI,KAAK,CAAC,8CAA8C,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;YACtF,CAAC,EAAE,MAAM,CAAC,CAAC;YAEX,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAgB,EAAE,EAAE;gBACzD,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;oBAC1C,YAAY,CAAC,OAAO,CAAC,CAAC;oBACtB,KAAK,EAAE,CAAC;oBACR,KAAK,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;wBACrE,6BAA6B;oBAC9B,CAAC,CAAC,CAAC;oBACH,OAAO,CAAC,KAAK,CAAC,CAAC;gBAChB,CAAC;YACF,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;gBAC1E,YAAY,CAAC,OAAO,CAAC,CAAC;gBACtB,KAAK,EAAE,CAAC;gBACR,MAAM,CAAC,GAAG,CAAC,CAAC;YACb,CAAC,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;IACJ,CAAC;CACD"}
@@ -1,5 +1,5 @@
1
- import type { CTraderMarket } from "./modules/market.js";
2
- import type { LightSymbol } from "./types.js";
1
+ import type { CTraderMarket } from "../modules/market.js";
2
+ import type { LightSymbol } from "../protocol/types.js";
3
3
  export declare class SymbolCache {
4
4
  private readonly market;
5
5
  private nameToId;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"symbol-cache.d.ts","sourceRoot":"","sources":["../../../src/core/symbol-cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,qBAAa,WAAW;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAoC;IACpD,OAAO,CAAC,UAAU,CAAyC;gBAE/C,MAAM,EAAE,aAAa;IAI3B,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAWvD,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAQ5D,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YAMhB,WAAW;YAKX,aAAa;CAI3B"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"symbol-cache.js","sourceRoot":"","sources":["../../../src/core/symbol-cache.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,WAAW;IACN,MAAM,CAAgB;IAC/B,QAAQ,GAA+B,IAAI,CAAC;IAC5C,UAAU,GAAoC,IAAI,CAAC;IAE3D,YAAY,MAAqB;QAChC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,UAA2B;QAC1C,IAAI,OAAO,UAAU,KAAK,QAAQ;YAAE,OAAO,UAAU,CAAC;QACtD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC;QAC7C,IAAI,EAAE,KAAK,SAAS;YACnB,MAAM,IAAI,KAAK,CACd,sBAAsB,UAAU,sDAAsD,CACtF,CAAC;QACH,OAAO,EAAE,CAAC;IACX,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,UAA2B;QAC1C,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QAC5C,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QACvC,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACxB,IAAI,GAAG,KAAK,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,aAAa,EAAE,sBAAsB,CAAC,CAAC;QAC9E,OAAO,GAAG,CAAC;IACZ,CAAC;IAED,KAAK,CAAC,OAAO;QACZ,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QACnD,IAAI,CAAC,QAAQ,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC7F,IAAI,CAAC,UAAU,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAChE,CAAC;IAEO,KAAK,CAAC,WAAW;QACxB,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI;YAAE,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACjD,OAAO,IAAI,CAAC,QAAS,CAAC;IACvB,CAAC;IAEO,KAAK,CAAC,aAAa;QAC1B,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI;YAAE,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACnD,OAAO,IAAI,CAAC,UAAW,CAAC;IACzB,CAAC;CACD"}