@cexyio/cexy 0.1.0-dev.3 → 0.1.0-dev.5
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 +33 -9
- package/dist/index.cjs +157 -44
- package/dist/index.d.cts +155 -29
- package/dist/index.d.ts +155 -29
- package/dist/index.js +155 -45
- 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;
|
|
@@ -129,24 +139,27 @@ var KNOWN_CODES = /* @__PURE__ */ new Set([
|
|
|
129
139
|
"UNDER_MAINTENANCE",
|
|
130
140
|
"ENGINE_OVERLOADED"
|
|
131
141
|
]);
|
|
142
|
+
var CLIENT_ERROR_CODES = { UNEXPECTED_REDIRECT: "UNEXPECTED_REDIRECT" };
|
|
132
143
|
function isKnownErrorCode(code) {
|
|
133
144
|
return KNOWN_CODES.has(code);
|
|
134
145
|
}
|
|
135
146
|
var DEFAULT_RETRYABLE_STATUS = /* @__PURE__ */ new Set([408, 429, 500, 502, 503, 504]);
|
|
147
|
+
var MAX_SERVER_WAIT_MS = 12e4;
|
|
136
148
|
function retryAfterMs(headers, details) {
|
|
137
149
|
let best = null;
|
|
138
|
-
const h = headers?.get("retry-after");
|
|
150
|
+
const h = headers?.get("retry-after")?.trim();
|
|
139
151
|
if (h) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
152
|
+
if (/^\d+(\.\d+)?$/.test(h)) {
|
|
153
|
+
const ms = Number(h) * 1e3;
|
|
154
|
+
if (Number.isFinite(ms)) best = ms;
|
|
155
|
+
} else if (/[a-z]/i.test(h)) {
|
|
143
156
|
const at = Date.parse(h);
|
|
144
|
-
if (
|
|
157
|
+
if (Number.isFinite(at)) best = Math.max(0, at - Date.now());
|
|
145
158
|
}
|
|
146
159
|
}
|
|
147
160
|
const d = details?.["retry_after_seconds"];
|
|
148
|
-
const ds = typeof d === "number" ? d : typeof d === "string" ? Number(d) : NaN;
|
|
149
|
-
if (Number.isFinite(ds)) best = Math.max(best ?? 0, ds * 1e3);
|
|
161
|
+
const ds = typeof d === "number" ? d : typeof d === "string" && /^\d+(\.\d+)?$/.test(d.trim()) ? Number(d) : NaN;
|
|
162
|
+
if (Number.isFinite(ds) && ds >= 0 && Number.isFinite(ds * 1e3)) best = Math.max(best ?? 0, ds * 1e3);
|
|
150
163
|
return best;
|
|
151
164
|
}
|
|
152
165
|
function errorFromResponse(status, body, headers, redact = (t) => t) {
|
|
@@ -309,6 +322,7 @@ var OPERATIONS = {
|
|
|
309
322
|
};
|
|
310
323
|
|
|
311
324
|
// src/http.ts
|
|
325
|
+
var IDEMPOTENT_OPS = /* @__PURE__ */ new Set(["join_pool", "exit_pool"]);
|
|
312
326
|
var BACKOFF_BASE_MS = 500;
|
|
313
327
|
var BACKOFF_MAX_MS = 1e4;
|
|
314
328
|
var Transport = class {
|
|
@@ -317,16 +331,15 @@ var Transport = class {
|
|
|
317
331
|
this.config = config;
|
|
318
332
|
}
|
|
319
333
|
/**
|
|
320
|
-
* Sends a request with the standard retry policy:
|
|
321
|
-
*
|
|
322
|
-
* honours it
|
|
323
|
-
*
|
|
334
|
+
* Sends a request with the standard retry policy: retryable errors and network failures are
|
|
335
|
+
* retried. Pool join/exit carry an `Idempotency-Key` reused on every attempt (the server
|
|
336
|
+
* honours it there, which makes their retries safe); the other mutations routed here
|
|
337
|
+
* (cancel-all) are naturally repeatable and send no key. `placeOrder` and `cancelOrder` use
|
|
324
338
|
* `attempt()` with their own policies.
|
|
325
339
|
*/
|
|
326
340
|
async request(spec, opts = {}) {
|
|
327
341
|
const info = OPERATIONS[spec.op];
|
|
328
|
-
const
|
|
329
|
-
const idempotencyKey = isMutation ? spec.idempotencyKey ?? opts.idempotencyKey ?? newId() : void 0;
|
|
342
|
+
const idempotencyKey = IDEMPOTENT_OPS.has(spec.op) ? spec.idempotencyKey ?? opts.idempotencyKey ?? newId() : void 0;
|
|
330
343
|
const maxRetries = opts.maxRetries ?? this.config.maxRetries;
|
|
331
344
|
for (let attempt = 0; ; attempt++) {
|
|
332
345
|
try {
|
|
@@ -337,8 +350,13 @@ var Transport = class {
|
|
|
337
350
|
}
|
|
338
351
|
}
|
|
339
352
|
}
|
|
340
|
-
/**
|
|
353
|
+
/**
|
|
354
|
+
* Waits before retry number `attempt + 1`, honouring server hints. A server hint longer than
|
|
355
|
+
* `MAX_SERVER_WAIT_MS` is not waited: `err` is thrown at once (it still carries the hint).
|
|
356
|
+
*/
|
|
341
357
|
async backoff(op2, info, attempt, err, idempotencyKey, signal) {
|
|
358
|
+
const hint = serverHintMs(err);
|
|
359
|
+
if (hint !== null && hint > MAX_SERVER_WAIT_MS) throw err;
|
|
342
360
|
const delayMs = this.retryDelay(attempt, err);
|
|
343
361
|
this.config.onRetry?.({
|
|
344
362
|
operation: op2,
|
|
@@ -353,8 +371,8 @@ var Transport = class {
|
|
|
353
371
|
}
|
|
354
372
|
/** Full-jitter exponential backoff, or the server's hint plus a little jitter. */
|
|
355
373
|
retryDelay(attempt, err) {
|
|
356
|
-
const hint =
|
|
357
|
-
if (hint !== null && hint > 0) return Math.ceil(hint + this.config.random() * 250);
|
|
374
|
+
const hint = serverHintMs(err);
|
|
375
|
+
if (hint !== null && hint > 0 && hint <= MAX_SERVER_WAIT_MS) return Math.ceil(hint + this.config.random() * 250);
|
|
358
376
|
const cap = Math.min(BACKOFF_MAX_MS, BACKOFF_BASE_MS * 2 ** attempt);
|
|
359
377
|
return Math.ceil(this.config.random() * cap);
|
|
360
378
|
}
|
|
@@ -369,7 +387,7 @@ var Transport = class {
|
|
|
369
387
|
body = JSON.stringify(spec.body);
|
|
370
388
|
headers.set("Content-Type", "application/json");
|
|
371
389
|
}
|
|
372
|
-
if (
|
|
390
|
+
if (IDEMPOTENT_OPS.has(spec.op) && spec.idempotencyKey) headers.set("Idempotency-Key", spec.idempotencyKey);
|
|
373
391
|
if (info.auth === "api_key") {
|
|
374
392
|
const auth = this.config.authenticator;
|
|
375
393
|
if (!auth) {
|
|
@@ -413,7 +431,7 @@ var Transport = class {
|
|
|
413
431
|
if (res.type === "opaqueredirect" || res.status >= 300 && res.status < 400 || res.redirected) {
|
|
414
432
|
throw new CexyApiError({
|
|
415
433
|
status: res.status,
|
|
416
|
-
code:
|
|
434
|
+
code: CLIENT_ERROR_CODES.UNEXPECTED_REDIRECT,
|
|
417
435
|
message: `${info.method} ${info.path}: the server answered with a redirect (HTTP ${res.status}); the SDK does not follow redirects. Check baseUrl.`,
|
|
418
436
|
retryable: false
|
|
419
437
|
});
|
|
@@ -452,6 +470,11 @@ var Transport = class {
|
|
|
452
470
|
return this.config.authenticator ? this.config.authenticator.redact(text) : text;
|
|
453
471
|
}
|
|
454
472
|
};
|
|
473
|
+
function serverHintMs(err) {
|
|
474
|
+
if (err instanceof RateLimitError) return err.retryAfterMs;
|
|
475
|
+
if (err instanceof CexyApiError) return retryAfterMs(void 0, err.details);
|
|
476
|
+
return null;
|
|
477
|
+
}
|
|
455
478
|
function isRetryable(err) {
|
|
456
479
|
if (err instanceof CexyConnectionError) return true;
|
|
457
480
|
if (err instanceof CexyApiError) return err.retryable || err.code === "CONCURRENT_MODIFICATION";
|
|
@@ -483,6 +506,7 @@ function errMessage(err) {
|
|
|
483
506
|
}
|
|
484
507
|
|
|
485
508
|
// src/limiter.ts
|
|
509
|
+
var MAX_BLOCK_MS = 12e4;
|
|
486
510
|
var RateLimiter = class {
|
|
487
511
|
#rpm;
|
|
488
512
|
#tokens;
|
|
@@ -516,14 +540,14 @@ var RateLimiter = class {
|
|
|
516
540
|
return;
|
|
517
541
|
}
|
|
518
542
|
const msPerToken = 6e4 / this.#rpm;
|
|
519
|
-
await this.#sleep(Math.ceil((1 - this.#tokens) * msPerToken), signal);
|
|
543
|
+
await this.#sleep(Math.min(MAX_BLOCK_MS, Math.ceil((1 - this.#tokens) * msPerToken)), signal);
|
|
520
544
|
}
|
|
521
545
|
}
|
|
522
546
|
/** Adapts to the server's rate-limit headers. Never raises the configured limit. */
|
|
523
547
|
update(headers) {
|
|
524
548
|
this.#refill();
|
|
525
549
|
const limit = num(headers.get("x-ratelimit-limit"));
|
|
526
|
-
if (limit !== null && limit
|
|
550
|
+
if (limit !== null && limit >= 1 && limit < this.#rpm) {
|
|
527
551
|
this.#rpm = limit;
|
|
528
552
|
this.#tokens = Math.min(this.#tokens, limit);
|
|
529
553
|
}
|
|
@@ -535,10 +559,13 @@ var RateLimiter = class {
|
|
|
535
559
|
else this.blockFor(6e4 / this.#rpm);
|
|
536
560
|
}
|
|
537
561
|
}
|
|
538
|
-
/**
|
|
562
|
+
/**
|
|
563
|
+
* Blocks all requests for `ms` (used for 429 Retry-After and `X-RateLimit-Reset`). Server
|
|
564
|
+
* hints are untrusted: non-finite values are ignored and the block is capped at 120 s.
|
|
565
|
+
*/
|
|
539
566
|
blockFor(ms) {
|
|
540
|
-
if (!(ms > 0)) return;
|
|
541
|
-
this.#blockedUntil = Math.max(this.#blockedUntil, this.#now() + ms);
|
|
567
|
+
if (!(ms > 0) || !Number.isFinite(ms)) return;
|
|
568
|
+
this.#blockedUntil = Math.max(this.#blockedUntil, this.#now() + Math.min(ms, MAX_BLOCK_MS));
|
|
542
569
|
}
|
|
543
570
|
#refill() {
|
|
544
571
|
const now = this.#now();
|
|
@@ -788,6 +815,14 @@ var WalletResource = class extends Resource {
|
|
|
788
815
|
return this.data({ op: "deposit_address", query: params }, opts);
|
|
789
816
|
}
|
|
790
817
|
};
|
|
818
|
+
var CANCEL_RETRY_CODES = /* @__PURE__ */ new Set(["INVALID_STATE", "SERVICE_UNAVAILABLE"]);
|
|
819
|
+
var CANCEL_BACKOFF_S = [1, 2, 4, 8, 15];
|
|
820
|
+
function errorCode(err) {
|
|
821
|
+
if (err instanceof CexyApiError) return err.code;
|
|
822
|
+
if (err instanceof CexyTimeoutError) return "TIMEOUT";
|
|
823
|
+
if (err instanceof CexyConnectionError) return "CONNECTION_ERROR";
|
|
824
|
+
return "ERROR";
|
|
825
|
+
}
|
|
791
826
|
var ORDER_AMOUNT_FIELDS = ["price", "quantity", "quote_quantity", "stop_price"];
|
|
792
827
|
var TradingResource = class extends Resource {
|
|
793
828
|
/** Open orders, optionally filtered by market/status. */
|
|
@@ -818,7 +853,7 @@ var TradingResource = class extends Resource {
|
|
|
818
853
|
*
|
|
819
854
|
* Retry safety rests on `client_order_id` (generated as a UUID when absent): it is unique
|
|
820
855
|
* per account and the server refuses a repeat before any funds move. The server does NOT
|
|
821
|
-
* honour `Idempotency-Key` on orders
|
|
856
|
+
* honour `Idempotency-Key` on orders, so none is sent. After an
|
|
822
857
|
* ambiguous failure (network error, timeout or 5xx) the SDK first looks the order up by
|
|
823
858
|
* `client_order_id` and returns it if it exists (`recovered: true`); only if it does not
|
|
824
859
|
* exist does it send the order again, with the same `client_order_id`, so a late-arriving
|
|
@@ -833,12 +868,11 @@ var TradingResource = class extends Resource {
|
|
|
833
868
|
assertAmountFields(order, ORDER_AMOUNT_FIELDS, "placeOrder");
|
|
834
869
|
const clientOrderId = order.client_order_id ?? newId();
|
|
835
870
|
const body = { ...order, client_order_id: clientOrderId };
|
|
836
|
-
const idempotencyKey = opts.idempotencyKey ?? newId();
|
|
837
871
|
const maxRetries = opts.maxRetries ?? this.t.config.maxRetries;
|
|
838
872
|
const info = OPERATIONS.place_order;
|
|
839
873
|
for (let attempt = 0; ; attempt++) {
|
|
840
874
|
try {
|
|
841
|
-
const raw = await this.t.attempt({ op: "place_order", body
|
|
875
|
+
const raw = await this.t.attempt({ op: "place_order", body }, opts);
|
|
842
876
|
const data = raw.data.data;
|
|
843
877
|
return { ...data, client_order_id: clientOrderId, recovered: false };
|
|
844
878
|
} catch (err) {
|
|
@@ -848,11 +882,11 @@ var TradingResource = class extends Resource {
|
|
|
848
882
|
const existing = await this.#lookup(clientOrderId, err, opts);
|
|
849
883
|
if (existing) return { order: existing, fills: [], client_order_id: clientOrderId, recovered: true };
|
|
850
884
|
if (duplicateAfterRetry || attempt >= maxRetries) throw err;
|
|
851
|
-
await this.t.backoff("place_order", info, attempt, err,
|
|
885
|
+
await this.t.backoff("place_order", info, attempt, err, void 0, opts.signal);
|
|
852
886
|
continue;
|
|
853
887
|
}
|
|
854
888
|
if (isRetryable(err) && attempt < maxRetries) {
|
|
855
|
-
await this.t.backoff("place_order", info, attempt, err,
|
|
889
|
+
await this.t.backoff("place_order", info, attempt, err, void 0, opts.signal);
|
|
856
890
|
continue;
|
|
857
891
|
}
|
|
858
892
|
throw err;
|
|
@@ -876,10 +910,9 @@ var TradingResource = class extends Resource {
|
|
|
876
910
|
async cancelOrder(orderId, opts = {}) {
|
|
877
911
|
const maxRetries = opts.maxRetries ?? this.t.config.maxRetries;
|
|
878
912
|
const info = OPERATIONS.cancel_order;
|
|
879
|
-
const idempotencyKey = opts.idempotencyKey ?? newId();
|
|
880
913
|
for (let attempt = 0; ; attempt++) {
|
|
881
914
|
try {
|
|
882
|
-
const raw = await this.t.attempt({ op: "cancel_order", pathParams: { order_id: orderId }
|
|
915
|
+
const raw = await this.t.attempt({ op: "cancel_order", pathParams: { order_id: orderId } }, opts);
|
|
883
916
|
return raw.data.data;
|
|
884
917
|
} catch (err) {
|
|
885
918
|
if (opts.signal?.aborted) throw err;
|
|
@@ -887,23 +920,13 @@ var TradingResource = class extends Resource {
|
|
|
887
920
|
return this.order(orderId, { signal: opts.signal, timeoutMs: opts.timeoutMs });
|
|
888
921
|
}
|
|
889
922
|
if (isRetryable(err) && attempt < maxRetries) {
|
|
890
|
-
await this.t.backoff("cancel_order", info, attempt, err,
|
|
923
|
+
await this.t.backoff("cancel_order", info, attempt, err, void 0, opts.signal);
|
|
891
924
|
continue;
|
|
892
925
|
}
|
|
893
926
|
throw err;
|
|
894
927
|
}
|
|
895
928
|
}
|
|
896
929
|
}
|
|
897
|
-
/**
|
|
898
|
-
* Cancels every open order in one market: `cancelAll({ symbol: "BTC/USDT" })`.
|
|
899
|
-
* To cancel across ALL markets, pass `symbol: null` explicitly: `cancelAll({ symbol: null })`.
|
|
900
|
-
* Omitting `symbol` is an error, so an account-wide cancel never happens by accident
|
|
901
|
-
* (the server itself treats `{}` as every market).
|
|
902
|
-
*
|
|
903
|
-
* The server limits cancel-all to 30 calls per minute per account. It is naturally
|
|
904
|
-
* repeatable, so it is retried after network errors; a retry reports only what that retry
|
|
905
|
-
* cancelled.
|
|
906
|
-
*/
|
|
907
930
|
async cancelAll(params, opts) {
|
|
908
931
|
const hasSymbol = !!params && typeof params === "object" && Object.prototype.hasOwnProperty.call(params, "symbol");
|
|
909
932
|
const symbol = hasSymbol ? params.symbol : void 0;
|
|
@@ -911,12 +934,97 @@ var TradingResource = class extends Resource {
|
|
|
911
934
|
if (typeof symbol === "string" && symbol !== "") body = { symbol };
|
|
912
935
|
else if (hasSymbol && symbol === null) body = {};
|
|
913
936
|
else throw new CexyConfigError('cancelAll(): pass { symbol: "BASE/QUOTE" }, or { symbol: null } to cancel in every market');
|
|
914
|
-
|
|
937
|
+
const once = (o) => this.data({ op: "cancel_all", body }, o ?? opts);
|
|
938
|
+
if (params.untilDone !== true) return once();
|
|
939
|
+
const maxRounds = params.maxRounds ?? 20;
|
|
940
|
+
const budgetMs = params.timeBudgetMs ?? 12e4;
|
|
941
|
+
if (!(maxRounds >= 1)) throw new CexyConfigError("cancelAll(): maxRounds must be >= 1");
|
|
942
|
+
if (!(budgetMs > 0)) throw new CexyConfigError("cancelAll(): timeBudgetMs must be > 0");
|
|
943
|
+
const now = this.t.config.now ?? Date.now;
|
|
944
|
+
const start = now();
|
|
945
|
+
const state = /* @__PURE__ */ new Map();
|
|
946
|
+
const roundOpts = { ...opts, maxRetries: 0 };
|
|
947
|
+
let rounds = 0;
|
|
948
|
+
let idle = 0;
|
|
949
|
+
let hasMore = false;
|
|
950
|
+
let lastErrorCode;
|
|
951
|
+
let stopped;
|
|
952
|
+
const result = () => {
|
|
953
|
+
const pick = (list) => [...state].filter(([, v]) => v.list === list).map(([id]) => id);
|
|
954
|
+
return {
|
|
955
|
+
cancelled: pick("cancelled"),
|
|
956
|
+
already_closed: pick("already_closed"),
|
|
957
|
+
failed: pick("failed"),
|
|
958
|
+
failures: [...state.values()].flatMap((v) => v.list === "failed" && v.failure ? [v.failure] : []),
|
|
959
|
+
has_more: hasMore,
|
|
960
|
+
rounds,
|
|
961
|
+
stopped,
|
|
962
|
+
...lastErrorCode !== void 0 ? { last_error_code: lastErrorCode } : {}
|
|
963
|
+
};
|
|
964
|
+
};
|
|
965
|
+
for (; ; ) {
|
|
966
|
+
let waitMs = 0;
|
|
967
|
+
let res;
|
|
968
|
+
try {
|
|
969
|
+
res = await once(roundOpts);
|
|
970
|
+
} catch (err) {
|
|
971
|
+
rounds++;
|
|
972
|
+
if (opts?.signal?.aborted) throw err;
|
|
973
|
+
if (!isRetryable(err)) {
|
|
974
|
+
stopped = "done";
|
|
975
|
+
throw new CancelAllInterruptedError(err, result());
|
|
976
|
+
}
|
|
977
|
+
lastErrorCode = errorCode(err);
|
|
978
|
+
if (rounds >= maxRounds) {
|
|
979
|
+
stopped = "max_rounds";
|
|
980
|
+
break;
|
|
981
|
+
}
|
|
982
|
+
const hint = err instanceof RateLimitError ? err.retryAfterMs : null;
|
|
983
|
+
if (hint !== null) {
|
|
984
|
+
waitMs = hint;
|
|
985
|
+
if (hint > MAX_SERVER_WAIT_MS) {
|
|
986
|
+
stopped = "time_budget";
|
|
987
|
+
break;
|
|
988
|
+
}
|
|
989
|
+
} else {
|
|
990
|
+
waitMs = (CANCEL_BACKOFF_S[Math.min(idle++, CANCEL_BACKOFF_S.length - 1)] ?? 15) * 1e3;
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
if (res) {
|
|
994
|
+
rounds++;
|
|
995
|
+
lastErrorCode = void 0;
|
|
996
|
+
hasMore = res.has_more;
|
|
997
|
+
const failures = res.failures ?? [];
|
|
998
|
+
for (const id of res.cancelled ?? []) state.set(id, { list: "cancelled" });
|
|
999
|
+
for (const id of res.already_closed ?? []) state.set(id, { list: "already_closed" });
|
|
1000
|
+
for (const id of res.failed ?? []) {
|
|
1001
|
+
const failure = failures.find((f) => f.order_id === id);
|
|
1002
|
+
state.set(id, failure ? { list: "failed", failure } : { list: "failed" });
|
|
1003
|
+
}
|
|
1004
|
+
const progress = (res.cancelled?.length ?? 0) + (res.already_closed?.length ?? 0) > 0;
|
|
1005
|
+
if (!res.has_more && !failures.some((f) => CANCEL_RETRY_CODES.has(f.code))) {
|
|
1006
|
+
stopped = "done";
|
|
1007
|
+
break;
|
|
1008
|
+
}
|
|
1009
|
+
if (rounds >= maxRounds) {
|
|
1010
|
+
stopped = "max_rounds";
|
|
1011
|
+
break;
|
|
1012
|
+
}
|
|
1013
|
+
if (progress) idle = 0;
|
|
1014
|
+
else waitMs = (CANCEL_BACKOFF_S[Math.min(idle++, CANCEL_BACKOFF_S.length - 1)] ?? 15) * 1e3;
|
|
1015
|
+
}
|
|
1016
|
+
if (now() - start + waitMs >= budgetMs) {
|
|
1017
|
+
stopped = "time_budget";
|
|
1018
|
+
break;
|
|
1019
|
+
}
|
|
1020
|
+
if (waitMs > 0) await this.t.config.sleep(waitMs, opts?.signal);
|
|
1021
|
+
}
|
|
1022
|
+
return result();
|
|
915
1023
|
}
|
|
916
1024
|
};
|
|
917
1025
|
|
|
918
1026
|
// src/version.ts
|
|
919
|
-
var VERSION = "0.1.0-dev.
|
|
1027
|
+
var VERSION = "0.1.0-dev.5";
|
|
920
1028
|
var USER_AGENT = `cexy-typescript/${VERSION}`;
|
|
921
1029
|
|
|
922
1030
|
// src/ws/emitter.ts
|
|
@@ -1684,7 +1792,8 @@ var CexyClient = class {
|
|
|
1684
1792
|
const sleep2 = options.sleep ?? sleep;
|
|
1685
1793
|
const limiter = options.rateLimit === false ? null : new RateLimiter({
|
|
1686
1794
|
requestsPerMinute: options.rateLimit?.requestsPerMinute ?? (authenticator ? DEFAULT_RPM_WITH_KEY : DEFAULT_RPM_ANONYMOUS),
|
|
1687
|
-
sleep: sleep2
|
|
1795
|
+
sleep: sleep2,
|
|
1796
|
+
...options.now ? { now: options.now } : {}
|
|
1688
1797
|
});
|
|
1689
1798
|
this.#baseUrl = baseUrl;
|
|
1690
1799
|
this.#transport = new Transport({
|
|
@@ -1697,6 +1806,7 @@ var CexyClient = class {
|
|
|
1697
1806
|
userAgent: canSetUserAgent() ? [USER_AGENT, options.userAgentSuffix].filter(Boolean).join(" ") : null,
|
|
1698
1807
|
sleep: sleep2,
|
|
1699
1808
|
random: options.random ?? Math.random,
|
|
1809
|
+
now: options.now ?? Date.now,
|
|
1700
1810
|
onRetry: options.onRetry
|
|
1701
1811
|
});
|
|
1702
1812
|
const t = this.#transport;
|
|
@@ -1766,4 +1876,4 @@ function canSetUserAgent() {
|
|
|
1766
1876
|
return !(typeof g.window !== "undefined" && typeof g.window.document !== "undefined");
|
|
1767
1877
|
}
|
|
1768
1878
|
|
|
1769
|
-
export { AccountResource, ApiKeyAuthenticator, AssetsResource, AuthenticationError, 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, 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, isLocalHost, isRetryable, paginate };
|
|
1879
|
+
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, isLocalHost, isRetryable, paginate };
|