// rate_limits.mbt — upstream `src/rate-limits.ts` mirror: the rate-limit
// snapshot shared by `_lody/rate_limits/get` (request + result) and
// `_lody/rate_limits/update` (notification payload).
//
// Time units: `*EpochSeconds` are Unix epoch seconds, `windowDurationSeconds`
// is seconds. `usedPercent` is a normalized 0..100 inclusive percentage;
// out-of-range values are decode errors, never clamped.
///|
/// `RateLimitsGetRequest` — `_lody/rate_limits/get` params. Not session
/// bound: every field is an optional filter.
pub(all) struct RateLimitsGetRequest {
session_id : String?
account_id : String?
model_id : String?
} derive(Eq, Debug)
///|
pub fn RateLimitsGetRequest::to_json(self : RateLimitsGetRequest) -> Json {
let pairs : Array[(String, Json)] = []
match self.session_id {
Some(v) => pairs.push(("sessionId", Json::string(v)))
None => ()
}
match self.account_id {
Some(v) => pairs.push(("accountId", Json::string(v)))
None => ()
}
match self.model_id {
Some(v) => pairs.push(("modelId", Json::string(v)))
None => ()
}
Json::object(Map::from_array(pairs))
}
///|
pub fn RateLimitsGetRequest::from_json(
raw : Json,
) -> Result[RateLimitsGetRequest, String] {
try {
let ctx = "lody.rateLimits.get.request"
let fields = object_fields(raw, ctx)
Ok(RateLimitsGetRequest::{
session_id: opt_string(fields, ctx, "sessionId"),
account_id: opt_string(fields, ctx, "accountId"),
model_id: opt_string(fields, ctx, "modelId"),
})
} catch {
DecodeError::Msg(message) => Err(message)
}
}
///|
/// `RateLimitScope` — which provider/account/model a limit applies to.
pub(all) struct RateLimitScope {
provider_id : String
account_id : String?
model_id : String?
} derive(Eq, Debug)
///|
pub fn RateLimitScope::to_json(self : RateLimitScope) -> Json {
let pairs : Array[(String, Json)] = [
("providerId", Json::string(self.provider_id)),
]
match self.account_id {
Some(v) => pairs.push(("accountId", Json::string(v)))
None => ()
}
match self.model_id {
Some(v) => pairs.push(("modelId", Json::string(v)))
None => ()
}
Json::object(Map::from_array(pairs))
}
///|
pub fn RateLimitScope::from_json(raw : Json) -> Result[RateLimitScope, String] {
try {
let ctx = "lody.rateLimits.scope"
let fields = object_fields(raw, ctx)
Ok(RateLimitScope::{
provider_id: req_string(fields, ctx, "providerId"),
account_id: opt_string(fields, ctx, "accountId"),
model_id: opt_string(fields, ctx, "modelId"),
})
} catch {
DecodeError::Msg(message) => Err(message)
}
}
///|
/// `RateLimitWindow` — one usage window; `usedPercent` is 0..100 inclusive.
pub(all) struct RateLimitWindow {
used_percent : Double
window_duration_seconds : Int64?
resets_at_epoch_seconds : Int64?
} derive(Eq, Debug)
///|
pub fn RateLimitWindow::to_json(self : RateLimitWindow) -> Json {
let pairs : Array[(String, Json)] = [
("usedPercent", Json::number(self.used_percent)),
]
match self.window_duration_seconds {
Some(v) =>
pairs.push(("windowDurationSeconds", Json::number(v.to_double())))
None => ()
}
match self.resets_at_epoch_seconds {
Some(v) => pairs.push(("resetsAtEpochSeconds", Json::number(v.to_double())))
None => ()
}
Json::object(Map::from_array(pairs))
}
///|
pub fn RateLimitWindow::from_json(
raw : Json,
) -> Result[RateLimitWindow, String] {
try {
let ctx = "lody.rateLimits.window"
let fields = object_fields(raw, ctx)
let used_percent = req_double(fields, ctx, "usedPercent")
guard 0.0 <= used_percent && used_percent <= 100.0 else {
raise DecodeError::Msg(
"\{ctx}: field \"usedPercent\" must be within 0..100, got \{used_percent}",
)
}
Ok(RateLimitWindow::{
used_percent,
window_duration_seconds: opt_int64(fields, ctx, "windowDurationSeconds"),
resets_at_epoch_seconds: opt_int64(fields, ctx, "resetsAtEpochSeconds"),
})
} catch {
DecodeError::Msg(message) => Err(message)
}
}
///|
/// `RateLimitWallet` — credit-balance state; money in cents, ISO currency
/// string (upstream constrains the format no further).
pub(all) struct RateLimitWallet {
balance_cents : Int64
total_cents : Int64
monthly_charge_limit_enabled : Bool
monthly_charge_limit_cents : Int64
monthly_used_cents : Int64
currency : String
} derive(Eq, Debug)
///|
pub fn RateLimitWallet::to_json(self : RateLimitWallet) -> Json {
Json::object(
Map::from_array([
("balanceCents", Json::number(self.balance_cents.to_double())),
("totalCents", Json::number(self.total_cents.to_double())),
(
"monthlyChargeLimitEnabled",
Json::boolean(self.monthly_charge_limit_enabled),
),
(
"monthlyChargeLimitCents",
Json::number(self.monthly_charge_limit_cents.to_double()),
),
("monthlyUsedCents", Json::number(self.monthly_used_cents.to_double())),
("currency", Json::string(self.currency)),
]),
)
}
///|
pub fn RateLimitWallet::from_json(
raw : Json,
) -> Result[RateLimitWallet, String] {
try {
let ctx = "lody.rateLimits.wallet"
let fields = object_fields(raw, ctx)
Ok(RateLimitWallet::{
balance_cents: req_int64(fields, ctx, "balanceCents"),
total_cents: req_int64(fields, ctx, "totalCents"),
monthly_charge_limit_enabled: req_bool(
fields, ctx, "monthlyChargeLimitEnabled",
),
monthly_charge_limit_cents: req_int64(
fields, ctx, "monthlyChargeLimitCents",
),
monthly_used_cents: req_int64(fields, ctx, "monthlyUsedCents"),
currency: req_string(fields, ctx, "currency"),
})
} catch {
DecodeError::Msg(message) => Err(message)
}
}
///|
/// `RateLimit` — one limit with its windows and optional wallet. `limitName`,
/// `planName`, and `wallet` are nullable-but-optional upstream without a
/// distinct absent meaning, so null and absent both decode to None.
pub(all) struct RateLimit {
limit_id : String
scope : RateLimitScope
limit_name : String?
plan_name : String?
windows : Array[RateLimitWindow]
wallet : RateLimitWallet?
} derive(Eq, Debug)
///|
pub fn RateLimit::to_json(self : RateLimit) -> Json {
let pairs : Array[(String, Json)] = [
("limitId", Json::string(self.limit_id)),
("scope", self.scope.to_json()),
]
match self.limit_name {
Some(v) => pairs.push(("limitName", Json::string(v)))
None => ()
}
match self.plan_name {
Some(v) => pairs.push(("planName", Json::string(v)))
None => ()
}
pairs.push(
("windows", Json::array(self.windows.map(fn(window) { window.to_json() }))),
)
match self.wallet {
Some(v) => pairs.push(("wallet", v.to_json()))
None => ()
}
Json::object(Map::from_array(pairs))
}
///|
pub fn RateLimit::from_json(raw : Json) -> Result[RateLimit, String] {
try {
let ctx = "lody.rateLimits.limit"
let fields = object_fields(raw, ctx)
let windows : Array[RateLimitWindow] = req_array(fields, ctx, "windows").map(item => {
match RateLimitWindow::from_json(item) {
Ok(window) => window
Err(message) => raise DecodeError::Msg(message)
}
},
)
Ok(RateLimit::{
limit_id: req_string(fields, ctx, "limitId"),
scope: req_sub(fields, ctx, "scope", RateLimitScope::from_json),
limit_name: opt_string(fields, ctx, "limitName"),
plan_name: opt_string(fields, ctx, "planName"),
windows,
wallet: opt_sub(fields, ctx, "wallet", RateLimitWallet::from_json),
})
} catch {
DecodeError::Msg(message) => Err(message)
}
}
///|
/// `RateLimitsSnapshot` — the shape of `_lody/rate_limits/get`'s result and
/// of the `_lody/rate_limits/update` notification payload.
pub(all) struct RateLimitsSnapshot {
rate_limits : Array[RateLimit]
fetched_at_epoch_seconds : Int64?
} derive(Eq, Debug)
///|
pub fn RateLimitsSnapshot::to_json(self : RateLimitsSnapshot) -> Json {
let pairs : Array[(String, Json)] = [
(
"rateLimits",
Json::array(self.rate_limits.map(fn(limit) { limit.to_json() })),
),
]
match self.fetched_at_epoch_seconds {
Some(v) =>
pairs.push(("fetchedAtEpochSeconds", Json::number(v.to_double())))
None => ()
}
Json::object(Map::from_array(pairs))
}
///|
pub fn RateLimitsSnapshot::from_json(
raw : Json,
) -> Result[RateLimitsSnapshot, String] {
try {
let ctx = "lody.rateLimits.snapshot"
let fields = object_fields(raw, ctx)
let rate_limits : Array[RateLimit] = req_array(fields, ctx, "rateLimits").map(item => {
match RateLimit::from_json(item) {
Ok(limit) => limit
Err(message) => raise DecodeError::Msg(message)
}
},
)
Ok(RateLimitsSnapshot::{
rate_limits,
fetched_at_epoch_seconds: opt_int64(fields, ctx, "fetchedAtEpochSeconds"),
})
} catch {
DecodeError::Msg(message) => Err(message)
}
}