# wai-room (crate joule-moq-room): an example configuration. Nothing secret belongs here: the # keys are a file of their own (`wai-room keygen ` makes it, mode 0600), outside every # repository, and the relay knows the clock's token by its SHA-256 alone. # The HTTP service, on loopback behind the front that serves the room's page. listen = "127.0.0.1:9682" # The path the front serves the service under, when it strips it (`/room-api`): a grant's proof # over HTTP, and a watch room's join proof, name the path the page addressed. public_prefix = "/room-api" keys = "/path/to/keys.toml" # The relay's WebSocket endpoint, for the clock's own session (loopback): the relay's # `websocket_listen` and `path`, as relay.example.toml sets them (tests/ports.rs holds the two # files, and the port table in wai/quickstart/README.md, to each other). relay_url = "ws://127.0.0.1:4480/moq" # Exit with status 70 past this resident memory (MiB), for the supervisor to restart it. max_resident_mb = 256 [room] # Publishers at once, those whose grants are still waited for among them; the composition # lays out this many tiles. max_publishers = 4 max_present = 16 # A grant's life, in seconds. publisher_grant_s = 1200 viewer_grant_s = 1800 # How long a publisher's grant holds its place before its tracks appear. join_wait_s = 90 # Grants one room takes; then a new room starts once it is empty. max_grants = 64 # Every room end-to-end encrypted (WAI confidentiality): a confidentiality record, an MLS # group whose external sender is the clock, and the room's log of MLS messages. Such a room # is never recorded, and its viewers are not members of its group. e2ee = false # Every room watches this file together (WAI co-watch): served whole, named by the room's # co-watch policy, with its duration in milliseconds. Empty for rooms that watch nothing. A # watch room is not also end-to-end encrypted, admitted by age or a room with co-performance. watch_source = "" watch_duration_ms = 0 # The actions every principal of a watch room may control: 1 play, 2 pause, 4 seek, 8 rate. watch_control = 15 # The skew window the clock states, in milliseconds: a whole number of seconds. watch_window_ms = 5000 # The keys (64 hexadecimal digits each, at most 16) that take an injector's grant (`POST /grant`, # the role `injector`) in a room without ads: a gateway's injector principal, which signs a # contribution's captions and cues (WAI essence-contribution §10.6, cue-injection §7). A room with # ads names its injectors in `[ads] injectors`. Not in an end-to-end encrypted room, a watch room, # a world room, a remote desktop room, a conversation or a call. injectors = [] # The service keeps one conversation (WAI live-messaging): an end-to-end encrypted room whose # members message one another, and its history store, which survives a restart (ciphertext, # receipts and signed records only). It needs no relay; nothing else is kept beside it (no # watch room, co-performance, admission by age, `[world]`, `[remote]`, `[room] e2ee` or `[call]`). # [messaging] # store = "/path/to/conversation" # the history store's directory, made when absent # max_members = 16 # admit = "open" # "open": any key that proves itself; "listed": `members` # members = [] # 64 hexadecimal digits each, for "listed" # grant_s = 604800 # a member's grant's life, at most 1 209 600 (fourteen days) # max_text = 4096 # the conversation statement's bounds (WMC1) # max_reaction = 16 # retention_days = 0 # 0: no bound stated # The service's room is a call (WAI live-messaging §10): a caller places it by a proof of its # key, rings each invitee with an invitation it signs, held in the invitee's inbox; the clock # signs a missed call at each deadline; the grants come with the call. # [call] # ring_ms = 30000 # how long an invitation rings, 1 000 to 300 000 # media = 3 # bit 0 audio, bit 1 video # max_invitees = 8 # max_inbox = 32 # invitations one inbox holds [co] # Co-performance (WAI co-performance): either value above 0 gives each room a co-performance # policy the authority signs, served with the room. The audience-input power every viewer's # grant carries: the most inputs it may send to one selection window (1 to 255; 0: none). audience_input = 0 # Every publisher's latency budget in milliseconds: a later object is marked, never mixed # unmarked (0: none). latency_budget_ms = 0 # Which publishers hold the direct power, to state turn schedules, hand any turn over and open # selection windows: "first" (the room's first publisher), "publishers" or "none". lead = "first" # Whether a publisher may ask for a grant that marks it an AI participant (its `ai` attribute). ai = true # How often the clock states each participant's fidelity, in seconds (0: when a lead asks). fidelity_every_s = 30 # How long after a window closes the clock commits to it, for inputs still in flight (ms). commit_after_ms = 1500 # How far ahead a schedule a page asks for starts, and a handover takes effect, at least (ms). lead_ms = 300 # The objects the clock logs in one room; past it, it still marks, and logs no more. max_objects = 200000 # The relay holds the floor and the audience's inputs once its configuration has the `[floor]` # lines `relay-lines` prints (commented out there). # Every room carries a shared world (WAI live-worlds): the authority signs its world statement, # every publisher's grant is an actor's (the attribute world = act, no media), and the clock # records each actor from its world track. The relay needs the commented world lines # `relay-lines` prints: the door that holds each world track to its owner's key, and the window # that keeps the room's world tracks for pages that enter late. # [world] # model_id = "<64 hexadecimal digits>" # the world model (wai.world.model's model header) # seed = 0 # width = 64 # height = 64 # fps = 24 # max_op_bytes = 4096 # 136 to 65536 # max_ops = 64 # ops one object holds, 1 to 4096 [rate] # Grants per client address: this many at once, then one more every this many seconds. client_burst = 6 client_every_s = 20 # And for everyone together. global_burst = 120 global_every_s = 10 # Every room admits by age (WAI age-assurance §5.6): a grant request carries a Privacy Pass # token (RFC 9577, type 0x0002 of RFC 9578), and the grant states its threshold. Absent: rooms # admit anyone. The keys are the issuers' public keys, RFC 9578 §6.5's SubjectPublicKeyInfo in # hexadecimal; operating an issuer, and its attester, is not the service's. # [age] # window_s = 3600 # the windows an admission receipt counts in # token_window_s = 600 # a challenge's redemption context holds for this window and the next # max_nonces = 65536 # nonces kept a window; past it, no further token of that window # origin = "room.example" # the service's server name; absent, the request's Host # receipts_out = "/path/to/age-receipts.jsonl" # [[age.issuers]] # name = "issuer.example" # keys = [{ threshold = 16, spki = "" }, { threshold = 18, spki = "" }] # [[age.ratings]] # the room's rating: one entry per scheme # scheme = "https://ratings.example/scheme" # value = "16" # min_age = 16 # AI captioners (WAI live-rooms §4.4): AI participants that enter each room through this service # under grants of their own, read its audio and sign its captions (`wai-room-agent caption`, # joule-moq-agent). The descriptor then has a role `captioner` holding the ai power (§3.3), and a # grant marking an AI participant is issued under such a role alone (§4.3 step 9). Not an # end-to-end encrypted room, a watch room, a world room, a remote desktop room, a conversation or # a call. [ai] captioners = 0 # captioners at once, 0 to 8; 0: no captioner role models = [] # the model pins (64 hexadecimal digits) a captioner may name; empty: any grant_s = 1800 # how long a captioner's grant lasts # Every room is a remote desktop room (WAI remote-desktop): one host's screen shared into it. The # host is the key `host` names, or, empty, the first key that presents an invitation the room's # authority signed (`wai-room invite `). Not also e2ee, a watch room, a room with # co-performance, one admitted by age or a world room. The relay holds the host's screen to its key # with a door: # [[receipts.door]] prefix = ["*", "*", "screen"], trust_field = 1. # [remote] # host = "" # 64 hexadecimal digits, or empty for an invitation # width = 1280 # the screen profile's size and rate # height = 720 # fps = 30 # allow = "none" # who may ask for a controller's grant: "all", "listed" or "none" # controllers = [] # the keys that may, for "listed" # control = 3 # a controller's classes: 1 pointer, 2 keys, 4 touch, 8 clipboard # max_age_ms = 1000 # the age bound no host's screen in effect may exceed # lead_ms = 500 # a grant exchange takes effect at least this far ahead # max_records_per_principal = 100000 # the most records of each principal but the host the clock holds; at the # # bound it cuts and removes that principal, and the session goes on. This one # # bites first: a two-hour session at ten input statements a second is 72000, and a # # flood at the policy's 120 events a second reaches it in about 14 minutes # max_records = 1000000 # the most records of a session's principals, the host's among them; at the bound # # it ends the session. A safety net: ten times the bound per principal, above a host # # and four controllers each at its bound (800000)