Skip to content

Compositions documentation - #278

Open
Gawor270 wants to merge 59 commits into
mainfrom
fce-2924-2925-smelter-cloud-docs
Open

Compositions documentation#278
Gawor270 wants to merge 59 commits into
mainfrom
fce-2924-2925-smelter-cloud-docs

Conversation

@Gawor270

@Gawor270 Gawor270 commented Jul 23, 2026

Copy link
Copy Markdown
Member

Closes FCE-2924, FCE-2925 and FCE-3137 by publishing the API specification here.

Documents compositions as a core Fishjam feature, integrated into the existing docs structure instead of a standalone section:

  • Concepts: explanation/compositions (what compositions are, core concepts, the scene model).
  • Tutorials: tutorials/compositions (create a composition end to end with curl).
  • How-to: how-to/compositions/ (write and deploy a template, compose a Fishjam room, drive a template with events, choose inputs and outputs).
  • API hub (api/reference): a Compositions section covering REST, the WebSocket event stream, authentication, and errors.

New top-level docs section for the hosted composition service: concept
overview (disambiguated from the client-side Smelter library), quick
start, template authoring with the composition SDK and CLI, room
composition, runtime events, an input/output guide, a scene-model
explainer, and an API reference. The REST reference renders a sanitized
preview OpenAPI spec via Scalar; the auth model and WebSocket event
stream are documented in prose.
@linear

linear Bot commented Jul 23, 2026

Copy link
Copy Markdown

FCE-2924

FCE-2925

FCE-3137

Gawor270 added 2 commits July 24, 2026 14:21
Replace the hand-written preview spec with one generated from the
service source, copied by scripts/update_api.sh (the source repo is
private, so it is cloned on demand instead of being a submodule) and
sanitized of internal-only fields. The committed spec comes from the
template-workers branch with the oneOf variant-title improvement
applied, matching what main will contain after the pending merge.

Align the docs with the actual API surface: templated outputs are
registered in a single multipart request to POST
.../output/{output_id}/template (config + template), not registered
first and uploaded after; rescaler takes a single child. Template code
samples are now type-checked by the build, with
@fishjam-cloud/composition linked from the js-server-sdk submodule.
CI's SUBMODULES_TOKEN covers the private source repo (same as the
fishjam and room-manager submodules), so clone-on-demand is not needed.
The repo has no semver release tags yet, so the submodule is checked out
at a branch instead of the latest tag.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds a new beta Smelter Cloud documentation section to the Docusaurus site, including concept docs, how-to guides, and a published OpenAPI/Scalar REST API reference.

Changes:

  • Introduces new docs/smelter/ docs tree (overview, quick start, scenes, how-tos, API reference) and sidebar categories.
  • Publishes Smelter Cloud REST API docs via Scalar at /api/smelter-cloud, backed by a committed OpenAPI JSON spec.
  • Updates tooling to fetch/copy the Smelter Cloud spec from a new submodule and links the local @fishjam-cloud/composition package for type-checkable examples.

Reviewed changes

