@cexyio/cexy 0.1.0-dev.3 → 0.1.0-dev.4
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 +20 -3
- package/dist/index.cjs +58 -13
- package/dist/index.d.cts +109 -12
- package/dist/index.d.ts +109 -12
- package/dist/index.js +58 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -60,7 +60,23 @@ await cexy.trading.cancelAll({ symbol: "BTC/USDT" }); // { symbol: null } = ever
|
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
`cancelAll` requires `symbol`: the server treats a missing symbol as "every market", so the SDK makes
|
|
63
|
-
you say so with `{ symbol: null }`.
|
|
63
|
+
you say so with `{ symbol: null }`. An unknown symbol throws `NotFoundError`.
|
|
64
|
+
|
|
65
|
+
One call handles at most 500 orders and puts each in exactly one list: `cancelled`, `already_closed`
|
|
66
|
+
(it filled, was refused or was cancelled elsewhere first; not an error) or `failed`, with the reason in
|
|
67
|
+
`failures` (`INVALID_STATE` for an order still being placed). `has_more: true` means more orders remain.
|
|
68
|
+
To let the SDK repeat the call for you:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
const res = await cexy.trading.cancelAll({ symbol: null, untilDone: true });
|
|
72
|
+
// res.stopped: "done" | "max_rounds" | "time_budget"; res.rounds: calls made
|
|
73
|
+
if (res.stopped !== "done" || res.failed.length) console.warn("left over:", res.failures);
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`untilDone` repeats while `has_more` is true or a failure is `INVALID_STATE` / `SERVICE_UNAVAILABLE`.
|
|
77
|
+
After a call without progress it waits 1, 2, 4, 8, then 15 s, and it stops after `maxRounds` calls
|
|
78
|
+
(default 20) or before a wait would pass `timeBudgetMs` (default 120 000). The server allows 30 cancel-all
|
|
79
|
+
calls per minute per account; a 429 is retried after its Retry-After, which counts against the budget.
|
|
64
80
|
|
|
65
81
|
Give both `apiKey` and `apiSecret`, or neither: passing only one throws at construction.
|
|
66
82
|
|
|
@@ -110,7 +126,7 @@ Every API failure throws a `CexyApiError` (or a subclass) with `status`, `code`,
|
|
|
110
126
|
| `UnprocessableError` | 422: `INSUFFICIENT_FUNDS`, `MARKET_UNAVAILABLE`, ... |
|
|
111
127
|
| `RateLimitError` | 429, with `retryAfterMs` |
|
|
112
128
|
| `ServerError` | 5xx |
|
|
113
|
-
| `CexyApiError` | any code this SDK version does not know yet |
|
|
129
|
+
| `CexyApiError` | any code this SDK version does not know yet, and `UNEXPECTED_REDIRECT` (the server answered with a 3xx; set by the SDK, see `CLIENT_ERROR_CODES`) |
|
|
114
130
|
|
|
115
131
|
Local problems use `CexyConfigError`, `InvalidAmountError`, `CexyConnectionError` / `CexyTimeoutError`
|
|
116
132
|
and `OrderStateUnknownError`. `ErrorCode` is a union of the known codes plus `string`, because new codes
|
|
@@ -231,7 +247,8 @@ endpoints from a server. Browsers do not let scripts set `User-Agent`, so the SD
|
|
|
231
247
|
`http://` / `ws://` solely for `localhost`, `127.0.0.1` or `::1` (local test servers).
|
|
232
248
|
- The SDK **never follows HTTP redirects**. A 3xx answer throws a `CexyApiError` with code
|
|
233
249
|
`UNEXPECTED_REDIRECT` (not retried), so credentials are never re-sent to another host and an order
|
|
234
|
-
is never re-posted to a redirect target. If you pass your own `fetch`, it must honour `redirect: "manual"
|
|
250
|
+
is never re-posted to a redirect target. If you pass your own `fetch`, it must honour `redirect: "manual"`: one that follows redirects
|
|
251
|
+
anyway has already sent your credentials by the time the SDK notices.
|
|
235
252
|
- The SDK redacts the secret from `toString()`, `util.inspect`, `JSON.stringify` and error messages.
|
|
236
253
|
- Keep keys in environment variables or a secret manager, not in code.
|
|
237
254
|
|
package/dist/index.cjs
CHANGED
|
@@ -131,6 +131,7 @@ var KNOWN_CODES = /* @__PURE__ */ new Set([
|
|
|
131
131
|
"UNDER_MAINTENANCE",
|
|
132
132
|
"ENGINE_OVERLOADED"
|
|
133
133
|
]);
|
|
134
|
+
var CLIENT_ERROR_CODES = { UNEXPECTED_REDIRECT: "UNEXPECTED_REDIRECT" };
|
|
134
135
|
function isKnownErrorCode(code) {
|
|
135
136
|
return KNOWN_CODES.has(code);
|
|
136
137
|
}
|
|
@@ -415,7 +416,7 @@ var Transport = class {
|
|
|
415
416
|
if (res.type === "opaqueredirect" || res.status >= 300 && res.status < 400 || res.redirected) {
|
|
416
417
|
throw new CexyApiError({
|
|
417
418
|
status: res.status,
|
|
418
|
-
code:
|
|
419
|
+
code: CLIENT_ERROR_CODES.UNEXPECTED_REDIRECT,
|
|
419
420
|
message: `${info.method} ${info.path}: the server answered with a redirect (HTTP ${res.status}); the SDK does not follow redirects. Check baseUrl.`,
|
|
420
421
|
retryable: false
|
|
421
422
|
});
|
|
@@ -790,6 +791,8 @@ var WalletResource = class extends Resource {
|
|
|
790
791
|
return this.data({ op: "deposit_address", query: params }, opts);
|
|
791
792
|
}
|
|
792
793
|
};
|
|
794
|
+
var CANCEL_RETRY_CODES = /* @__PURE__ */ new Set(["INVALID_STATE", "SERVICE_UNAVAILABLE"]);
|
|
795
|
+
var CANCEL_BACKOFF_S = [1, 2, 4, 8, 15];
|
|
793
796
|
var ORDER_AMOUNT_FIELDS = ["price", "quantity", "quote_quantity", "stop_price"];
|
|
794
797
|
var TradingResource = class extends Resource {
|
|
795
798
|
/** Open orders, optionally filtered by market/status. */
|
|
@@ -896,16 +899,6 @@ var TradingResource = class extends Resource {
|
|
|
896
899
|
}
|
|
897
900
|
}
|
|
898
901
|
}
|
|
899
|
-
/**
|
|
900
|
-
* Cancels every open order in one market: `cancelAll({ symbol: "BTC/USDT" })`.
|
|
901
|
-
* To cancel across ALL markets, pass `symbol: null` explicitly: `cancelAll({ symbol: null })`.
|
|
902
|
-
* Omitting `symbol` is an error, so an account-wide cancel never happens by accident
|
|
903
|
-
* (the server itself treats `{}` as every market).
|
|
904
|
-
*
|
|
905
|
-
* The server limits cancel-all to 30 calls per minute per account. It is naturally
|
|
906
|
-
* repeatable, so it is retried after network errors; a retry reports only what that retry
|
|
907
|
-
* cancelled.
|
|
908
|
-
*/
|
|
909
902
|
async cancelAll(params, opts) {
|
|
910
903
|
const hasSymbol = !!params && typeof params === "object" && Object.prototype.hasOwnProperty.call(params, "symbol");
|
|
911
904
|
const symbol = hasSymbol ? params.symbol : void 0;
|
|
@@ -913,12 +906,62 @@ var TradingResource = class extends Resource {
|
|
|
913
906
|
if (typeof symbol === "string" && symbol !== "") body = { symbol };
|
|
914
907
|
else if (hasSymbol && symbol === null) body = {};
|
|
915
908
|
else throw new CexyConfigError('cancelAll(): pass { symbol: "BASE/QUOTE" }, or { symbol: null } to cancel in every market');
|
|
916
|
-
|
|
909
|
+
const once = () => this.data({ op: "cancel_all", body }, opts);
|
|
910
|
+
if (params.untilDone !== true) return once();
|
|
911
|
+
const maxRounds = params.maxRounds ?? 20;
|
|
912
|
+
const budgetMs = params.timeBudgetMs ?? 12e4;
|
|
913
|
+
if (!(maxRounds >= 1)) throw new CexyConfigError("cancelAll(): maxRounds must be >= 1");
|
|
914
|
+
if (!(budgetMs > 0)) throw new CexyConfigError("cancelAll(): timeBudgetMs must be > 0");
|
|
915
|
+
const now = this.t.config.now ?? Date.now;
|
|
916
|
+
const start = now();
|
|
917
|
+
const state = /* @__PURE__ */ new Map();
|
|
918
|
+
let rounds = 0;
|
|
919
|
+
let idle = 0;
|
|
920
|
+
let last;
|
|
921
|
+
let stopped;
|
|
922
|
+
for (; ; ) {
|
|
923
|
+
last = await once();
|
|
924
|
+
rounds++;
|
|
925
|
+
const failures = last.failures ?? [];
|
|
926
|
+
for (const id of last.cancelled ?? []) state.set(id, { list: "cancelled" });
|
|
927
|
+
for (const id of last.already_closed ?? []) state.set(id, { list: "already_closed" });
|
|
928
|
+
for (const id of last.failed ?? []) {
|
|
929
|
+
const failure = failures.find((f) => f.order_id === id);
|
|
930
|
+
state.set(id, failure ? { list: "failed", failure } : { list: "failed" });
|
|
931
|
+
}
|
|
932
|
+
const progress = (last.cancelled?.length ?? 0) + (last.already_closed?.length ?? 0) > 0;
|
|
933
|
+
if (!last.has_more && !failures.some((f) => CANCEL_RETRY_CODES.has(f.code))) {
|
|
934
|
+
stopped = "done";
|
|
935
|
+
break;
|
|
936
|
+
}
|
|
937
|
+
if (rounds >= maxRounds) {
|
|
938
|
+
stopped = "max_rounds";
|
|
939
|
+
break;
|
|
940
|
+
}
|
|
941
|
+
let waitMs = 0;
|
|
942
|
+
if (progress) idle = 0;
|
|
943
|
+
else waitMs = (CANCEL_BACKOFF_S[Math.min(idle++, CANCEL_BACKOFF_S.length - 1)] ?? 15) * 1e3;
|
|
944
|
+
if (now() - start + waitMs >= budgetMs) {
|
|
945
|
+
stopped = "time_budget";
|
|
946
|
+
break;
|
|
947
|
+
}
|
|
948
|
+
if (waitMs > 0) await this.t.config.sleep(waitMs, opts?.signal);
|
|
949
|
+
}
|
|
950
|
+
const pick = (list) => [...state].filter(([, v]) => v.list === list).map(([id]) => id);
|
|
951
|
+
return {
|
|
952
|
+
cancelled: pick("cancelled"),
|
|
953
|
+
already_closed: pick("already_closed"),
|
|
954
|
+
failed: pick("failed"),
|
|
955
|
+
failures: [...state.values()].flatMap((v) => v.list === "failed" && v.failure ? [v.failure] : []),
|
|
956
|
+
has_more: last.has_more,
|
|
957
|
+
rounds,
|
|
958
|
+
stopped
|
|
959
|
+
};
|
|
917
960
|
}
|
|
918
961
|
};
|
|
919
962
|
|
|
920
963
|
// src/version.ts
|
|
921
|
-
var VERSION = "0.1.0-dev.
|
|
964
|
+
var VERSION = "0.1.0-dev.4";
|
|
922
965
|
var USER_AGENT = `cexy-typescript/${VERSION}`;
|
|
923
966
|
|
|
924
967
|
// src/ws/emitter.ts
|
|
@@ -1699,6 +1742,7 @@ var CexyClient = class {
|
|
|
1699
1742
|
userAgent: canSetUserAgent() ? [USER_AGENT, options.userAgentSuffix].filter(Boolean).join(" ") : null,
|
|
1700
1743
|
sleep: sleep2,
|
|
1701
1744
|
random: options.random ?? Math.random,
|
|
1745
|
+
now: options.now ?? Date.now,
|
|
1702
1746
|
onRetry: options.onRetry
|
|
1703
1747
|
});
|
|
1704
1748
|
const t = this.#transport;
|
|
@@ -1772,6 +1816,7 @@ exports.AccountResource = AccountResource;
|
|
|
1772
1816
|
exports.ApiKeyAuthenticator = ApiKeyAuthenticator;
|
|
1773
1817
|
exports.AssetsResource = AssetsResource;
|
|
1774
1818
|
exports.AuthenticationError = AuthenticationError;
|
|
1819
|
+
exports.CLIENT_ERROR_CODES = CLIENT_ERROR_CODES;
|
|
1775
1820
|
exports.CexyApiError = CexyApiError;
|
|
1776
1821
|
exports.CexyClient = CexyClient;
|
|
1777
1822
|
exports.CexyConfigError = CexyConfigError;
|
package/dist/index.d.cts
CHANGED
|
@@ -163,6 +163,8 @@ interface TransportConfig {
|
|
|
163
163
|
userAgent: string | null;
|
|
164
164
|
sleep: (ms: number, signal?: AbortSignal) => Promise<void>;
|
|
165
165
|
random: () => number;
|
|
166
|
+
/** Milliseconds clock (default `Date.now`); injectable for tests. */
|
|
167
|
+
now?: () => number;
|
|
166
168
|
onRetry?: ((info: RetryInfo) => void) | undefined;
|
|
167
169
|
}
|
|
168
170
|
interface CallSpec {
|
|
@@ -730,7 +732,11 @@ interface paths {
|
|
|
730
732
|
put?: never;
|
|
731
733
|
/**
|
|
732
734
|
* Cancels every open order, optionally within one market.
|
|
733
|
-
* @description Best-effort: a failure on one order does not stop the rest, and
|
|
735
|
+
* @description Best-effort: a failure on one order does not stop the rest, and every outcome is reported. A panic-button endpoint that stops at the first problem is worse than useless.
|
|
736
|
+
*
|
|
737
|
+
* An order still being placed when the call starts (status `pending`, for as long as its own placement request runs) is waited for, up to 500 ms per call in total: cancelled if it opens, reported in `already_closed` if it fills or is refused, and in `failed` with code `INVALID_STATE` if it is still being placed at the deadline. Orders placed after the call starts are not part of it. At most 500 orders per call; `has_more` says there are others.
|
|
738
|
+
*
|
|
739
|
+
* Limited to 30 calls a minute per account, on top of the general request limit.
|
|
734
740
|
*/
|
|
735
741
|
post: operations["cancel_all"];
|
|
736
742
|
delete?: never;
|
|
@@ -1037,12 +1043,31 @@ interface components {
|
|
|
1037
1043
|
/** @description Limit the cancellation to one market. Omitted or `null`, every market's open orders are cancelled. */
|
|
1038
1044
|
symbol?: string | null;
|
|
1039
1045
|
};
|
|
1040
|
-
/**
|
|
1046
|
+
/**
|
|
1047
|
+
* @description What a bulk cancellation achieved.
|
|
1048
|
+
*
|
|
1049
|
+
* Every order the call handled is in exactly one of `cancelled`, `already_closed` and `failed`.
|
|
1050
|
+
*/
|
|
1041
1051
|
CancelAllResponse: {
|
|
1052
|
+
/** @description Orders that closed on their own (filled, rejected, cancelled elsewhere) before this call reached them. Nothing was done to them, and they are not failures. */
|
|
1053
|
+
already_closed: string[];
|
|
1042
1054
|
/** @description Orders cancelled. */
|
|
1043
1055
|
cancelled: string[];
|
|
1044
|
-
/** @description Orders that could not be cancelled.
|
|
1056
|
+
/** @description Orders that could not be cancelled in this call. Check `failures` for why, then refresh or call again. */
|
|
1045
1057
|
failed: string[];
|
|
1058
|
+
/** @description Why each order in `failed` could not be cancelled. */
|
|
1059
|
+
failures: components["schemas"]["CancelFailureResponse"][];
|
|
1060
|
+
/** @description More open orders exist than one call handles (500). Call again. */
|
|
1061
|
+
has_more: boolean;
|
|
1062
|
+
};
|
|
1063
|
+
/** @description Why one order could not be cancelled. */
|
|
1064
|
+
CancelFailureResponse: {
|
|
1065
|
+
/** @description The error code of the attempt, as in any error response: e.g. `INVALID_STATE` for an order still being placed when the wait ran out, or `MARKET_UNAVAILABLE`. */
|
|
1066
|
+
code: string;
|
|
1067
|
+
/** @description Its message. */
|
|
1068
|
+
message: string;
|
|
1069
|
+
/** @description The order. */
|
|
1070
|
+
order_id: string;
|
|
1046
1071
|
};
|
|
1047
1072
|
/**
|
|
1048
1073
|
* @description Candle/kline intervals for market data.
|
|
@@ -2877,6 +2902,24 @@ interface operations {
|
|
|
2877
2902
|
};
|
|
2878
2903
|
};
|
|
2879
2904
|
};
|
|
2905
|
+
/** @description No such market */
|
|
2906
|
+
404: {
|
|
2907
|
+
headers: {
|
|
2908
|
+
[name: string]: unknown;
|
|
2909
|
+
};
|
|
2910
|
+
content: {
|
|
2911
|
+
"application/json": components["schemas"]["ErrorResponse"];
|
|
2912
|
+
};
|
|
2913
|
+
};
|
|
2914
|
+
/** @description Over 30 calls a minute for this account; `details.retry_after_seconds` says when to retry */
|
|
2915
|
+
429: {
|
|
2916
|
+
headers: {
|
|
2917
|
+
[name: string]: unknown;
|
|
2918
|
+
};
|
|
2919
|
+
content: {
|
|
2920
|
+
"application/json": components["schemas"]["ErrorResponse"];
|
|
2921
|
+
};
|
|
2922
|
+
};
|
|
2880
2923
|
};
|
|
2881
2924
|
};
|
|
2882
2925
|
order_history: {
|
|
@@ -3181,6 +3224,21 @@ type AssetNetwork = S["AssetNetworkResponse"];
|
|
|
3181
3224
|
type Balance = S["BalanceResponse"];
|
|
3182
3225
|
type CancelAllRequest = S["CancelAllRequest"];
|
|
3183
3226
|
type CancelAllResult = S["CancelAllResponse"];
|
|
3227
|
+
/** Why one order could not be cancelled (`CancelAllResult.failures`). */
|
|
3228
|
+
type CancelFailure = S["CancelFailureResponse"];
|
|
3229
|
+
/** Why a `cancelAll({ ..., untilDone: true })` loop ended. */
|
|
3230
|
+
type CancelAllStopReason = "done" | "max_rounds" | "time_budget";
|
|
3231
|
+
/**
|
|
3232
|
+
* Merged result of a `cancelAll({ ..., untilDone: true })` loop. Every order is in exactly one
|
|
3233
|
+
* of `cancelled`, `already_closed` and `failed`, in its latest state; `has_more` is the last
|
|
3234
|
+
* round's.
|
|
3235
|
+
*/
|
|
3236
|
+
interface CancelAllUntilDoneResult extends CancelAllResult {
|
|
3237
|
+
/** Number of cancel-all calls made. */
|
|
3238
|
+
rounds: number;
|
|
3239
|
+
/** `done`: nothing left to retry; otherwise the loop's limit that ended it. */
|
|
3240
|
+
stopped: CancelAllStopReason;
|
|
3241
|
+
}
|
|
3184
3242
|
type Candle = S["CandleResponse"];
|
|
3185
3243
|
type CandleInterval = S["CandleInterval"];
|
|
3186
3244
|
type DepositAddress = S["DepositAddressResponse"];
|
|
@@ -3344,6 +3402,14 @@ interface PlaceOrderResult extends PlaceOrderResponse {
|
|
|
3344
3402
|
*/
|
|
3345
3403
|
interface CancelAllParams {
|
|
3346
3404
|
symbol: string | null;
|
|
3405
|
+
/**
|
|
3406
|
+
* Repeat the call until nothing is left to retry (see `cancelAll`). Default false: one call.
|
|
3407
|
+
*/
|
|
3408
|
+
untilDone?: boolean;
|
|
3409
|
+
/** With `untilDone`: at most this many calls. Default 20. */
|
|
3410
|
+
maxRounds?: number;
|
|
3411
|
+
/** With `untilDone`: stop before a wait would take the loop to this many ms. Default 120000. */
|
|
3412
|
+
timeBudgetMs?: number;
|
|
3347
3413
|
}
|
|
3348
3414
|
declare class TradingResource extends Resource {
|
|
3349
3415
|
#private;
|
|
@@ -3380,12 +3446,27 @@ declare class TradingResource extends Resource {
|
|
|
3380
3446
|
* Cancels every open order in one market: `cancelAll({ symbol: "BTC/USDT" })`.
|
|
3381
3447
|
* To cancel across ALL markets, pass `symbol: null` explicitly: `cancelAll({ symbol: null })`.
|
|
3382
3448
|
* Omitting `symbol` is an error, so an account-wide cancel never happens by accident
|
|
3383
|
-
* (the server itself treats `{}` as every market).
|
|
3449
|
+
* (the server itself treats `{}` as every market). An unknown symbol throws `NotFoundError`.
|
|
3450
|
+
*
|
|
3451
|
+
* One call handles at most 500 orders. Every order it handled is in exactly one list:
|
|
3452
|
+
* `cancelled`; `already_closed` (it filled, was refused or was cancelled elsewhere first:
|
|
3453
|
+
* not an error); or `failed`, with the reason in `failures` (`INVALID_STATE` for an order
|
|
3454
|
+
* still being placed when the server's 500 ms wait ran out). `has_more` says more orders
|
|
3455
|
+
* remain: call again.
|
|
3456
|
+
*
|
|
3457
|
+
* With `untilDone: true` the SDK does that for you. It repeats while `has_more` is true or a
|
|
3458
|
+
* failure is `INVALID_STATE` / `SERVICE_UNAVAILABLE`. After a call that made no progress it
|
|
3459
|
+
* waits 1, 2, 4, 8 and then 15 s, starting over after any progress. It stops after
|
|
3460
|
+
* `maxRounds` calls or before a wait would pass `timeBudgetMs`, and returns the merged
|
|
3461
|
+
* result with `rounds` and `stopped`. Other failure codes are returned, never retried.
|
|
3384
3462
|
*
|
|
3385
|
-
* The server
|
|
3386
|
-
*
|
|
3387
|
-
*
|
|
3463
|
+
* The server allows 30 cancel-all calls per minute per account (a 429 is retried after its
|
|
3464
|
+
* Retry-After). The call is naturally repeatable and needs no Idempotency-Key, so it is
|
|
3465
|
+
* retried after network errors; a retry reports only what that retry did.
|
|
3388
3466
|
*/
|
|
3467
|
+
cancelAll(params: CancelAllParams & {
|
|
3468
|
+
untilDone: true;
|
|
3469
|
+
}, opts?: RequestOptions): Promise<CancelAllUntilDoneResult>;
|
|
3389
3470
|
cancelAll(params: CancelAllParams, opts?: RequestOptions): Promise<CancelAllResult>;
|
|
3390
3471
|
}
|
|
3391
3472
|
|
|
@@ -3484,7 +3565,16 @@ declare class RateLimitError extends CexyApiError {
|
|
|
3484
3565
|
/** 5xx */
|
|
3485
3566
|
declare class ServerError extends CexyApiError {
|
|
3486
3567
|
}
|
|
3487
|
-
/**
|
|
3568
|
+
/**
|
|
3569
|
+
* Codes the SDK itself sets on a `CexyApiError`; the API never sends them, so they are not in
|
|
3570
|
+
* errors.yaml and `isKnownErrorCode()` returns false for them.
|
|
3571
|
+
* - `UNEXPECTED_REDIRECT`: the server answered with a 3xx. The SDK never follows redirects (the
|
|
3572
|
+
* credentials would go to the redirect target); not retryable.
|
|
3573
|
+
*/
|
|
3574
|
+
declare const CLIENT_ERROR_CODES: {
|
|
3575
|
+
readonly UNEXPECTED_REDIRECT: "UNEXPECTED_REDIRECT";
|
|
3576
|
+
};
|
|
3577
|
+
/** True for codes listed in errors.yaml (server codes; see `CLIENT_ERROR_CODES` for the SDK's own). */
|
|
3488
3578
|
declare function isKnownErrorCode(code: string): code is KnownErrorCode;
|
|
3489
3579
|
/**
|
|
3490
3580
|
* Builds the right error subclass for an HTTP error response.
|
|
@@ -3844,7 +3934,12 @@ interface CexyClientOptions {
|
|
|
3844
3934
|
timeoutMs?: number;
|
|
3845
3935
|
/** Retries after the first attempt for retryable failures. Default 3. */
|
|
3846
3936
|
maxRetries?: number;
|
|
3847
|
-
/**
|
|
3937
|
+
/**
|
|
3938
|
+
* A `fetch` implementation. Default: the global `fetch` (Node 22+, browsers).
|
|
3939
|
+
* It must honour `redirect: "manual"` (the SDK never follows redirects). A fetch that follows
|
|
3940
|
+
* them anyway has already sent the credentials to the redirect target by the time the SDK sees
|
|
3941
|
+
* `response.redirected` and throws `UNEXPECTED_REDIRECT`.
|
|
3942
|
+
*/
|
|
3848
3943
|
fetch?: FetchLike;
|
|
3849
3944
|
/**
|
|
3850
3945
|
* Client-side rate limit in requests per minute, or `false` to disable. Default 100/min
|
|
@@ -3866,6 +3961,8 @@ interface CexyClientOptions {
|
|
|
3866
3961
|
sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;
|
|
3867
3962
|
/** @internal Deterministic jitter in tests. */
|
|
3868
3963
|
random?: () => number;
|
|
3964
|
+
/** @internal Replace the clock in tests (milliseconds). */
|
|
3965
|
+
now?: () => number;
|
|
3869
3966
|
}
|
|
3870
3967
|
/**
|
|
3871
3968
|
* CEXY.io REST client.
|
|
@@ -3925,11 +4022,11 @@ declare function isAmount(value: unknown): value is Amount;
|
|
|
3925
4022
|
declare function assertAmountFields(body: Record<string, unknown>, fields: readonly string[], context: string): void;
|
|
3926
4023
|
|
|
3927
4024
|
/** SDK version, kept in sync with package.json (a test enforces this). */
|
|
3928
|
-
declare const VERSION = "0.1.0-dev.
|
|
4025
|
+
declare const VERSION = "0.1.0-dev.4";
|
|
3929
4026
|
/** Default User-Agent product token. */
|
|
3930
|
-
declare const USER_AGENT = "cexy-typescript/0.1.0-dev.
|
|
4027
|
+
declare const USER_AGENT = "cexy-typescript/0.1.0-dev.4";
|
|
3931
4028
|
|
|
3932
4029
|
/** True for loopback hosts, the only ones where plain-text transport may be allowed. */
|
|
3933
4030
|
declare function isLocalHost(hostname: string): boolean;
|
|
3934
4031
|
|
|
3935
|
-
export { AccountResource, type Amount, type ApiKey, ApiKeyAuthenticator, type ApiScope, type Asset, type AssetNetwork, AssetsResource, type AuthRequest, type AuthResult, type AuthenticatedFrame, AuthenticationError, type Authenticator, type Balance, type BalanceUpdatedEvent, type BookLevel, type CancelAllParams, type CancelAllRequest, type CancelAllResult, type Candle, type CandleInterval, CexyApiError, type CexyApiErrorInit, CexyClient, type CexyClientOptions, CexyConfigError, CexyConnectionError, CexyError, CexyTimeoutError, CexyWebSocket, CexyWebSocketError, type CexyWebSocketEvents, type CexyWebSocketOptions, type CloseInfo, ConflictError, type CursorParams, DEFAULT_BASE_URL, DEFAULT_RPM_ANONYMOUS, DEFAULT_RPM_WITH_KEY, DEFAULT_WS_URL, type Deposit, type DepositAddress, type DepositEvent, type DepositStatus, type ErrorBody, type ErrorCode, type ErrorFrame, type EventMap, type ExchangeConfig, type ExitPoolRequest, type ExitPoolResult, ExportsResource, type FeeSchedule, FeesResource, type FetchLike, type Fill, ForbiddenError, InvalidAmountError, type IterateOptions, type JoinPoolRequest, type JoinPoolResult, JurisdictionBlockedError, KNOWN_EVENT_TYPES, type KnownErrorCode, type LedgerEntry, type LedgerEntryKind, type LiquidityRole, type Listener, LiveOrderBook, type LiveOrderBookEvents, type LiveOrderBookOptions, type MaintenanceState, type Market, type MarketStatus, type MarketStatusEvent, MarketsResource, type Network, NetworksResource, NotFoundError, type Notification, type NotificationKind, OPERATIONS, type OperationAuth, type OperationId, type OperationInfo, type OperationScope, type Order, type OrderBook, type OrderBookUpdateData, type OrderBookUpdateEvent, type OrderEvent, type OrderSide, OrderStateUnknownError, type OrderStatus, type OrderType, PRIVATE_CHANNELS, type Page, type PlaceOrderRequest, type PlaceOrderResponse, type PlaceOrderResult, type PongFrame, type Pool, type PoolStatus, PoolsResource, type PublicTrade, type QueryOf, RateLimitError, RateLimiter, type RateLimiterOptions, type RateLimiterState, type ReconnectOptions, type RequestOptions, type ResyncReason, type RetryInfo, SUPPORTED_PROTOCOL_VERSION, ServerError, type ServerTime, type SessionRevokedData, type SessionRevokedEvent, type SnapshotSource, type SortDirection, type SubAccount, type SubscribeResult, type SubscribedFrame, type TickerUpdateEvent, type TimeInForce, type TradeNewEvent, TradingResource, type TriggerDirection, TypedEmitter, USER_AGENT, UnprocessableError, type UnsubscribedFrame, VERSION, ValidationError, WS_BOOK_DEPTH, WalletResource, type WebSocketConstructor, type WebSocketLike, type WelcomeFrame, type Withdrawal, type WithdrawalAddress, type WithdrawalStatus, type WithdrawalUpdatedEvent, type WsEvent, type WsLogger, assertAmountFields, type components, errorFromResponse, isAmount, isKnownErrorCode, isLocalHost, isRetryable, type operations, paginate, type paths };
|
|
4032
|
+
export { AccountResource, type Amount, type ApiKey, ApiKeyAuthenticator, type ApiScope, type Asset, type AssetNetwork, AssetsResource, type AuthRequest, type AuthResult, type AuthenticatedFrame, AuthenticationError, type Authenticator, type Balance, type BalanceUpdatedEvent, type BookLevel, CLIENT_ERROR_CODES, type CancelAllParams, type CancelAllRequest, type CancelAllResult, type CancelAllStopReason, type CancelAllUntilDoneResult, type CancelFailure, type Candle, type CandleInterval, CexyApiError, type CexyApiErrorInit, CexyClient, type CexyClientOptions, CexyConfigError, CexyConnectionError, CexyError, CexyTimeoutError, CexyWebSocket, CexyWebSocketError, type CexyWebSocketEvents, type CexyWebSocketOptions, type CloseInfo, ConflictError, type CursorParams, DEFAULT_BASE_URL, DEFAULT_RPM_ANONYMOUS, DEFAULT_RPM_WITH_KEY, DEFAULT_WS_URL, type Deposit, type DepositAddress, type DepositEvent, type DepositStatus, type ErrorBody, type ErrorCode, type ErrorFrame, type EventMap, type ExchangeConfig, type ExitPoolRequest, type ExitPoolResult, ExportsResource, type FeeSchedule, FeesResource, type FetchLike, type Fill, ForbiddenError, InvalidAmountError, type IterateOptions, type JoinPoolRequest, type JoinPoolResult, JurisdictionBlockedError, KNOWN_EVENT_TYPES, type KnownErrorCode, type LedgerEntry, type LedgerEntryKind, type LiquidityRole, type Listener, LiveOrderBook, type LiveOrderBookEvents, type LiveOrderBookOptions, type MaintenanceState, type Market, type MarketStatus, type MarketStatusEvent, MarketsResource, type Network, NetworksResource, NotFoundError, type Notification, type NotificationKind, OPERATIONS, type OperationAuth, type OperationId, type OperationInfo, type OperationScope, type Order, type OrderBook, type OrderBookUpdateData, type OrderBookUpdateEvent, type OrderEvent, type OrderSide, OrderStateUnknownError, type OrderStatus, type OrderType, PRIVATE_CHANNELS, type Page, type PlaceOrderRequest, type PlaceOrderResponse, type PlaceOrderResult, type PongFrame, type Pool, type PoolStatus, PoolsResource, type PublicTrade, type QueryOf, RateLimitError, RateLimiter, type RateLimiterOptions, type RateLimiterState, type ReconnectOptions, type RequestOptions, type ResyncReason, type RetryInfo, SUPPORTED_PROTOCOL_VERSION, ServerError, type ServerTime, type SessionRevokedData, type SessionRevokedEvent, type SnapshotSource, type SortDirection, type SubAccount, type SubscribeResult, type SubscribedFrame, type TickerUpdateEvent, type TimeInForce, type TradeNewEvent, TradingResource, type TriggerDirection, TypedEmitter, USER_AGENT, UnprocessableError, type UnsubscribedFrame, VERSION, ValidationError, WS_BOOK_DEPTH, WalletResource, type WebSocketConstructor, type WebSocketLike, type WelcomeFrame, type Withdrawal, type WithdrawalAddress, type WithdrawalStatus, type WithdrawalUpdatedEvent, type WsEvent, type WsLogger, assertAmountFields, type components, errorFromResponse, isAmount, isKnownErrorCode, isLocalHost, isRetryable, type operations, paginate, type paths };
|
package/dist/index.d.ts
CHANGED
|
@@ -163,6 +163,8 @@ interface TransportConfig {
|
|
|
163
163
|
userAgent: string | null;
|
|
164
164
|
sleep: (ms: number, signal?: AbortSignal) => Promise<void>;
|
|
165
165
|
random: () => number;
|
|
166
|
+
/** Milliseconds clock (default `Date.now`); injectable for tests. */
|
|
167
|
+
now?: () => number;
|
|
166
168
|
onRetry?: ((info: RetryInfo) => void) | undefined;
|
|
167
169
|
}
|
|
168
170
|
interface CallSpec {
|
|
@@ -730,7 +732,11 @@ interface paths {
|
|
|
730
732
|
put?: never;
|
|
731
733
|
/**
|
|
732
734
|
* Cancels every open order, optionally within one market.
|
|
733
|
-
* @description Best-effort: a failure on one order does not stop the rest, and
|
|
735
|
+
* @description Best-effort: a failure on one order does not stop the rest, and every outcome is reported. A panic-button endpoint that stops at the first problem is worse than useless.
|
|
736
|
+
*
|
|
737
|
+
* An order still being placed when the call starts (status `pending`, for as long as its own placement request runs) is waited for, up to 500 ms per call in total: cancelled if it opens, reported in `already_closed` if it fills or is refused, and in `failed` with code `INVALID_STATE` if it is still being placed at the deadline. Orders placed after the call starts are not part of it. At most 500 orders per call; `has_more` says there are others.
|
|
738
|
+
*
|
|
739
|
+
* Limited to 30 calls a minute per account, on top of the general request limit.
|
|
734
740
|
*/
|
|
735
741
|
post: operations["cancel_all"];
|
|
736
742
|
delete?: never;
|
|
@@ -1037,12 +1043,31 @@ interface components {
|
|
|
1037
1043
|
/** @description Limit the cancellation to one market. Omitted or `null`, every market's open orders are cancelled. */
|
|
1038
1044
|
symbol?: string | null;
|
|
1039
1045
|
};
|
|
1040
|
-
/**
|
|
1046
|
+
/**
|
|
1047
|
+
* @description What a bulk cancellation achieved.
|
|
1048
|
+
*
|
|
1049
|
+
* Every order the call handled is in exactly one of `cancelled`, `already_closed` and `failed`.
|
|
1050
|
+
*/
|
|
1041
1051
|
CancelAllResponse: {
|
|
1052
|
+
/** @description Orders that closed on their own (filled, rejected, cancelled elsewhere) before this call reached them. Nothing was done to them, and they are not failures. */
|
|
1053
|
+
already_closed: string[];
|
|
1042
1054
|
/** @description Orders cancelled. */
|
|
1043
1055
|
cancelled: string[];
|
|
1044
|
-
/** @description Orders that could not be cancelled.
|
|
1056
|
+
/** @description Orders that could not be cancelled in this call. Check `failures` for why, then refresh or call again. */
|
|
1045
1057
|
failed: string[];
|
|
1058
|
+
/** @description Why each order in `failed` could not be cancelled. */
|
|
1059
|
+
failures: components["schemas"]["CancelFailureResponse"][];
|
|
1060
|
+
/** @description More open orders exist than one call handles (500). Call again. */
|
|
1061
|
+
has_more: boolean;
|
|
1062
|
+
};
|
|
1063
|
+
/** @description Why one order could not be cancelled. */
|
|
1064
|
+
CancelFailureResponse: {
|
|
1065
|
+
/** @description The error code of the attempt, as in any error response: e.g. `INVALID_STATE` for an order still being placed when the wait ran out, or `MARKET_UNAVAILABLE`. */
|
|
1066
|
+
code: string;
|
|
1067
|
+
/** @description Its message. */
|
|
1068
|
+
message: string;
|
|
1069
|
+
/** @description The order. */
|
|
1070
|
+
order_id: string;
|
|
1046
1071
|
};
|
|
1047
1072
|
/**
|
|
1048
1073
|
* @description Candle/kline intervals for market data.
|
|
@@ -2877,6 +2902,24 @@ interface operations {
|
|
|
2877
2902
|
};
|
|
2878
2903
|
};
|
|
2879
2904
|
};
|
|
2905
|
+
/** @description No such market */
|
|
2906
|
+
404: {
|
|
2907
|
+
headers: {
|
|
2908
|
+
[name: string]: unknown;
|
|
2909
|
+
};
|
|
2910
|
+
content: {
|
|
2911
|
+
"application/json": components["schemas"]["ErrorResponse"];
|
|
2912
|
+
};
|
|
2913
|
+
};
|
|
2914
|
+
/** @description Over 30 calls a minute for this account; `details.retry_after_seconds` says when to retry */
|
|
2915
|
+
429: {
|
|
2916
|
+
headers: {
|
|
2917
|
+
[name: string]: unknown;
|
|
2918
|
+
};
|
|
2919
|
+
content: {
|
|
2920
|
+
"application/json": components["schemas"]["ErrorResponse"];
|
|
2921
|
+
};
|
|
2922
|
+
};
|
|
2880
2923
|
};
|
|
2881
2924
|
};
|
|
2882
2925
|
order_history: {
|
|
@@ -3181,6 +3224,21 @@ type AssetNetwork = S["AssetNetworkResponse"];
|
|
|
3181
3224
|
type Balance = S["BalanceResponse"];
|
|
3182
3225
|
type CancelAllRequest = S["CancelAllRequest"];
|
|
3183
3226
|
type CancelAllResult = S["CancelAllResponse"];
|
|
3227
|
+
/** Why one order could not be cancelled (`CancelAllResult.failures`). */
|
|
3228
|
+
type CancelFailure = S["CancelFailureResponse"];
|
|
3229
|
+
/** Why a `cancelAll({ ..., untilDone: true })` loop ended. */
|
|
3230
|
+
type CancelAllStopReason = "done" | "max_rounds" | "time_budget";
|
|
3231
|
+
/**
|
|
3232
|
+
* Merged result of a `cancelAll({ ..., untilDone: true })` loop. Every order is in exactly one
|
|
3233
|
+
* of `cancelled`, `already_closed` and `failed`, in its latest state; `has_more` is the last
|
|
3234
|
+
* round's.
|
|
3235
|
+
*/
|
|
3236
|
+
interface CancelAllUntilDoneResult extends CancelAllResult {
|
|
3237
|
+
/** Number of cancel-all calls made. */
|
|
3238
|
+
rounds: number;
|
|
3239
|
+
/** `done`: nothing left to retry; otherwise the loop's limit that ended it. */
|
|
3240
|
+
stopped: CancelAllStopReason;
|
|
3241
|
+
}
|
|
3184
3242
|
type Candle = S["CandleResponse"];
|
|
3185
3243
|
type CandleInterval = S["CandleInterval"];
|
|
3186
3244
|
type DepositAddress = S["DepositAddressResponse"];
|
|
@@ -3344,6 +3402,14 @@ interface PlaceOrderResult extends PlaceOrderResponse {
|
|
|
3344
3402
|
*/
|
|
3345
3403
|
interface CancelAllParams {
|
|
3346
3404
|
symbol: string | null;
|
|
3405
|
+
/**
|
|
3406
|
+
* Repeat the call until nothing is left to retry (see `cancelAll`). Default false: one call.
|
|
3407
|
+
*/
|
|
3408
|
+
untilDone?: boolean;
|
|
3409
|
+
/** With `untilDone`: at most this many calls. Default 20. */
|
|
3410
|
+
maxRounds?: number;
|
|
3411
|
+
/** With `untilDone`: stop before a wait would take the loop to this many ms. Default 120000. */
|
|
3412
|
+
timeBudgetMs?: number;
|
|
3347
3413
|
}
|
|
3348
3414
|
declare class TradingResource extends Resource {
|
|
3349
3415
|
#private;
|
|
@@ -3380,12 +3446,27 @@ declare class TradingResource extends Resource {
|
|
|
3380
3446
|
* Cancels every open order in one market: `cancelAll({ symbol: "BTC/USDT" })`.
|
|
3381
3447
|
* To cancel across ALL markets, pass `symbol: null` explicitly: `cancelAll({ symbol: null })`.
|
|
3382
3448
|
* Omitting `symbol` is an error, so an account-wide cancel never happens by accident
|
|
3383
|
-
* (the server itself treats `{}` as every market).
|
|
3449
|
+
* (the server itself treats `{}` as every market). An unknown symbol throws `NotFoundError`.
|
|
3450
|
+
*
|
|
3451
|
+
* One call handles at most 500 orders. Every order it handled is in exactly one list:
|
|
3452
|
+
* `cancelled`; `already_closed` (it filled, was refused or was cancelled elsewhere first:
|
|
3453
|
+
* not an error); or `failed`, with the reason in `failures` (`INVALID_STATE` for an order
|
|
3454
|
+
* still being placed when the server's 500 ms wait ran out). `has_more` says more orders
|
|
3455
|
+
* remain: call again.
|
|
3456
|
+
*
|
|
3457
|
+
* With `untilDone: true` the SDK does that for you. It repeats while `has_more` is true or a
|
|
3458
|
+
* failure is `INVALID_STATE` / `SERVICE_UNAVAILABLE`. After a call that made no progress it
|
|
3459
|
+
* waits 1, 2, 4, 8 and then 15 s, starting over after any progress. It stops after
|
|
3460
|
+
* `maxRounds` calls or before a wait would pass `timeBudgetMs`, and returns the merged
|
|
3461
|
+
* result with `rounds` and `stopped`. Other failure codes are returned, never retried.
|
|
3384
3462
|
*
|
|
3385
|
-
* The server
|
|
3386
|
-
*
|
|
3387
|
-
*
|
|
3463
|
+
* The server allows 30 cancel-all calls per minute per account (a 429 is retried after its
|
|
3464
|
+
* Retry-After). The call is naturally repeatable and needs no Idempotency-Key, so it is
|
|
3465
|
+
* retried after network errors; a retry reports only what that retry did.
|
|
3388
3466
|
*/
|
|
3467
|
+
cancelAll(params: CancelAllParams & {
|
|
3468
|
+
untilDone: true;
|
|
3469
|
+
}, opts?: RequestOptions): Promise<CancelAllUntilDoneResult>;
|
|
3389
3470
|
cancelAll(params: CancelAllParams, opts?: RequestOptions): Promise<CancelAllResult>;
|
|
3390
3471
|
}
|
|
3391
3472
|
|
|
@@ -3484,7 +3565,16 @@ declare class RateLimitError extends CexyApiError {
|
|
|
3484
3565
|
/** 5xx */
|
|
3485
3566
|
declare class ServerError extends CexyApiError {
|
|
3486
3567
|
}
|
|
3487
|
-
/**
|
|
3568
|
+
/**
|
|
3569
|
+
* Codes the SDK itself sets on a `CexyApiError`; the API never sends them, so they are not in
|
|
3570
|
+
* errors.yaml and `isKnownErrorCode()` returns false for them.
|
|
3571
|
+
* - `UNEXPECTED_REDIRECT`: the server answered with a 3xx. The SDK never follows redirects (the
|
|
3572
|
+
* credentials would go to the redirect target); not retryable.
|
|
3573
|
+
*/
|
|
3574
|
+
declare const CLIENT_ERROR_CODES: {
|
|
3575
|
+
readonly UNEXPECTED_REDIRECT: "UNEXPECTED_REDIRECT";
|
|
3576
|
+
};
|
|
3577
|
+
/** True for codes listed in errors.yaml (server codes; see `CLIENT_ERROR_CODES` for the SDK's own). */
|
|
3488
3578
|
declare function isKnownErrorCode(code: string): code is KnownErrorCode;
|
|
3489
3579
|
/**
|
|
3490
3580
|
* Builds the right error subclass for an HTTP error response.
|
|
@@ -3844,7 +3934,12 @@ interface CexyClientOptions {
|
|
|
3844
3934
|
timeoutMs?: number;
|
|
3845
3935
|
/** Retries after the first attempt for retryable failures. Default 3. */
|
|
3846
3936
|
maxRetries?: number;
|
|
3847
|
-
/**
|
|
3937
|
+
/**
|
|
3938
|
+
* A `fetch` implementation. Default: the global `fetch` (Node 22+, browsers).
|
|
3939
|
+
* It must honour `redirect: "manual"` (the SDK never follows redirects). A fetch that follows
|
|
3940
|
+
* them anyway has already sent the credentials to the redirect target by the time the SDK sees
|
|
3941
|
+
* `response.redirected` and throws `UNEXPECTED_REDIRECT`.
|
|
3942
|
+
*/
|
|
3848
3943
|
fetch?: FetchLike;
|
|
3849
3944
|
/**
|
|
3850
3945
|
* Client-side rate limit in requests per minute, or `false` to disable. Default 100/min
|
|
@@ -3866,6 +3961,8 @@ interface CexyClientOptions {
|
|
|
3866
3961
|
sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;
|
|
3867
3962
|
/** @internal Deterministic jitter in tests. */
|
|
3868
3963
|
random?: () => number;
|
|
3964
|
+
/** @internal Replace the clock in tests (milliseconds). */
|
|
3965
|
+
now?: () => number;
|
|
3869
3966
|
}
|
|
3870
3967
|
/**
|
|
3871
3968
|
* CEXY.io REST client.
|
|
@@ -3925,11 +4022,11 @@ declare function isAmount(value: unknown): value is Amount;
|
|
|
3925
4022
|
declare function assertAmountFields(body: Record<string, unknown>, fields: readonly string[], context: string): void;
|
|
3926
4023
|
|
|
3927
4024
|
/** SDK version, kept in sync with package.json (a test enforces this). */
|
|
3928
|
-
declare const VERSION = "0.1.0-dev.
|
|
4025
|
+
declare const VERSION = "0.1.0-dev.4";
|
|
3929
4026
|
/** Default User-Agent product token. */
|
|
3930
|
-
declare const USER_AGENT = "cexy-typescript/0.1.0-dev.
|
|
4027
|
+
declare const USER_AGENT = "cexy-typescript/0.1.0-dev.4";
|
|
3931
4028
|
|
|
3932
4029
|
/** True for loopback hosts, the only ones where plain-text transport may be allowed. */
|
|
3933
4030
|
declare function isLocalHost(hostname: string): boolean;
|
|
3934
4031
|
|
|
3935
|
-
export { AccountResource, type Amount, type ApiKey, ApiKeyAuthenticator, type ApiScope, type Asset, type AssetNetwork, AssetsResource, type AuthRequest, type AuthResult, type AuthenticatedFrame, AuthenticationError, type Authenticator, type Balance, type BalanceUpdatedEvent, type BookLevel, type CancelAllParams, type CancelAllRequest, type CancelAllResult, type Candle, type CandleInterval, CexyApiError, type CexyApiErrorInit, CexyClient, type CexyClientOptions, CexyConfigError, CexyConnectionError, CexyError, CexyTimeoutError, CexyWebSocket, CexyWebSocketError, type CexyWebSocketEvents, type CexyWebSocketOptions, type CloseInfo, ConflictError, type CursorParams, DEFAULT_BASE_URL, DEFAULT_RPM_ANONYMOUS, DEFAULT_RPM_WITH_KEY, DEFAULT_WS_URL, type Deposit, type DepositAddress, type DepositEvent, type DepositStatus, type ErrorBody, type ErrorCode, type ErrorFrame, type EventMap, type ExchangeConfig, type ExitPoolRequest, type ExitPoolResult, ExportsResource, type FeeSchedule, FeesResource, type FetchLike, type Fill, ForbiddenError, InvalidAmountError, type IterateOptions, type JoinPoolRequest, type JoinPoolResult, JurisdictionBlockedError, KNOWN_EVENT_TYPES, type KnownErrorCode, type LedgerEntry, type LedgerEntryKind, type LiquidityRole, type Listener, LiveOrderBook, type LiveOrderBookEvents, type LiveOrderBookOptions, type MaintenanceState, type Market, type MarketStatus, type MarketStatusEvent, MarketsResource, type Network, NetworksResource, NotFoundError, type Notification, type NotificationKind, OPERATIONS, type OperationAuth, type OperationId, type OperationInfo, type OperationScope, type Order, type OrderBook, type OrderBookUpdateData, type OrderBookUpdateEvent, type OrderEvent, type OrderSide, OrderStateUnknownError, type OrderStatus, type OrderType, PRIVATE_CHANNELS, type Page, type PlaceOrderRequest, type PlaceOrderResponse, type PlaceOrderResult, type PongFrame, type Pool, type PoolStatus, PoolsResource, type PublicTrade, type QueryOf, RateLimitError, RateLimiter, type RateLimiterOptions, type RateLimiterState, type ReconnectOptions, type RequestOptions, type ResyncReason, type RetryInfo, SUPPORTED_PROTOCOL_VERSION, ServerError, type ServerTime, type SessionRevokedData, type SessionRevokedEvent, type SnapshotSource, type SortDirection, type SubAccount, type SubscribeResult, type SubscribedFrame, type TickerUpdateEvent, type TimeInForce, type TradeNewEvent, TradingResource, type TriggerDirection, TypedEmitter, USER_AGENT, UnprocessableError, type UnsubscribedFrame, VERSION, ValidationError, WS_BOOK_DEPTH, WalletResource, type WebSocketConstructor, type WebSocketLike, type WelcomeFrame, type Withdrawal, type WithdrawalAddress, type WithdrawalStatus, type WithdrawalUpdatedEvent, type WsEvent, type WsLogger, assertAmountFields, type components, errorFromResponse, isAmount, isKnownErrorCode, isLocalHost, isRetryable, type operations, paginate, type paths };
|
|
4032
|
+
export { AccountResource, type Amount, type ApiKey, ApiKeyAuthenticator, type ApiScope, type Asset, type AssetNetwork, AssetsResource, type AuthRequest, type AuthResult, type AuthenticatedFrame, AuthenticationError, type Authenticator, type Balance, type BalanceUpdatedEvent, type BookLevel, CLIENT_ERROR_CODES, type CancelAllParams, type CancelAllRequest, type CancelAllResult, type CancelAllStopReason, type CancelAllUntilDoneResult, type CancelFailure, type Candle, type CandleInterval, CexyApiError, type CexyApiErrorInit, CexyClient, type CexyClientOptions, CexyConfigError, CexyConnectionError, CexyError, CexyTimeoutError, CexyWebSocket, CexyWebSocketError, type CexyWebSocketEvents, type CexyWebSocketOptions, type CloseInfo, ConflictError, type CursorParams, DEFAULT_BASE_URL, DEFAULT_RPM_ANONYMOUS, DEFAULT_RPM_WITH_KEY, DEFAULT_WS_URL, type Deposit, type DepositAddress, type DepositEvent, type DepositStatus, type ErrorBody, type ErrorCode, type ErrorFrame, type EventMap, type ExchangeConfig, type ExitPoolRequest, type ExitPoolResult, ExportsResource, type FeeSchedule, FeesResource, type FetchLike, type Fill, ForbiddenError, InvalidAmountError, type IterateOptions, type JoinPoolRequest, type JoinPoolResult, JurisdictionBlockedError, KNOWN_EVENT_TYPES, type KnownErrorCode, type LedgerEntry, type LedgerEntryKind, type LiquidityRole, type Listener, LiveOrderBook, type LiveOrderBookEvents, type LiveOrderBookOptions, type MaintenanceState, type Market, type MarketStatus, type MarketStatusEvent, MarketsResource, type Network, NetworksResource, NotFoundError, type Notification, type NotificationKind, OPERATIONS, type OperationAuth, type OperationId, type OperationInfo, type OperationScope, type Order, type OrderBook, type OrderBookUpdateData, type OrderBookUpdateEvent, type OrderEvent, type OrderSide, OrderStateUnknownError, type OrderStatus, type OrderType, PRIVATE_CHANNELS, type Page, type PlaceOrderRequest, type PlaceOrderResponse, type PlaceOrderResult, type PongFrame, type Pool, type PoolStatus, PoolsResource, type PublicTrade, type QueryOf, RateLimitError, RateLimiter, type RateLimiterOptions, type RateLimiterState, type ReconnectOptions, type RequestOptions, type ResyncReason, type RetryInfo, SUPPORTED_PROTOCOL_VERSION, ServerError, type ServerTime, type SessionRevokedData, type SessionRevokedEvent, type SnapshotSource, type SortDirection, type SubAccount, type SubscribeResult, type SubscribedFrame, type TickerUpdateEvent, type TimeInForce, type TradeNewEvent, TradingResource, type TriggerDirection, TypedEmitter, USER_AGENT, UnprocessableError, type UnsubscribedFrame, VERSION, ValidationError, WS_BOOK_DEPTH, WalletResource, type WebSocketConstructor, type WebSocketLike, type WelcomeFrame, type Withdrawal, type WithdrawalAddress, type WithdrawalStatus, type WithdrawalUpdatedEvent, type WsEvent, type WsLogger, assertAmountFields, type components, errorFromResponse, isAmount, isKnownErrorCode, isLocalHost, isRetryable, type operations, paginate, type paths };
|
package/dist/index.js
CHANGED
|
@@ -129,6 +129,7 @@ var KNOWN_CODES = /* @__PURE__ */ new Set([
|
|
|
129
129
|
"UNDER_MAINTENANCE",
|
|
130
130
|
"ENGINE_OVERLOADED"
|
|
131
131
|
]);
|
|
132
|
+
var CLIENT_ERROR_CODES = { UNEXPECTED_REDIRECT: "UNEXPECTED_REDIRECT" };
|
|
132
133
|
function isKnownErrorCode(code) {
|
|
133
134
|
return KNOWN_CODES.has(code);
|
|
134
135
|
}
|
|
@@ -413,7 +414,7 @@ var Transport = class {
|
|
|
413
414
|
if (res.type === "opaqueredirect" || res.status >= 300 && res.status < 400 || res.redirected) {
|
|
414
415
|
throw new CexyApiError({
|
|
415
416
|
status: res.status,
|
|
416
|
-
code:
|
|
417
|
+
code: CLIENT_ERROR_CODES.UNEXPECTED_REDIRECT,
|
|
417
418
|
message: `${info.method} ${info.path}: the server answered with a redirect (HTTP ${res.status}); the SDK does not follow redirects. Check baseUrl.`,
|
|
418
419
|
retryable: false
|
|
419
420
|
});
|
|
@@ -788,6 +789,8 @@ var WalletResource = class extends Resource {
|
|
|
788
789
|
return this.data({ op: "deposit_address", query: params }, opts);
|
|
789
790
|
}
|
|
790
791
|
};
|
|
792
|
+
var CANCEL_RETRY_CODES = /* @__PURE__ */ new Set(["INVALID_STATE", "SERVICE_UNAVAILABLE"]);
|
|
793
|
+
var CANCEL_BACKOFF_S = [1, 2, 4, 8, 15];
|
|
791
794
|
var ORDER_AMOUNT_FIELDS = ["price", "quantity", "quote_quantity", "stop_price"];
|
|
792
795
|
var TradingResource = class extends Resource {
|
|
793
796
|
/** Open orders, optionally filtered by market/status. */
|
|
@@ -894,16 +897,6 @@ var TradingResource = class extends Resource {
|
|
|
894
897
|
}
|
|
895
898
|
}
|
|
896
899
|
}
|
|
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
900
|
async cancelAll(params, opts) {
|
|
908
901
|
const hasSymbol = !!params && typeof params === "object" && Object.prototype.hasOwnProperty.call(params, "symbol");
|
|
909
902
|
const symbol = hasSymbol ? params.symbol : void 0;
|
|
@@ -911,12 +904,62 @@ var TradingResource = class extends Resource {
|
|
|
911
904
|
if (typeof symbol === "string" && symbol !== "") body = { symbol };
|
|
912
905
|
else if (hasSymbol && symbol === null) body = {};
|
|
913
906
|
else throw new CexyConfigError('cancelAll(): pass { symbol: "BASE/QUOTE" }, or { symbol: null } to cancel in every market');
|
|
914
|
-
|
|
907
|
+
const once = () => this.data({ op: "cancel_all", body }, opts);
|
|
908
|
+
if (params.untilDone !== true) return once();
|
|
909
|
+
const maxRounds = params.maxRounds ?? 20;
|
|
910
|
+
const budgetMs = params.timeBudgetMs ?? 12e4;
|
|
911
|
+
if (!(maxRounds >= 1)) throw new CexyConfigError("cancelAll(): maxRounds must be >= 1");
|
|
912
|
+
if (!(budgetMs > 0)) throw new CexyConfigError("cancelAll(): timeBudgetMs must be > 0");
|
|
913
|
+
const now = this.t.config.now ?? Date.now;
|
|
914
|
+
const start = now();
|
|
915
|
+
const state = /* @__PURE__ */ new Map();
|
|
916
|
+
let rounds = 0;
|
|
917
|
+
let idle = 0;
|
|
918
|
+
let last;
|
|
919
|
+
let stopped;
|
|
920
|
+
for (; ; ) {
|
|
921
|
+
last = await once();
|
|
922
|
+
rounds++;
|
|
923
|
+
const failures = last.failures ?? [];
|
|
924
|
+
for (const id of last.cancelled ?? []) state.set(id, { list: "cancelled" });
|
|
925
|
+
for (const id of last.already_closed ?? []) state.set(id, { list: "already_closed" });
|
|
926
|
+
for (const id of last.failed ?? []) {
|
|
927
|
+
const failure = failures.find((f) => f.order_id === id);
|
|
928
|
+
state.set(id, failure ? { list: "failed", failure } : { list: "failed" });
|
|
929
|
+
}
|
|
930
|
+
const progress = (last.cancelled?.length ?? 0) + (last.already_closed?.length ?? 0) > 0;
|
|
931
|
+
if (!last.has_more && !failures.some((f) => CANCEL_RETRY_CODES.has(f.code))) {
|
|
932
|
+
stopped = "done";
|
|
933
|
+
break;
|
|
934
|
+
}
|
|
935
|
+
if (rounds >= maxRounds) {
|
|
936
|
+
stopped = "max_rounds";
|
|
937
|
+
break;
|
|
938
|
+
}
|
|
939
|
+
let waitMs = 0;
|
|
940
|
+
if (progress) idle = 0;
|
|
941
|
+
else waitMs = (CANCEL_BACKOFF_S[Math.min(idle++, CANCEL_BACKOFF_S.length - 1)] ?? 15) * 1e3;
|
|
942
|
+
if (now() - start + waitMs >= budgetMs) {
|
|
943
|
+
stopped = "time_budget";
|
|
944
|
+
break;
|
|
945
|
+
}
|
|
946
|
+
if (waitMs > 0) await this.t.config.sleep(waitMs, opts?.signal);
|
|
947
|
+
}
|
|
948
|
+
const pick = (list) => [...state].filter(([, v]) => v.list === list).map(([id]) => id);
|
|
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
|
+
};
|
|
915
958
|
}
|
|
916
959
|
};
|
|
917
960
|
|
|
918
961
|
// src/version.ts
|
|
919
|
-
var VERSION = "0.1.0-dev.
|
|
962
|
+
var VERSION = "0.1.0-dev.4";
|
|
920
963
|
var USER_AGENT = `cexy-typescript/${VERSION}`;
|
|
921
964
|
|
|
922
965
|
// src/ws/emitter.ts
|
|
@@ -1697,6 +1740,7 @@ var CexyClient = class {
|
|
|
1697
1740
|
userAgent: canSetUserAgent() ? [USER_AGENT, options.userAgentSuffix].filter(Boolean).join(" ") : null,
|
|
1698
1741
|
sleep: sleep2,
|
|
1699
1742
|
random: options.random ?? Math.random,
|
|
1743
|
+
now: options.now ?? Date.now,
|
|
1700
1744
|
onRetry: options.onRetry
|
|
1701
1745
|
});
|
|
1702
1746
|
const t = this.#transport;
|
|
@@ -1766,4 +1810,4 @@ function canSetUserAgent() {
|
|
|
1766
1810
|
return !(typeof g.window !== "undefined" && typeof g.window.document !== "undefined");
|
|
1767
1811
|
}
|
|
1768
1812
|
|
|
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 };
|
|
1813
|
+
export { AccountResource, ApiKeyAuthenticator, AssetsResource, AuthenticationError, CLIENT_ERROR_CODES, 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 };
|