perp-cli 0.14.3 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (363) hide show
  1. package/README.ja.md +243 -0
  2. package/README.ko.md +243 -0
  3. package/README.md +138 -405
  4. package/README.zh.md +243 -0
  5. package/dist/agent-wallet/store.d.ts +3 -2
  6. package/dist/agent-wallet/store.js +2 -2
  7. package/dist/api/public/hyperliquid.js +4 -0
  8. package/dist/api/public/lighter.d.ts +5 -0
  9. package/dist/api/public/lighter.js +5 -0
  10. package/dist/api/public/pacifica.js +85 -15
  11. package/dist/api/public/urls.d.ts +2 -0
  12. package/dist/api/public/urls.js +3 -0
  13. package/dist/arb/sizing.js +4 -2
  14. package/dist/arb/state.d.ts +6 -0
  15. package/dist/arb/utils.d.ts +1 -2
  16. package/dist/arb/utils.js +1 -2
  17. package/dist/balance-by-address.d.ts +39 -0
  18. package/dist/balance-by-address.js +44 -0
  19. package/dist/bot/apex/pulse.js +3 -0
  20. package/dist/bot/apex/radar.js +2 -1
  21. package/dist/bot/engine.d.ts +10 -1
  22. package/dist/bot/engine.js +14 -6
  23. package/dist/bot/indicators.d.ts +7 -0
  24. package/dist/bot/indicators.js +16 -0
  25. package/dist/bot/perp-order.d.ts +4 -4
  26. package/dist/bot/perp-order.js +5 -5
  27. package/dist/bot/quarantine.d.ts +1 -1
  28. package/dist/bot/quarantine.js +1 -1
  29. package/dist/bot/quote-rules.js +1 -1
  30. package/dist/bot/strategies/apex-strategy.js +3 -2
  31. package/dist/bot/strategies/engine-mm.js +6 -5
  32. package/dist/bot/strategies/funding-arb-strategy.js +12 -5
  33. package/dist/bot/strategies/funding-arb-utils.d.ts +15 -3
  34. package/dist/bot/strategies/funding-arb-utils.js +53 -20
  35. package/dist/bot/strategies/funding-auto.js +2 -2
  36. package/dist/bot/strategies/liquidation-mm.d.ts +1 -0
  37. package/dist/bot/strategies/liquidation-mm.js +8 -2
  38. package/dist/bot/strategies/momentum-breakout.d.ts +1 -0
  39. package/dist/bot/strategies/momentum-breakout.js +11 -3
  40. package/dist/bot/strategies/spot-perp-arb-strategy.d.ts +1 -1
  41. package/dist/bot/strategies/spot-perp-arb-strategy.js +6 -4
  42. package/dist/bot/strategies/spot-perp-executor.d.ts +1 -1
  43. package/dist/bot/strategies/spot-perp-executor.js +3 -3
  44. package/dist/bot/strategy-types.d.ts +2 -1
  45. package/dist/bot/tui/BotDashboard.d.ts +1 -1
  46. package/dist/bot/tui/BotDashboard.js +1 -1
  47. package/dist/cache.js +12 -6
  48. package/dist/cli-program.d.ts +15 -0
  49. package/dist/cli-program.js +126 -6
  50. package/dist/commands/account.js +168 -24
  51. package/dist/commands/agent-import.d.ts +7 -0
  52. package/dist/commands/agent-import.js +30 -1
  53. package/dist/commands/agent.d.ts +6 -3
  54. package/dist/commands/agent.js +160 -12
  55. package/dist/commands/arb/index.js +23 -81
  56. package/dist/commands/arb-auto.d.ts +24 -0
  57. package/dist/commands/arb-auto.js +175 -97
  58. package/dist/commands/arb.d.ts +20 -0
  59. package/dist/commands/arb.js +107 -163
  60. package/dist/commands/backtest.js +23 -21
  61. package/dist/commands/bot.js +1 -1
  62. package/dist/commands/builder.js +1 -1
  63. package/dist/commands/funds.js +113 -3
  64. package/dist/commands/init.d.ts +1 -1
  65. package/dist/commands/init.js +27 -7
  66. package/dist/commands/manage.js +23 -21
  67. package/dist/commands/market.d.ts +48 -0
  68. package/dist/commands/market.js +395 -100
  69. package/dist/commands/options.d.ts +14 -0
  70. package/dist/commands/options.js +151 -0
  71. package/dist/commands/pacifica-earn.d.ts +5 -0
  72. package/dist/commands/pacifica-earn.js +455 -0
  73. package/dist/commands/pacifica-orders.d.ts +14 -0
  74. package/dist/commands/pacifica-orders.js +142 -0
  75. package/dist/commands/portfolio.d.ts +16 -0
  76. package/dist/commands/portfolio.js +83 -55
  77. package/dist/commands/rebalance.d.ts +1 -0
  78. package/dist/commands/rebalance.js +15 -0
  79. package/dist/commands/risk.d.ts +11 -2
  80. package/dist/commands/risk.js +39 -44
  81. package/dist/commands/trade.d.ts +1 -0
  82. package/dist/commands/trade.js +67 -62
  83. package/dist/commands/wallet.js +1 -1
  84. package/dist/config.d.ts +2 -2
  85. package/dist/config.js +15 -4
  86. package/dist/constants.js +6 -0
  87. package/dist/cross-chain-margin.d.ts +3 -1
  88. package/dist/cross-chain-margin.js +4 -2
  89. package/dist/dashboard/server.js +3 -3
  90. package/dist/dashboard/ui.js +9 -6
  91. package/dist/errors.d.ts +29 -1
  92. package/dist/errors.js +35 -3
  93. package/dist/exchanges/address.d.ts +8 -0
  94. package/dist/exchanges/address.js +47 -0
  95. package/dist/exchanges/arcus/adapter.d.ts +16 -12
  96. package/dist/exchanges/arcus/adapter.js +45 -18
  97. package/dist/exchanges/arcus/agent.d.ts +1 -1
  98. package/dist/exchanges/arcus/agent.js +1 -1
  99. package/dist/exchanges/arcus/client.js +1 -1
  100. package/dist/exchanges/arcus/public.js +3 -2
  101. package/dist/exchanges/arcus/signing.d.ts +2 -3
  102. package/dist/exchanges/arcus/signing.js +1 -1
  103. package/dist/exchanges/arcus/spot-chain.d.ts +1 -1
  104. package/dist/exchanges/arcus/spot-chain.js +1 -1
  105. package/dist/exchanges/arcus/spot-router.d.ts +1 -1
  106. package/dist/exchanges/arcus/spot-router.js +2 -2
  107. package/dist/exchanges/arcus/spot.d.ts +2 -3
  108. package/dist/exchanges/arcus/spot.js +2 -3
  109. package/dist/exchanges/aster-spot.d.ts +3 -3
  110. package/dist/exchanges/aster-spot.js +6 -9
  111. package/dist/exchanges/aster-typed-data.d.ts +1 -1
  112. package/dist/exchanges/aster-typed-data.js +1 -1
  113. package/dist/exchanges/aster.d.ts +30 -10
  114. package/dist/exchanges/aster.js +153 -53
  115. package/dist/exchanges/builder-fee.d.ts +1 -1
  116. package/dist/exchanges/builder-fee.js +13 -2
  117. package/dist/exchanges/canonical-symbols.d.ts +8 -2
  118. package/dist/exchanges/canonical-symbols.js +46 -2
  119. package/dist/exchanges/capabilities.d.ts +2 -0
  120. package/dist/exchanges/capabilities.js +2 -1
  121. package/dist/exchanges/derive/client.d.ts +37 -0
  122. package/dist/exchanges/derive/client.js +135 -0
  123. package/dist/exchanges/derive/options.d.ts +73 -0
  124. package/dist/exchanges/derive/options.js +379 -0
  125. package/dist/exchanges/extended/adapter.d.ts +96 -0
  126. package/dist/exchanges/extended/adapter.js +241 -0
  127. package/dist/exchanges/extended/client.d.ts +38 -0
  128. package/dist/exchanges/extended/client.js +88 -0
  129. package/dist/exchanges/extended/public.d.ts +133 -0
  130. package/dist/exchanges/extended/public.js +436 -0
  131. package/dist/exchanges/grvt/adapter.d.ts +100 -0
  132. package/dist/exchanges/grvt/adapter.js +283 -0
  133. package/dist/exchanges/grvt/client.d.ts +25 -0
  134. package/dist/exchanges/grvt/client.js +86 -0
  135. package/dist/exchanges/grvt/public.d.ts +151 -0
  136. package/dist/exchanges/grvt/public.js +438 -0
  137. package/dist/exchanges/hyperliquid-outcome.d.ts +2 -0
  138. package/dist/exchanges/hyperliquid-outcome.js +29 -1
  139. package/dist/exchanges/hyperliquid-spot.d.ts +9 -1
  140. package/dist/exchanges/hyperliquid-spot.js +24 -16
  141. package/dist/exchanges/hyperliquid.d.ts +199 -22
  142. package/dist/exchanges/hyperliquid.js +550 -202
  143. package/dist/exchanges/index.d.ts +1 -1
  144. package/dist/exchanges/index.js +1 -1
  145. package/dist/exchanges/interface.d.ts +157 -13
  146. package/dist/exchanges/interface.js +47 -0
  147. package/dist/exchanges/ioc-outcome.d.ts +1 -1
  148. package/dist/exchanges/ioc-outcome.js +1 -1
  149. package/dist/exchanges/legacy-trading-v2.d.ts +2 -2
  150. package/dist/exchanges/legacy-trading-v2.js +7 -2
  151. package/dist/exchanges/lighter-public.d.ts +67 -12
  152. package/dist/exchanges/lighter-public.js +250 -82
  153. package/dist/exchanges/lighter-signer.d.ts +1 -1
  154. package/dist/exchanges/lighter-signer.js +1 -1
  155. package/dist/exchanges/lighter-spot.d.ts +10 -5
  156. package/dist/exchanges/lighter-spot.js +105 -97
  157. package/dist/exchanges/lighter.d.ts +80 -21
  158. package/dist/exchanges/lighter.js +312 -105
  159. package/dist/exchanges/ondo/adapter.d.ts +38 -13
  160. package/dist/exchanges/ondo/adapter.js +86 -27
  161. package/dist/exchanges/ondo/agent.d.ts +1 -1
  162. package/dist/exchanges/ondo/agent.js +1 -1
  163. package/dist/exchanges/ondo/client.d.ts +1 -1
  164. package/dist/exchanges/ondo/client.js +2 -2
  165. package/dist/exchanges/ondo/public.d.ts +35 -3
  166. package/dist/exchanges/ondo/public.js +75 -32
  167. package/dist/exchanges/ondo/spot.d.ts +2 -2
  168. package/dist/exchanges/ondo/spot.js +3 -3
  169. package/dist/exchanges/options-interface.d.ts +158 -0
  170. package/dist/exchanges/options-interface.js +17 -0
  171. package/dist/exchanges/options-venues.d.ts +12 -0
  172. package/dist/exchanges/options-venues.js +35 -0
  173. package/dist/exchanges/outcome-interface.d.ts +4 -0
  174. package/dist/exchanges/pacifica-atomic.d.ts +211 -0
  175. package/dist/exchanges/pacifica-atomic.js +440 -0
  176. package/dist/exchanges/pacifica-decimal.d.ts +10 -0
  177. package/dist/exchanges/pacifica-decimal.js +51 -0
  178. package/dist/exchanges/pacifica-presigned.d.ts +53 -0
  179. package/dist/exchanges/pacifica-presigned.js +141 -0
  180. package/dist/exchanges/pacifica-print.d.ts +200 -0
  181. package/dist/exchanges/pacifica-print.js +417 -0
  182. package/dist/exchanges/pacifica-spot.d.ts +8 -2
  183. package/dist/exchanges/pacifica-spot.js +26 -18
  184. package/dist/exchanges/pacifica-typed-data.d.ts +1 -1
  185. package/dist/exchanges/pacifica-typed-data.js +1 -1
  186. package/dist/exchanges/pacifica-vaults.d.ts +130 -0
  187. package/dist/exchanges/pacifica-vaults.js +277 -0
  188. package/dist/exchanges/pacifica.d.ts +108 -10
  189. package/dist/exchanges/pacifica.js +428 -171
  190. package/dist/exchanges/precision.d.ts +3 -1
  191. package/dist/exchanges/precision.js +9 -2
  192. package/dist/exchanges/public-balances.d.ts +25 -0
  193. package/dist/exchanges/public-balances.js +158 -0
  194. package/dist/exchanges/public-positions.d.ts +43 -0
  195. package/dist/exchanges/public-positions.js +154 -0
  196. package/dist/exchanges/qfex/adapter.d.ts +69 -13
  197. package/dist/exchanges/qfex/adapter.js +102 -17
  198. package/dist/exchanges/qfex/agent.d.ts +1 -1
  199. package/dist/exchanges/qfex/agent.js +1 -1
  200. package/dist/exchanges/qfex/client.d.ts +1 -1
  201. package/dist/exchanges/qfex/client.js +1 -1
  202. package/dist/exchanges/qfex/errors.d.ts +1 -1
  203. package/dist/exchanges/qfex/errors.js +2 -2
  204. package/dist/exchanges/qfex/public.d.ts +65 -12
  205. package/dist/exchanges/qfex/public.js +131 -25
  206. package/dist/exchanges/qfex/signing.d.ts +2 -2
  207. package/dist/exchanges/qfex/signing.js +4 -5
  208. package/dist/exchanges/qfex/ws-transport.d.ts +3 -3
  209. package/dist/exchanges/qfex/ws-transport.js +3 -3
  210. package/dist/exchanges/rate-limiter.d.ts +1 -1
  211. package/dist/exchanges/rate-limiter.js +5 -2
  212. package/dist/exchanges/registry.d.ts +1 -1
  213. package/dist/exchanges/registry.js +1 -1
  214. package/dist/exchanges/risex/adapter.d.ts +160 -0
  215. package/dist/exchanges/risex/adapter.js +842 -0
  216. package/dist/exchanges/risex/agent.d.ts +154 -0
  217. package/dist/exchanges/risex/agent.js +384 -0
  218. package/dist/exchanges/risex/client.d.ts +47 -0
  219. package/dist/exchanges/risex/client.js +174 -0
  220. package/dist/exchanges/risex/nonce.d.ts +43 -0
  221. package/dist/exchanges/risex/nonce.js +212 -0
  222. package/dist/exchanges/risex/public.d.ts +64 -0
  223. package/dist/exchanges/risex/public.js +150 -0
  224. package/dist/exchanges/risex/session.d.ts +71 -0
  225. package/dist/exchanges/risex/session.js +171 -0
  226. package/dist/exchanges/risex/typed-data.d.ts +173 -0
  227. package/dist/exchanges/risex/typed-data.js +240 -0
  228. package/dist/exchanges/risex/units.d.ts +29 -0
  229. package/dist/exchanges/risex/units.js +104 -0
  230. package/dist/exchanges/slippage.d.ts +1 -1
  231. package/dist/exchanges/slippage.js +1 -1
  232. package/dist/exchanges/spot-factory.d.ts +3 -3
  233. package/dist/exchanges/spot-factory.js +8 -8
  234. package/dist/exchanges/spot-interface.d.ts +5 -5
  235. package/dist/exchanges/spot-interface.js +2 -2
  236. package/dist/exchanges/spot-result.d.ts +3 -3
  237. package/dist/exchanges/spot-result.js +3 -3
  238. package/dist/exchanges/trading-v2.d.ts +3 -3
  239. package/dist/exchanges/trading-v2.js +9 -6
  240. package/dist/exchanges/txflow/adapter.d.ts +61 -0
  241. package/dist/exchanges/txflow/adapter.js +150 -0
  242. package/dist/exchanges/txflow/client.d.ts +47 -0
  243. package/dist/exchanges/txflow/client.js +155 -0
  244. package/dist/exchanges/txflow/public.d.ts +87 -0
  245. package/dist/exchanges/txflow/public.js +355 -0
  246. package/dist/exchanges/unknown-symbol.d.ts +34 -0
  247. package/dist/exchanges/unknown-symbol.js +56 -0
  248. package/dist/exchanges/variational/adapter.d.ts +67 -0
  249. package/dist/exchanges/variational/adapter.js +137 -0
  250. package/dist/exchanges/variational/client.d.ts +21 -0
  251. package/dist/exchanges/variational/client.js +66 -0
  252. package/dist/exchanges/variational/public.d.ts +126 -0
  253. package/dist/exchanges/variational/public.js +430 -0
  254. package/dist/exchanges/venue-types.d.ts +52 -10
  255. package/dist/exchanges/venue-types.js +82 -11
  256. package/dist/exchanges/venue.d.ts +150 -11
  257. package/dist/exchanges/venue.js +126 -4
  258. package/dist/exchanges/venues/arcus.d.ts +1 -2
  259. package/dist/exchanges/venues/arcus.js +5 -4
  260. package/dist/exchanges/venues/aster.d.ts +2 -2
  261. package/dist/exchanges/venues/aster.js +6 -4
  262. package/dist/exchanges/venues/create-helpers.d.ts +1 -1
  263. package/dist/exchanges/venues/create-helpers.js +3 -3
  264. package/dist/exchanges/venues/extended.d.ts +21 -0
  265. package/dist/exchanges/venues/extended.js +96 -0
  266. package/dist/exchanges/venues/grvt.d.ts +30 -0
  267. package/dist/exchanges/venues/grvt.js +98 -0
  268. package/dist/exchanges/venues/hyperliquid.d.ts +2 -2
  269. package/dist/exchanges/venues/hyperliquid.js +19 -8
  270. package/dist/exchanges/venues/index.d.ts +7 -2
  271. package/dist/exchanges/venues/index.js +8 -2
  272. package/dist/exchanges/venues/lighter-family.d.ts +7 -9
  273. package/dist/exchanges/venues/lighter-family.js +9 -11
  274. package/dist/exchanges/venues/lighter-rh.d.ts +2 -2
  275. package/dist/exchanges/venues/lighter-rh.js +20 -8
  276. package/dist/exchanges/venues/lighter.d.ts +1 -1
  277. package/dist/exchanges/venues/lighter.js +18 -6
  278. package/dist/exchanges/venues/ondo.d.ts +1 -1
  279. package/dist/exchanges/venues/ondo.js +5 -3
  280. package/dist/exchanges/venues/pacifica.d.ts +2 -2
  281. package/dist/exchanges/venues/pacifica.js +15 -4
  282. package/dist/exchanges/venues/qfex.d.ts +1 -1
  283. package/dist/exchanges/venues/qfex.js +4 -2
  284. package/dist/exchanges/venues/risex-release.d.ts +14 -0
  285. package/dist/exchanges/venues/risex-release.js +14 -0
  286. package/dist/exchanges/venues/risex.d.ts +31 -0
  287. package/dist/exchanges/venues/risex.js +131 -0
  288. package/dist/exchanges/venues/txflow.d.ts +18 -0
  289. package/dist/exchanges/venues/txflow.js +77 -0
  290. package/dist/exchanges/venues/variational.d.ts +21 -0
  291. package/dist/exchanges/venues/variational.js +85 -0
  292. package/dist/execution-log.d.ts +1 -1
  293. package/dist/funding/legacy-public.d.ts +6 -4
  294. package/dist/funding/legacy-public.js +42 -41
  295. package/dist/funding/normalize.d.ts +1 -1
  296. package/dist/funding/normalize.js +1 -1
  297. package/dist/funding/rates.d.ts +95 -6
  298. package/dist/funding/rates.js +99 -19
  299. package/dist/index.js +7 -6
  300. package/dist/jobs.d.ts +1 -0
  301. package/dist/jobs.js +25 -1
  302. package/dist/landing.d.ts +2 -0
  303. package/dist/landing.js +1 -1
  304. package/dist/liquidity.d.ts +3 -1
  305. package/dist/liquidity.js +8 -4
  306. package/dist/mcp-pacifica-earn.d.ts +9 -0
  307. package/dist/mcp-pacifica-earn.js +64 -0
  308. package/dist/mcp-server.js +211 -68
  309. package/dist/pacifica/client.d.ts +69 -5
  310. package/dist/pacifica/client.js +181 -8
  311. package/dist/pacifica/rate-limit.d.ts +144 -0
  312. package/dist/pacifica/rate-limit.js +267 -0
  313. package/dist/pacifica/types/order.d.ts +2 -1
  314. package/dist/plan-executor.js +7 -2
  315. package/dist/positions-by-address.d.ts +34 -0
  316. package/dist/positions-by-address.js +46 -0
  317. package/dist/rebalance.js +1 -1
  318. package/dist/risk.d.ts +2 -1
  319. package/dist/risk.js +2 -4
  320. package/dist/settings.d.ts +32 -3
  321. package/dist/signer/ows-evm.d.ts +1 -1
  322. package/dist/signer/ows-evm.js +1 -1
  323. package/dist/smart-order.d.ts +1 -1
  324. package/dist/smart-order.js +1 -1
  325. package/dist/strategies/funding-arb.d.ts +1 -1
  326. package/dist/strategies/funding-arb.js +36 -63
  327. package/dist/trade-validator.js +2 -2
  328. package/dist/utils.d.ts +22 -3
  329. package/dist/utils.js +11 -3
  330. package/dist/venue-health.d.ts +40 -0
  331. package/dist/venue-health.js +75 -0
  332. package/dist/withdraw-gate.d.ts +1 -1
  333. package/dist/withdraw-gate.js +1 -1
  334. package/dist/ws/arcus-market.d.ts +9 -0
  335. package/dist/ws/arcus-market.js +9 -0
  336. package/dist/ws/aster-market.d.ts +33 -0
  337. package/dist/ws/aster-market.js +30 -0
  338. package/dist/ws/index.d.ts +980 -0
  339. package/dist/ws/index.js +4460 -0
  340. package/dist/ws/lighter-market.d.ts +14 -0
  341. package/dist/ws/lighter-market.js +13 -0
  342. package/dist/ws/node.d.ts +996 -0
  343. package/dist/ws/node.js +4554 -0
  344. package/dist/ws/pacifica-instrument.d.ts +8 -0
  345. package/dist/ws/pacifica-instrument.js +8 -0
  346. package/dist/ws/unclassified.d.ts +16 -0
  347. package/dist/ws/unclassified.js +43 -0
  348. package/dist/ws-cli/credentials.d.ts +62 -0
  349. package/dist/ws-cli/credentials.js +126 -0
  350. package/package.json +71 -10
  351. package/skills/perp-cli/SKILL.md +153 -36
  352. package/skills/perp-cli/package.json +15 -2
  353. package/skills/perp-cli/references/agent-operations.md +22 -12
  354. package/skills/perp-cli/references/commands.md +143 -17
  355. package/skills/perp-cli/references/strategies.md +38 -3
  356. package/skills/perp-cli/references/ws-library.md +523 -0
  357. package/skills/perp-cli/scripts/arb-monitor.sh +13 -10
  358. package/skills/perp-cli/scripts/funding-analysis.sh +57 -29
  359. package/skills/perp-cli/scripts/preflight.sh +27 -19
  360. package/skills/perp-cli/scripts/spot-perp-scan.sh +58 -38
  361. package/skills/perp-cli/scripts/validate-arb.sh +56 -39
  362. package/dist/cli-spec.d.ts +0 -46
  363. package/dist/cli-spec.js +0 -81
