Skip to content

Commit 9901429

Browse files
committed
docs(api): document core vs helpers split and typed sync errors
1 parent 457d9fd commit 9901429

2 files changed

Lines changed: 33 additions & 23 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,8 @@ All notable changes to `moqx` will be documented in this file.
1919
`op: :publish` and the matching `publish_ref`.
2020
- **Breaking:** publisher write lifecycle now has explicit synchronous gating.
2121
Writes no longer silently drop before downstream activation.
22-
`write_frame/2` and `open_subgroup/3` now fail with
23-
`{:error, "track_not_active"}` before subscribe activation and
24-
`{:error, "track_closed"}` after `finish_track/1`.
22+
`write_frame/2` and `open_subgroup/3` now fail synchronously with typed
23+
`%MOQX.RequestError{code: :track_not_active | :track_closed}`.
2524
- Subscriber data-path race handling now tolerates early subgroup streams that
2625
arrive just before local `SubscribeOk` state installation, reducing first-frame
2726
loss risk under control/data-plane reordering.
@@ -39,7 +38,12 @@ All notable changes to `moqx` will be documented in this file.
3938
`{:moqx_error, ..., reason}`) are no longer the primary public contract.
4039
Async failures now flow through `%MOQX.RequestError{}` and
4140
`%MOQX.TransportError{}`.
42-
- `await_catalog/2` now consumes the typed fetch message contract.
41+
- Added explicit publisher track lifecycle events for track owners:
42+
`{:moqx_track_active, %MOQX.TrackActive{...}}` and
43+
`{:moqx_track_closed, %MOQX.TrackClosed{...}}`.
44+
- **Breaking:** helper-level convenience APIs moved out of core `MOQX` into
45+
`MOQX.Helpers` (`publish_catalog/2`, `update_catalog/2`, `fetch_catalog/2`,
46+
`await_catalog/2`).
4347
- Mix tasks (`moqx.e2e.pubsub`, `moqx.moqtail.demo`) and integration helpers now
4448
follow the typed async contract.
4549

README.md

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,10 @@ Today `moqx` supports a single client-side path:
4444
- broadcasts, tracks, and frame delivery
4545
- live subscription via SUBSCRIBE with `FilterType::LatestObject`
4646
- raw fetch for retrieving track objects by range (subscriber sessions only)
47-
- publisher-side catalog publication helpers via `publish_catalog/2` and `update_catalog/2`
48-
- raw catalog retrieval via `fetch_catalog/2` and `await_catalog/2`
47+
- optional helper-layer catalog publication via `MOQX.Helpers.publish_catalog/2`
48+
and `MOQX.Helpers.update_catalog/2`
49+
- optional helper-layer catalog retrieval via `MOQX.Helpers.fetch_catalog/2`
50+
and `MOQX.Helpers.await_catalog/2`
4951
- CMSF catalog parsing and track discovery via `MOQX.Catalog`
5052
- relay authentication through the connect URL query, using `?jwt=...`
5153
- path-rooted relay authorization, where the connect URL path must match the token `root`
@@ -66,7 +68,10 @@ Out of scope for `v0.1`:
6668

6769
## Public API
6870

69-
The intended API is the single `MOQX` module.
71+
`moqx` exposes:
72+
73+
- `MOQX` — low-level core message-passing API
74+
- `MOQX.Helpers` — opt-in convenience helpers built on top of `MOQX`
7075

7176
### Connect
7277

@@ -173,31 +178,32 @@ broadcast =
173178
end
174179

175180
catalog_json = ~s({"version":1,"supportsDeltaUpdates":false,"tracks":[{"name":"video","role":"video"}]})
176-
{:ok, catalog_track} = MOQX.publish_catalog(broadcast, catalog_json)
177-
:ok = MOQX.update_catalog(catalog_track, catalog_json)
181+
{:ok, catalog_track} = MOQX.Helpers.publish_catalog(broadcast, catalog_json)
182+
:ok = MOQX.Helpers.update_catalog(catalog_track, catalog_json)
178183

