@pear-protocol/core-sdk 1.4.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/index.d.ts +146 -13
- package/dist/core/index.js +111 -28
- package/dist/index.js +35 -6
- package/dist/index.test.d.ts +2 -0
- package/dist/index.test.js +88 -0
- package/dist/types.d.ts +1 -1
- package/dist/utils.d.ts +2 -1
- package/dist/utils.js +5 -1
- package/package.json +7 -4
package/dist/core/index.d.ts
CHANGED
|
@@ -362,6 +362,7 @@ declare class Core {
|
|
|
362
362
|
side: "BUY" | "SELL";
|
|
363
363
|
reduceOnly: boolean;
|
|
364
364
|
isExternal: boolean;
|
|
365
|
+
synthetic: boolean;
|
|
365
366
|
quantity: string;
|
|
366
367
|
price: string;
|
|
367
368
|
usd: string;
|
|
@@ -389,6 +390,7 @@ declare class Core {
|
|
|
389
390
|
side: "BUY" | "SELL";
|
|
390
391
|
reduceOnly: boolean;
|
|
391
392
|
isExternal: boolean;
|
|
393
|
+
synthetic: boolean;
|
|
392
394
|
quantity: string;
|
|
393
395
|
price: string;
|
|
394
396
|
usd: string;
|
|
@@ -532,6 +534,7 @@ declare class Core {
|
|
|
532
534
|
side: "BUY" | "SELL";
|
|
533
535
|
reduceOnly: boolean;
|
|
534
536
|
isExternal: boolean;
|
|
537
|
+
synthetic: boolean;
|
|
535
538
|
quantity: string;
|
|
536
539
|
price: string;
|
|
537
540
|
usd: string;
|
|
@@ -664,6 +667,7 @@ declare class Core {
|
|
|
664
667
|
side: "BUY" | "SELL";
|
|
665
668
|
reduceOnly: boolean;
|
|
666
669
|
isExternal: boolean;
|
|
670
|
+
synthetic: boolean;
|
|
667
671
|
quantity: string;
|
|
668
672
|
price: string;
|
|
669
673
|
usd: string;
|
|
@@ -829,6 +833,7 @@ declare class Core {
|
|
|
829
833
|
side: "BUY" | "SELL";
|
|
830
834
|
reduceOnly: boolean;
|
|
831
835
|
isExternal: boolean;
|
|
836
|
+
synthetic: boolean;
|
|
832
837
|
quantity: string;
|
|
833
838
|
price: string;
|
|
834
839
|
usd: string;
|
|
@@ -963,6 +968,7 @@ declare class Core {
|
|
|
963
968
|
side: "BUY" | "SELL";
|
|
964
969
|
reduceOnly: boolean;
|
|
965
970
|
isExternal: boolean;
|
|
971
|
+
synthetic: boolean;
|
|
966
972
|
quantity: string;
|
|
967
973
|
price: string;
|
|
968
974
|
usd: string;
|
|
@@ -1095,6 +1101,7 @@ declare class Core {
|
|
|
1095
1101
|
side: "BUY" | "SELL";
|
|
1096
1102
|
reduceOnly: boolean;
|
|
1097
1103
|
isExternal: boolean;
|
|
1104
|
+
synthetic: boolean;
|
|
1098
1105
|
quantity: string;
|
|
1099
1106
|
price: string;
|
|
1100
1107
|
usd: string;
|
|
@@ -1260,6 +1267,7 @@ declare class Core {
|
|
|
1260
1267
|
side: "BUY" | "SELL";
|
|
1261
1268
|
reduceOnly: boolean;
|
|
1262
1269
|
isExternal: boolean;
|
|
1270
|
+
synthetic: boolean;
|
|
1263
1271
|
quantity: string;
|
|
1264
1272
|
price: string;
|
|
1265
1273
|
usd: string;
|
|
@@ -1394,6 +1402,7 @@ declare class Core {
|
|
|
1394
1402
|
side: "BUY" | "SELL";
|
|
1395
1403
|
reduceOnly: boolean;
|
|
1396
1404
|
isExternal: boolean;
|
|
1405
|
+
synthetic: boolean;
|
|
1397
1406
|
quantity: string;
|
|
1398
1407
|
price: string;
|
|
1399
1408
|
usd: string;
|
|
@@ -1526,6 +1535,7 @@ declare class Core {
|
|
|
1526
1535
|
side: "BUY" | "SELL";
|
|
1527
1536
|
reduceOnly: boolean;
|
|
1528
1537
|
isExternal: boolean;
|
|
1538
|
+
synthetic: boolean;
|
|
1529
1539
|
quantity: string;
|
|
1530
1540
|
price: string;
|
|
1531
1541
|
usd: string;
|
|
@@ -1691,6 +1701,7 @@ declare class Core {
|
|
|
1691
1701
|
side: "BUY" | "SELL";
|
|
1692
1702
|
reduceOnly: boolean;
|
|
1693
1703
|
isExternal: boolean;
|
|
1704
|
+
synthetic: boolean;
|
|
1694
1705
|
quantity: string;
|
|
1695
1706
|
price: string;
|
|
1696
1707
|
usd: string;
|
|
@@ -1811,26 +1822,50 @@ declare class Core {
|
|
|
1811
1822
|
list: (query?: HttpTypes.NotificationListParamsInput, headers?: ClientHeaders) => Promise<{
|
|
1812
1823
|
notifications: {
|
|
1813
1824
|
id: string;
|
|
1814
|
-
category: "TAKE_PROFIT_HIT" | "STOP_LOSS_HIT" | "TRIGGER_ORDER_HIT";
|
|
1825
|
+
category: "TAKE_PROFIT_HIT" | "STOP_LOSS_HIT" | "TRIGGER_ORDER_HIT" | "TAKE_PROFIT_FAILED" | "STOP_LOSS_FAILED" | "TRIGGER_ORDER_FAILED" | "ATTACHED_TRIGGER_DISCARDED";
|
|
1815
1826
|
parameters: {
|
|
1816
1827
|
type: "take_profit";
|
|
1817
1828
|
triggerId: string;
|
|
1818
1829
|
positionId: string;
|
|
1819
1830
|
connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
|
|
1831
|
+
metric?: "price" | "ratio" | "weighted_ratio" | "funding_rate" | "prediction_market" | "btc_dominance" | "notional" | "upnl" | "upnl_bps" | "ratio_trailing" | "price_trailing" | "weighted_ratio_trailing" | "notional_trailing" | "upnl_trailing" | "upnl_bps_trailing" | undefined;
|
|
1832
|
+
level?: number | undefined;
|
|
1833
|
+
reason?: string | undefined;
|
|
1820
1834
|
} | {
|
|
1821
1835
|
type: "stop_loss";
|
|
1822
1836
|
triggerId: string;
|
|
1823
1837
|
positionId: string;
|
|
1824
1838
|
connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
|
|
1839
|
+
metric?: "price" | "ratio" | "weighted_ratio" | "funding_rate" | "prediction_market" | "btc_dominance" | "notional" | "upnl" | "upnl_bps" | "ratio_trailing" | "price_trailing" | "weighted_ratio_trailing" | "notional_trailing" | "upnl_trailing" | "upnl_bps_trailing" | undefined;
|
|
1840
|
+
level?: number | undefined;
|
|
1841
|
+
reason?: string | undefined;
|
|
1825
1842
|
} | {
|
|
1826
1843
|
type: "trigger_order";
|
|
1827
1844
|
triggerId: string;
|
|
1828
1845
|
positionId: string;
|
|
1829
1846
|
connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
|
|
1847
|
+
metric?: "price" | "ratio" | "weighted_ratio" | "funding_rate" | "prediction_market" | "btc_dominance" | "notional" | "upnl" | "upnl_bps" | "ratio_trailing" | "price_trailing" | "weighted_ratio_trailing" | "notional_trailing" | "upnl_trailing" | "upnl_bps_trailing" | undefined;
|
|
1848
|
+
level?: number | undefined;
|
|
1849
|
+
reason?: string | undefined;
|
|
1830
1850
|
} | {
|
|
1831
1851
|
type: "default_trigger";
|
|
1832
1852
|
triggerId: string;
|
|
1833
1853
|
connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
|
|
1854
|
+
metric?: "price" | "ratio" | "weighted_ratio" | "funding_rate" | "prediction_market" | "btc_dominance" | "notional" | "upnl" | "upnl_bps" | "ratio_trailing" | "price_trailing" | "weighted_ratio_trailing" | "notional_trailing" | "upnl_trailing" | "upnl_bps_trailing" | undefined;
|
|
1855
|
+
level?: number | undefined;
|
|
1856
|
+
reason?: string | undefined;
|
|
1857
|
+
} | {
|
|
1858
|
+
type: "attached_trigger_discarded";
|
|
1859
|
+
positionId: string;
|
|
1860
|
+
positionKey: string;
|
|
1861
|
+
connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
|
|
1862
|
+
discarded: {
|
|
1863
|
+
bracketType: "STOP_LOSS" | "TAKE_PROFIT";
|
|
1864
|
+
metric: "price" | "ratio" | "weighted_ratio" | "funding_rate" | "prediction_market" | "btc_dominance" | "notional" | "upnl" | "upnl_bps" | "ratio_trailing" | "price_trailing" | "weighted_ratio_trailing" | "notional_trailing" | "upnl_trailing" | "upnl_bps_trailing";
|
|
1865
|
+
reason: "TRIGGER_LIMIT" | "TRAILING_ALREADY_EXISTS";
|
|
1866
|
+
level?: number | undefined;
|
|
1867
|
+
}[];
|
|
1868
|
+
activeTriggerLimit: number;
|
|
1834
1869
|
};
|
|
1835
1870
|
isRead: boolean;
|
|
1836
1871
|
createdAt: string;
|
|
@@ -1857,12 +1892,16 @@ declare class Core {
|
|
|
1857
1892
|
};
|
|
1858
1893
|
positions: {
|
|
1859
1894
|
list: (query: HttpTypes.PositionListParamsInput, headers?: ClientHeaders) => Promise<{
|
|
1895
|
+
limit: number;
|
|
1896
|
+
nextCursor: string | undefined;
|
|
1860
1897
|
positions: {
|
|
1861
1898
|
id: string;
|
|
1862
1899
|
tradeAccountId: string;
|
|
1863
1900
|
connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
|
|
1864
1901
|
status: "OPEN" | "CLOSED";
|
|
1902
|
+
origin: "PARTIAL" | "PEAR" | "EXTERNAL";
|
|
1865
1903
|
exposure: Record<string, `-${string}` | `+${string}`>;
|
|
1904
|
+
totalFundingPayment: Record<string, `-${string}` | `+${string}`>;
|
|
1866
1905
|
initialExposureUSD: Record<string, `-${string}` | `+${string}`>;
|
|
1867
1906
|
createdAt: string;
|
|
1868
1907
|
updatedAt: string;
|
|
@@ -1874,8 +1913,9 @@ declare class Core {
|
|
|
1874
1913
|
positions: {
|
|
1875
1914
|
id: string;
|
|
1876
1915
|
createdAt: string;
|
|
1877
|
-
exposure: Record<string, string
|
|
1916
|
+
exposure: Record<string, `-${string}` | `+${string}`>;
|
|
1878
1917
|
status: "OPEN";
|
|
1918
|
+
origin: "PARTIAL" | "PEAR" | "EXTERNAL";
|
|
1879
1919
|
connector: "hyperliquid" | "binance" | "bybit" | "okx" | "lighter";
|
|
1880
1920
|
}[];
|
|
1881
1921
|
}>;
|
|
@@ -2058,14 +2098,77 @@ declare class Core {
|
|
|
2058
2098
|
}>;
|
|
2059
2099
|
};
|
|
2060
2100
|
rebalance: {
|
|
2061
|
-
|
|
2101
|
+
manual: (positionId: string, body: HttpTypes.RebalanceManual, headers?: ClientHeaders) => Promise<{
|
|
2062
2102
|
plan: {
|
|
2063
2103
|
outcome: "full_rebalance";
|
|
2064
2104
|
} | {
|
|
2065
|
-
outcome: "partial_rebalance"
|
|
2105
|
+
outcome: "partial_rebalance";
|
|
2106
|
+
messages: [string, ...string[]];
|
|
2107
|
+
} | {
|
|
2108
|
+
outcome: "no_rebalance";
|
|
2109
|
+
messages: [string, ...string[]];
|
|
2110
|
+
} | {
|
|
2111
|
+
outcome: "failed";
|
|
2066
2112
|
messages: [string, ...string[]];
|
|
2067
2113
|
};
|
|
2068
2114
|
}>;
|
|
2115
|
+
auto: {
|
|
2116
|
+
list: (query?: HttpTypes.AutoRebalanceListParamsInput, headers?: ClientHeaders) => Promise<{
|
|
2117
|
+
limit: number;
|
|
2118
|
+
nextCursor: string | undefined;
|
|
2119
|
+
items: {
|
|
2120
|
+
id: string;
|
|
2121
|
+
positionId: string;
|
|
2122
|
+
status: "ACTIVE" | "PAUSED";
|
|
2123
|
+
weightSource: "INITIAL_WEIGHT" | "LIVE_BETA";
|
|
2124
|
+
minimumDriftPct: string;
|
|
2125
|
+
createdAt: string;
|
|
2126
|
+
updatedAt: string;
|
|
2127
|
+
timeframe?: "1d" | "1h" | "4h" | undefined;
|
|
2128
|
+
}[];
|
|
2129
|
+
}>;
|
|
2130
|
+
create: (body: HttpTypes.CreateAutoRebalanceConfig, headers?: ClientHeaders) => Promise<{
|
|
2131
|
+
config: {
|
|
2132
|
+
id: string;
|
|
2133
|
+
positionId: string;
|
|
2134
|
+
status: "ACTIVE" | "PAUSED";
|
|
2135
|
+
weightSource: "INITIAL_WEIGHT" | "LIVE_BETA";
|
|
2136
|
+
minimumDriftPct: string;
|
|
2137
|
+
createdAt: string;
|
|
2138
|
+
updatedAt: string;
|
|
2139
|
+
timeframe?: "1d" | "1h" | "4h" | undefined;
|
|
2140
|
+
};
|
|
2141
|
+
}>;
|
|
2142
|
+
update: (id: string, body: HttpTypes.UpdateAutoRebalanceConfig, headers?: ClientHeaders) => Promise<{
|
|
2143
|
+
config: {
|
|
2144
|
+
id: string;
|
|
2145
|
+
positionId: string;
|
|
2146
|
+
status: "ACTIVE" | "PAUSED";
|
|
2147
|
+
weightSource: "INITIAL_WEIGHT" | "LIVE_BETA";
|
|
2148
|
+
minimumDriftPct: string;
|
|
2149
|
+
createdAt: string;
|
|
2150
|
+
updatedAt: string;
|
|
2151
|
+
timeframe?: "1d" | "1h" | "4h" | undefined;
|
|
2152
|
+
};
|
|
2153
|
+
}>;
|
|
2154
|
+
cancel: (id: string, headers?: ClientHeaders) => Promise<void>;
|
|
2155
|
+
};
|
|
2156
|
+
listEvents: (positionId: string, query?: HttpTypes.RebalanceEventListParamsInput, headers?: ClientHeaders) => Promise<{
|
|
2157
|
+
limit: number;
|
|
2158
|
+
nextCursor: string | undefined;
|
|
2159
|
+
items: {
|
|
2160
|
+
id: string;
|
|
2161
|
+
autoRebalanceConfigId: string;
|
|
2162
|
+
positionId: string;
|
|
2163
|
+
weightSource: "INITIAL_WEIGHT" | "LIVE_BETA";
|
|
2164
|
+
driftPct: string;
|
|
2165
|
+
currentWeights: Record<string, number>;
|
|
2166
|
+
targetWeights: Record<string, number>;
|
|
2167
|
+
status: "FAILED" | "SUCCESS";
|
|
2168
|
+
createdAt: string;
|
|
2169
|
+
error?: string | undefined;
|
|
2170
|
+
}[];
|
|
2171
|
+
}>;
|
|
2069
2172
|
};
|
|
2070
2173
|
savedBaskets: {
|
|
2071
2174
|
list: (headers?: ClientHeaders) => Promise<{
|
|
@@ -2159,6 +2262,7 @@ declare class Core {
|
|
|
2159
2262
|
side: "BUY" | "SELL";
|
|
2160
2263
|
reduceOnly: boolean;
|
|
2161
2264
|
isExternal: boolean;
|
|
2265
|
+
synthetic: boolean;
|
|
2162
2266
|
quantity: string;
|
|
2163
2267
|
price: string;
|
|
2164
2268
|
usd: string;
|
|
@@ -2204,6 +2308,7 @@ declare class Core {
|
|
|
2204
2308
|
side: "BUY" | "SELL";
|
|
2205
2309
|
reduceOnly: boolean;
|
|
2206
2310
|
isExternal: boolean;
|
|
2311
|
+
synthetic: boolean;
|
|
2207
2312
|
quantity: string;
|
|
2208
2313
|
price: string;
|
|
2209
2314
|
usd: string;
|
|
@@ -2254,6 +2359,7 @@ declare class Core {
|
|
|
2254
2359
|
side: "BUY" | "SELL";
|
|
2255
2360
|
reduceOnly: boolean;
|
|
2256
2361
|
isExternal: boolean;
|
|
2362
|
+
synthetic: boolean;
|
|
2257
2363
|
quantity: string;
|
|
2258
2364
|
price: string;
|
|
2259
2365
|
usd: string;
|
|
@@ -2299,6 +2405,7 @@ declare class Core {
|
|
|
2299
2405
|
side: "BUY" | "SELL";
|
|
2300
2406
|
reduceOnly: boolean;
|
|
2301
2407
|
isExternal: boolean;
|
|
2408
|
+
synthetic: boolean;
|
|
2302
2409
|
quantity: string;
|
|
2303
2410
|
price: string;
|
|
2304
2411
|
usd: string;
|
|
@@ -2322,15 +2429,24 @@ declare class Core {
|
|
|
2322
2429
|
}>;
|
|
2323
2430
|
};
|
|
2324
2431
|
sync: {
|
|
2325
|
-
|
|
2326
|
-
since:
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2432
|
+
fills: {
|
|
2433
|
+
since: (body: HttpTypes.SyncFillsSinceRequest, headers?: ClientHeaders) => Promise<{
|
|
2434
|
+
sinceMs: number;
|
|
2435
|
+
neverSynced: boolean;
|
|
2436
|
+
confirmedExchangeFillIds?: string[] | undefined;
|
|
2437
|
+
}>;
|
|
2438
|
+
reconcile: (body: HttpTypes.ReconcileFillsRequest, headers?: ClientHeaders) => Promise<Record<string, never>>;
|
|
2439
|
+
confirm: (body: HttpTypes.ConfirmFillsRequest, headers?: ClientHeaders) => Promise<Record<string, never>>;
|
|
2440
|
+
create: (body: HttpTypes.CreateApplicablesRequest, headers?: ClientHeaders) => Promise<Record<string, never>>;
|
|
2441
|
+
createBulk: (body: HttpTypes.CreateApplicablesRequest, headers?: ClientHeaders) => Promise<Record<string, never>>;
|
|
2442
|
+
};
|
|
2443
|
+
funding: {
|
|
2444
|
+
since: (body: HttpTypes.SyncFundingSinceRequest, headers?: ClientHeaders) => Promise<{
|
|
2445
|
+
sinceMs: number;
|
|
2446
|
+
}>;
|
|
2447
|
+
create: (body: HttpTypes.CreateFundingPaymentsRequest, headers?: ClientHeaders) => Promise<Record<string, never>>;
|
|
2448
|
+
createBulk: (body: HttpTypes.CreateFundingPaymentsRequest, headers?: ClientHeaders) => Promise<Record<string, never>>;
|
|
2449
|
+
};
|
|
2334
2450
|
};
|
|
2335
2451
|
trade: {
|
|
2336
2452
|
open: (body: HttpTypes.CreateTradeOpen, headers?: ClientHeaders) => Promise<{
|
|
@@ -3160,6 +3276,7 @@ declare class Core {
|
|
|
3160
3276
|
side: "BUY" | "SELL";
|
|
3161
3277
|
reduceOnly: boolean;
|
|
3162
3278
|
isExternal: boolean;
|
|
3279
|
+
synthetic: boolean;
|
|
3163
3280
|
quantity: string;
|
|
3164
3281
|
price: string;
|
|
3165
3282
|
usd: string;
|
|
@@ -3292,6 +3409,7 @@ declare class Core {
|
|
|
3292
3409
|
side: "BUY" | "SELL";
|
|
3293
3410
|
reduceOnly: boolean;
|
|
3294
3411
|
isExternal: boolean;
|
|
3412
|
+
synthetic: boolean;
|
|
3295
3413
|
quantity: string;
|
|
3296
3414
|
price: string;
|
|
3297
3415
|
usd: string;
|
|
@@ -3457,6 +3575,7 @@ declare class Core {
|
|
|
3457
3575
|
side: "BUY" | "SELL";
|
|
3458
3576
|
reduceOnly: boolean;
|
|
3459
3577
|
isExternal: boolean;
|
|
3578
|
+
synthetic: boolean;
|
|
3460
3579
|
quantity: string;
|
|
3461
3580
|
price: string;
|
|
3462
3581
|
usd: string;
|
|
@@ -3577,6 +3696,7 @@ declare class Core {
|
|
|
3577
3696
|
side: "BUY" | "SELL";
|
|
3578
3697
|
reduceOnly: boolean;
|
|
3579
3698
|
isExternal: boolean;
|
|
3699
|
+
synthetic: boolean;
|
|
3580
3700
|
quantity: string;
|
|
3581
3701
|
price: string;
|
|
3582
3702
|
usd: string;
|
|
@@ -3709,6 +3829,7 @@ declare class Core {
|
|
|
3709
3829
|
side: "BUY" | "SELL";
|
|
3710
3830
|
reduceOnly: boolean;
|
|
3711
3831
|
isExternal: boolean;
|
|
3832
|
+
synthetic: boolean;
|
|
3712
3833
|
quantity: string;
|
|
3713
3834
|
price: string;
|
|
3714
3835
|
usd: string;
|
|
@@ -3874,6 +3995,7 @@ declare class Core {
|
|
|
3874
3995
|
side: "BUY" | "SELL";
|
|
3875
3996
|
reduceOnly: boolean;
|
|
3876
3997
|
isExternal: boolean;
|
|
3998
|
+
synthetic: boolean;
|
|
3877
3999
|
quantity: string;
|
|
3878
4000
|
price: string;
|
|
3879
4001
|
usd: string;
|
|
@@ -3994,6 +4116,7 @@ declare class Core {
|
|
|
3994
4116
|
side: "BUY" | "SELL";
|
|
3995
4117
|
reduceOnly: boolean;
|
|
3996
4118
|
isExternal: boolean;
|
|
4119
|
+
synthetic: boolean;
|
|
3997
4120
|
quantity: string;
|
|
3998
4121
|
price: string;
|
|
3999
4122
|
usd: string;
|
|
@@ -4126,6 +4249,7 @@ declare class Core {
|
|
|
4126
4249
|
side: "BUY" | "SELL";
|
|
4127
4250
|
reduceOnly: boolean;
|
|
4128
4251
|
isExternal: boolean;
|
|
4252
|
+
synthetic: boolean;
|
|
4129
4253
|
quantity: string;
|
|
4130
4254
|
price: string;
|
|
4131
4255
|
usd: string;
|
|
@@ -4291,6 +4415,7 @@ declare class Core {
|
|
|
4291
4415
|
side: "BUY" | "SELL";
|
|
4292
4416
|
reduceOnly: boolean;
|
|
4293
4417
|
isExternal: boolean;
|
|
4418
|
+
synthetic: boolean;
|
|
4294
4419
|
quantity: string;
|
|
4295
4420
|
price: string;
|
|
4296
4421
|
usd: string;
|
|
@@ -4386,6 +4511,14 @@ declare class Core {
|
|
|
4386
4511
|
openPositions: number;
|
|
4387
4512
|
}[];
|
|
4388
4513
|
}>;
|
|
4514
|
+
totals: (query: HttpTypes.StatisticsTotalsQueryParamsInput, headers?: ClientHeaders) => Promise<{
|
|
4515
|
+
data: {
|
|
4516
|
+
totalVolume: number;
|
|
4517
|
+
totalFees: number;
|
|
4518
|
+
totalTrades: number;
|
|
4519
|
+
totalUsers: number;
|
|
4520
|
+
};
|
|
4521
|
+
}>;
|
|
4389
4522
|
};
|
|
4390
4523
|
tca: {
|
|
4391
4524
|
execution: (executionId: string, headers?: ClientHeaders) => Promise<{
|
package/dist/core/index.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { gzipJson } from '../utils';
|
|
2
|
+
|
|
1
3
|
class Core {
|
|
2
4
|
client;
|
|
3
5
|
clientId;
|
|
@@ -245,12 +247,48 @@ class Core {
|
|
|
245
247
|
}
|
|
246
248
|
};
|
|
247
249
|
rebalance = {
|
|
248
|
-
|
|
249
|
-
return await this.client.fetch(`/rebalance/
|
|
250
|
+
manual: async (positionId, body, headers) => {
|
|
251
|
+
return await this.client.fetch(`/rebalance/manual/${positionId}`, {
|
|
250
252
|
method: "POST",
|
|
251
253
|
headers,
|
|
252
254
|
body: this.withClientId(body)
|
|
253
255
|
});
|
|
256
|
+
},
|
|
257
|
+
auto: {
|
|
258
|
+
list: async (query, headers) => {
|
|
259
|
+
return await this.client.fetch(`/rebalance/auto`, {
|
|
260
|
+
method: "GET",
|
|
261
|
+
headers,
|
|
262
|
+
query
|
|
263
|
+
});
|
|
264
|
+
},
|
|
265
|
+
create: async (body, headers) => {
|
|
266
|
+
return await this.client.fetch(`/rebalance/auto`, {
|
|
267
|
+
method: "POST",
|
|
268
|
+
headers,
|
|
269
|
+
body
|
|
270
|
+
});
|
|
271
|
+
},
|
|
272
|
+
update: async (id, body, headers) => {
|
|
273
|
+
return await this.client.fetch(`/rebalance/auto/${id}`, {
|
|
274
|
+
method: "PATCH",
|
|
275
|
+
headers,
|
|
276
|
+
body
|
|
277
|
+
});
|
|
278
|
+
},
|
|
279
|
+
cancel: async (id, headers) => {
|
|
280
|
+
return await this.client.fetch(`/rebalance/auto/${id}/cancel`, {
|
|
281
|
+
method: "POST",
|
|
282
|
+
headers
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
listEvents: async (positionId, query, headers) => {
|
|
287
|
+
return await this.client.fetch(`/rebalance/${positionId}/events`, {
|
|
288
|
+
method: "GET",
|
|
289
|
+
headers,
|
|
290
|
+
query
|
|
291
|
+
});
|
|
254
292
|
}
|
|
255
293
|
};
|
|
256
294
|
savedBaskets = {
|
|
@@ -310,33 +348,71 @@ class Core {
|
|
|
310
348
|
}
|
|
311
349
|
};
|
|
312
350
|
sync = {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
351
|
+
fills: {
|
|
352
|
+
since: async (body, headers) => {
|
|
353
|
+
return await this.client.fetch(`/sync/fills/since`, {
|
|
354
|
+
method: "POST",
|
|
355
|
+
headers,
|
|
356
|
+
body
|
|
357
|
+
});
|
|
358
|
+
},
|
|
359
|
+
reconcile: async (body, headers) => {
|
|
360
|
+
return await this.client.fetch(`/sync/fills/reconcile`, {
|
|
361
|
+
method: "POST",
|
|
362
|
+
headers,
|
|
363
|
+
body
|
|
364
|
+
});
|
|
365
|
+
},
|
|
366
|
+
confirm: async (body, headers) => {
|
|
367
|
+
return await this.client.fetch(`/sync/fills/confirm`, {
|
|
368
|
+
method: "POST",
|
|
369
|
+
headers,
|
|
370
|
+
body
|
|
371
|
+
});
|
|
372
|
+
},
|
|
373
|
+
create: async (body, headers) => {
|
|
374
|
+
return await this.client.fetch(`/sync/fills/create`, {
|
|
375
|
+
method: "POST",
|
|
376
|
+
headers,
|
|
377
|
+
body
|
|
378
|
+
});
|
|
379
|
+
},
|
|
380
|
+
createBulk: async (body, headers) => {
|
|
381
|
+
const file = await gzipJson(body);
|
|
382
|
+
const formData = new FormData();
|
|
383
|
+
formData.append("file", file, "payload.json.gz");
|
|
384
|
+
return await this.client.fetch(`/sync/fills/create/bulk`, {
|
|
385
|
+
method: "POST",
|
|
386
|
+
headers: { ...headers, "content-type": null },
|
|
387
|
+
body: formData
|
|
388
|
+
});
|
|
389
|
+
}
|
|
333
390
|
},
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
391
|
+
funding: {
|
|
392
|
+
since: async (body, headers) => {
|
|
393
|
+
return await this.client.fetch(`/sync/funding/since`, {
|
|
394
|
+
method: "POST",
|
|
395
|
+
headers,
|
|
396
|
+
body
|
|
397
|
+
});
|
|
398
|
+
},
|
|
399
|
+
create: async (body, headers) => {
|
|
400
|
+
return await this.client.fetch(`/sync/funding/create`, {
|
|
401
|
+
method: "POST",
|
|
402
|
+
headers,
|
|
403
|
+
body
|
|
404
|
+
});
|
|
405
|
+
},
|
|
406
|
+
createBulk: async (body, headers) => {
|
|
407
|
+
const file = await gzipJson(body);
|
|
408
|
+
const formData = new FormData();
|
|
409
|
+
formData.append("file", file, "payload.json.gz");
|
|
410
|
+
return await this.client.fetch(`/sync/funding/create/bulk`, {
|
|
411
|
+
method: "POST",
|
|
412
|
+
headers: { ...headers, "content-type": null },
|
|
413
|
+
body: formData
|
|
414
|
+
});
|
|
415
|
+
}
|
|
340
416
|
}
|
|
341
417
|
};
|
|
342
418
|
trade = {
|
|
@@ -499,6 +575,13 @@ class Core {
|
|
|
499
575
|
headers,
|
|
500
576
|
query
|
|
501
577
|
});
|
|
578
|
+
},
|
|
579
|
+
totals: async (query, headers) => {
|
|
580
|
+
return await this.client.fetch(`/statistics/totals`, {
|
|
581
|
+
method: "GET",
|
|
582
|
+
headers,
|
|
583
|
+
query
|
|
584
|
+
});
|
|
502
585
|
}
|
|
503
586
|
};
|
|
504
587
|
tca = {
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,28 @@ import { HttpClient } from './http';
|
|
|
7
7
|
import { FetchError } from './utils';
|
|
8
8
|
export * from '@pear-protocol/utils';
|
|
9
9
|
|
|
10
|
+
const SESSION_REFRESH_PATH = "/auth/session/refresh";
|
|
11
|
+
const SESSION_REFRESH_TIMEOUT_MS = 15e3;
|
|
12
|
+
const isSessionRefreshRequest = (request) => {
|
|
13
|
+
try {
|
|
14
|
+
return new URL(request.url).pathname.includes(SESSION_REFRESH_PATH);
|
|
15
|
+
} catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
const withTimeout = async (promise, ms, label) => {
|
|
20
|
+
let timer;
|
|
21
|
+
try {
|
|
22
|
+
return await Promise.race([
|
|
23
|
+
promise,
|
|
24
|
+
new Promise((_, reject) => {
|
|
25
|
+
timer = setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), ms);
|
|
26
|
+
})
|
|
27
|
+
]);
|
|
28
|
+
} finally {
|
|
29
|
+
clearTimeout(timer);
|
|
30
|
+
}
|
|
31
|
+
};
|
|
10
32
|
class PearSDK {
|
|
11
33
|
admin;
|
|
12
34
|
auth;
|
|
@@ -31,7 +53,7 @@ class PearSDK {
|
|
|
31
53
|
const refreshSession = async () => {
|
|
32
54
|
if (!refreshInFlight) {
|
|
33
55
|
logger.info("[session-refresh] Refreshing session...");
|
|
34
|
-
refreshInFlight = this.auth.refreshSession().then(() => logger.info("[session-refresh] Session refreshed successfully")).catch((err) => {
|
|
56
|
+
refreshInFlight = withTimeout(this.auth.refreshSession(), SESSION_REFRESH_TIMEOUT_MS, "Session refresh").then(() => logger.info("[session-refresh] Session refreshed successfully")).catch((err) => {
|
|
35
57
|
logger.error("[session-refresh] Refresh failed:", String(err));
|
|
36
58
|
throw err;
|
|
37
59
|
}).finally(() => {
|
|
@@ -42,18 +64,25 @@ class PearSDK {
|
|
|
42
64
|
}
|
|
43
65
|
return refreshInFlight;
|
|
44
66
|
};
|
|
67
|
+
const expire = (reason) => {
|
|
68
|
+
logger.error(`[session-refresh] ${reason}`);
|
|
69
|
+
config.onSessionExpired?.();
|
|
70
|
+
throw new FetchError("Session expired. Please log in again.", "Unauthorized", 401);
|
|
71
|
+
};
|
|
72
|
+
const alreadyRetried = /* @__PURE__ */ new WeakSet();
|
|
45
73
|
const sessionRefreshMiddleware = async (response, retry, request) => {
|
|
46
74
|
if (response.status !== 401) return response;
|
|
75
|
+
if (isSessionRefreshRequest(request)) return response;
|
|
47
76
|
logger.warn(`[session-refresh] 401 received for ${request.method} ${request.url}`);
|
|
77
|
+
if (alreadyRetried.has(request)) return expire("Still 401 after refresh, giving up");
|
|
48
78
|
try {
|
|
49
79
|
await refreshSession();
|
|
50
|
-
logger.info(`[session-refresh] Retrying ${request.method} ${request.url}`);
|
|
51
|
-
return retry();
|
|
52
80
|
} catch {
|
|
53
|
-
|
|
54
|
-
config.onSessionExpired?.();
|
|
55
|
-
throw new FetchError("Session expired. Please log in again.", "Unauthorized", 401);
|
|
81
|
+
return expire("Session expired, cannot recover");
|
|
56
82
|
}
|
|
83
|
+
alreadyRetried.add(request);
|
|
84
|
+
logger.info(`[session-refresh] Retrying ${request.method} ${request.url}`);
|
|
85
|
+
return retry();
|
|
57
86
|
};
|
|
58
87
|
client.useResponse(sessionRefreshMiddleware);
|
|
59
88
|
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { describe, afterEach, vi, it, expect } from 'vitest';
|
|
2
|
+
import PearSDK from './index';
|
|
3
|
+
|
|
4
|
+
const json = (status, body = {}) => {
|
|
5
|
+
return new Response(JSON.stringify(body), {
|
|
6
|
+
status,
|
|
7
|
+
headers: { "content-type": "application/json" }
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
const silentLogger = {
|
|
11
|
+
error: () => {
|
|
12
|
+
},
|
|
13
|
+
warn: () => {
|
|
14
|
+
},
|
|
15
|
+
info: () => {
|
|
16
|
+
},
|
|
17
|
+
debug: () => {
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
const setup = (routes) => {
|
|
21
|
+
const calls = [];
|
|
22
|
+
const fetchMock = vi.fn(async (input) => {
|
|
23
|
+
const key = `${input.method} ${new URL(input.url).pathname}`;
|
|
24
|
+
calls.push(key);
|
|
25
|
+
const queue = routes[key];
|
|
26
|
+
if (!queue || queue.length === 0) {
|
|
27
|
+
throw new Error(`unexpected request: ${key}`);
|
|
28
|
+
}
|
|
29
|
+
const responder = queue.length > 1 ? queue.shift() : queue[0];
|
|
30
|
+
return responder();
|
|
31
|
+
});
|
|
32
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
33
|
+
const onSessionExpired = vi.fn();
|
|
34
|
+
const sdk = new PearSDK({
|
|
35
|
+
url: "https://gateway.test",
|
|
36
|
+
auth: { type: "session" },
|
|
37
|
+
onSessionExpired,
|
|
38
|
+
logger: silentLogger
|
|
39
|
+
});
|
|
40
|
+
return { sdk, onSessionExpired, calls };
|
|
41
|
+
};
|
|
42
|
+
describe("session-refresh middleware", () => {
|
|
43
|
+
afterEach(() => {
|
|
44
|
+
vi.unstubAllGlobals();
|
|
45
|
+
vi.useRealTimers();
|
|
46
|
+
vi.restoreAllMocks();
|
|
47
|
+
});
|
|
48
|
+
it("rejects (never hangs) when the refresh endpoint itself 401s on a dead cookie", async () => {
|
|
49
|
+
const { sdk, onSessionExpired, calls } = setup({
|
|
50
|
+
"GET /positions": [() => json(401, { message: "unauthorized" })],
|
|
51
|
+
"POST /auth/session/refresh": [() => json(401, { message: "refresh failed" })]
|
|
52
|
+
});
|
|
53
|
+
await expect(sdk.core.positions.list({})).rejects.toMatchObject({ status: 401 });
|
|
54
|
+
expect(onSessionExpired).toHaveBeenCalledTimes(1);
|
|
55
|
+
expect(calls).toEqual(["GET /positions", "POST /auth/session/refresh"]);
|
|
56
|
+
});
|
|
57
|
+
it("gives up after a single retry when the request still 401s after a successful refresh", async () => {
|
|
58
|
+
const { sdk, onSessionExpired, calls } = setup({
|
|
59
|
+
"GET /positions": [() => json(401)],
|
|
60
|
+
"POST /auth/session/refresh": [() => json(200)]
|
|
61
|
+
});
|
|
62
|
+
await expect(sdk.core.positions.list({})).rejects.toMatchObject({ status: 401 });
|
|
63
|
+
expect(calls.filter((call) => call === "GET /positions")).toHaveLength(2);
|
|
64
|
+
expect(calls.filter((call) => call === "POST /auth/session/refresh")).toHaveLength(1);
|
|
65
|
+
expect(onSessionExpired).toHaveBeenCalledTimes(1);
|
|
66
|
+
});
|
|
67
|
+
it("transparently refreshes and retries the original request on a recoverable 401", async () => {
|
|
68
|
+
const { sdk, onSessionExpired, calls } = setup({
|
|
69
|
+
"GET /positions": [() => json(401), () => json(200, { positions: ["ok"] })],
|
|
70
|
+
"POST /auth/session/refresh": [() => json(200)]
|
|
71
|
+
});
|
|
72
|
+
await expect(sdk.core.positions.list({})).resolves.toMatchObject({ positions: ["ok"] });
|
|
73
|
+
expect(onSessionExpired).not.toHaveBeenCalled();
|
|
74
|
+
expect(calls).toEqual(["GET /positions", "POST /auth/session/refresh", "GET /positions"]);
|
|
75
|
+
});
|
|
76
|
+
it("caps a stalled refresh at the timeout instead of wedging the queue", async () => {
|
|
77
|
+
vi.useFakeTimers();
|
|
78
|
+
const { sdk, onSessionExpired } = setup({
|
|
79
|
+
"GET /positions": [() => json(401)],
|
|
80
|
+
"POST /auth/session/refresh": [() => new Promise(() => {
|
|
81
|
+
})]
|
|
82
|
+
});
|
|
83
|
+
const settled = expect(sdk.core.positions.list({})).rejects.toMatchObject({ status: 401 });
|
|
84
|
+
await vi.advanceTimersByTimeAsync(15e3);
|
|
85
|
+
await settled;
|
|
86
|
+
expect(onSessionExpired).toHaveBeenCalledTimes(1);
|
|
87
|
+
});
|
|
88
|
+
});
|
package/dist/types.d.ts
CHANGED
|
@@ -111,6 +111,6 @@ type FetchArgs = Omit<RequestInit, 'headers' | 'body'> & {
|
|
|
111
111
|
};
|
|
112
112
|
type RequestMiddleware = (request: Request, next: () => Promise<Response>) => Promise<Response>;
|
|
113
113
|
type ResponseMiddleware = (response: Response, retry: () => Promise<Response>, request: Request) => Promise<Response>;
|
|
114
|
-
type ClientIdBody = HttpTypes.
|
|
114
|
+
type ClientIdBody = HttpTypes.RebalanceManual | HttpTypes.CreateSchedule | HttpTypes.CreateTradeOpen | HttpTypes.CreateTradeAdjust | HttpTypes.CreateTradeClose | HttpTypes.CreateTradeCloseAll | HttpTypes.CreateTriggerOpen | HttpTypes.CreateTriggerClose;
|
|
115
115
|
|
|
116
116
|
export type { AuthMode, ClientHeaders, ClientIdBody, FetchArgs, FetchInput, FetchParams, Logger, RequestMiddleware, ResponseMiddleware, SDKConfig };
|
package/dist/utils.d.ts
CHANGED
|
@@ -9,5 +9,6 @@ declare class FetchError extends Error {
|
|
|
9
9
|
statusText: string | undefined;
|
|
10
10
|
constructor(message: string, statusText?: string, status?: number);
|
|
11
11
|
}
|
|
12
|
+
declare function gzipJson(value: unknown): Promise<Blob>;
|
|
12
13
|
|
|
13
|
-
export { FetchError, getBaseUrl, normalizeRequest, normalizeResponseData };
|
|
14
|
+
export { FetchError, getBaseUrl, gzipJson, normalizeRequest, normalizeResponseData };
|
package/dist/utils.js
CHANGED
|
@@ -44,5 +44,9 @@ class FetchError extends Error {
|
|
|
44
44
|
this.status = status;
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
|
+
async function gzipJson(value) {
|
|
48
|
+
const stream = new Blob([JSON.stringify(value)]).stream().pipeThrough(new CompressionStream("gzip"));
|
|
49
|
+
return await new Response(stream).blob();
|
|
50
|
+
}
|
|
47
51
|
|
|
48
|
-
export { FetchError, getBaseUrl, normalizeRequest, normalizeResponseData };
|
|
52
|
+
export { FetchError, getBaseUrl, gzipJson, normalizeRequest, normalizeResponseData };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pear-protocol/core-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "Pear Protocol Core SDK",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -22,17 +22,20 @@
|
|
|
22
22
|
"scripts": {
|
|
23
23
|
"build": "tsup",
|
|
24
24
|
"clean": "rm -rf dist .turbo",
|
|
25
|
+
"test": "vitest run",
|
|
26
|
+
"test:watch": "vitest",
|
|
25
27
|
"typecheck": "tsc --noEmit"
|
|
26
28
|
},
|
|
27
29
|
"dependencies": {
|
|
28
|
-
"@pear-protocol/types": "^1.
|
|
29
|
-
"@pear-protocol/utils": "^0.0
|
|
30
|
+
"@pear-protocol/types": "^1.8.0",
|
|
31
|
+
"@pear-protocol/utils": "^0.1.0",
|
|
30
32
|
"qs": "^6.14.0"
|
|
31
33
|
},
|
|
32
34
|
"devDependencies": {
|
|
33
35
|
"@backend/typescript-config": "workspace:*",
|
|
34
36
|
"@types/qs": "^6.14.0",
|
|
35
37
|
"tsup": "8.5.1",
|
|
36
|
-
"typescript": "5.9.3"
|
|
38
|
+
"typescript": "5.9.3",
|
|
39
|
+
"vitest": "4.1.2"
|
|
37
40
|
}
|
|
38
41
|
}
|