Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion demo/web/src/meet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ function join(): void {
tile("local", name, localCanvas, true);
localPreview = new Publish.Preview.Renderer({
canvas: localCanvas,
frame: local.cameraCapture.out.frame,
frames: local.cameraCapture.out.frames,
display: local.cameraCapture.out.display,
flip: true,
});
Expand Down
13 changes: 13 additions & 0 deletions doc/bin/relay/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,19 @@ Every option is also a `--flag` or `MOQ_*` environment variable, and
[`demo/relay/`](https://github.com/moq-dev/moq/tree/main/demo/relay) has
working configs for development, production, and a cluster.

## Embedding

`Relay::load` is the embedder API: it binds listeners, resolves auth, and
builds the cluster. Mount extra routes on `web.routes()` and publish from
application workers on `cluster.origin`. `rs/moq-relay/tests/embed.rs` is
the small public example (custom `/app` plus an origin worker).

`Relay` is `#[non_exhaustive]`. Destructure with `..`. Dropping `workers`
or `uring` releases the QUIC port while the rest still compiles; keep those
fields if `runtime.workers` is set. An owning runner for that hazard is
the relay-embedding quest on `dev`. Embedding is not a
[moq-dev/smoke](https://github.com/moq-dev/smoke) client.

## Operate

| Task | Guide |
Expand Down
20 changes: 20 additions & 0 deletions doc/lib/js/hang.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,23 @@ import * as Container from "@moq/hang/container";
Most apps never import it directly; the elements and `Broadcast` classes in
the watch and publish packages do. Reach for it when hand-rolling a catalog
or building a custom player.

## Migrating

A hang catalog is a JSON **Snapshot**, not one full root per frame. Read it
with `Json.Snapshot.Consumer` and `Catalog.RootSchema`, the way
`@moq/watch` does:

```ts
const track = broadcast.track(Catalog.TRACK).subscribe({ priority: Catalog.PRIORITY.catalog });
const catalog = new Json.Snapshot.Consumer<Catalog.Root>({

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Import Json in the catalog migration example

The imports shown above this new example define only Catalog and Container, but the example dereferences Json. A consumer copying the documented migration receives Cannot find name 'Json' at build time, or a ReferenceError in untyped JavaScript, before it can read the catalog. Add the @moq/json namespace import to the snippet.

Useful? React with 👍 / 👎.

track,
schema: Catalog.RootSchema,
});
const root = await catalog.next();
```

Frame 0 of a group is a full catalog; later frames are RFC 7396 merge patches.
`JSON.parse` plus `RootSchema` on every frame is the old consumer and rejects
the deltas. Compressed catalogs use `Catalog.TRACK_COMPRESSED` and
`compression: true` on the same consumer.
6 changes: 5 additions & 1 deletion doc/lib/js/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,11 @@ React and Solid adapters for the reactive state.
Below the elements, `Watch.Broadcast` and `Publish.Broadcast` are the same
pipelines without DOM, and `@moq/net` is the protocol itself. Examples:
[`js/net/examples/`](https://github.com/moq-dev/moq/tree/main/js/net/examples)
covers connecting, publishing, subscribing, and discovery.
covers connecting, publishing, subscribing, and discovery. The reconnecting
`Connection` handle, catalog Snapshot reads, and stats Snapshot versus Window
are covered by [moq-dev/smoke](https://github.com/moq-dev/smoke)'s from-dev
channel (`./dev.sh`). See also the [net](/lib/js/net#migrating) and
[hang](/lib/js/hang#migrating) migration notes.

## Browser support

Expand Down
25 changes: 25 additions & 0 deletions doc/lib/js/net.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,28 @@ Examples in
[`js/net/examples/`](https://github.com/moq-dev/moq/tree/main/js/net/examples).
Runs in the browser and, over WebSocket, in Node, Bun, and Deno; see
[server-side](/lib/js/#server-side).

The unpublished `dev` surface is proven by the from-dev channel in
[moq-dev/smoke](https://github.com/moq-dev/smoke) (`./dev.sh`), not by an
in-tree packaged fixture.

## Migrating

- **`Connection.Reload` / `Connection.Shared` are gone.** `new Connection({ url })`
is the reconnecting handle: one origin and one reconnect loop per relay URL.
`Connection.connect` is still the one-shot session. `closed` settles when
*this handle* is released, not when a session drops. The failure that stopped
retrying the current URL is `error`; `url.set(next)` recovers the same handle
(credential refresh).
- **Do not call `consume` on the reconnecting handle.** `Established.consume(path)`
stays on a one-shot session. A `Connection` exposes `origin`; resolve with
`origin.request(path)` (swaps on a republish) and discover with
`connection.announced(prefix)`. Announce events carry `pattern`, not `path`.
- **`broadcast.track(name).subscribe(opts)` is the public read.**
`broadcast.subscribe(name)` is the wire-layer helper. Hang catalog reads go
through the track handle, then `ordered()` when a codec needs sequence order.
`ordered()` takes the subscription over: `recvGroup` throws afterwards.
- **JSON is three modes**, in [`@moq/json`](https://www.npmjs.com/package/@moq/json):
`Snapshot` (lossy latest-value, merge-patch deltas), `Stream` (lossless
append-log), `Window` (retained range). Pick the mode; do not parse every
frame as a full document. Live stats are Snapshot. Billing rollups are Window.
8 changes: 8 additions & 0 deletions doc/lib/rs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ The reference implementation. Every crate is on
## Quick start

`moq-tokio` configures the endpoint; `moq-net` does the protocol.
`moq-native` is a tombstone: replace `moq-native` with `moq-tokio` in
`Cargo.toml` and `moq_native` with `moq_tokio` in source. There is no
compatibility shim.

A hang catalog or live stats track is `moq_json::snapshot`; a retained
rollup is `moq_json::window`. Subscribe with
`broadcast.track(name)?.subscribe(...)`, then the JSON consumer, not a
generic frame reader.

```rust
// The Origin is the local hub: the session fills it with remote broadcasts
Expand Down
7 changes: 4 additions & 3 deletions js/json/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@
[![npm version](https://img.shields.io/npm/v/@moq/json)](https://www.npmjs.com/package/@moq/json)
[![TypeScript](https://img.shields.io/badge/TypeScript-ready-blue.svg)](https://www.typescriptlang.org/)

JSON publishing over [Media over QUIC](https://moq.dev/) tracks, in two modes:
JSON publishing over [Media over QUIC](https://moq.dev/) tracks, in three modes:

- **`Snapshot`**: lossy. One JSON value updated over time; a consumer only gets the most recent value. Intermediate updates are collapsed and older groups are dropped.
- **`Snapshot`**: lossy. One JSON value updated over time; a consumer only gets the most recent value. Intermediate updates are collapsed and older groups are dropped. Hang catalogs and live stats use this.
- **`Stream`**: lossless. An ordered append-log of self-contained records; every record is preserved and delivered in order, nothing is ever superseded.
- **`Window`**: a bounded run of records, appended to the back and dropped from the front. A late reader is restated what is still retained (billing rollups).

Pick `Snapshot` when consumers care about "what is the value now" (a catalog, a status document) and `Stream` when they care about every record (an event log, a media timeline).
Pick `Snapshot` when consumers care about "what is the value now", `Stream` when they care about every record of an unbounded log, and `Window` when old records retire. Do not parse every Snapshot frame as a full document: frame 0 is a snapshot and later frames are RFC 7396 merge patches.

## Quick Start

Expand Down
1 change: 0 additions & 1 deletion quest/m1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ does not require it.
- [FFI frame cursor](/quest/m1/api-ffi-frame-cursor.md) - empty groups and cancelled reads do not become false EOF or lost frames
- [Subscription bounds](/quest/m1/api-subscription-bounds.md) - local and requested ranges use consistent exclusive ends
- [Publisher finish borrows](/quest/m1/api-finish-borrow.md) - finish borrows the handle so abort can still run after a clean end
- [External API proof](/quest/m1/api-release-proof.md) - packaged callers exercise real moq.pro use cases and record each audit finding's disposition
- [Monotonic timeline](/quest/m1/monotonic-timeline.md) - a marker group of one empty frame declares a break and moves the live edge; producers refuse a rewind; consumers jump the playhead on an unproven hole and drop rewind detection
- [Anonymous rank](/quest/m1/anonymous-route-rank.md) - moq-net: a route through an anonymous hop ranks below every identified route at any cost, and hop 0 travels the chain to say so
- [A/V clock](/quest/m1/plan-av-clock.md) - the audio playhead drives Sync.reference while audio plays, through per-track sync handles
Expand Down
2 changes: 1 addition & 1 deletion quest/m1/api-finish-borrow.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,4 @@ then `just test smoke-full` because `moq-ffi` behavior changes.

## Related

- [External API proof](/quest/m1/api-release-proof.md) - records this disposition
- [Merge dev](/quest/m1/merge-dev.md) - records this disposition
79 changes: 0 additions & 79 deletions quest/m1/api-release-proof.md

This file was deleted.

20 changes: 19 additions & 1 deletion quest/m1/merge-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,28 @@ merge for it. The rest of the archive line, wildcard resolution, and every
additive quest that builds on dev-only code start on main afterwards from
[m2](/quest/m2/README.md).

The 2026-09-12 external API audit is closed. Proof is
[moq-dev/smoke](https://github.com/moq-dev/smoke) `./dev.sh` (unpublished
`dev` checkout, not crates.io/npm latest) plus
`rs/moq-relay/tests/embed.rs` for custom routes and origin workers.
Comment on lines +48 to +51

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"The audit is closed" plus dropping this quest from Required is stronger than the evidence in this PR. The packaged-consumer proof is moq-dev/smoke#36, which is still open, and that job checks out moq dev rather than a recorded revision.

The original gate was "fixture in CI + exact revisions." Pointing at ./dev.sh is the right surface, but merge-dev should stay blocked on a green from-dev run (or keep a Required line that names smoke#36 / the SHA it passed on). Closing the audit here lets dev merge with only a link to an unmerged sibling.

Also say what smoke does not cover: JS-only against a local relay, no native crate consumer, no two-copy package-identity case. Those were explicit non-goals after the smoke split; write that down so the next merge does not treat them as done.

(Written by grok-4.6)

Embedding ownership of `workers`/`uring` stays on
[Relay embedding](/quest/m1/api-relay-embedding.md).

| Finding | Disposition | Revision |
|---|---|---|
| FFI pending reads serialize independent datagram/group lanes | Fixed: independent group and datagram lanes | `1f7b2b45b` (#3651) |

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The independent-lane fix is #3645 (fix(ffi): let group and datagram reads progress independently). #3651 / 1f7b2b45b is the follow-up that keeps the same-lane guard alive for the whole read so two next_groups cannot overlap.

Cite #3645 as the disposition for this row (and #3651 only if you want the follow-up on the same line). As written, the table points at the wrong revision for the audit finding.

(Written by grok-4.6)

| Shared/private connections disagree on credential-refresh recovery and terminal state | Fixed: one URL-recovery contract, `closed` is handle disposal | `b5a289a05` (#3636) |
| Relay embedding can discard newly added socket owners without a compile error | Deferred to [Embedding](/quest/m1/api-relay-embedding.md); `tests/embed.rs` covers routes and origin workers on the current load API | open |
| FFI first-frame convenience treats empty groups as EOF and loses an acquired group on cancellation | Deferred to [Frame cursor](/quest/m1/api-ffi-frame-cursor.md) | open |
| JSON/binary readers hide the subscription cleanup handle | Abandoned: finish must be `&mut` so abort can follow | `a8dbf886d` (#3637) |
| Local inclusive ends cannot express the empty exclusive range | Deferred to [Bounds](/quest/m1/api-subscription-bounds.md) | open |
| Typed Getter input can be rejected solely for lacking an internal brand | Fixed: `getter()` reuses any conforming Getter | `26b505995` (#3639) |
| JSON edit guard logs failed implicit publication | Fixed: `modify` refuses a closed track, a failed drop aborts it | `ff45019fc` (#3644) |
| Terminal publisher methods inconsistently retain the caller's handle | Deferred to [Finish borrows](/quest/m1/api-finish-borrow.md) | open |

## Required

- [m0](/quest/m0/README.md) - every release blocker lands or is punted before the merge
- [External API proof](/quest/m1/api-release-proof.md) - the packaged consumer fixture and explicit fix/deferral decisions must be recorded before merge
- [Monotonic timeline](/quest/m1/monotonic-timeline.md) - so a shed marker still jumps the playhead on a timestamp hole (#3291)
- [Wildcard docs](/quest/m1/wildcard-docs.md) - the release that follows ships pattern advertisements, so their docs ship in it

Expand Down
Loading
Loading