Commit graph

13 commits

Author SHA1 Message Date
cdca1f13ce feat(dispatcher): typed handler delivery with raw fallback; Prefix on %Message{} 2026-07-05 07:30:04 -03:00
45aa60de3d feat(api): endpoint/4 declaration macro with compiled route table 2026-07-05 05:10:19 -03:00
ae1f312e3b feat(struct): defoverridable generated fns + {:id_map, t} dictionary type 2026-07-05 04:24:02 -03:00
b278e3eeaa feat(model): channel structs + factory dispatch on wire type 2026-07-05 04:01:55 -03:00
202be23ba0 feat(struct): :number type, string-wire flags, wire_string opt, include_fields 2026-07-05 03:46:10 -03:00
1bf9b84518 feat(struct): discord_struct DSL — defstruct, @type t, field table generation 2026-07-05 03:23:18 -03:00
ed084ef5a3 feat(flags): bitfield DSL with raw-int storage and named views 2026-07-05 03:17:20 -03:00
022d157d65 feat(enum): open integer enum DSL with {:unknown, n} lossless round-trip 2026-07-05 03:13:31 -03:00
f3ddb9defb feat(api/cache): add channel-message history, thread creation, snowflakes, cached threads
- 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.
2026-07-04 13:12:54 -03:00
f44d30954a fix(gateway): decode HELLO coalesced with the 101 upgrade; hermetic test env
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.
2026-07-04 01:25:48 -03:00
2dec62e72d Phase 4: ETS cache, event coverage, gateway send budget, member chunking
- Dexcord.Cache GenServer: creates 8 public ETS tables (me/guilds/channels/
  users sets; members/roles/presences/voice_states ordered_set keyed {guild_id,x}).
  Writes only via handle_dispatch/3 (single writer = Dispatcher, gateway-ordered);
  reads are direct ETS. Full event coverage incl. GUILD_DELETE cascade purge and
  cache_presences toggle. Read API + bang variants.
- Dispatcher: inline Cache.handle_dispatch before handler task; op-8 chunk request
  on real GUILD_CREATE when request_guild_members and :guild_members intent set.
- Gateway: send-budget token bucket (default 115/60s, heartbeats bypass); op-3/op-8
  consume tokens, queue when empty (bounded, drop+warn), drain on :send_refill ticks.
- Supervisor: Cache child after Session, before Finch.
- Config: validate cache_presences / request_guild_members are booleans.
2026-07-04 00:52:58 -03:00
50a16666b4 Phase 3: REST rate limiter, typed endpoints, error struct
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.
2026-07-04 00:26:58 -03:00
12689862c8 feat(gateway): phase 2 reliability core (resume/zombie/backoff/fatal) + FakeGateway
- 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
2026-07-04 00:09:33 -03:00