1#[cfg(doctest)]
33#[doc = include_str!("../README.md")]
34struct ReadmeDoctests;
35
36#[macro_use]
37pub mod macros;
38
39pub mod auth;
40pub mod client;
41pub mod error;
42pub mod rate_limit;
43pub mod request;
44pub mod session_signer;
45pub mod signer_limit;
46
47#[cfg(feature = "keychain")]
48pub mod keychain;
49
50const LOG_BODY_MAX_LEN: usize = 512;
52
53pub fn truncate_for_log(s: &str) -> std::borrow::Cow<'_, str> {
58 if s.len() <= LOG_BODY_MAX_LEN {
59 std::borrow::Cow::Borrowed(s)
60 } else {
61 let truncated = &s[..s.floor_char_boundary(LOG_BODY_MAX_LEN)];
62 std::borrow::Cow::Owned(format!("{}... [truncated]", truncated))
63 }
64}
65
66pub use auth::{current_timestamp, Base64Format, Signer};
67pub use client::{
68 retry_after_header, HttpClient, HttpClientBuilder, DEFAULT_POOL_SIZE, DEFAULT_TIMEOUT_MS,
69};
70pub use error::ApiError;
71pub use rate_limit::{RateLimiter, RetryConfig};
72pub use request::{QueryBuilder, Request, RequestError};
73pub use session_signer::{DepositWalletRole, SessionSignerScope};
74pub use signer_limit::{
75 BurstCapacityExceeded, RateLimitStatus, SignerLimiter, Tier, TradingBucket, TradingRequest,
76};
77
78#[cfg(feature = "keychain")]
79pub use keychain::KeychainError;
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
86 fn test_truncate_for_log_short_string_unchanged() {
87 let short = "hello world";
88 let result = truncate_for_log(short);
89 assert_eq!(result.as_ref(), short);
90 }
91
92 #[test]
93 fn test_truncate_for_log_exact_limit_unchanged() {
94 let exact = "a".repeat(LOG_BODY_MAX_LEN);
95 let result = truncate_for_log(&exact);
96 assert_eq!(result.as_ref(), exact.as_str());
97 }
98
99 #[test]
100 fn test_truncate_for_log_over_limit_truncated() {
101 let long = "x".repeat(LOG_BODY_MAX_LEN + 100);
102 let result = truncate_for_log(&long);
103 assert!(result.ends_with("... [truncated]"));
104 assert!(result.len() < long.len());
105 }
106
107 #[test]
108 fn test_truncate_for_log_multibyte_char_boundary() {
109 let mut s = "a".repeat(LOG_BODY_MAX_LEN - 1);
111 s.push('\u{1F600}'); s.push_str("overflow");
113 let result = truncate_for_log(&s);
114 assert!(result.ends_with("... [truncated]"));
115 assert!(result.is_char_boundary(0));
117 }
118}