Skip to content

feat: send match.find_or_create, the race-free route into a live match - #35

Merged
Taure merged 3 commits into
mainfrom
feat/match-find-or-create
Aug 14, 2026
Merged

Taure merged 3 commits into
mainfrom
feat/match-find-or-create

Conversation

@Taure

@Taure Taure commented Aug 14, 2026 •

Copy link
Copy Markdown
Contributor

asobi v0.86.0 adds an inbound frame, match.find_or_create: get into a live
match of a mode, spawning one if there is none. It is the match twin of
world.find_or_create, and it is answered with match.joined - the same frame
match.join is answered with, so there is no new reply type and nothing new to
dispatch.

{"type": "match.find_or_create", "cid": "1", "payload": {"mode": "arena"}}

What changed

This SDK is a transport, so it has no per-verb send helper (none for
world.find_or_create or match.join either) and adding one would cut against
the documented scope. The frame goes out through ws.send() like every other
one, and its reply resolves that promise through the existing cid
correlation. What was missing was the documentation and a test.

  • README.md: one line in the Quick start beside the existing match.join
    send, and a ### Finding or creating a match section carrying the detail.
  • test/match-find-or-create.test.ts: pins the outbound shape (the payload as
    given, under a cid), the reply routing (resolves on match.joined, identical
    to what match.join resolves with), and that each refusal rejects with its
    reason and leaves the session alone.

The facts it states

Every match parameter comes from the mode's server-side config: a client names
the mode and cannot set max_players or the tick rate. Eligibility is the
mode's quick_play flag, which defaults to false for match modes, so a mode
that has not opted in is refused with quick_play_disabled - listed is
browser visibility, a separate axis. Refusals also include not_found,
match_capacity_reached, wrong_mode_type and join_rate_limited. More can
be added server-side, so the list is not exhaustive.

Version floor is v0.86.0, not v0.85.0. The handler clause is asobi
8f7d950, which is tagged v0.86.0; v0.85.0 is 97f4cbb, the commit before
it, and does not carry the frame. Worth reconciling against the other six SDK
PRs if they went out with v0.85.0.

Corrections in 6e6ed10

Two claims in the first push were wrong, both documentation only.

not_found was missing from the refusals. asobi_match_lobby:eligible/2
returns it when mode_config/1 hands back an empty map, i.e. the mode name is
unknown or not configured (src/matches/asobi_match_lobby.erl:216). It is the
refusal a typo'd or unregistered mode reaches first, so it is now in both the
README list and the test's refusal table, and both read as open rather than
closed.

"The payload takes mode only" was too strong. It holds for match parameters,
which is the half worth stating and stays, but the handler parses an optional
ctx out of the same payload and forwards it to the game's join callback, as
match.join does (src/ws/asobi_ws_handler.erl:660-666). This SDK exposes no
join context on match.join, so none is exposed here either and the two stay
symmetric; the docs simply no longer claim mode is the only key the frame
accepts.

Checks

npx vitest run (146 passed, 9 files), npx tsc --noEmit,
npx tsc -p tsconfig.test.json, npx eslint src.

Held for the human gate - do not merge.

The match twin of world.find_or_create, answered with match.joined - the same
frame match.join is answered with, so the reply routes through the existing cid
correlation unchanged and there is no new event to dispatch.

Sending it needs no new method: this SDK is a transport, and the frame goes out
through ws.send() like every other one. What was missing was the documentation
and a test pinning the wire shape (mode alone), the reply routing, and the
refusals a caller has to branch on - quick_play_disabled first, since a match
mode defaults to quick_play = false.

Requires a server on asobi core v0.86.0 or newer: asobi 8f7d950 carries the
handler clause and is tagged v0.86.0, while v0.85.0 is the commit before it.
@Taure
Taure force-pushed the feat/match-find-or-create branch from 0a08638 to d5f34bd Compare August 14, 2026 11:49
Taure added 2 commits August 14, 2026 14:48
asobi_match_lobby:eligible/2 returns not_found when mode_config/1 hands back an
empty map, i.e. the mode name is unknown or unconfigured. That is the refusal a
typo'd or unregistered mode reaches first, and it was missing from both the
README list and the test's refusal table. The list now reads as open rather than
closed, since the server may add more.

Also drops the flat "payload takes mode only" claim. It is true of match
PARAMETERS, which is the useful half and stays, but the handler parses an
optional ctx out of the same payload and forwards it to the game's join
callback, exactly as match.join does. This SDK exposes no join context on
match.join, so it stays unexposed here too and the docs simply no longer claim
mode is the only key the frame accepts.
The refusal fixture paired code ws.request_failed with the message the
server uses for a code it does NOT define. ws.request_failed is in the
catalogue (asobi_error.erl:268) with its own message, so that pairing is
a shape the server never emits - and a test fixture is exactly where a
reader goes to learn the wire shape.
@Taure
Taure merged commit 97ed5a0 into main Aug 14, 2026
3 checks passed
@Taure
Taure deleted the feat/match-find-or-create branch August 14, 2026 13:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant