tempest-react-sdk 0.54.0 → 0.56.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +74 -73
  2. package/dist/components/AudioPlayer/AudioPlayer.cjs +1 -1
  3. package/dist/components/AudioPlayer/AudioPlayer.js +6 -6
  4. package/dist/components/VideoPlayer/VideoPlayer.cjs +2 -0
  5. package/dist/components/VideoPlayer/VideoPlayer.cjs.map +1 -0
  6. package/dist/components/VideoPlayer/VideoPlayer.js +229 -0
  7. package/dist/components/VideoPlayer/VideoPlayer.js.map +1 -0
  8. package/dist/components/VideoPlayer/VideoPlayer.module.cjs +2 -0
  9. package/dist/components/VideoPlayer/VideoPlayer.module.cjs.map +1 -0
  10. package/dist/components/VideoPlayer/VideoPlayer.module.js +19 -0
  11. package/dist/components/VideoPlayer/VideoPlayer.module.js.map +1 -0
  12. package/dist/components/VideoPlayer/playback-rates.cjs +2 -0
  13. package/dist/components/VideoPlayer/playback-rates.cjs.map +1 -0
  14. package/dist/components/VideoPlayer/playback-rates.js +11 -0
  15. package/dist/components/VideoPlayer/playback-rates.js.map +1 -0
  16. package/dist/imaging/exceptions.cjs +1 -1
  17. package/dist/imaging/exceptions.cjs.map +1 -1
  18. package/dist/imaging/exceptions.js +5 -1
  19. package/dist/imaging/exceptions.js.map +1 -1
  20. package/dist/imaging/frame.cjs +2 -0
  21. package/dist/imaging/frame.cjs.map +1 -0
  22. package/dist/imaging/frame.js +82 -0
  23. package/dist/imaging/frame.js.map +1 -0
  24. package/dist/imaging.cjs +1 -1
  25. package/dist/imaging.d.ts +611 -494
  26. package/dist/imaging.js +10 -9
  27. package/dist/styles/VideoPlayer.css +23 -0
  28. package/dist/styles/media.css +22 -0
  29. package/dist/styles.css +1 -1
  30. package/dist/tempest-react-sdk.cjs +1 -1
  31. package/dist/tempest-react-sdk.d.ts +389 -23
  32. package/dist/tempest-react-sdk.js +213 -209
  33. package/dist/webrtc/mesh-quality.cjs +2 -0
  34. package/dist/webrtc/mesh-quality.cjs.map +1 -0
  35. package/dist/webrtc/mesh-quality.js +51 -0
  36. package/dist/webrtc/mesh-quality.js.map +1 -0
  37. package/dist/webrtc/peer-link.cjs +2 -0
  38. package/dist/webrtc/peer-link.cjs.map +1 -0
  39. package/dist/webrtc/peer-link.js +45 -0
  40. package/dist/webrtc/peer-link.js.map +1 -0
  41. package/dist/webrtc/peer-mesh.cjs +2 -0
  42. package/dist/webrtc/peer-mesh.cjs.map +1 -0
  43. package/dist/webrtc/peer-mesh.js +155 -0
  44. package/dist/webrtc/peer-mesh.js.map +1 -0
  45. package/package.json +1 -1
@@ -242,7 +242,7 @@ export declare interface AIChatComposerHandle {
242
242
  getValue: () => string;
243
243
  }
244
244
 
245
- export declare interface AIChatComposerProps extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, OverriddenDomProps_8> {
245
+ export declare interface AIChatComposerProps extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, OverriddenDomProps_9> {
246
246
  /** Called with the trimmed prompt. The field clears only when this does not throw. */
247
247
  onSend: (text: string) => void | Promise<void>;
248
248
  /**
@@ -313,7 +313,7 @@ export declare interface AIChatMessage {
313
313
  data?: Record<string, unknown>;
314
314
  }
315
315
 
316
- export declare interface AIChatProps extends Omit<HTMLAttributes<HTMLDivElement>, OverriddenDomProps_7> {
316
+ export declare interface AIChatProps extends Omit<HTMLAttributes<HTMLDivElement>, OverriddenDomProps_8> {
317
317
  /** The transcript, **oldest first**. Never reordered by the component. */
318
318
  messages: readonly AIChatMessage[];
319
319
  /** Renders the composer when given. Receives the trimmed prompt. */
@@ -1221,7 +1221,7 @@ export declare interface AudioPlayerHandle {
1221
1221
  current: () => HTMLAudioElement | null;
1222
1222
  }
1223
1223
 
1224
- export declare interface AudioPlayerProps extends Omit<HTMLAttributes<HTMLDivElement>, OverriddenDomProps_4> {
1224
+ export declare interface AudioPlayerProps extends Omit<HTMLAttributes<HTMLDivElement>, OverriddenDomProps_5> {
1225
1225
  /**
1226
1226
  * What to play — a URL, or a `Blob`/`File` straight from a recorder.
1227
1227
  *
@@ -1324,7 +1324,7 @@ export declare interface AudioRecorderOptions {
1324
1324
  onError?: (error: unknown) => void;
1325
1325
  }
1326
1326
 
1327
- export declare interface AudioRecorderProps extends Omit<HTMLAttributes<HTMLDivElement>, OverriddenDomProps_5> {
1327
+ export declare interface AudioRecorderProps extends Omit<HTMLAttributes<HTMLDivElement>, OverriddenDomProps_6> {
1328
1328
  /**
1329
1329
  * Called once a recording is finished and (when asked) converted.
1330
1330
  *
@@ -1601,7 +1601,7 @@ export declare interface BarcodePoint {
1601
1601
  */
1602
1602
  export declare function BarcodeScanner({ onScan, formats, paused, detector, intervalMs, repeatDelayMs, torch, aspectRatio, locale, footer, unsupported, onError, className, ...rest }: BarcodeScannerProps): JSX.Element;
1603
1603
 
1604
- export declare interface BarcodeScannerProps extends Omit<HTMLAttributes<HTMLDivElement>, OverriddenDomProps_6> {
1604
+ export declare interface BarcodeScannerProps extends Omit<HTMLAttributes<HTMLDivElement>, OverriddenDomProps_7> {
1605
1605
  /** Called for every accepted read — repeats of the same value are suppressed. */
1606
1606
  onScan: (result: BarcodeScanResult) => void;
1607
1607
  /** Symbologies to look for. Defaults to QR + EAN-13 + Code 128. */
@@ -2381,7 +2381,7 @@ export declare interface ChatComposerHandle {
2381
2381
  setValue: (text: string) => void;
2382
2382
  }
2383
2383
 
2384
- export declare interface ChatComposerProps extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, OverriddenDomProps_3> {
2384
+ export declare interface ChatComposerProps extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, OverriddenDomProps_4> {
2385
2385
  /** Called with the trimmed text. The field clears only when this does not throw. */
2386
2386
  onSend: (text: string) => void | Promise<void>;
2387
2387
  /** Locale for the placeholder and the send label. Default `"pt-BR"`. */
@@ -2437,7 +2437,7 @@ export declare interface ChatMessage {
2437
2437
  data?: Record<string, unknown>;
2438
2438
  }
2439
2439
 
2440
- export declare interface ChatProps extends Omit<HTMLAttributes<HTMLDivElement>, OverriddenDomProps_2> {
2440
+ export declare interface ChatProps extends Omit<HTMLAttributes<HTMLDivElement>, OverriddenDomProps_3> {
2441
2441
  /** The thread, **oldest first**. Never reordered by the component. */
2442
2442
  messages: readonly ChatMessage[];
2443
2443
  /** Author id treated as "own" — decides side, colour and status ticks. */
@@ -3728,6 +3728,33 @@ export declare interface CreatePasskeyClientOptions {
3728
3728
  credentials?: CredentialsContainerLike;
3729
3729
  }
3730
3730
 
3731
+ /**
3732
+ * One `RTCPeerConnection` per peer, with the slots negotiated up front.
3733
+ *
3734
+ * The signalling protocol stays yours: this produces and accepts three message
3735
+ * shapes (`offer`, `answer`, `ice`) and leaves delivery, room membership and
3736
+ * identity to your server. What it owns is the part that is the same in every
3737
+ * mesh and wrong in most of them — see {@link PeerMesh} for the traps each
3738
+ * method exists to avoid.
3739
+ *
3740
+ * @param options - See {@link PeerMeshOptions}.
3741
+ * @returns The mesh.
3742
+ *
3743
+ * @example
3744
+ * const mesh = createPeerMesh({
3745
+ * slots: [
3746
+ * { name: "mic", kind: "audio" },
3747
+ * { name: "cam", kind: "video" },
3748
+ * ],
3749
+ * send: (message) => socket.send(message),
3750
+ * onPeers: setPeers,
3751
+ * });
3752
+ * socket.onMessage = (message) => void mesh.accept(message);
3753
+ * await mesh.addPeer("peer-2", { offerer: true });
3754
+ * await mesh.setLocalTrack("mic", micTrack);
3755
+ */
3756
+ export declare function createPeerMesh(options: PeerMeshOptions): PeerMesh;
3757
+
3731
3758
  /**
3732
3759
  * Record a live GPS trajectory from `navigator.geolocation.watchPosition`.
3733
3760
  * Framework-free — the {@link usePositionTracker} hook wraps this for React.
@@ -5058,6 +5085,17 @@ export declare const DEFAULT_MAX_GAIN = 3;
5058
5085
  */
5059
5086
  export declare const DEFAULT_MODE_DURATION_FACTORS: Record<TravelMode, number>;
5060
5087
 
5088
+ /**
5089
+ * The speed presets the player offers, and why they stop at 2×.
5090
+ *
5091
+ * The spec lets a browser drop the audio once `playbackRate` leaves a range it
5092
+ * considers useful, and that limit varies by engine. These four sit inside every
5093
+ * range measured, so the default control never silences a clip by accident. A
5094
+ * caller who wants 4× can pass it — and should test it with sound on the
5095
+ * browsers they support before promising it.
5096
+ */
5097
+ export declare const DEFAULT_PLAYBACK_RATES: readonly number[];
5098
+
5061
5099
  /**
5062
5100
  * COSE algorithms offered when the server sends no `pubKeyCredParams`, in
5063
5101
  * preference order.
@@ -5783,7 +5821,7 @@ export declare interface Filter {
5783
5821
  */
5784
5822
  export declare function FilterBar({ fields, value, onChange, locale, actions, className, ...rest }: FilterBarProps): JSX.Element;
5785
5823
 
5786
- export declare interface FilterBarProps extends Omit<HTMLAttributes<HTMLDivElement>, OverriddenDomProps_12> {
5824
+ export declare interface FilterBarProps extends Omit<HTMLAttributes<HTMLDivElement>, OverriddenDomProps_13> {
5787
5825
  /** Fields the user may filter by. */
5788
5826
  fields: readonly FilterField[];
5789
5827
  /** Applied filters. Controlled. */
@@ -8083,7 +8121,7 @@ export declare type MarkdownInline = {
8083
8121
  type: "break";
8084
8122
  };
8085
8123
 
8086
- export declare interface MarkdownProps extends Omit<HTMLAttributes<HTMLDivElement>, OverriddenDomProps_11> {
8124
+ export declare interface MarkdownProps extends Omit<HTMLAttributes<HTMLDivElement>, OverriddenDomProps_12> {
8087
8125
  /** The Markdown source. */
8088
8126
  source: string;
8089
8127
  /**
@@ -8121,7 +8159,7 @@ export declare interface MarkdownProps extends Omit<HTMLAttributes<HTMLDivElemen
8121
8159
  */
8122
8160
  export declare function Masonry<T>({ items, children, itemKey, columns, gap, className, style, ...rest }: MasonryProps<T>): JSX.Element;
8123
8161
 
8124
- export declare interface MasonryProps<T> extends Omit<HTMLAttributes<HTMLDivElement>, OverriddenDomProps_10> {
8162
+ export declare interface MasonryProps<T> extends Omit<HTMLAttributes<HTMLDivElement>, OverriddenDomProps_11> {
8125
8163
  /** What to lay out. */
8126
8164
  items: readonly T[];
8127
8165
  /** Render one card. */
@@ -8363,6 +8401,109 @@ export declare interface MercatorPoint {
8363
8401
  y: number;
8364
8402
  }
8365
8403
 
8404
+ /** A message the mesh produces and accepts. The transport is the caller's. */
8405
+ export declare type MeshMessage = {
8406
+ type: "offer";
8407
+ to: string;
8408
+ from?: string;
8409
+ sdp: string;
8410
+ } | {
8411
+ type: "answer";
8412
+ to: string;
8413
+ from?: string;
8414
+ sdp: string;
8415
+ } | {
8416
+ type: "ice";
8417
+ to: string;
8418
+ from?: string;
8419
+ candidate: string | null;
8420
+ sdpMid: string | null;
8421
+ sdpMLineIndex: number | null;
8422
+ };
8423
+
8424
+ /** One remote participant, as the mesh currently sees it. */
8425
+ export declare interface MeshPeer {
8426
+ /** The id the caller registered this peer under. */
8427
+ peerId: string;
8428
+ /** The connection's own state, straight from `RTCPeerConnection`. */
8429
+ connection: RTCPeerConnectionState;
8430
+ /** Inbound stream per slot name, `null` for a slot the peer is not sending. */
8431
+ streams: Record<string, MediaStream | null>;
8432
+ }
8433
+
8434
+ /** Encoder limits, before the room divides them. */
8435
+ export declare interface MeshQuality {
8436
+ /**
8437
+ * Cap per video slot, in kbps. `null` leaves that slot uncapped.
8438
+ *
8439
+ * Divided by the size of the room — see {@link PeerMesh.applyQuality}.
8440
+ */
8441
+ video?: Record<string, number | null>;
8442
+ /**
8443
+ * Cap per audio slot, in **bps**, matching `setSenderBitrate`.
8444
+ *
8445
+ * Never divided. Audio is an order of magnitude cheaper than video and is
8446
+ * the part of a call that has to survive: dividing it buys back a few
8447
+ * percent of the uplink in exchange for the only thing everyone needs.
8448
+ */
8449
+ audio?: Record<string, number>;
8450
+ /** Frame ceiling written onto every video encoding. */
8451
+ maxFramerate?: number;
8452
+ /** What a video encoder gives up first. */
8453
+ degradationPreference?: RTCDegradationPreference;
8454
+ /**
8455
+ * Total uplink to divide among the peers, in kbps.
8456
+ *
8457
+ * A mesh sends one copy of everything **per participant**, so a cap that is
8458
+ * comfortable one-to-one saturates a home connection with four people.
8459
+ */
8460
+ uplinkBudgetKbps?: number;
8461
+ /**
8462
+ * Floor each video slot keeps after the division, in kbps.
8463
+ *
8464
+ * Dividing without a floor eventually allocates tens of kbps per stream,
8465
+ * which buys a blur that updates once a second: everybody loses the picture
8466
+ * instead of the excess giving way.
8467
+ */
8468
+ minVideoKbps?: number;
8469
+ /**
8470
+ * Budget below which `maintain-framerate` is overridden.
8471
+ *
8472
+ * Somebody who asked for fluidity wants a good picture in motion, not the
8473
+ * number 60. Once the share of the uplink is this small, holding the frame
8474
+ * rate halves what each frame gets and the result is worse than the lower
8475
+ * rate it replaced.
8476
+ */
8477
+ fluidFloorKbps?: number;
8478
+ }
8479
+
8480
+ /**
8481
+ * One media lane, negotiated once and reused for the life of the link.
8482
+ *
8483
+ * The order of the slot list is the wire protocol: the offerer allocates one
8484
+ * m-line per slot in this order, so a slot's `mid` is its ordinal and both ends
8485
+ * read the same identity off it. Reorder the list and the two sides disagree
8486
+ * about which lane carries the camera.
8487
+ */
8488
+ export declare interface MeshSlot {
8489
+ /** Stable name the caller uses in {@link PeerMesh.setLocalTrack}. */
8490
+ name: string;
8491
+ /** Whether the lane carries audio or video. */
8492
+ kind: MeshSlotKind;
8493
+ }
8494
+
8495
+ /** What a slot carries. */
8496
+ export declare type MeshSlotKind = "audio" | "video";
8497
+
8498
+ /**
8499
+ * The single state a call badge shows.
8500
+ *
8501
+ * `connected` covers being alone in the room: a mesh with no peers has nothing
8502
+ * to connect to and is not failing, which is the case a naive "any link
8503
+ * connected?" check reports as broken for as long as nobody else joins.
8504
+ */
8505
+ export declare type MeshState = "connecting" | "connected" | "reconnecting" | "failed" | "closed";
8506
+
8366
8507
  export declare type Messages = Record<string, string>;
8367
8508
 
8368
8509
  /** Lifecycle of a microphone stream. */
@@ -9402,37 +9543,49 @@ export { Outlet }
9402
9543
  declare type OverriddenDomProps = "children" | "title" | "onSelect";
9403
9544
 
9404
9545
  /** DOM attributes this component redefines. */
9405
- declare type OverriddenDomProps_10 = "children";
9546
+ declare type OverriddenDomProps_10 = "children" | "onChange" | "defaultValue";
9406
9547
 
9407
9548
  /** DOM attributes this component redefines. */
9408
9549
  declare type OverriddenDomProps_11 = "children";
9409
9550
 
9410
9551
  /** DOM attributes this component redefines. */
9411
- declare type OverriddenDomProps_12 = "children" | "onChange";
9552
+ declare type OverriddenDomProps_12 = "children";
9412
9553
 
9413
9554
  /** DOM attributes this component redefines. */
9414
- declare type OverriddenDomProps_2 = "children" | "onSubmit";
9555
+ declare type OverriddenDomProps_13 = "children" | "onChange";
9415
9556
 
9416
- /** DOM attributes the composer redefines. */
9417
- declare type OverriddenDomProps_3 = "onSubmit" | "value" | "defaultValue" | "rows";
9557
+ /**
9558
+ * DOM attributes this component redefines.
9559
+ *
9560
+ * `onRateChange` is a real collision, not tidiness: React types it on every
9561
+ * element as the media `ratechange` handler, `ReactEventHandler`. Ours carries
9562
+ * the rate the viewer picked, and a `(rate: number) => void` is not assignable
9563
+ * to a handler that receives an event — same shape of clash as `Input`'s `size`
9564
+ * against `HTMLInputElement.size`. The DOM one is useless on a `<div>` anyway:
9565
+ * the event fires on the media element inside, which this component owns.
9566
+ */
9567
+ declare type OverriddenDomProps_2 = "children" | "onRateChange";
9418
9568
 
9419
9569
  /** DOM attributes this component redefines. */
9420
- declare type OverriddenDomProps_4 = "children";
9570
+ declare type OverriddenDomProps_3 = "children" | "onSubmit";
9571
+
9572
+ /** DOM attributes the composer redefines. */
9573
+ declare type OverriddenDomProps_4 = "onSubmit" | "value" | "defaultValue" | "rows";
9421
9574
 
9422
9575
  /** DOM attributes this component redefines. */
9423
- declare type OverriddenDomProps_5 = "children" | "onError";
9576
+ declare type OverriddenDomProps_5 = "children";
9424
9577
 
9425
9578
  /** DOM attributes this component redefines. */
9426
9579
  declare type OverriddenDomProps_6 = "children" | "onError";
9427
9580
 
9428
9581
  /** DOM attributes this component redefines. */
9429
- declare type OverriddenDomProps_7 = "children" | "onSubmit";
9430
-
9431
- /** DOM attributes the composer redefines. */
9432
- declare type OverriddenDomProps_8 = "onSubmit" | "value" | "defaultValue" | "rows";
9582
+ declare type OverriddenDomProps_7 = "children" | "onError";
9433
9583
 
9434
9584
  /** DOM attributes this component redefines. */
9435
- declare type OverriddenDomProps_9 = "children" | "onChange" | "defaultValue";
9585
+ declare type OverriddenDomProps_8 = "children" | "onSubmit";
9586
+
9587
+ /** DOM attributes the composer redefines. */
9588
+ declare type OverriddenDomProps_9 = "onSubmit" | "value" | "defaultValue" | "rows";
9436
9589
 
9437
9590
  /**
9438
9591
  * Page wrapper with header + (optional) toolbar + content + footer. Pairs
@@ -9811,6 +9964,87 @@ export declare interface PcmAudio {
9811
9964
  sampleRate: number;
9812
9965
  }
9813
9966
 
9967
+ /** A running mesh. */
9968
+ export declare interface PeerMesh {
9969
+ /**
9970
+ * Open a link to a peer.
9971
+ *
9972
+ * `offerer` decides which side sends the offer, and exactly one side of each
9973
+ * link must say `true`. Drive it from the arrival order your server already
9974
+ * imposes — the peer that joined **later** offers, the one already in the
9975
+ * room answers. That avoids glare by construction, without the rollback
9976
+ * dance of perfect negotiation and without depending on a browser
9977
+ * implementing argument-less `setLocalDescription`.
9978
+ */
9979
+ addPeer: (peerId: string, options: {
9980
+ offerer: boolean;
9981
+ }) => Promise<void>;
9982
+ /** Close one link and give its share of the uplink back to the others. */
9983
+ removePeer: (peerId: string) => void;
9984
+ /** Feed the mesh an `offer`, `answer` or `ice` message from `from`. */
9985
+ accept: (message: MeshMessage & {
9986
+ from: string;
9987
+ }) => Promise<void>;
9988
+ /**
9989
+ * Publish or retract one slot across every live link.
9990
+ *
9991
+ * `null` retracts: the sender keeps its negotiated transceiver and stops
9992
+ * producing, which is what mutes a microphone without disturbing the other
9993
+ * slots or the connection. Nothing renegotiates — the m-lines were allocated
9994
+ * before any track existed, which is what makes a mesh survive toggling: a
9995
+ * renegotiation per toggle is N-1 simultaneous offer/answer rounds every time
9996
+ * somebody unmutes.
9997
+ */
9998
+ setLocalTrack: (slot: string, track: MediaStreamTrack | null) => Promise<void>;
9999
+ /** Apply encoder limits, divided by the current size of the room. */
10000
+ applyQuality: (quality: MeshQuality) => Promise<void>;
10001
+ /** Replace the ICE servers used for links opened from now on. */
10002
+ setIceServers: (servers: RTCIceServer[]) => void;
10003
+ /** Close every link and report `closed`. */
10004
+ stop: () => void;
10005
+ /** The peers as the mesh currently sees them. */
10006
+ readonly peers: MeshPeer[];
10007
+ }
10008
+
10009
+ /** Options for `createPeerMesh`. */
10010
+ export declare interface PeerMeshOptions {
10011
+ /** The lanes every link negotiates, in the order they are allocated. */
10012
+ slots: readonly MeshSlot[];
10013
+ /** Send one message to the peer named by `to`. The transport is yours. */
10014
+ send: (message: MeshMessage) => void;
10015
+ /** ICE servers for every connection this mesh opens. */
10016
+ iceServers?: RTCIceServer[];
10017
+ /** Called whenever the peer list or any peer's streams change. */
10018
+ onPeers?: (peers: MeshPeer[]) => void;
10019
+ /** Called when the aggregate state changes, with an optional detail. */
10020
+ onState?: (state: MeshState, detail?: string) => void;
10021
+ /** Called for a failure worth surfacing that is not fatal to the mesh. */
10022
+ onNotice?: (reason: string) => void;
10023
+ /** Initial encoder limits. */
10024
+ quality?: MeshQuality;
10025
+ /**
10026
+ * Applies a local description, so the SDP can be rewritten on the way out.
10027
+ *
10028
+ * Defaults to `connection.setLocalDescription(description)`. The reason it
10029
+ * is a seam is `setTunedLocalDescription`: the mesh is what creates every
10030
+ * offer and answer, so without a hook here there is nowhere left to put the
10031
+ * Opus rewrite, and a call that adopts the mesh silently loses the bitrate
10032
+ * and channel layout it had negotiated before.
10033
+ *
10034
+ * Profiles are keyed by **audio m-line position**, which is legitimate for
10035
+ * exactly the reason slot routing is: the slot list fixes the order, so the
10036
+ * first audio slot is always the first audio m-line.
10037
+ *
10038
+ * @example
10039
+ * setLocalDescription: (connection, description) =>
10040
+ * setTunedLocalDescription(connection, description, {
10041
+ * 0: MIC_PROFILE,
10042
+ * 1: SYSTEM_AUDIO_PROFILE,
10043
+ * }),
10044
+ */
10045
+ setLocalDescription?: (connection: RTCPeerConnection, description: RTCSessionDescriptionInit) => Promise<unknown>;
10046
+ }
10047
+
9814
10048
  /**
9815
10049
  * What percentage of `total` is `part`, with an empty base yielding `0`.
9816
10050
  *
@@ -10834,6 +11068,22 @@ export declare interface ResizableProps extends Omit<HTMLAttributes<HTMLDivEleme
10834
11068
  children: [ReactNode, ReactNode];
10835
11069
  }
10836
11070
 
11071
+ /**
11072
+ * Decide what the encoder gives up, letting physics override the preference.
11073
+ *
11074
+ * `maintain-framerate` is honoured while there are bits enough for the frames to
11075
+ * be worth keeping. Once the room's division has taken the budget below the
11076
+ * fluid floor, holding the rate halves what each frame receives and the picture
11077
+ * is worse than the lower rate it replaced — so below that line the preference
11078
+ * is overridden rather than obeyed.
11079
+ *
11080
+ * @param quality - What was asked for.
11081
+ * @param effective - What the room's share actually allows.
11082
+ * @returns The degradation preference to write onto the senders, or `undefined`
11083
+ * when the caller expressed no preference.
11084
+ */
11085
+ export declare function resolveDegradation(quality: MeshQuality, effective: MeshQuality): RTCDegradationPreference | undefined;
11086
+
10837
11087
  export declare type ResolvedTheme = "light" | "dark";
10838
11088
 
10839
11089
  /**
@@ -11183,6 +11433,26 @@ export declare interface SafeAreaProps extends HTMLAttributes<HTMLDivElement> {
11183
11433
  children?: ReactNode;
11184
11434
  }
11185
11435
 
11436
+ /**
11437
+ * Divide the video caps by the size of the room.
11438
+ *
11439
+ * A mesh sends one copy of everything per participant, so the uplink is the
11440
+ * shared resource and the caps are what compete for it. Nothing is divided while
11441
+ * the caller is alone with one peer — that is the case the largest sizes exist
11442
+ * for, and dividing a budget that is not being shared would make them
11443
+ * unreachable in the only call where they fit.
11444
+ *
11445
+ * The floor is what keeps the division honest: without it a busy room allocates
11446
+ * tens of kbps per stream, and everybody loses the picture instead of the excess
11447
+ * giving way.
11448
+ *
11449
+ * @param quality - The caps as asked for.
11450
+ * @param peers - How many links are live.
11451
+ * @returns The caps to actually apply. The input is never mutated, so a room
11452
+ * that empties out climbs back to what was asked for.
11453
+ */
11454
+ export declare function scaleForRoom(quality: MeshQuality, peers: number): MeshQuality;
11455
+
11186
11456
  /** The ten steps of a Tempest tint scale, lightest to darkest. */
11187
11457
  export declare type ScaleStep = 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900;
11188
11458
 
@@ -13175,7 +13445,7 @@ export declare interface TransferItem {
13175
13445
  data?: Record<string, unknown>;
13176
13446
  }
13177
13447
 
13178
- export declare interface TransferProps extends Omit<HTMLAttributes<HTMLDivElement>, OverriddenDomProps_9> {
13448
+ export declare interface TransferProps extends Omit<HTMLAttributes<HTMLDivElement>, OverriddenDomProps_10> {
13179
13449
  /** The whole catalogue. Both panes are derived from it. */
13180
13450
  items: readonly TransferItem[];
13181
13451
  /** Ids on the target side. Controlled. */
@@ -16407,6 +16677,88 @@ export declare interface ViaCEPResult {
16407
16677
  siafi?: string;
16408
16678
  }
16409
16679
 
16680
+ /**
16681
+ * Playback transport for one video: play/pause, seek, volume, speed, fullscreen.
16682
+ *
16683
+ * Built on a real `<video>` element, and deliberately **not** an overlay: the
16684
+ * controls sit in a bar under the frame rather than on top of it. Controls drawn
16685
+ * over video have to earn their contrast against arbitrary pixels, which no
16686
+ * `--tempest-*` token can promise — every text token in this SDK is resolved
16687
+ * against a known surface, and the two contrast defects this repo shipped were
16688
+ * both a text token used over a surface it was never checked against. A bar with
16689
+ * its own surface inherits the theme and is legible by construction.
16690
+ *
16691
+ * The seek bar, the volume slider and the speed picker are bare `<input>` and
16692
+ * `<select>` elements rather than the SDK's `Slider` and `Select`: those are form
16693
+ * fields, with a label row and a value badge, and a transport wants neither. The
16694
+ * native elements keep the keyboard and screen-reader behaviour that matters here
16695
+ * for free.
16696
+ *
16697
+ * @example
16698
+ * const rec = useVideoRecorder(screen.stream);
16699
+ * {rec.recording && (
16700
+ * <VideoPlayer src={rec.recording.blob} durationMs={rec.recording.durationMs} />
16701
+ * )}
16702
+ */
16703
+ export declare function VideoPlayer({ src, durationMs, poster, tracks, aspectRatio, rate, rates, onRateChange, shiftPitch, fullscreen, autoPlay, loop, muted, locale, actions, onEnded, onError, disabled, className, ...rest }: VideoPlayerProps): JSX.Element;
16704
+
16705
+ export declare interface VideoPlayerProps extends Omit<HTMLAttributes<HTMLDivElement>, OverriddenDomProps_2> {
16706
+ /**
16707
+ * What to play — a URL, or a `Blob`/`File` straight from a recorder.
16708
+ *
16709
+ * A `Blob` is wrapped in an object URL that is revoked when it changes or the
16710
+ * component unmounts, so a session that records twenty clips does not leak
16711
+ * twenty URLs for the lifetime of the tab.
16712
+ */
16713
+ src: string | Blob | null;
16714
+ /**
16715
+ * Known length in milliseconds.
16716
+ *
16717
+ * Pass it whenever you have it — a recording from `useVideoRecorder` always
16718
+ * does. Without it the element's own `duration` is used, and a fresh
16719
+ * `MediaRecorder` blob may report `Infinity` until it is probed for one.
16720
+ */
16721
+ durationMs?: number;
16722
+ /** Still shown before playback. Pair it with `captureFrame` from `/imaging`. */
16723
+ poster?: string;
16724
+ /** Caption and subtitle files. */
16725
+ tracks?: readonly VideoTextTrack[];
16726
+ /** Frame shape while the video has no intrinsic size yet. Default `16 / 9`. */
16727
+ aspectRatio?: number;
16728
+ /**
16729
+ * Playback rate. Controlled when passed with `onRateChange`.
16730
+ *
16731
+ * Written to both `playbackRate` and `defaultPlaybackRate`, because the
16732
+ * element resets the first to the second when a source loads — a player that
16733
+ * only writes `playbackRate` silently drops back to 1× on every clip change.
16734
+ */
16735
+ rate?: number;
16736
+ /** Presets the control offers. `[]` hides it. Default {@link DEFAULT_PLAYBACK_RATES}. */
16737
+ rates?: readonly number[];
16738
+ /** Called with the rate the viewer picked. */
16739
+ onRateChange?: (rate: number) => void;
16740
+ /** Let the pitch rise with the rate (`preservesPitch = false`). Default `false`. */
16741
+ shiftPitch?: boolean;
16742
+ /** Offer a fullscreen button where the browser supports it. Default `true`. */
16743
+ fullscreen?: boolean;
16744
+ /** Start playing as soon as `src` is ready. Default `false`. */
16745
+ autoPlay?: boolean;
16746
+ /** Loop. Default `false`. */
16747
+ loop?: boolean;
16748
+ /** Start muted. Autoplay without a gesture needs this. Default `false`. */
16749
+ muted?: boolean;
16750
+ /** Locale for the labels. Default `"pt-BR"`. */
16751
+ locale?: "pt-BR" | "en";
16752
+ /** Rendered at the end of the control row — a download button, a delete button. */
16753
+ actions?: ReactNode;
16754
+ /** Fired when playback reaches the end. */
16755
+ onEnded?: () => void;
16756
+ /** Fired when the element reports a decode/network error. */
16757
+ onError?: (error: unknown) => void;
16758
+ /** No `src` yet, or playback not allowed. */
16759
+ disabled?: boolean;
16760
+ }
16761
+
16410
16762
  /** Imperative video recorder. Same shape as the audio one. */
16411
16763
  export declare type VideoRecorderHandle = MediaRecorderHandle;
16412
16764
 
@@ -16452,6 +16804,20 @@ export declare interface VideoRecorderOptions {
16452
16804
  */
16453
16805
  export declare type VideoRecording = MediaRecording;
16454
16806
 
16807
+ /** One caption or subtitle file, rendered as a `<track>`. */
16808
+ export declare interface VideoTextTrack {
16809
+ /** URL of the WebVTT file. */
16810
+ src: string;
16811
+ /** BCP 47 language tag, e.g. `"pt-BR"`. */
16812
+ srcLang: string;
16813
+ /** Name shown in the browser's own track menu. */
16814
+ label: string;
16815
+ /** Track kind. Default `"captions"`. */
16816
+ kind?: "subtitles" | "captions" | "descriptions" | "chapters" | "metadata";
16817
+ /** Whether this track is on unless the viewer picks another. */
16818
+ default?: boolean;
16819
+ }
16820
+
16455
16821
  /**
16456
16822
  * Fixed-height virtual list. Renders only the visible window plus a small
16457
16823
  * overscan buffer. Suitable for lists of thousands of identical rows.