@cexyio/cexy 0.1.0-dev.4 → 0.1.0-dev.6
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 +36 -8
- package/dist/index.cjs +165 -65
- package/dist/index.d.cts +181 -36
- package/dist/index.d.ts +181 -36
- package/dist/index.js +163 -66
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -29,6 +29,16 @@ var OrderStateUnknownError = class extends CexyError {
|
|
|
29
29
|
this.clientOrderId = clientOrderId;
|
|
30
30
|
}
|
|
31
31
|
};
|
|
32
|
+
var CancelAllInterruptedError = class extends CexyError {
|
|
33
|
+
error;
|
|
34
|
+
partial;
|
|
35
|
+
constructor(error, partial) {
|
|
36
|
+
const what = error instanceof CexyApiError ? `${error.code}: ${error.message}` : String(error);
|
|
37
|
+
super(`cancelAll stopped after ${partial.rounds} round(s): ${what}`, { cause: error });
|
|
38
|
+
this.error = error;
|
|
39
|
+
this.partial = partial;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
32
42
|
var CexyApiError = class extends CexyError {
|
|
33
43
|
status;
|
|
34
44
|
code;
|
|
@@ -127,27 +137,30 @@ var KNOWN_CODES = /* @__PURE__ */ new Set([
|
|
|
127
137
|
"INTERNAL",
|
|
128
138
|
"SERVICE_UNAVAILABLE",
|
|
129
139
|
"UNDER_MAINTENANCE",
|
|
130
|
-
"ENGINE_OVERLOADED"
|
|
140
|
+
"ENGINE_OVERLOADED",
|
|
141
|
+
"PRICE_UNAVAILABLE"
|
|
131
142
|
]);
|
|
132
143
|
var CLIENT_ERROR_CODES = { UNEXPECTED_REDIRECT: "UNEXPECTED_REDIRECT" };
|
|
133
144
|
function isKnownErrorCode(code) {
|
|
134
145
|
return KNOWN_CODES.has(code);
|
|
135
146
|
}
|
|
136
147
|
var DEFAULT_RETRYABLE_STATUS = /* @__PURE__ */ new Set([408, 429, 500, 502, 503, 504]);
|
|
148
|
+
var MAX_SERVER_WAIT_MS = 12e4;
|
|
137
149
|
function retryAfterMs(headers, details) {
|
|
138
150
|
let best = null;
|
|
139
|
-
const h = headers?.get("retry-after");
|
|
151
|
+
const h = headers?.get("retry-after")?.trim();
|
|
140
152
|
if (h) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
153
|
+
if (/^\d+(\.\d+)?$/.test(h)) {
|
|
154
|
+
const ms = Number(h) * 1e3;
|
|
155
|
+
if (Number.isFinite(ms)) best = ms;
|
|
156
|
+
} else if (/[a-z]/i.test(h)) {
|
|
144
157
|
const at = Date.parse(h);
|
|
145
|
-
if (
|
|
158
|
+
if (Number.isFinite(at)) best = Math.max(0, at - Date.now());
|
|
146
159
|
}
|
|
147
160
|
}
|
|
148
161
|
const d = details?.["retry_after_seconds"];
|
|
149
|
-
const ds = typeof d === "number" ? d : typeof d === "string" ? Number(d) : NaN;
|
|
150
|
-
if (Number.isFinite(ds)) best = Math.max(best ?? 0, ds * 1e3);
|
|
162
|
+
const ds = typeof d === "number" ? d : typeof d === "string" && /^\d+(\.\d+)?$/.test(d.trim()) ? Number(d) : NaN;
|
|
163
|
+
if (Number.isFinite(ds) && ds >= 0 && Number.isFinite(ds * 1e3)) best = Math.max(best ?? 0, ds * 1e3);
|
|
151
164
|
return best;
|
|
152
165
|
}
|
|
153
166
|
function errorFromResponse(status, body, headers, redact = (t) => t) {
|
|
@@ -310,6 +323,7 @@ var OPERATIONS = {
|
|
|
310
323
|
};
|
|
311
324
|
|
|
312
325
|
// src/http.ts
|
|
326
|
+
var IDEMPOTENT_OPS = /* @__PURE__ */ new Set(["join_pool", "exit_pool"]);
|
|
313
327
|
var BACKOFF_BASE_MS = 500;
|
|
314
328
|
var BACKOFF_MAX_MS = 1e4;
|
|
315
329
|
var Transport = class {
|
|
@@ -318,16 +332,15 @@ var Transport = class {
|
|
|
318
332
|
this.config = config;
|
|
319
333
|
}
|
|
320
334
|
/**
|
|
321
|
-
* Sends a request with the standard retry policy:
|
|
322
|
-
*
|
|
323
|
-
* honours it
|
|
324
|
-
*
|
|
335
|
+
* Sends a request with the standard retry policy: retryable errors and network failures are
|
|
336
|
+
* retried. Pool join/exit carry an `Idempotency-Key` reused on every attempt (the server
|
|
337
|
+
* honours it there, which makes their retries safe); the other mutations routed here
|
|
338
|
+
* (cancel-all) are naturally repeatable and send no key. `placeOrder` and `cancelOrder` use
|
|
325
339
|
* `attempt()` with their own policies.
|
|
326
340
|
*/
|
|
327
341
|
async request(spec, opts = {}) {
|
|
328
342
|
const info = OPERATIONS[spec.op];
|
|
329
|
-
const
|
|
330
|
-
const idempotencyKey = isMutation ? spec.idempotencyKey ?? opts.idempotencyKey ?? newId() : void 0;
|
|
343
|
+
const idempotencyKey = IDEMPOTENT_OPS.has(spec.op) ? spec.idempotencyKey ?? opts.idempotencyKey ?? newId() : void 0;
|
|
331
344
|
const maxRetries = opts.maxRetries ?? this.config.maxRetries;
|
|
332
345
|
for (let attempt = 0; ; attempt++) {
|
|
333
346
|
try {
|
|
@@ -338,8 +351,13 @@ var Transport = class {
|
|
|
338
351
|
}
|
|
339
352
|
}
|
|
340
353
|
}
|
|
341
|
-
/**
|
|
354
|
+
/**
|
|
355
|
+
* Waits before retry number `attempt + 1`, honouring server hints. A server hint longer than
|
|
356
|
+
* `MAX_SERVER_WAIT_MS` is not waited: `err` is thrown at once (it still carries the hint).
|
|
357
|
+
*/
|
|
342
358
|
async backoff(op2, info, attempt, err, idempotencyKey, signal) {
|
|
359
|
+
const hint = serverHintMs(err);
|
|
360
|
+
if (hint !== null && hint > MAX_SERVER_WAIT_MS) throw err;
|
|
343
361
|
const delayMs = this.retryDelay(attempt, err);
|
|
344
362
|
this.config.onRetry?.({
|
|
345
363
|
operation: op2,
|
|
@@ -354,8 +372,8 @@ var Transport = class {
|
|
|
354
372
|
}
|
|
355
373
|
/** Full-jitter exponential backoff, or the server's hint plus a little jitter. */
|
|
356
374
|
retryDelay(attempt, err) {
|
|
357
|
-
const hint =
|
|
358
|
-
if (hint !== null && hint > 0) return Math.ceil(hint + this.config.random() * 250);
|
|
375
|
+
const hint = serverHintMs(err);
|
|
376
|
+
if (hint !== null && hint > 0 && hint <= MAX_SERVER_WAIT_MS) return Math.ceil(hint + this.config.random() * 250);
|
|
359
377
|
const cap = Math.min(BACKOFF_MAX_MS, BACKOFF_BASE_MS * 2 ** attempt);
|
|
360
378
|
return Math.ceil(this.config.random() * cap);
|
|
361
379
|
}
|
|
@@ -370,7 +388,7 @@ var Transport = class {
|
|
|
370
388
|
body = JSON.stringify(spec.body);
|
|
371
389
|
headers.set("Content-Type", "application/json");
|
|
372
390
|
}
|
|
373
|
-
if (
|
|
391
|
+
if (IDEMPOTENT_OPS.has(spec.op) && spec.idempotencyKey) headers.set("Idempotency-Key", spec.idempotencyKey);
|
|
374
392
|
if (info.auth === "api_key") {
|
|
375
393
|
const auth = this.config.authenticator;
|
|
376
394
|
if (!auth) {
|
|
@@ -453,6 +471,11 @@ var Transport = class {
|
|
|
453
471
|
return this.config.authenticator ? this.config.authenticator.redact(text) : text;
|
|
454
472
|
}
|
|
455
473
|
};
|
|
474
|
+
function serverHintMs(err) {
|
|
475
|
+
if (err instanceof RateLimitError) return err.retryAfterMs;
|
|
476
|
+
if (err instanceof CexyApiError) return retryAfterMs(void 0, err.details);
|
|
477
|
+
return null;
|
|
478
|
+
}
|
|
456
479
|
function isRetryable(err) {
|
|
457
480
|
if (err instanceof CexyConnectionError) return true;
|
|
458
481
|
if (err instanceof CexyApiError) return err.retryable || err.code === "CONCURRENT_MODIFICATION";
|
|
@@ -484,6 +507,7 @@ function errMessage(err) {
|
|
|
484
507
|
}
|
|
485
508
|
|
|
486
509
|
// src/limiter.ts
|
|
510
|
+
var MAX_BLOCK_MS = 12e4;
|
|
487
511
|
var RateLimiter = class {
|
|
488
512
|
#rpm;
|
|
489
513
|
#tokens;
|
|
@@ -517,14 +541,25 @@ var RateLimiter = class {
|
|
|
517
541
|
return;
|
|
518
542
|
}
|
|
519
543
|
const msPerToken = 6e4 / this.#rpm;
|
|
520
|
-
await this.#sleep(Math.ceil((1 - this.#tokens) * msPerToken), signal);
|
|
544
|
+
await this.#sleep(Math.min(MAX_BLOCK_MS, Math.ceil((1 - this.#tokens) * msPerToken)), signal);
|
|
521
545
|
}
|
|
522
546
|
}
|
|
547
|
+
/**
|
|
548
|
+
* How long `acquire()` would wait right now, in ms (0 when a request may go at once). Lets a
|
|
549
|
+
* caller with a time budget, such as the cancelAll untilDone loop, count the limiter's wait.
|
|
550
|
+
*/
|
|
551
|
+
pendingWaitMs() {
|
|
552
|
+
this.#refill();
|
|
553
|
+
const block = this.#blockedUntil - this.#now();
|
|
554
|
+
if (block > 0) return block;
|
|
555
|
+
if (this.#tokens >= 1) return 0;
|
|
556
|
+
return Math.min(MAX_BLOCK_MS, Math.ceil((1 - this.#tokens) * (6e4 / this.#rpm)));
|
|
557
|
+
}
|
|
523
558
|
/** Adapts to the server's rate-limit headers. Never raises the configured limit. */
|
|
524
559
|
update(headers) {
|
|
525
560
|
this.#refill();
|
|
526
561
|
const limit = num(headers.get("x-ratelimit-limit"));
|
|
527
|
-
if (limit !== null && limit
|
|
562
|
+
if (limit !== null && limit >= 1 && limit < this.#rpm) {
|
|
528
563
|
this.#rpm = limit;
|
|
529
564
|
this.#tokens = Math.min(this.#tokens, limit);
|
|
530
565
|
}
|
|
@@ -536,10 +571,13 @@ var RateLimiter = class {
|
|
|
536
571
|
else this.blockFor(6e4 / this.#rpm);
|
|
537
572
|
}
|
|
538
573
|
}
|
|
539
|
-
/**
|
|
574
|
+
/**
|
|
575
|
+
* Blocks all requests for `ms` (used for 429 Retry-After and `X-RateLimit-Reset`). Server
|
|
576
|
+
* hints are untrusted: non-finite values are ignored and the block is capped at 120 s.
|
|
577
|
+
*/
|
|
540
578
|
blockFor(ms) {
|
|
541
|
-
if (!(ms > 0)) return;
|
|
542
|
-
this.#blockedUntil = Math.max(this.#blockedUntil, this.#now() + ms);
|
|
579
|
+
if (!(ms > 0) || !Number.isFinite(ms)) return;
|
|
580
|
+
this.#blockedUntil = Math.max(this.#blockedUntil, this.#now() + Math.min(ms, MAX_BLOCK_MS));
|
|
543
581
|
}
|
|
544
582
|
#refill() {
|
|
545
583
|
const now = this.#now();
|
|
@@ -791,6 +829,12 @@ var WalletResource = class extends Resource {
|
|
|
791
829
|
};
|
|
792
830
|
var CANCEL_RETRY_CODES = /* @__PURE__ */ new Set(["INVALID_STATE", "SERVICE_UNAVAILABLE"]);
|
|
793
831
|
var CANCEL_BACKOFF_S = [1, 2, 4, 8, 15];
|
|
832
|
+
function errorCode(err) {
|
|
833
|
+
if (err instanceof CexyApiError) return err.code;
|
|
834
|
+
if (err instanceof CexyTimeoutError) return "TIMEOUT";
|
|
835
|
+
if (err instanceof CexyConnectionError) return "CONNECTION_ERROR";
|
|
836
|
+
return "ERROR";
|
|
837
|
+
}
|
|
794
838
|
var ORDER_AMOUNT_FIELDS = ["price", "quantity", "quote_quantity", "stop_price"];
|
|
795
839
|
var TradingResource = class extends Resource {
|
|
796
840
|
/** Open orders, optionally filtered by market/status. */
|
|
@@ -821,7 +865,7 @@ var TradingResource = class extends Resource {
|
|
|
821
865
|
*
|
|
822
866
|
* Retry safety rests on `client_order_id` (generated as a UUID when absent): it is unique
|
|
823
867
|
* per account and the server refuses a repeat before any funds move. The server does NOT
|
|
824
|
-
* honour `Idempotency-Key` on orders
|
|
868
|
+
* honour `Idempotency-Key` on orders, so none is sent. After an
|
|
825
869
|
* ambiguous failure (network error, timeout or 5xx) the SDK first looks the order up by
|
|
826
870
|
* `client_order_id` and returns it if it exists (`recovered: true`); only if it does not
|
|
827
871
|
* exist does it send the order again, with the same `client_order_id`, so a late-arriving
|
|
@@ -836,12 +880,11 @@ var TradingResource = class extends Resource {
|
|
|
836
880
|
assertAmountFields(order, ORDER_AMOUNT_FIELDS, "placeOrder");
|
|
837
881
|
const clientOrderId = order.client_order_id ?? newId();
|
|
838
882
|
const body = { ...order, client_order_id: clientOrderId };
|
|
839
|
-
const idempotencyKey = opts.idempotencyKey ?? newId();
|
|
840
883
|
const maxRetries = opts.maxRetries ?? this.t.config.maxRetries;
|
|
841
884
|
const info = OPERATIONS.place_order;
|
|
842
885
|
for (let attempt = 0; ; attempt++) {
|
|
843
886
|
try {
|
|
844
|
-
const raw = await this.t.attempt({ op: "place_order", body
|
|
887
|
+
const raw = await this.t.attempt({ op: "place_order", body }, opts);
|
|
845
888
|
const data = raw.data.data;
|
|
846
889
|
return { ...data, client_order_id: clientOrderId, recovered: false };
|
|
847
890
|
} catch (err) {
|
|
@@ -851,11 +894,11 @@ var TradingResource = class extends Resource {
|
|
|
851
894
|
const existing = await this.#lookup(clientOrderId, err, opts);
|
|
852
895
|
if (existing) return { order: existing, fills: [], client_order_id: clientOrderId, recovered: true };
|
|
853
896
|
if (duplicateAfterRetry || attempt >= maxRetries) throw err;
|
|
854
|
-
await this.t.backoff("place_order", info, attempt, err,
|
|
897
|
+
await this.t.backoff("place_order", info, attempt, err, void 0, opts.signal);
|
|
855
898
|
continue;
|
|
856
899
|
}
|
|
857
900
|
if (isRetryable(err) && attempt < maxRetries) {
|
|
858
|
-
await this.t.backoff("place_order", info, attempt, err,
|
|
901
|
+
await this.t.backoff("place_order", info, attempt, err, void 0, opts.signal);
|
|
859
902
|
continue;
|
|
860
903
|
}
|
|
861
904
|
throw err;
|
|
@@ -879,10 +922,9 @@ var TradingResource = class extends Resource {
|
|
|
879
922
|
async cancelOrder(orderId, opts = {}) {
|
|
880
923
|
const maxRetries = opts.maxRetries ?? this.t.config.maxRetries;
|
|
881
924
|
const info = OPERATIONS.cancel_order;
|
|
882
|
-
const idempotencyKey = opts.idempotencyKey ?? newId();
|
|
883
925
|
for (let attempt = 0; ; attempt++) {
|
|
884
926
|
try {
|
|
885
|
-
const raw = await this.t.attempt({ op: "cancel_order", pathParams: { order_id: orderId }
|
|
927
|
+
const raw = await this.t.attempt({ op: "cancel_order", pathParams: { order_id: orderId } }, opts);
|
|
886
928
|
return raw.data.data;
|
|
887
929
|
} catch (err) {
|
|
888
930
|
if (opts.signal?.aborted) throw err;
|
|
@@ -890,7 +932,7 @@ var TradingResource = class extends Resource {
|
|
|
890
932
|
return this.order(orderId, { signal: opts.signal, timeoutMs: opts.timeoutMs });
|
|
891
933
|
}
|
|
892
934
|
if (isRetryable(err) && attempt < maxRetries) {
|
|
893
|
-
await this.t.backoff("cancel_order", info, attempt, err,
|
|
935
|
+
await this.t.backoff("cancel_order", info, attempt, err, void 0, opts.signal);
|
|
894
936
|
continue;
|
|
895
937
|
}
|
|
896
938
|
throw err;
|
|
@@ -904,7 +946,7 @@ var TradingResource = class extends Resource {
|
|
|
904
946
|
if (typeof symbol === "string" && symbol !== "") body = { symbol };
|
|
905
947
|
else if (hasSymbol && symbol === null) body = {};
|
|
906
948
|
else throw new CexyConfigError('cancelAll(): pass { symbol: "BASE/QUOTE" }, or { symbol: null } to cancel in every market');
|
|
907
|
-
const once = () => this.data({ op: "cancel_all", body }, opts);
|
|
949
|
+
const once = (o) => this.data({ op: "cancel_all", body }, o ?? opts);
|
|
908
950
|
if (params.untilDone !== true) return once();
|
|
909
951
|
const maxRounds = params.maxRounds ?? 20;
|
|
910
952
|
const budgetMs = params.timeBudgetMs ?? 12e4;
|
|
@@ -913,53 +955,90 @@ var TradingResource = class extends Resource {
|
|
|
913
955
|
const now = this.t.config.now ?? Date.now;
|
|
914
956
|
const start = now();
|
|
915
957
|
const state = /* @__PURE__ */ new Map();
|
|
958
|
+
const roundOpts = { ...opts, maxRetries: 0 };
|
|
916
959
|
let rounds = 0;
|
|
917
960
|
let idle = 0;
|
|
918
|
-
let
|
|
961
|
+
let hasMore = false;
|
|
962
|
+
let lastErrorCode;
|
|
919
963
|
let stopped;
|
|
964
|
+
const result = () => {
|
|
965
|
+
const pick = (list) => [...state].filter(([, v]) => v.list === list).map(([id]) => id);
|
|
966
|
+
return {
|
|
967
|
+
cancelled: pick("cancelled"),
|
|
968
|
+
already_closed: pick("already_closed"),
|
|
969
|
+
failed: pick("failed"),
|
|
970
|
+
failures: [...state.values()].flatMap((v) => v.list === "failed" && v.failure ? [v.failure] : []),
|
|
971
|
+
has_more: hasMore,
|
|
972
|
+
rounds,
|
|
973
|
+
stopped,
|
|
974
|
+
...lastErrorCode !== void 0 ? { last_error_code: lastErrorCode } : {}
|
|
975
|
+
};
|
|
976
|
+
};
|
|
920
977
|
for (; ; ) {
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
978
|
+
let waitMs = 0;
|
|
979
|
+
let res;
|
|
980
|
+
try {
|
|
981
|
+
res = await once(roundOpts);
|
|
982
|
+
} catch (err) {
|
|
983
|
+
rounds++;
|
|
984
|
+
if (opts?.signal?.aborted) throw err;
|
|
985
|
+
if (!isRetryable(err)) {
|
|
986
|
+
stopped = "done";
|
|
987
|
+
throw new CancelAllInterruptedError(err, result());
|
|
988
|
+
}
|
|
989
|
+
lastErrorCode = errorCode(err);
|
|
990
|
+
if (rounds >= maxRounds) {
|
|
991
|
+
stopped = "max_rounds";
|
|
992
|
+
break;
|
|
993
|
+
}
|
|
994
|
+
const hint = err instanceof RateLimitError ? err.retryAfterMs : null;
|
|
995
|
+
if (hint !== null) {
|
|
996
|
+
waitMs = hint;
|
|
997
|
+
if (hint > MAX_SERVER_WAIT_MS) {
|
|
998
|
+
stopped = "time_budget";
|
|
999
|
+
break;
|
|
1000
|
+
}
|
|
1001
|
+
} else {
|
|
1002
|
+
waitMs = (CANCEL_BACKOFF_S[Math.min(idle++, CANCEL_BACKOFF_S.length - 1)] ?? 15) * 1e3;
|
|
1003
|
+
}
|
|
934
1004
|
}
|
|
935
|
-
if (
|
|
936
|
-
|
|
937
|
-
|
|
1005
|
+
if (res) {
|
|
1006
|
+
rounds++;
|
|
1007
|
+
lastErrorCode = void 0;
|
|
1008
|
+
hasMore = res.has_more;
|
|
1009
|
+
const failures = res.failures ?? [];
|
|
1010
|
+
for (const id of res.cancelled ?? []) state.set(id, { list: "cancelled" });
|
|
1011
|
+
for (const id of res.already_closed ?? []) state.set(id, { list: "already_closed" });
|
|
1012
|
+
for (const id of res.failed ?? []) {
|
|
1013
|
+
const failure = failures.find((f) => f.order_id === id);
|
|
1014
|
+
state.set(id, failure ? { list: "failed", failure } : { list: "failed" });
|
|
1015
|
+
}
|
|
1016
|
+
const progress = (res.cancelled?.length ?? 0) + (res.already_closed?.length ?? 0) > 0;
|
|
1017
|
+
if (!res.has_more && !failures.some((f) => CANCEL_RETRY_CODES.has(f.code))) {
|
|
1018
|
+
stopped = "done";
|
|
1019
|
+
break;
|
|
1020
|
+
}
|
|
1021
|
+
if (rounds >= maxRounds) {
|
|
1022
|
+
stopped = "max_rounds";
|
|
1023
|
+
break;
|
|
1024
|
+
}
|
|
1025
|
+
if (progress) idle = 0;
|
|
1026
|
+
else waitMs = (CANCEL_BACKOFF_S[Math.min(idle++, CANCEL_BACKOFF_S.length - 1)] ?? 15) * 1e3;
|
|
938
1027
|
}
|
|
939
|
-
|
|
940
|
-
if (
|
|
941
|
-
else waitMs = (CANCEL_BACKOFF_S[Math.min(idle++, CANCEL_BACKOFF_S.length - 1)] ?? 15) * 1e3;
|
|
942
|
-
if (now() - start + waitMs >= budgetMs) {
|
|
1028
|
+
const limiterMs = this.t.config.limiter?.pendingWaitMs() ?? 0;
|
|
1029
|
+
if (now() - start + Math.max(waitMs, limiterMs) >= budgetMs) {
|
|
943
1030
|
stopped = "time_budget";
|
|
1031
|
+
if (limiterMs > waitMs) lastErrorCode = "RATE_LIMITED";
|
|
944
1032
|
break;
|
|
945
1033
|
}
|
|
946
1034
|
if (waitMs > 0) await this.t.config.sleep(waitMs, opts?.signal);
|
|
947
1035
|
}
|
|
948
|
-
|
|
949
|
-
return {
|
|
950
|
-
cancelled: pick("cancelled"),
|
|
951
|
-
already_closed: pick("already_closed"),
|
|
952
|
-
failed: pick("failed"),
|
|
953
|
-
failures: [...state.values()].flatMap((v) => v.list === "failed" && v.failure ? [v.failure] : []),
|
|
954
|
-
has_more: last.has_more,
|
|
955
|
-
rounds,
|
|
956
|
-
stopped
|
|
957
|
-
};
|
|
1036
|
+
return result();
|
|
958
1037
|
}
|
|
959
1038
|
};
|
|
960
1039
|
|
|
961
1040
|
// src/version.ts
|
|
962
|
-
var VERSION = "0.1.0-dev.
|
|
1041
|
+
var VERSION = "0.1.0-dev.6";
|
|
963
1042
|
var USER_AGENT = `cexy-typescript/${VERSION}`;
|
|
964
1043
|
|
|
965
1044
|
// src/ws/emitter.ts
|
|
@@ -1727,7 +1806,8 @@ var CexyClient = class {
|
|
|
1727
1806
|
const sleep2 = options.sleep ?? sleep;
|
|
1728
1807
|
const limiter = options.rateLimit === false ? null : new RateLimiter({
|
|
1729
1808
|
requestsPerMinute: options.rateLimit?.requestsPerMinute ?? (authenticator ? DEFAULT_RPM_WITH_KEY : DEFAULT_RPM_ANONYMOUS),
|
|
1730
|
-
sleep: sleep2
|
|
1809
|
+
sleep: sleep2,
|
|
1810
|
+
...options.now ? { now: options.now } : {}
|
|
1731
1811
|
});
|
|
1732
1812
|
this.#baseUrl = baseUrl;
|
|
1733
1813
|
this.#transport = new Transport({
|
|
@@ -1810,4 +1890,21 @@ function canSetUserAgent() {
|
|
|
1810
1890
|
return !(typeof g.window !== "undefined" && typeof g.window.document !== "undefined");
|
|
1811
1891
|
}
|
|
1812
1892
|
|
|
1813
|
-
|
|
1893
|
+
// src/ledger.ts
|
|
1894
|
+
var KNOWN_LEDGER_REFERENCE_TYPES = /* @__PURE__ */ new Set([
|
|
1895
|
+
"deposit",
|
|
1896
|
+
"withdrawal",
|
|
1897
|
+
"order",
|
|
1898
|
+
"trade",
|
|
1899
|
+
"transfer",
|
|
1900
|
+
"adjustment",
|
|
1901
|
+
"pool",
|
|
1902
|
+
"futures_transfer",
|
|
1903
|
+
"system"
|
|
1904
|
+
]);
|
|
1905
|
+
function isLedgerReference(ref, type) {
|
|
1906
|
+
if (typeof ref !== "object" || ref === null || typeof ref.type !== "string") return false;
|
|
1907
|
+
return type === void 0 ? KNOWN_LEDGER_REFERENCE_TYPES.has(ref.type) : ref.type === type;
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
export { AccountResource, ApiKeyAuthenticator, AssetsResource, AuthenticationError, CLIENT_ERROR_CODES, CancelAllInterruptedError, CexyApiError, CexyClient, CexyConfigError, CexyConnectionError, CexyError, CexyTimeoutError, CexyWebSocket, CexyWebSocketError, ConflictError, DEFAULT_BASE_URL, DEFAULT_RPM_ANONYMOUS, DEFAULT_RPM_WITH_KEY, DEFAULT_WS_URL, ExportsResource, FeesResource, ForbiddenError, InvalidAmountError, JurisdictionBlockedError, KNOWN_EVENT_TYPES, LiveOrderBook, MAX_SERVER_WAIT_MS, MarketsResource, NetworksResource, NotFoundError, OPERATIONS, OrderStateUnknownError, PRIVATE_CHANNELS, PoolsResource, RateLimitError, RateLimiter, SUPPORTED_PROTOCOL_VERSION, ServerError, TradingResource, TypedEmitter, USER_AGENT, UnprocessableError, VERSION, ValidationError, WS_BOOK_DEPTH, WalletResource, assertAmountFields, errorFromResponse, isAmount, isKnownErrorCode, isLedgerReference, isLocalHost, isRetryable, paginate };
|