Copilot reviewed 16 out of 18 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
yarn.lock Adds workspace link entry for @fishjam-cloud/composition.
static/api/smelter-cloud-openapi.json Adds committed Smelter Cloud OpenAPI 3.1 JSON spec for publishing.
spelling.txt Adds rtmp to spellcheck allowlist.
scripts/update_api.sh Adds branch-based submodule checkout and JSON spec sanitization/copy step.
package.json Adds linked dependency on @fishjam-cloud/composition for examples/typechecking.
docusaurus.config.ts Adds a Scalar instance to render the Smelter Cloud REST API reference page.
docs/smelter/what-is-smelter-cloud.mdx Adds Smelter Cloud concept overview and navigation pointers.
docs/smelter/scenes.mdx Documents video/audio scene model and live updates.
docs/smelter/quick-start.mdx Adds end-to-end tutorial for creating/registering inputs/outputs and publishing.
docs/smelter/how-to/write-and-deploy-a-template.mdx Adds template authoring/build/deploy guide including multipart upload endpoint.
docs/smelter/how-to/inputs-and-outputs.mdx Summarizes supported input/output protocols and key fields.
docs/smelter/how-to/drive-a-template-with-events.mdx Documents event delivery to templates via /event endpoint and eventBus.
docs/smelter/how-to/compose-a-fishjam-room.mdx Documents linking a Fishjam room and templating room-driven layouts.
docs/smelter/how-to/category.json Adds How-to Guides generated index under Smelter Cloud section.
docs/smelter/api-reference.mdx Adds entry-point page for REST API, WebSocket auth, and error format.
docs/smelter/category.json Adds top-level “Smelter Cloud” sidebar category at position 1.
.gitmodules Adds api/smelter-cloud submodule entry.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread scripts/update_api.sh Outdated
Comment thread docs/smelter/how-to/write-and-deploy-a-template.mdx Outdated
Comment thread docs/smelter/quick-start.mdx Outdated
Guard the jq dependency in update_api.sh, use optional chaining on peer
metadata in the template example, and fix quick-start wording: a
whip_client output publishes to a WHIP endpoint; playback is WHEP on the
receiving service.
@Gawor270
Gawor270 marked this pull request as ready for review July 24, 2026 14:37
Gawor270 added 6 commits July 24, 2026 16:53
The reference page now lives at /api/smelter-cloud next to the other API
docs, the Scalar page moves to /api/smelter-cloud/rest (mirroring the
/api + /api/rest pair of the server API), and the API hub page links
both. Smelter section links updated.
Replace the navbar dropdown with a single API Reference link landing on
the /api index, where the Composition API (Smelter Cloud) sits as a
subsection next to the SDK references and the hub page. The prose page
is renamed Composition API to match the spec title shown by Scalar.
Split the single autogenerated sidebar in two: the Docs sidebar drops
the api category, and a new apiSidebar (docs and versioned) holds the
API index, the SDK references, and the Composition API page. Landing on
API Reference now shows only API navigation instead of the full docs
tree.
Dissolve the standalone Smelter Cloud section: the concept page (with
the scene model) lives in explanation/, the quick start in tutorials/,
and the guides in how-to/compositions/. All content now presents
compositions as a Fishjam feature named Compositions, without beta
notes.

The API Reference returns to its earlier shape. The Composition API is
published like the other APIs: a Scalar page at /api/compositions, a
second document on /api/rest, a navbar dropdown listing both APIs, and
a Compositions section (REST, WebSocket, auth, errors) on the API hub
page. A presentation overlay (scripts/composition_openapi_overlay.jq)
adds operation summaries, tag groups, request examples, and titles for
anonymous oneOf variants. The submodule and spec are renamed to
api/composition and composition-openapi.json.

The room guide now documents the real flow: a single Fishjam
track_forwardings call forwards the room, links the composition, and
registers inputs automatically. The template guide starts from a simple
static example, and the room-aware hooks live in the room guide.
@Gawor270 Gawor270 changed the title [FCE-2924][FCE-2925] Smelter Cloud documentation Compositions documentation Jul 27, 2026
@Gawor270
Gawor270 requested a review from Copilot July 27, 2026 16:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 15 out of 17 changed files in this pull request and generated 4 comments.

Comment thread .gitmodules Outdated
Comment thread scripts/update_api.sh Outdated
Comment thread docusaurus.config.ts
Comment thread scripts/composition_openapi_overlay.jq Outdated
Gawor270 added 3 commits July 30, 2026 11:47
The submodule was moved to api/composition earlier but kept its old
api/smelter-cloud section name in .gitmodules.
Bump the api/composition submodule to the template-workers merge of
fishjam-cloud/foundry#133 and refresh the published spec. The source
spec now carries all presentation metadata itself: operation summaries,
human tag groups with a new Room forwarding tag, request body examples
for every operation, titled union variants, and tagged unions whose
examples validate against their schemas.
The overlay existed to add summaries, tags, examples, and variant
titles the generated spec lacked, and to strip internal fields and
relative links. All of it now lives in the source generator
(fishjam-cloud/foundry#133), and the overlay verifiably produces
byte-identical output to a plain copy, so update_api.sh copies the
spec directly and no longer needs jq. Also quote the paths in
checkout_submodule_branch.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 14 out of 16 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (7)

docs/how-to/compositions/compose-a-fishjam-room.mdx:114

  • This curl example uses a placeholder Authorization: ****** header, which is not a valid HTTP Authorization value and omits the required Bearer prefix for the Management Token.
  -H "Authorization: Bearer $TOKEN" \

docusaurus.config.ts:390

  • The /api/rest Scalar config declares a sources entry for the Composition API, but the page-level authentication.preferredSecurityScheme is set to management_token, which does not exist in composition-openapi.json (it uses BearerAuth). This can break or misconfigure the auth UI when switching to the Composition source, and it’s also redundant given the dedicated /api/compositions Scalar page below.
              title: "Composition API",
              slug: "composition",
              url: "/docs/api/composition-openapi.json",
            },
          ],

docs/how-to/compositions/compose-a-fishjam-room.mdx:97

  • This curl example uses a placeholder Authorization: ****** header, which is not a valid HTTP Authorization value and omits the required Bearer prefix for the Management Token.
  -H "Authorization: Bearer $TOKEN" \

