- Api.get_channel_messages/2,3 (opts + Nostrum-compatible locator), query
baked into the path so the rate limiter buckets it correctly
- Api.start_thread_with_message/3,4 (POST .../messages/:id/threads)
- Dexcord.Snowflake: from_datetime/to_datetime/to_unix (replaces Nostrum.Snowflake)
- Cache.threads/1: thread-type channels (10/11/12) for a guild
- FakeRest now records query_string so query building is testable
Added to support migrating Alamedya off Nostrum. 178 tests, 0 failures.
Root cause of the order/seed-dependent integration failures: when the WS
upgrade's 101 response and the server's first frame (HELLO) arrive in one TCP
segment, Mint returns them as [status, headers, {:data, hello}, {:done}] - the
{:data} ordered BEFORE the {:done} that builds the websocket. process_responses
only decoded {:data} once the websocket existed, so the coalesced HELLO was
silently dropped and the client wedged in :hello_wait. Coalescing is far more
likely under full-suite scheduler load, which also starved the cadence-sensitive
tests - hence the flaky, seed-varying failures. Buffer pre-upgrade bytes and
decode them the instant the websocket is built.
Test hermeticity:
- Add Dexcord.EnvSandbox: snapshot all :dexcord app env in setup, restore
wholesale on_exit. Replaces every file's hand-rolled per-key save/restore so no
knob (timing bounds, budgets, ratelimit clock, base URLs) can leak between tests.
- gateway_fatal_test: await the directly-started supervisor's full termination
(monitor + DOWN) instead of a fire-and-forget Process.exit, so its globally-named
singletons and named ETS are gone before the next test's tree starts.
Add Dexcord.Api.Ratelimit (route->bucket learning, per-bucket windows via
monotonic X-RateLimit-Reset-After deadlines, global lock, injectable clock,
probe serialization for unknown routes). Rework Dexcord.Api.request/4 around
acquire/wait/update with 429 + global handling and up to 3 retries; add the
~16 typed endpoints and a Dexcord.Api.Error struct. Start Ratelimit in the
supervisor after Finch. Add unit tests (route-key table, bucket/global math
with injected clock) and integration tests against a new Dexcord.FakeRest
Bandit server.
- fix heartbeat timer loss in :hello_wait (re-arm during identify-gap wait)
- honor server op 1 in :identifying/:hello_wait, not just :connected/:resuming
- full op 9 handling: d:false in :resuming re-IDENTIFYs on the same socket after
the mandated 1-5s; d:false elsewhere floors the reconnect; d:true keeps session
- resume-loop cap (5 consecutive failed resumes -> fresh IDENTIFY) via Session ETS
- explicit conn_gen/stale-socket guard backstopping Mint's :unknown
- bounded TCP connect + configurable handshake watchdogs so a stalled reconnect
self-heals instead of wedging
- FakeGateway scripted Bandit/WebSock test server + TestHandler
- integration suite (happy/zombie/kill/close-codes/op7/op9/replay/cap/backoff/gap/
stale), fatal-path end-to-end, and unit tests for resume counter + backoff math