179184
{:ok, track} = MOQX.create_track(broadcast, "video")
180185
:ok = MOQX.write_frame(track, "frame-1")
181186
:ok = MOQX.write_frame(track, "frame-2")
182187
:ok = MOQX.finish_track(track)
183188

184189
# lifecycle gating on the same handle:
185-
{:error, "track_closed"} = MOQX.write_frame(track, "frame-3")
190+
{:error, %MOQX.RequestError{code: :track_closed}} = MOQX.write_frame(track, "frame-3")
186191
```
187192

188193
Write calls are explicitly lifecycle-gated (no silent drops):
189194

190-
- `{:error, "track_not_active"}` before a downstream subscribe activates the track
191-
- `{:error, "track_closed"}` after `finish_track/1`
195+
- `{:error, %MOQX.RequestError{code: :track_not_active}}` before downstream
196+
subscribe activation
197+
- `{:error, %MOQX.RequestError{code: :track_closed}}` after `finish_track/1`
192198

193199
### Publisher-side catalog publication
194200

195201
In moqtail-style relays, the publisher is responsible for publishing the
196202
`"catalog"` track. The relay then forwards that catalog track downstream to
197203
subscribers.
198204

199-
Use `publish_catalog/2` for initial publication, then `update_catalog/2` for
200-
subsequent catalog objects:
205+
Use `MOQX.Helpers.publish_catalog/2` for initial publication, then
206+
`MOQX.Helpers.update_catalog/2` for subsequent catalog objects:
201207

202208
```elixir
203209
{:ok, publish_ref} = MOQX.publish(publisher, "my-namespace")
@@ -210,8 +216,8 @@ broadcast =
210216
catalog_json =
211217
~s({"version":1,"supportsDeltaUpdates":false,"tracks":[{"name":"video","role":"video"}]})
212218

213-
{:ok, catalog_track} = MOQX.publish_catalog(broadcast, catalog_json)
214-
:ok = MOQX.update_catalog(catalog_track, catalog_json)
219+
{:ok, catalog_track} = MOQX.Helpers.publish_catalog(broadcast, catalog_json)
220+
:ok = MOQX.Helpers.update_catalog(catalog_track, catalog_json)
215221
```
216222

217223
### Subscribe
@@ -356,16 +362,16 @@ Options:
356362
- `start` -- `{group_id, object_id}` (default `{0, 0}`)
357363
- `end` -- `{group_id, object_id}` (default: open-ended)
358364

359-
`fetch_catalog/2` is a convenience wrapper that fetches the first catalog
360-
object with sensible defaults (namespace `"moqtail"`, track `"catalog"`,
361-
range `{0,0}..{0,1}`).
365+
`MOQX.Helpers.fetch_catalog/2` is a convenience wrapper that fetches the first
366+
catalog object with sensible defaults (namespace `"moqtail"`, track
367+
`"catalog"`, range `{0,0}..{0,1}`).
362368

363-
`await_catalog/2` collects the fetch messages and decodes the payload into
364-
an `MOQX.Catalog` struct in one call:
369+
`MOQX.Helpers.await_catalog/2` collects the fetch messages and decodes the
370+
payload into an `MOQX.Catalog` struct in one call:
365371

366372
```elixir
367-
{:ok, ref} = MOQX.fetch_catalog(subscriber)
368-
{:ok, catalog} = MOQX.await_catalog(ref)
373+
{:ok, ref} = MOQX.Helpers.fetch_catalog(subscriber)
374+
{:ok, catalog} = MOQX.Helpers.await_catalog(ref)
369375

370376
catalog |> MOQX.Catalog.video_tracks() |> Enum.map(& &1.name)
371377
#=> ["259", "260"]

0 commit comments

Comments
 (0)