docs/how-to/compositions/compose-a-fishjam-room.mdx:125

  • This curl example uses a placeholder Authorization: ****** header, which is not a valid HTTP Authorization value and omits the required Bearer prefix for the Management Token.
  -H "Authorization: Bearer $TOKEN"

docs/how-to/compositions/compose-a-fishjam-room.mdx:136

  • This curl example uses a placeholder Authorization: ****** header, which is not a valid HTTP Authorization value and omits the required Bearer prefix for the Management Token.
  -H "Authorization: Bearer $TOKEN"

docs/api/reference.md:93

  • The Composition authentication table contains broken/placeholder header values (e.g. missing Bearer, missing closing backticks) which will render incorrectly and gives an invalid auth example.
| Control-plane calls (composition, inputs, outputs, renderers, events, room) | `Authorization: Bearer <token>`: your Fishjam **Management Token**, the same token used across Fishjam.                                                 |
| Publishing to an input (`/whip/{input_id}`)                                 | The **input's** own bearer token, returned when you register a `whip_server` input (or the one you supplied). This is distinct from your account token. |
| Playing back an output (`/whep/{output_id}`)                                | Optional. Public playback is allowed; add a Bearer token only if you want to require one.                                                               |

docs/how-to/compositions/compose-a-fishjam-room.mdx:88

  • This curl example uses a placeholder Authorization: ****** header, which is not a valid HTTP Authorization value and omits the required Bearer prefix for the Management Token.

This issue also appears in the following locations of the same file:

  • line 97
  • line 114
  • line 125
  • line 136
  -H "Authorization: Bearer $TOKEN" \

Verified the compositions docs against foundry, fishjam, and the SFU, and
fixed the places where they diverged from the implementation:

- Drop the claim that a track forwarding can be removed from a live room.
  Fishjam routes track_forwardings with only: [:create], and the SFU only
  tears a forwarding down on room stop or endpoint crash.
- Describe cleanup as it works: after five minutes with no media on any
  input, rather than as soon as the composition has no inputs.
- Explain cleanup_without_inputs: false as widening the cleanup condition
  to need inputs and outputs quiet, not as switching cleanup off.
- Note that a room forwards to one composition at a time, with the repeat
  call being a no-op and a different target returning 409.
- Cover the start, reset, and delete lifecycle calls, and list every
  endpoint that can answer 503, not just composition creation.

@PiotrWodecki PiotrWodecki left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

postponing review until internal things are live

The shared cleanup warning repeated the paragraph it sat under in both
how-tos, so it is now only the part those paragraphs do not say: nothing will
delete this composition for you.

Both how-tos created a composition and then used $COMPOSITION without ever
capturing it, and two of them used $COMPOSITION_URL and $TOKEN with nothing
defining them, so following either from the top produced requests to an empty
URL. Both now save the id, and both carry the same environment block the
tutorial uses.

Also: the room how-to now says where to get the livestream URL and token it
asks you to paste, its two links to the Server API agree with each other, the
reference states that unknown fields are rejected rather than ignored, and the
intro no longer says the composed stream can be published anywhere when the
point is that it goes to one destination you choose.
@Gawor270
Gawor270 requested a review from PiotrWodecki August 11, 2026 14:01
@Gawor270

Gawor270 commented Aug 11, 2026

Copy link
Copy Markdown
Member Author

Updated with new composition api openapi after fixes and other improvements

@PiotrWodecki PiotrWodecki left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Mostly seems to match the current/future behavior, only stylistic changes are left

Comment thread docs/explanation/compositions.mdx Outdated
Comment thread docs/explanation/compositions.mdx Outdated
Comment thread docs/explanation/compositions.mdx Outdated
Comment thread docs/explanation/compositions.mdx Outdated
Comment thread docs/explanation/compositions.mdx Outdated
Comment thread docs/how-to/compositions/inputs-and-outputs.mdx Outdated
Comment thread docs/how-to/compositions/inputs-and-outputs.mdx Outdated
Comment thread docs/tutorials/compositions.mdx Outdated
Comment thread docs/tutorials/compositions.mdx Outdated
Comment thread docs/tutorials/compositions.mdx Outdated
The tutorial used inset as a verb once and then as a name for the layout twice,
170 lines later, without ever introducing that name. Step 4 meanwhile described
the same thing as a rounded box and as tucked into the corner. It is a corner
overlay everywhere now.
The tutorial described the layout twice, once in prose and once as a box
drawing, and neither showed what the composition actually produces. The clip
is the real thing: smelter rendering the Step 4 scene from the same two mp4
inputs, then the Step 6 update switching to tiles, captured through an mp4
output rather than a screen recording.
baseUrl is /docs, so a bare /video/... src pointed outside the site and the
element loaded nothing. useBaseUrl emits /docs/video/... instead.
The clip ran through the Step 6 layout switch and the caption announced it,
which gave away the step before the reader gets there. It is now ten seconds
of the corner overlay alone, and the caption describes just that.
The livestream is scaffolding here, not the subject, so getting one should be
as short as possible. One unauthenticated call now returns both the streamer
token and the stream id, replacing two authenticated calls.