@@ -1,7 +1,9 @@
1
1
  import { getNetworkConfig } from "./constants.js";
2
- import { buildSignedRequest, buildAgentSignedRequest } from "./signing.js";
2
+ import { buildSignedRequest, buildAgentSignedRequest, signWithWallet } from "./signing.js";
3
3
  import { PerpError, extractErrorMessage, orderNotSent, orderOutcomeUnknown, sendFailure } from "../errors.js";
4
4
  import { invalidateCache } from "../cache.js";
5
+ import { requireSolanaAddress } from "../exchanges/address.js";
6
+ import { PACIFICA_COST_CANCEL, PACIFICA_COST_STANDARD, PACIFICA_MAX_THROTTLE_WAIT_MS, PACIFICA_READ_NEED, PACIFICA_SIGNED_MAX_WAIT_MS, pacificaRateLimiter, } from "./rate-limit.js";
5
7
  /** Per-request timeout of a POST (fetch + body read). */
6
8
  export const PACIFICA_POST_TIMEOUT_MS = 15_000;
7
9
  /**
@@ -14,6 +16,37 @@ export const PACIFICA_POST_TIMEOUT_MS = 15_000;
14
16
  const DEFINITE_4XX_PATHS = new Set(["/positions/tpsl", "/account/leverage"]);
15
17
  /** POST endpoints that only read (signed listings): a failure there is an ordinary read error. */
