feat(openapi): spec the MoQ join-token mint surface - #30
Conversation
MoQ is live end-to-end but had no entry in openapi.yaml, so no SDK and no CLI
command could be generated for it. Adds the MoQ tag and both mint operations
(POST /moq/publish/{ns}/{track} -> moq:write, GET /moq/subscribe/{ns}/{track}
-> moq:read), the MoqJoinToken response schema, and ns/track path parameters
constrained to ^[a-z0-9-]{1,64}$ to match the gateway regex.
Specs the failures alongside the happy path: 400 MOQ_JOIN_BAD_RESOURCE, 401,
the 402 x402 challenge, 403, 429, and the fail-closed 503
MOQ_JOIN_UNCONFIGURED. Adds X402PaymentRequired/X402Accepts and a reusable
PaymentRequired response, because the 402 body is not the Error envelope --
its error member is a string and the normalized error object is nested under
error_detail. Verified against api.wave.online: both a missing key and an
unrecognized key return 402 on these routes, not 401.
The MoQ media session is deliberately not modelled -- it is not an HTTP
surface. The tag description covers the direct-to-relay flow, the join query
parameter / x-wave-moq-join header token carriers, and pins the surface to
draft-ietf-moq-transport-18 (draft-19, published 2026-07-06, not yet
deployed).
Closes #24
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_0d122155-8867-4a9d-a261-2da8672e5051) |
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 37 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
✨ Finishing Touches🧪 Generate unit tests (beta)
✨ Simplify code
Comment |
Closes #24.
What
Adds the
MoQtag and the two join-token mint operations toopenapi.yaml— the Media over QUIC product is live end-to-end and had no entry in the spec, so no SDK and no CLI command could be generated for it.mintMoqPublishTokenPOST /moq/publish/{ns}/{track}moq:writemintMoqSubscribeTokenGET /moq/subscribe/{ns}/{track}moq:readMoqJoinTokenresponse schema:ok,relayWsUrl,joinToken,expiresIn,ns,track,role,scope, optionalprotocol.MoqNamespaceParam/MoqTrackParamconstrained to^[a-z0-9-]{1,64}$, matching the gateway's segment regex exactly.x-wave-declare-protocolpublish header (documented as best-effort: an unrecognized or unauthorized value is ignored and never fails the mint).Failures are specified, not just the happy path
400 MOQ_JOIN_BAD_RESOURCE,401,402(x402 challenge),403,429, and the fail-closed503 MOQ_JOIN_UNCONFIGURED— plus a reusablePaymentRequiredresponse and newX402PaymentRequired/X402Acceptsschemas.The 402 needed its own schema because it is not the
Errorenvelope: itserrormember is a plain string ("payment required") and the normalized WAVE error object is nested undererror_detail. Every other 402 in this document$refsError, which does not match what the gateway returns.Boundary: the wire protocol is not modelled
The MoQ media session is not an HTTP surface, so it is described in prose in the tag description rather than modelled: the direct-to-relay flow, and the two token carriers (
?join=query parameter for browser WebSocket clients that cannot set headers;x-wave-moq-joinheader server-to-server).The surface corresponds to
draft-ietf-moq-transport-18— what the relay currently speaks (preferreddraft-18, negotiatingdraft-07..draft-18over ALPN).draft-19was published 2026-07-06 and is not yet deployed; adoption is tracked separately. The mint contract is transport-version independent — a draft bump changes the wire session, not this HTTP contract.Receipts
1. Live probes against
api.wave.online(unauthenticated only — no credentials were used):Behaviour note: a request with a syntactically-valid-but-unrecognized bearer token also returns
402, not401, on these routes — the x402 challenge is offered ahead of key rejection. The spec'sPaymentRequireddescription records this so a generated client does not treat 402 as exceptional.401remains specified because the shared auth gate can still produce it.2. Codegen runs clean from this spec alone (
sdks/codegen/generate.py --spec <this openapi.yaml>, run in a scratch tree so no SDK output is committed here):Emitted Go client:
Ruby (
ruby -c sdk-ruby/lib/wave/moq.rb→Syntax OK) and Rust (pub fn moq(&self) -> moq::Moq<'_>) register the product on the umbrella client identically.3. The generated client reaches the real route. Driving the generated Ruby SDK against production with no credentials:
That is the correct outcome for an unauthenticated caller and proves the generated method builds and calls the right path.
What is NOT verified
moq:write-scoped API key, and no credentials were used for this change. The mint path is proven from the gateway side, but the receipt for "generated client → realjoinToken" is still outstanding.go build/cargo checkon the generated trees were not run — both wanted to fetch modules from the network in the sandbox. CI runs these gates.sdksbefore it will run onmain's spec at all — see below. That is a pre-existing break, not caused by this PR.Pre-existing codegen break (separate PR)
generate.pycurrently dies onmain's spec withTypeError: cannot use 'list' as a dict key—Attestation.sig/WaveAttestation.siguse the OpenAPI 3.1 nullable formtype: [string, null], whichparse_spec._field_typepasses through as a Python list into every renderer's type map. Reproduced on the unmodifiedorigin/mainspec, so it predates this change. Fixed in a companionsdksPR; the codegen output above was produced with that fix applied.Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.Note
Low Risk
Spec-only changes to openapi.yaml and CHANGELOG.md; no gateway or relay runtime code. Contract risk is limited to generated clients and integrators relying on the new 402/x402 and MoQ mint shapes.
Overview
Adds the MoQ OpenAPI product so SDK/CLI codegen can target live join-token mint routes that were previously undocumented.
New HTTP operations:
POST /moq/publish/{ns}/{track}(mintMoqPublishToken,moq:write) andGET /moq/subscribe/{ns}/{track}(mintMoqSubscribeToken,moq:read). Path params useMoqNamespaceParam/MoqTrackParamwith^[a-z0-9-]{1,64}$. Publish mint documents optionalx-wave-declare-protocolfor billing (ignored when unrecognized/unauthorized; never fails the mint).Response and errors:
MoqJoinToken(relayWsUrl,joinToken,expiresIn, boundns/track,role,scope, optionalprotocol) withCache-Control: no-store. Failures include400 MOQ_JOIN_BAD_RESOURCE, standard auth/quota responses, reusablePaymentRequired(402) pointing atX402PaymentRequired/X402Accepts(402 body is not the normalErrorenvelope), and503 MOQ_JOIN_UNCONFIGUREDviaMoqJoinUnconfigured.The MoQ tag prose clarifies direct-to-relay media (not API gateway), token carriers (
joinquery vsx-wave-moq-join), and pins wire transport to draft-ietf-moq-transport-18 while keeping this HTTP mint contract transport-independent. CHANGELOG records the same under Unreleased.Reviewed by Cursor Bugbot for commit 8c8cbb2. Configure here.
Summary by cubic
Adds the MoQ join-token mint surface to
openapi.yamlso SDKs and the CLI can mint publish/subscribe tokens for Media over QUIC. Defines endpoints, response schema, and the x402 payment challenge.New Features
MoQtag withmintMoqPublishToken(POST /moq/publish/{ns}/{track},moq:write) andmintMoqSubscribeToken(GET /moq/subscribe/{ns}/{track},moq:read).MoqJoinTokenresponse (relayWsUrl,joinToken,expiresIn,ns,track,role,scope, optionalprotocol); publish accepts optionalx-wave-declare-protocol.ns/trackconstrained to^[a-z0-9-]{1,64}$; explicit 400/401/402/403/429/503 responses; reusablePaymentRequiredusingX402PaymentRequired/X402Accepts(not theErrorenvelope).draft-ietf-moq-transport-18.Migration
X402PaymentRequired(notError); missing or unrecognized API keys may return 402 on these routes.joinToken(Cache-Control: no-store); mint per session and carry it via thejoinquery param orx-wave-moq-joinheader when connecting torelayWsUrl.Written for commit 8c8cbb2. Summary will update on new commits.