It also means the result can be watched in the livestreaming demo instead of
sending readers to a third-party WHEP player, since that demo takes exactly
the room name used here. A note says the Sandbox API is for prototyping and
production creates livestreams through the Server API, and cleanup still goes
that way because the Sandbox API only creates.
The clip above already shows the layout, so naming it again after the playback
instructions repeats what the reader has just watched.
@Gawor270
Gawor270 requested a review from PiotrWodecki August 13, 2026 13:47
@fishjam-cloud fishjam-cloud deleted a comment from Gawor270 Aug 13, 2026
Restores the Sandbox API flow reverted in d69e4b9, with the one change that
made it fail: the livestream is created with public=false.

The room-manager keys its in-memory room lookup on the whole room config, and
public is part of that config, so a livestream created as public is stored
under a different key than the one the viewer path looks for. getSandboxViewerToken
in the client SDK sends no public parameter, so it always looks for the
unlisted variant and a public livestream is invisible to it.

Verified end to end against production: the create call returns a streamer
token, and the viewer token call the demo makes returns 200 for the same room
name.
The inputs table already lists what a whip_server input accepts, from a phone
camera to a hardware encoder, so pointing at a third-party publisher on top
added nothing. OBS stays, it ships WHIP output.

The template how-to also promised that the tutorial's livestream plays back in
any WHEP player without a token. Since the tutorial now creates it unlisted
through the Sandbox API, that is no longer true.
The composition pages tell you to copy your Management Token and then ask you
to paste it into YOUR_FISHJAM_TOKEN. Everywhere else in the docs it is the
Management Token, so the placeholder now says so too.
The page handed the reader a template and then jumped straight to sending
events, with no route from one to the other. It now names the multipart deploy
request and the livestream the output needs, each linked to the page that
covers it.
Two pages sent readers to an empty URL. The template how-to publishes with
$STREAMER_TOKEN and deletes $STREAM without setting either, and the inputs
and outputs guide uses $COMPOSITION_URL, $TOKEN and $COMPOSITION with no
environment block at all. Both now define what they use, and say which
tutorial step produces the composition, the livestream and its token.
Doing it in the preamble meant both sat idle through scaffolding, writing and
building the template, and a composition with no input media deletes itself
after five minutes, so the reader would reach the deploy step with nothing to
deploy to. The environment block now lives in the deploy section.

The inputs and outputs guide keeps no environment block: it is a reference for
picking types, not a walkthrough.
Comment thread docs/tutorials/compositions.mdx Outdated
Comment thread docs/how-to/compositions/drive-a-template-with-events.mdx Outdated
Comment thread docs/_common/compositions/idle-cleanup.mdx Outdated
Comment thread docs/how-to/compositions/inputs-and-outputs.mdx Outdated
The Sandbox API URL is a separate credential that can be regenerated and
revoked on its own, so it cannot be derived by appending /room-manager to the
Fishjam URL. The tutorial exports it like every other value it needs, and Step
5 points back at the same one rather than describing how to build it.
It was created in the preamble and then sat through the whole template
example, which is the one thing the page warns about two paragraphs later.
Creation now happens in the deploy section, next to the output it needs.
The route is /api/composition/{composition_id}/whip/{input_id}. Posting to
rtc.fishjam.io/whip/... answers 400 missing field composition_id, so the
shortened form sent publishers nowhere.
With cleanup_without_inputs off, cleanup still runs, it just waits for the
outputs to go quiet as well as the inputs. Claiming nothing will clean it up,
or that an idle one survives indefinitely, promised more than the code does:
is_inactive returns inputs_inactive && outputs_inactive in that mode, so an
idle composition is still collected. What survives is one whose output keeps
publishing.
main now requires url on the mp4 input and no longer has an hls input at all,
so the spec asset, the input table and every prose list of supported protocols
follow. The submodule points at main again, the way update-api leaves it.
@Gawor270
Gawor270 requested a review from PiotrWodecki August 14, 2026 10:38

@PiotrWodecki PiotrWodecki left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

good job

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.

3 participants