16
18
  const READ_POST_PATHS = new Set(["/account/subaccount/list", "/agent/list", "/account/api_keys"]);
19
+ /** Cancels cost 0.5 credits (docs: rate-limits "Order cancellation 0.5"), by path and by signed operation type. */
20
+ const CANCEL_POST_PATHS = new Set(["/orders/cancel", "/orders/stop/cancel", "/orders/cancel_all", "/orders/twap/cancel"]);
21
+ const CANCEL_OPERATIONS = new Set(["cancel_order", "cancel_stop_order", "cancel_all_orders", "cancel_twap_order"]);
22
+ /** Signed operation types of the READ_POST_PATHS listings: the read need applies before and after signing. */
23
+ const READ_OPERATIONS = new Set(["list_subaccounts", "list_agent_wallets", "list_api_keys"]);
24
+ /**
25
+ * A signed write needs only its own cost (never the read reserve); `maxWaitMs` = how long it may
26
+ * wait at this point (before signing: the normal bound; after signing: inside expiry_window).
27
+ */
28
+ function writeNeed(cancel, maxWaitMs) {
29
+ const cost = cancel ? PACIFICA_COST_CANCEL : PACIFICA_COST_STANDARD;
30
+ return { cost, reserve: 0, maxWaitMs };
31
+ }
32
+ /**
33
+ * Credits ×10 reserved for one POST /orders/batch. The docs (api/rate-limits "Credit Costs") price
34
+ * a "Standard request/action" at 1 credit and an "Order cancellation" at 0.5 and say nothing
35
+ * batch-specific (batch-order page: no cost); every action is individually signed and processed,
36
+ * so the batch is reserved per ACTION — the conservative reading (over-reserving only throttles
37
+ * earlier; the venue's ratelimit headers on the response settle the real count).
38
+ */
39
+ export function pacificaBatchCost(types) {
40
+ return types.reduce((a, t) => a + (t === "Cancel" || t === "CancelStopOrder" ? PACIFICA_COST_CANCEL : PACIFICA_COST_STANDARD), 0);
41
+ }
42
+ /** Query parameters that carry a Solana address (account reads, Print orders, vaults). */
43
+ const ADDRESS_PARAMS = new Set(["account", "game_account", "lake"]);
44
+ export { requireSolanaAddress };
45
+ function checkAddressParams(params) {
46
+ for (const [k, v] of Object.entries(params ?? {}))
47
+ if (ADDRESS_PARAMS.has(k) && v !== undefined && v !== null)
48
+ requireSolanaAddress(v, k);
49
+ }
17
50
  export class PacificaClient {
18
51
  baseUrl;
19
52
  apiKey;
@@ -24,12 +57,21 @@ export class PacificaClient {
24
57
  * against the agent key. Undefined for master/PK signers.
25
58
  */
26
59
  requestAgentWallet;
60
+ /** Credit-quota state for this base URL + key tier (rate-limit.ts; process-local): unsigned GETs (IP quota) … */
61
+ rate;
62
+ /** … and signed POSTs (may report the account's quota) kept apart. */
63
+ signedRate;
27
64
  /** Attach (or clear) the agent wallet used for subsequent signed requests. */
28
65
  setRequestAgentWallet(agentWallet) {
29
66
  this.requestAgentWallet = agentWallet;
30
67
  }
31
68
  /** Build a signed POST body, attaching agent_wallet when an agent is the active signer. */
32
69
  async signedBody(operationType, payload, account, signMessage) {
70
+ // Throttle BEFORE signing: a wait after signing would eat into the body's expiry_window.
71
+ // A fail-fast RATE_LIMITED here sent nothing (details.sent === false).
72
+ await this.signedRate.awaitCapacity(operationType, READ_OPERATIONS.has(operationType)
73
+ ? PACIFICA_READ_NEED
74
+ : writeNeed(CANCEL_OPERATIONS.has(operationType), PACIFICA_MAX_THROTTLE_WAIT_MS));
33
75
  try {
34
76
  return await (this.requestAgentWallet
35
77
  ? buildAgentSignedRequest(operationType, payload, account, this.requestAgentWallet, signMessage)
@@ -44,6 +86,8 @@ export class PacificaClient {
44
86
  this.baseUrl =
45
87
  config.baseUrl || getNetworkConfig(config.network).restUrl;
46
88
  this.apiKey = config.apiKey;
89
+ this.rate = pacificaRateLimiter(this.baseUrl, this.apiKey, "unsigned");
90
+ this.signedRate = pacificaRateLimiter(this.baseUrl, this.apiKey, "signed");
47
91
  }
48
92
  headers() {
49
93
  const h = { "Content-Type": "application/json" };
@@ -52,6 +96,7 @@ export class PacificaClient {
52
96
  return h;
53
97
  }
54
98
  async get(path, params) {
99
+ checkAddressParams(params);
55
100
  const url = new URL(`${this.baseUrl}${path}`);
56
101
  if (params) {
57
102
  Object.entries(params).forEach(([k, v]) => {
@@ -59,9 +104,20 @@ export class PacificaClient {
59
104
  url.searchParams.set(k, v);
60
105
  });
61
106
  }
62
- const res = await fetch(url.toString(), { headers: this.headers() });
107
+ const ticket = await this.rate.acquire(`GET ${path}`, PACIFICA_READ_NEED);
108
+ let res;
109
+ try {
110
+ res = await fetch(url.toString(), { headers: this.headers() });
111
+ }
112
+ finally {
113
+ ticket.release();
114
+ }
115
+ this.rate.observe(res);
63
116
  if (!res.ok) {
64
117
  const text = await res.text();
118
+ // Structural (by status): RATE_LIMITED with retryAfterMs; never retried here.
119
+ if (res.status === 429)
120
+ throw this.rate.rateLimitedError(`GET ${path}`, res, text);
65
121
  throw new Error(`GET ${path} failed (${res.status}): ${text}`);
66
122
  }
67
123
  const json = await res.json();
@@ -77,14 +133,21 @@ export class PacificaClient {
77
133
  * outcome unknown → ORDER_PENDING (sendFailure), never a retryable network error. No connection
78
134
  * at all → not sent. A 4xx is the venue's refusal and keeps the plain `POST <path> failed
79
135
  * (<status>): <body>` error the adapters map (422 business codes) — except on
80
- * DEFINITE_4XX_PATHS, where it is a definite ACTION_REJECTED (429 stays the plain error →
81
- * RATE_LIMITED). A fetch timeout (PACIFICA_POST_TIMEOUT_MS) on a write is ORDER_PENDING too;
136
+ * DEFINITE_4XX_PATHS, where it is a definite ACTION_REJECTED. HTTP 429 → RATE_LIMITED
137
+ * (details.sent === false, retryAfterMs) — never retried, a write is never resubmitted.
138
+ * "429 = not executed" is our reading of the docs ("When credits are exhausted, requests return
139
+ * HTTP 429"), not an explicit Pacifica statement. Before sending, the credit throttle may wait up
140
+ * to PACIFICA_SIGNED_MAX_WAIT_MS (the body is already signed) or fail fast with RATE_LIMITED
141
+ * (nothing sent). A write needs only its own cost, never the read reserve. A fetch timeout (PACIFICA_POST_TIMEOUT_MS) on a write is ORDER_PENDING too;
82
142
  * on a listing read a timeout is TIMEOUT and any other transport failure EXCHANGE_UNREACHABLE.
83
143
  */
84
- async post(path, body) {
144
+ async post(path, body, needOverride) {
85
145
  const write = !READ_POST_PATHS.has(path);
86
146
  const what = `POST ${path}`;
87
147
  const remediation = `Do NOT resubmit — the request may have been executed. Check open orders, positions and balances first: perp -e pacifica account orders / portfolio`;
148
+ const ticket = await this.signedRate.acquire(what, needOverride !== undefined ? needOverride : write
149
+ ? writeNeed(CANCEL_POST_PATHS.has(path), PACIFICA_SIGNED_MAX_WAIT_MS)
150
+ : { ...PACIFICA_READ_NEED, maxWaitMs: PACIFICA_SIGNED_MAX_WAIT_MS });
88
151
  try {
89
152
  let res;
90
153
  let text;
@@ -95,6 +158,7 @@ export class PacificaClient {
95
158
  body: JSON.stringify(body),
96
159
  signal: AbortSignal.timeout(PACIFICA_POST_TIMEOUT_MS),
97
160
  });
161
+ ticket.settle(res);
98
162
  text = await res.text();
99
163
  }
100
164
  catch (e) {
@@ -110,8 +174,11 @@ export class PacificaClient {
110
174
  if (write && res.status >= 500) {
111
175
  throw orderOutcomeUnknown("pacifica", what, new Error(`HTTP ${res.status}: ${text.slice(0, 200)}`), remediation);
112
176
  }
177
+ // Refused before processing (credits exhausted): nothing executed, never resubmitted here.
178
+ if (res.status === 429)
179
+ throw this.signedRate.rateLimitedError(what, res, text);
113
180
  if (!res.ok) {
114
- if (DEFINITE_4XX_PATHS.has(path) && res.status >= 400 && res.status < 500 && res.status !== 429) {
181
+ if (DEFINITE_4XX_PATHS.has(path) && res.status >= 400 && res.status < 500) {
115
182
  throw new PerpError("ACTION_REJECTED", `Pacifica ${what} refused (HTTP ${res.status}, nothing was changed): ${text.slice(0, 300)}`, {
116
183
  exchange: "pacifica",
117
184
  httpStatus: res.status,
@@ -130,6 +197,7 @@ export class PacificaClient {
130
197
  }
131
198
  }
132
199
  finally {
200
+ ticket.release(); // no-op once settled; a transport failure frees the reservation
133
201
  // Every POST is an account write (order / cancel / TP/SL / leverage / transfer): drop the
134
202
  // shared acct: disk cache so no later read serves the pre-write positions / orders.
135
203
  invalidateCache("acct");
@@ -377,6 +445,71 @@ export class PacificaClient {
377
445
  const body = await this.signedBody("withdraw_from_lake", params, account, signMessage);
378
446
  return this.post("/lake/withdraw", body);
379
447
  }
448
+ // ==================== PRINT (game) + VAULT READS / PRE-SIGNED WRITES ====================
449
+ // Shapes and parsing live in src/exchanges/pacifica-print.ts / pacifica-vaults.ts.
450
+ /**
451
+ * Unauthenticated GET that keeps the whole {success, data, has_more, next_cursor} envelope.
452
+ * Same credit limiter as get() (unsigned IP quota, PACIFICA_READ_NEED: may wait for the window,
453
+ * else RATE_LIMITED sent:false); the response headers are recorded; HTTP 429 → RATE_LIMITED
454
+ * (structural, never retried). Timeout → TIMEOUT, transport failure → EXCHANGE_UNREACHABLE,
455
+ * non-JSON / non-object body → EXCHANGE_ERROR (a read: nothing can have changed).
456
+ */
457
+ async getEnvelope(path, params = {}) {
458
+ checkAddressParams(params);
459
+ const url = new URL(`${this.baseUrl}${path}`);
460
+ for (const [k, v] of Object.entries(params))
461
+ url.searchParams.set(k, v);
462
+ const what = `GET ${path}`;
463
+ const ticket = await this.rate.acquire(what, PACIFICA_READ_NEED);
464
+ let res;
465
+ let text;
466
+ try {
467
+ res = await fetch(url.toString(), { headers: this.headers(), signal: AbortSignal.timeout(PACIFICA_POST_TIMEOUT_MS) });
468
+ ticket.settle(res);
469
+ text = await res.text();
470
+ }
471
+ catch (e) {
472
+ const timedOut = e instanceof Error && (e.name === "TimeoutError" || e.name === "AbortError");
473
+ throw new PerpError(timedOut ? "TIMEOUT" : "EXCHANGE_UNREACHABLE", `Pacifica GET ${path} ${timedOut ? `timed out after ${PACIFICA_POST_TIMEOUT_MS} ms` : `failed: ${extractErrorMessage(e)}`}`, {
474
+ exchange: "pacifica", remediation: "Retry; if it keeps failing check the network and Pacifica's status",
475
+ });
476
+ }
477
+ finally {
478
+ ticket.release(); // no-op once settled; a transport failure frees the reservation
479
+ }
480
+ if (res.status === 429)
481
+ throw this.rate.rateLimitedError(what, res, text);
482
+ if (!res.ok)
483
+ throw new Error(`GET ${path} failed (${res.status}): ${text}`);
484
+ let json;
485
+ try {
486
+ json = JSON.parse(text);
487
+ }
488
+ catch {
489
+ throw new PerpError("EXCHANGE_ERROR", `Pacifica GET ${path} returned a non-JSON body (HTTP ${res.status}): ${text.slice(0, 160)}`, { exchange: "pacifica" });
490
+ }
491
+ if (json === null || typeof json !== "object" || Array.isArray(json)) {
492
+ throw new PerpError("EXCHANGE_ERROR", `Pacifica GET ${path} returned a non-object body: ${text.slice(0, 160)}`, { exchange: "pacifica" });
493
+ }
494
+ return json;
495
+ }
496
+ /**
497
+ * POST a body the caller already built and signed (Print / vault writes sign their own canonical
498
+ * message so `--dry-run` can show the exact body). Same unknown-outcome rules as every write.
499
+ */
500
+ async postPresigned(path, body) {
501
+ return this.post(path, body);
502
+ }
503
+ /**
504
+ * Pre-sign credit wait for a pre-signed write (same rule as signedBody / amend): call BEFORE
505
+ * building + signing, so the post-sign wait in post() (≤ PACIFICA_SIGNED_MAX_WAIT_MS, inside the
506
+ * 5 s expiry_window) finds credits. Cost: the docs' rate-limits table lists no Print / vault
507
+ * entry — "Standard request/action: 1 credit" applies (end_game is not an order cancellation).
508
+ * Fail-fast RATE_LIMITED here sent and signed nothing (details.sent === false).
509
+ */
510
+ async awaitPresignedCapacity(operationType) {
511
+ await this.signedRate.awaitCapacity(operationType, writeNeed(false, PACIFICA_MAX_THROTTLE_WAIT_MS));
512
+ }
380
513
  // ==================== BUILDER CODE ====================
381
514
  async approveBuilderCode(params, account, signMessage) {
382
515
  const body = await this.signedBody("approve_builder_code", params, account, signMessage);
@@ -408,7 +541,47 @@ export class PacificaClient {
408
541
  return this.post("/referral/user/code/claim", body);
409
542
  }
410
543
  // ==================== BATCH ====================
411
- async batchOrders(actions) {
412
- return this.post("/orders/batch", { actions });
544
+ /**
545
+ * POST /orders/batch with the per-action cost (pacificaBatchCost) reserved. `maxWaitMs` caps the
546
+ * post-sign throttle wait (default PACIFICA_SIGNED_MAX_WAIT_MS, never more): a caller with a
547
+ * tighter signature deadline passes what is left of it, so a wait can never send an expired batch
548
+ * — a longer wait fails fast with RATE_LIMITED (sent: false, nothing sent).
549
+ */
550
+ async batchOrders(actions, opts = {}) {
551
+ const maxWaitMs = Math.max(0, Math.min(opts.maxWaitMs !== undefined ? opts.maxWaitMs : PACIFICA_SIGNED_MAX_WAIT_MS, PACIFICA_SIGNED_MAX_WAIT_MS));
552
+ return this.post("/orders/batch", { actions }, { cost: pacificaBatchCost(actions.map(a => a.type)), reserve: 0, maxWaitMs });
553
+ }
554
+ /**
555
+ * Pre-sign throttle for a batch (like signedBody does for single writes): wait — up to
556
+ * PACIFICA_MAX_THROTTLE_WAIT_MS, else RATE_LIMITED with nothing signed or sent — until the
557
+ * batch's whole cost fits, so the post-sign acquire in batchOrders normally finds the credits.
558
+ */
559
+ async awaitBatchCapacity(types) {
560
+ await this.signedRate.awaitCapacity("POST /orders/batch", { cost: pacificaBatchCost(types), reserve: 0, maxWaitMs: PACIFICA_MAX_THROTTLE_WAIT_MS });
561
+ }
562
+ /**
563
+ * One signed batch action body (docs rest-api/orders/batch-order: "Batch orders are not signed
564
+ * as a whole, but rather by its individual actions components"; each action's `data` carries the
565
+ * fields of its standalone endpoint, signed with that endpoint's operation type). Nothing is sent.
566
+ * `header` fixes the signed timestamp / expiry window, so every action of one batch can share
567
+ * one timestamp. agent_wallet is attached when an agent is the active signer. A signing failure
568
+ * → ORDER_REJECTED (orderNotSent).
569
+ */
570
+ async signBatchAction(operationType, payload, account, signMessage, header) {
571
+ const full = { type: operationType, timestamp: header.timestamp, expiry_window: header.expiry_window };
572
+ try {
573
+ const [, signature] = await signWithWallet(full, payload, signMessage);
574
+ return {
575
+ account,
576
+ ...(this.requestAgentWallet ? { agent_wallet: this.requestAgentWallet } : {}),
577
+ signature,
578
+ timestamp: full.timestamp,
579
+ expiry_window: full.expiry_window,
580
+ ...payload,
581
+ };
582
+ }
583
+ catch (e) {
584
+ throw orderNotSent("pacifica", operationType, e);
585
+ }
413
586
  }
414
587
  }
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Pacifica credit rate limit, read from the venue's own response headers.
3
+ *
4
+ * docs.pacifica.fi api-documentation/api/rate-limits (read 2026-10-19): credit-based, rolling
5
+ * 60 s window; 100 credits / 60 s per unidentified IP, 300 with a valid API Config Key (more for
6
+ * higher fee tiers); standard request 1, cancel 0.5, heavy GET 3-12 (1-4 with a key). Exhausted →
7
+ * HTTP 429. "All credit values are multiplied by 10 to support fractional costs":
8
+ *
9
+ * ratelimit: "credits";r=1200;t=32 r = remaining (×10), t = seconds until refresh
10
+ * ratelimit-policy: "credits";q=1250;w=60 q = quota per window (×10), w = window seconds
11
+ *
12
+ * Live mainnet GET /info/prices (2026-10-19, no key): `ratelimit: "credits";r=980;t=22`,
13
+ * `ratelimit-policy: "credits";q=1000;w=60`. Values below stay in those ×10 units.
14
+ *
15
+ * CloudFront caches some GETs (/info: `x-cache: Hit from cloudfront`, `age: 16`): a cache hit
16
+ * replays the headers of whoever filled the cache (live: q=3000, a keyed caller) — not this
17
+ * caller's quota, so a hit carries no information.
18
+ *
19
+ * Scope: one state per REST base URL (mainnet / testnet), credential tier (no key = IP quota;
20
+ * an API Config Key has its own) and request kind (signed POST vs unsigned GET). Process-local: other perp-cli processes (CLI + MCP + bots) on the
21
+ * same IP spend the same quota unseen, so a 429 can still happen — it is then surfaced as
22
+ * RATE_LIMITED, never retried here.
23
+ */
24
+ import { PerpError } from "../errors.js";
25
+ /** One parsed `ratelimit` (+ optional `ratelimit-policy`) observation, in credits ×10. */
26
+ export interface PacificaRateLimitInfo {
27
+ remaining: number;
28
+ resetSec: number;
29
+ /** null = `ratelimit-policy` absent or malformed. */
30
+ quota: number | null;
31
+ windowSec: number | null;
32
+ }
33
+ /**
34
+ * Strict parse of the `ratelimit` / `ratelimit-policy` header values. `ratelimit` absent or
35
+ * malformed (no `"credits"` item, missing / non-integer / duplicate r or t) → null: no info, never
36
+ * a guessed value. A malformed policy only nulls quota / windowSec.
37
+ */
38
+ export declare function parsePacificaRateLimit(ratelimit: string | null, policy: string | null): PacificaRateLimitInfo | null;
39
+ /** `Retry-After` in delta-seconds → ms; absent / HTTP-date / malformed → null. */
40
+ export declare function parseRetryAfterMs(raw: string | null): number | null;
41
+ type HeaderSource = {
42
+ headers?: {
43
+ get(name: string): string | null;
44
+ };
45
+ } | null | undefined;
46
+ /** Parsed rate-limit info of a response this caller's request produced; null = no info. */
47
+ export declare function pacificaRateLimitOf(res: HeaderSource): PacificaRateLimitInfo | null;
48
+ /** Read reserve (credits ×10): the largest documented heavy-GET cost (12 credits) stays unspent after a read. */
49
+ export declare const PACIFICA_READ_RESERVE = 120;
50
+ /** Cost (credits ×10) of a standard request / action (docs: 1 credit). */
51
+ export declare const PACIFICA_COST_STANDARD = 10;
52
+ /** Cost (credits ×10) of an order cancellation (docs: 0.5 credits). */
53
+ export declare const PACIFICA_COST_CANCEL = 5;
54
+ /** Longest pre-send wait before failing fast with RATE_LIMITED. */
55
+ export declare const PACIFICA_MAX_THROTTLE_WAIT_MS = 15000;
56
+ /** Longest wait between signing and sending (signed bodies expire after expiry_window = 5 s). */
57
+ export declare const PACIFICA_SIGNED_MAX_WAIT_MS = 2000;
58
+ export interface RateClock {
59
+ now(): number;
60
+ sleep(ms: number): Promise<void>;
61
+ }
62
+ /** What a request needs before it may be sent. */
63
+ export interface RateNeed {
64
+ /** Credits ×10 this request is assumed to cost (PACIFICA_COST_*). */
65
+ cost: number;
66
+ /**
67
+ * Credits ×10 that must still be left after this request (observed remaining − in flight − cost):
68
+ * reads keep the heavy-GET reserve (PACIFICA_READ_RESERVE); writes 0 — a write needs only its own
69
+ * cost, so an amend's replacement leg is never blocked by the read reserve.
70
+ */
71
+ reserve: number;
72
+ /** Longest pre-send wait; longer → RATE_LIMITED fail-fast (0 = never wait). */
73
+ maxWaitMs: number;
74
+ }
75
+ export declare const PACIFICA_READ_NEED: RateNeed;
76
+ /** A reserved request: settle with its response (or release on a transport failure). Idempotent. */
77
+ export interface RateTicket {
78
+ settle(res: HeaderSource): PacificaRateLimitInfo | null;
79
+ release(): void;
80
+ }
81
+ export declare class PacificaRateLimiter {
82
+ private readonly label;
83
+ private readonly clock;
84
+ private obs;
85
+ /** Credits ×10 reserved by requests sent and not yet settled — not reset by observe(). */
86
+ private inFlight;
87
+ private lastRaw;
88
+ private skew;
89
+ constructor(label: string, clock?: RateClock);
90
+ /** clock.now() made monotonic: a backwards step is absorbed instead of restarting elapsed time. */
91
+ private now;
92
+ /** ms until the observed window refreshes; null = no live observation. */
93
+ private resetWaitMs;
94
+ /** Current state for diagnostics (credits ×10); null = no live observation. */
95
+ snapshot(): {
96
+ remaining: number;
97
+ inFlight: number;
98
+ effectiveRemaining: number;
99
+ resetInMs: number;
100
+ } | null;
101
+ /** ms to wait before a request with `need` may be sent: 0 = now (no info, or enough credits left). */
102
+ waitMs(need: Pick<RateNeed, "cost" | "reserve">): number;
103
+ private ticket;
104
+ /**
105
+ * Pre-send throttle + reservation. Enough credits (or no info) → the cost is reserved
106
+ * synchronously, before any await, so concurrent callers see each other. Otherwise waits for the
107
+ * window to refresh (total ≤ need.maxWaitMs) or fails fast with RATE_LIMITED (sent: false).
108
+ */
109
+ acquire(what: string, need: RateNeed): Promise<RateTicket>;
110
+ /** Like acquire but never waits or refuses (health probe): reserves and records only. */
111
+ track(cost: number): RateTicket;
112
+ /** Wait (no reservation) until `need` would pass — used before signing, so the post-sign acquire finds credits. */
113
+ awaitCapacity(what: string, need: RateNeed): Promise<void>;
114
+ private throttled;
115
+ /**
116
+ * Record a response's headers (any status). No / malformed / cached headers → unchanged. Within
117
+ * the live window an observation with a higher `r` (a late response from before others landed)
118
+ * or a different `q` (another quota: account vs IP) is dropped.
119
+ */
120
+ observe(res: HeaderSource): PacificaRateLimitInfo | null;
121
+ /**
122
+ * HTTP 429 → RATE_LIMITED (structural, by status). retryAfterMs = `Retry-After`, else the
123
+ * ratelimit reset `t`, else absent (clamped to the window). The quota is recorded as exhausted.
124
+ *
125
+ * `sent: false` ("not executed") is OUR reading of the docs — "When credits are exhausted,
126
+ * requests return HTTP 429" — i.e. the request is refused before processing. Pacifica does not
127
+ * state explicitly that a 429'd write was not executed.
128
+ */
129
+ rateLimitedError(what: string, res: HeaderSource & {
130
+ status: number;
131
+ }, body: string): PerpError;
132
+ }
133
+ /** A Pacifica RATE_LIMITED that sent nothing (pre-send throttle or HTTP 429): a definite refusal. */
134
+ export declare function isPacificaRateLimited(e: unknown): boolean;
135
+ /**
136
+ * The process-local limiter for a REST base URL + credential tier (no key = IP quota) + request
137
+ * kind. Signed POSTs are kept apart from unsigned GETs: credits are shared per main account and
138
+ * scale with its fee tier, so signed responses can report an account quota (e.g. q=3000) while
139
+ * keyless GETs report the IP quota (q=1000).
140
+ */
141
+ export declare function pacificaRateLimiter(baseUrl: string, apiKey: string | undefined, kind: "signed" | "unsigned"): PacificaRateLimiter;
142
+ /** Test hook: forget every limiter's state. */
143
+ export declare function resetPacificaRateLimiters(): void;
144
+ export {};