Repository navigation
feat: send match.find_or_create, the race-free route into a live match - #35
Merged
Merged
Conversation
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
force-pushed
the
feat/match-find-or-create
branch
from
August 14, 2026 11:49
0a08638 to
d5f34bd
Compare
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
asobi v0.86.0 adds an inbound frame,
match.find_or_create: get into a livematch of a mode, spawning one if there is none. It is the match twin of
world.find_or_create, and it is answered withmatch.joined- the same framematch.joinis answered with, so there is no new reply type and nothing new todispatch.
{"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_createormatch.joineither) and adding one would cut againstthe documented scope. The frame goes out through
ws.send()like every otherone, and its reply resolves that promise through the existing
cidcorrelation. What was missing was the documentation and a test.
README.md: one line in the Quick start beside the existingmatch.joinsend, and a
### Finding or creating a matchsection carrying the detail.test/match-find-or-create.test.ts: pins the outbound shape (the payload asgiven, under a cid), the reply routing (resolves on
match.joined, identicalto what
match.joinresolves with), and that each refusal rejects with itsreason 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_playersor the tick rate. Eligibility is themode's
quick_playflag, which defaults tofalsefor match modes, so a modethat has not opted in is refused with
quick_play_disabled-listedisbrowser visibility, a separate axis. Refusals also include
not_found,match_capacity_reached,wrong_mode_typeandjoin_rate_limited. More canbe 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 taggedv0.86.0;v0.85.0is97f4cbb, the commit beforeit, 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_foundwas missing from the refusals.asobi_match_lobby:eligible/2returns it when
mode_config/1hands back an empty map, i.e. the mode name isunknown or not configured (
src/matches/asobi_match_lobby.erl:216). It is therefusal 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
modeonly" was too strong. It holds for match parameters,which is the half worth stating and stays, but the handler parses an optional
ctxout of the same payload and forwards it to the game'sjoincallback, asmatch.joindoes (src/ws/asobi_ws_handler.erl:660-666). This SDK exposes nojoin context on
match.join, so none is exposed here either and the two staysymmetric; the docs simply no longer claim
modeis the only key the frameaccepts.
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.