tempest-react-sdk 0.52.0 → 0.53.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 (57) hide show
  1. package/README.md +35 -5
  2. package/dist/audio/audio-bus.cjs +2 -0
  3. package/dist/audio/audio-bus.cjs.map +1 -0
  4. package/dist/audio/audio-bus.js +116 -0
  5. package/dist/audio/audio-bus.js.map +1 -0
  6. package/dist/audio/use-audio-bus.cjs +2 -0
  7. package/dist/audio/use-audio-bus.cjs.map +1 -0
  8. package/dist/audio/use-audio-bus.js +11 -0
  9. package/dist/audio/use-audio-bus.js.map +1 -0
  10. package/dist/components/RangeSlider/RangeSlider.cjs +1 -1
  11. package/dist/components/RangeSlider/RangeSlider.cjs.map +1 -1
  12. package/dist/components/RangeSlider/RangeSlider.js +23 -23
  13. package/dist/components/RangeSlider/RangeSlider.js.map +1 -1
  14. package/dist/components/Slider/Slider.cjs +1 -1
  15. package/dist/components/Slider/Slider.cjs.map +1 -1
  16. package/dist/components/Slider/Slider.js +9 -9
  17. package/dist/components/Slider/Slider.js.map +1 -1
  18. package/dist/forms/FormField.cjs +1 -1
  19. package/dist/forms/FormField.cjs.map +1 -1
  20. package/dist/forms/FormField.js +23 -21
  21. package/dist/forms/FormField.js.map +1 -1
  22. package/dist/query/QueryProvider.cjs +1 -1
  23. package/dist/query/QueryProvider.cjs.map +1 -1
  24. package/dist/query/QueryProvider.js +13 -11
  25. package/dist/query/QueryProvider.js.map +1 -1
  26. package/dist/query/foreign-client-warning.cjs +2 -0
  27. package/dist/query/foreign-client-warning.cjs.map +1 -0
  28. package/dist/query/foreign-client-warning.js +12 -0
  29. package/dist/query/foreign-client-warning.js.map +1 -0
  30. package/dist/tempest-react-sdk.cjs +1 -1
  31. package/dist/tempest-react-sdk.d.ts +478 -35
  32. package/dist/tempest-react-sdk.js +52 -47
  33. package/dist/utils/duplicate-instance.cjs +2 -0
  34. package/dist/utils/duplicate-instance.cjs.map +1 -0
  35. package/dist/utils/duplicate-instance.js +6 -0
  36. package/dist/utils/duplicate-instance.js.map +1 -0
  37. package/dist/webrtc/opus-sdp.cjs +3 -0
  38. package/dist/webrtc/opus-sdp.cjs.map +1 -0
  39. package/dist/webrtc/opus-sdp.js +94 -0
  40. package/dist/webrtc/opus-sdp.js.map +1 -0
  41. package/dist/webrtc/sender-bitrate.cjs +2 -0
  42. package/dist/webrtc/sender-bitrate.cjs.map +1 -0
  43. package/dist/webrtc/sender-bitrate.js +15 -0
  44. package/dist/webrtc/sender-bitrate.js.map +1 -0
  45. package/dist/ws/create-web-socket.cjs +1 -1
  46. package/dist/ws/create-web-socket.cjs.map +1 -1
  47. package/dist/ws/create-web-socket.js +123 -47
  48. package/dist/ws/create-web-socket.js.map +1 -1
  49. package/dist/ws/resilience.cjs +2 -0
  50. package/dist/ws/resilience.cjs.map +1 -0
  51. package/dist/ws/resilience.js +21 -0
  52. package/dist/ws/resilience.js.map +1 -0
  53. package/dist/ws/use-web-socket.cjs +1 -1
  54. package/dist/ws/use-web-socket.cjs.map +1 -1
  55. package/dist/ws/use-web-socket.js +37 -23
  56. package/dist/ws/use-web-socket.js.map +1 -1
  57. package/package.json +1 -1
@@ -1059,6 +1059,88 @@ export declare type AsyncStatus = "idle" | "pending" | "success" | "error";
1059
1059
  */
1060
1060
  export declare const AUDIO_MIME_CANDIDATES: readonly string[];
1061
1061
 
1062
+ /** A running mix. */
1063
+ export declare interface AudioBus {
1064
+ /**
1065
+ * Play a stream through the shared mix.
1066
+ *
1067
+ * @param stream - The stream to play. Only its first audio track is used.
1068
+ * @param options - `gain` is the initial multiplier, default `1`.
1069
+ * @returns A handle to adjust or detach this source.
1070
+ */
1071
+ attach: (stream: MediaStream, options?: {
1072
+ gain?: number;
1073
+ }) => AudioBusHandle;
1074
+ /** Scale every source, on top of its own gain. */
1075
+ setMasterGain: (gain: number) => void;
1076
+ /** Current master gain, after clamping. */
1077
+ readonly masterGain: number;
1078
+ /**
1079
+ * Route the whole mix to one output device.
1080
+ *
1081
+ * @param deviceId - Device id from `useMediaDevices().audioOutputs`, or `""`
1082
+ * for the system default.
1083
+ * @returns `false` when the engine cannot route audio, or the device is gone.
1084
+ */
1085
+ setOutputDevice: (deviceId: string) => Promise<boolean>;
1086
+ /** Device id the mix is routed to. `""` is the system default. */
1087
+ readonly outputDevice: string;
1088
+ /**
1089
+ * Resume a context the browser started suspended.
1090
+ *
1091
+ * Autoplay policy suspends a context created outside a user gesture, and a
1092
+ * suspended context is silent with no error anywhere. Call this from the
1093
+ * click that starts playback.
1094
+ */
1095
+ resume: () => Promise<void>;
1096
+ /**
1097
+ * Detach everything and close the context this bus created.
1098
+ *
1099
+ * Idempotent, and the bus stays callable afterwards: `attach` hands back an
1100
+ * inert handle instead of throwing. That is not politeness — creating a node
1101
+ * on a closed `AudioContext` throws `InvalidStateError`, and the stream that
1102
+ * arrives late is the normal case (a WebRTC `ontrack` firing after the
1103
+ * component that owned the bus went away).
1104
+ */
1105
+ close: () => void;
1106
+ /** Whether this browser gave us a Web Audio graph at all. */
1107
+ readonly supported: boolean;
1108
+ /** Whether this browser can route the mix to a chosen output device. */
1109
+ readonly canSelectOutput: boolean;
1110
+ }
1111
+
1112
+ /** One source attached to the bus. */
1113
+ export declare interface AudioBusHandle {
1114
+ /**
1115
+ * Set this source's gain, where `1` is the level it arrived at.
1116
+ *
1117
+ * Values above `1` are the point of the whole graph: `element.volume` is
1118
+ * clamped at `1`, so a quiet talker could only ever be attenuated — the one
1119
+ * correction nobody needs.
1120
+ */
1121
+ setGain: (gain: number) => void;
1122
+ /** Current gain, after clamping. */
1123
+ readonly gain: number;
1124
+ /** Detach this source and release its nodes. The bus stays up. */
1125
+ stop: () => void;
1126
+ }
1127
+
1128
+ /** Options for {@link createAudioBus}. */
1129
+ export declare interface AudioBusOptions {
1130
+ /** Ceiling for every gain on this bus. Default {@link DEFAULT_MAX_GAIN}. */
1131
+ maxGain?: number;
1132
+ /** Override the master limiter, or pass `false` to run without one. */
1133
+ limiter?: Partial<LimiterSettings> | false;
1134
+ /**
1135
+ * Reuse an existing `AudioContext` instead of creating one.
1136
+ *
1137
+ * Browsers cap the number of live contexts (Chrome allows around six), so a
1138
+ * page that already has one — a level meter, a player — should hand it over
1139
+ * rather than open a second.
1140
+ */
1141
+ context?: AudioContext;
1142
+ }
1143
+
1062
1144
  /**
1063
1145
  * Playback transport for one clip: play/pause, a seek bar, elapsed and total time.
1064
1146
  *
@@ -2910,6 +2992,34 @@ export declare const CPFInput: ForwardRefExoticComponent<Omit<InputProps, "value
2910
2992
  */
2911
2993
  export declare function createApiClient(config: ApiClientConfig): ApiClient;
2912
2994
 
2995
+ /**
2996
+ * Mix several streams into one output, with gain above 100% and a master limiter.
2997
+ *
2998
+ * Three things make this a graph instead of a few `<audio>` elements:
2999
+ *
3000
+ * 1. **`element.volume` is clamped at `1`.** A participant who speaks too quietly
3001
+ * can only be turned *down* — the one correction nobody needs. A `GainNode`
3002
+ * has no ceiling, so this bus takes one (`maxGain`, default 3).
3003
+ * 2. **Clipping is a property of the sum.** Three sources at 200% each are clean
3004
+ * alone and distort the instant they play together. A per-source limiter
3005
+ * cannot see that; the one after the mix can, which is where this puts it.
3006
+ * 3. **`setSinkId` lives on the element, not on the context.** Sending the mix to
3007
+ * a headset while the rest of the system keeps the speakers is only reachable
3008
+ * by leaving through a `MediaStreamAudioDestinationNode` into a real
3009
+ * `<audio>`. `AudioContext.setSinkId` has far thinner support.
3010
+ *
3011
+ * @param options - See {@link AudioBusOptions}.
3012
+ * @returns The bus. On an engine with no Web Audio it is inert but callable, and
3013
+ * `supported` is `false` — a page without sound beats a page that throws.
3014
+ *
3015
+ * @example
3016
+ * const bus = createAudioBus({ maxGain: 3 });
3017
+ * const handle = bus.attach(remoteStream, { gain: 1 });
3018
+ * handle.setGain(2.4); // above 1 — the point of the whole thing
3019
+ * await bus.setOutputDevice(headsetId);
3020
+ */
3021
+ export declare function createAudioBus({ maxGain, limiter: limiterOptions, context: injectedContext, }?: AudioBusOptions): AudioBus;
3022
+
2913
3023
  /**
2914
3024
  * Create an isolated audio player that tracks a single "current" clip.
2915
3025
  * Multiple players coexist independently; use this when several layers of UI
@@ -4015,12 +4125,29 @@ export declare interface CreateThemeOptions {
4015
4125
  export declare function createVideoRecorder(stream: MediaStream, options?: VideoRecorderOptions): VideoRecorderHandle;
4016
4126
 
4017
4127
  /**
4018
- * Open a WebSocket with automatic exponential-backoff reconnect, optional
4019
- * heartbeat pings, and typed JSON parsing.
4128
+ * Open a WebSocket that survives a bad network: exponential backoff with jitter,
4129
+ * a handshake timeout, a silence watchdog, optional heartbeat pings and typed
4130
+ * JSON parsing.
4131
+ *
4132
+ * Three failure modes are covered that an event-driven retry loop misses on its
4133
+ * own, because none of them fire an event: a handshake that hangs instead of
4134
+ * failing, an open socket whose link died mid-flight, and a device with its
4135
+ * radio off burning the retry budget. See `handshakeTimeout`, `silenceTimeout`
4136
+ * and `waitForOnline`.
4020
4137
  *
4021
4138
  * @param url - Full ws:// or wss:// URL.
4022
4139
  * @param options - Connection configuration and callbacks.
4023
- * @returns Controller exposing `send`, `close`, `reconnect`, and `status`.
4140
+ * @returns Controller exposing `send`, `close`, `reconnect`, `setSilenceTimeout`,
4141
+ * `opened` and `status`.
4142
+ *
4143
+ * @example
4144
+ * const socket = createWebSocket(url, {
4145
+ * silenceTimeout: 75_000,
4146
+ * onReconnecting: (n, total) => setBanner(`Reconectando ${n}/${total}…`),
4147
+ * onReconnected: () => refetchEverything(),
4148
+ * onLost: (reason) => setBanner(reason === "rejected" ? "Acesso negado" : "Sem conexão"),
4149
+ * });
4150
+ * await socket.opened;
4024
4151
  */
4025
4152
  export declare function createWebSocket<T = unknown>(url: string, options?: CreateWebSocketOptions<T>): WebSocketController;
4026
4153
 
@@ -4033,6 +4160,50 @@ export declare interface CreateWebSocketOptions<T> {
4033
4160
  initialBackoff?: number;
4034
4161
  /** Maximum backoff (ms). Default: 30000. */
4035
4162
  maxBackoff?: number;
4163
+ /**
4164
+ * Fraction of each backoff delay added at random, 0–1. Default: 0.3.
4165
+ *
4166
+ * Matters when the *server* is what went down: every client retries on the
4167
+ * same schedule, so the box comes back up into a synchronized stampede. Pass
4168
+ * `0` for a fixed schedule.
4169
+ */
4170
+ jitter?: number;
4171
+ /**
4172
+ * How long one handshake may stay in `CONNECTING` before the attempt is
4173
+ * abandoned and retried (ms). Default: 8000. Pass 0 to disable.
4174
+ *
4175
+ * A `WebSocket` that cannot reach its server does not necessarily fail: it
4176
+ * sits in `CONNECTING` firing neither `open` nor `close` nor `error`. A retry
4177
+ * chain built only on those events stops on its first hung attempt and never
4178
+ * moves again — and hung, rather than refused, is precisely how a bad mobile
4179
+ * link behaves, which is the case reconnection exists for.
4180
+ */
4181
+ handshakeTimeout?: number;
4182
+ /**
4183
+ * Silence tolerated on an open socket before the link is treated as dead (ms).
4184
+ * Default: 0 (off).
4185
+ *
4186
+ * The socket only reports a connection that closes cleanly. A link that dies
4187
+ * mid-flight leaves `readyState` at `OPEN` on this side with nothing ever
4188
+ * arriving again, so silence is the only symptom available. The timer is
4189
+ * re-armed by **any** inbound frame, not just by pings — traffic is traffic.
4190
+ *
4191
+ * Set it to a comfortable multiple of the server's ping interval (2.5× is a
4192
+ * good default) so one dropped ping is not mistaken for an outage. When the
4193
+ * server announces its own interval in the handshake, feed that back with
4194
+ * {@link WebSocketController.setSilenceTimeout} instead of hard-coding the
4195
+ * value on both ends.
4196
+ */
4197
+ silenceTimeout?: number;
4198
+ /**
4199
+ * Suspend the retry schedule while `navigator.onLine` is false, and resume on
4200
+ * the `online` event. Default: true.
4201
+ *
4202
+ * Burning retries against a radio that is switched off is how a phone
4203
+ * exhausts its budget inside a tunnel and gives up exactly when it comes out
4204
+ * the other side.
4205
+ */
4206
+ waitForOnline?: boolean;
4036
4207
  /**
4037
4208
  * Ping interval (ms). When set, the client sends `pingPayload` periodically
4038
4209
  * to keep the socket alive. Default: 0 (disabled).
@@ -4073,6 +4244,34 @@ export declare interface CreateWebSocketOptions<T> {
4073
4244
  onClose?: (event: CloseEvent) => void;
4074
4245
  onError?: (event: Event) => void;
4075
4246
  onStatusChange?: (status: WebSocketStatus) => void;
4247
+ /**
4248
+ * A retry has been scheduled. `attempt` is 1-based, `total` is `maxRetries`.
4249
+ *
4250
+ * Reconnecting is not an error and reads badly as one: announcing every
4251
+ * attempt puts a fresh "the connection dropped" in front of someone whose
4252
+ * session is in the middle of coming back on its own. Show a quiet
4253
+ * reconnecting state here and treat {@link CreateWebSocketOptions.onLost} as
4254
+ * the failure.
4255
+ */
4256
+ onReconnecting?: (attempt: number, total: number) => void;
4257
+ /**
4258
+ * The socket is back up after at least one retry.
4259
+ *
4260
+ * Nothing is resumed for you: a server that keys state by connection sees a
4261
+ * brand-new client, so this is where the caller re-subscribes, re-joins or
4262
+ * refetches whatever the gap invalidated.
4263
+ */
4264
+ onReconnected?: () => void;
4265
+ /**
4266
+ * No further attempt will be made — `"rejected"` when the server refused the
4267
+ * client outright (close code 4400–4499, minus the 4408 heartbeat timeout),
4268
+ * `"exhausted"` when the schedule ran out.
4269
+ *
4270
+ * This is the one that deserves UI, because it is the only state the caller
4271
+ * can act on: offer a "try again" that calls
4272
+ * {@link WebSocketController.reconnect}.
4273
+ */
4274
+ onLost?: (reason: WebSocketLostReason) => void;
4076
4275
  }
4077
4276
 
4078
4277
  /**
@@ -4700,6 +4899,9 @@ export declare const DEFAULT_CHUNK_SIZE: number;
4700
4899
  */
4701
4900
  export declare const DEFAULT_CIRCUITY_FACTOR = 1.3;
4702
4901
 
4902
+ /** Default ceiling for a per-source or master gain, as a multiplier. */
4903
+ export declare const DEFAULT_MAX_GAIN = 3;
4904
+
4703
4905
  /**
4704
4906
  * Per-mode multipliers applied to the car duration. Mirrors
4705
4907
  * `DEFAULT_MODE_DURATION_FACTORS` from `tempest-fastapi-sdk` — motorcycles are
@@ -5831,25 +6033,6 @@ export declare interface FormatPhoneOptions {
5831
6033
  mobile?: boolean;
5832
6034
  }
5833
6035
 
5834
- /**
5835
- * Glue between `react-hook-form` `Controller` and the SDK's controlled
5836
- * components. Wraps any control that accepts `{ value, onChange, label,
5837
- * error }` and routes RHF state into it — eliminating the per-field
5838
- * `<Controller render={...} />` boilerplate.
5839
- *
5840
- * @example
5841
- * const form = useZodForm(schema);
5842
- * <FormProvider {...form}>
5843
- * <Form>
5844
- * <FormField name="email" label="Email" required>
5845
- * <Input type="email" />
5846
- * </FormField>
5847
- * <FormField name="cep" label="CEP">
5848
- * <CEPInput />
5849
- * </FormField>
5850
- * </Form>
5851
- * </FormProvider>;
5852
- */
5853
6036
  export declare function FormField<TValues extends FieldValues = FieldValues, TName extends FieldPath<TValues> = FieldPath<TValues>>({ name, label, helperText, required, control, children }: FormFieldProps<TValues, TName>): JSX.Element;
5854
6037
 
5855
6038
  export declare interface FormFieldChildProps {
@@ -6165,6 +6348,17 @@ export { HashRouter }
6165
6348
  */
6166
6349
  export declare function haversineKm(origin: Coordinate, destination: Coordinate): number;
6167
6350
 
6351
+ /**
6352
+ * Heartbeat timeout, which sits inside the rejection range but is not one.
6353
+ *
6354
+ * `tempest-fastapi-sdk` closes with 4408 when no `pong` arrived within
6355
+ * `WS_HEARTBEAT_TIMEOUT_SECONDS`. That is the *link* failing, not the server
6356
+ * refusing the peer — exactly the case reconnection exists for. Treating the
6357
+ * whole 4400–4499 range as fatal, which is the obvious reading, makes one
6358
+ * missed pong permanent.
6359
+ */
6360
+ export declare const HEARTBEAT_CLOSE_CODE = 4408;
6361
+
6168
6362
  /** Convert a hex color to OKLCH. */
6169
6363
  export declare function hexToOklch(hex: string): Oklch;
6170
6364
 
@@ -6895,6 +7089,18 @@ export declare function isPlatformAuthenticatorAvailable(): Promise<boolean>;
6895
7089
  */
6896
7090
  export declare function isPushSupported(): boolean;
6897
7091
 
7092
+ /**
7093
+ * Whether a close code means the server refused this client for good.
7094
+ *
7095
+ * @param code - The `CloseEvent.code`.
7096
+ * @returns `true` when reconnecting can only reproduce the refusal.
7097
+ *
7098
+ * @example
7099
+ * isRejectionCloseCode(4401); // true — unauthorized
7100
+ * isRejectionCloseCode(4408); // false — heartbeat timeout, retry it
7101
+ */
7102
+ export declare function isRejectionCloseCode(code: number): boolean;
7103
+
6898
7104
  /**
6899
7105
  * Whether an HTTP status describes a condition a replay can plausibly fix.
6900
7106
  *
@@ -7308,6 +7514,20 @@ export declare interface LightboxProps {
7308
7514
  className?: string;
7309
7515
  }
7310
7516
 
7517
+ /** Shape of the master limiter. Matches `DynamicsCompressorNode`'s params. */
7518
+ export declare interface LimiterSettings {
7519
+ /** dBFS above which the compressor starts working. */
7520
+ threshold: number;
7521
+ /** dB range over which the curve bends. `0` is a hard knee. */
7522
+ knee: number;
7523
+ /** Input/output ratio above the threshold. 20 is limiting, not compression. */
7524
+ ratio: number;
7525
+ /** Seconds to clamp a peak. */
7526
+ attack: number;
7527
+ /** Seconds to let go. */
7528
+ release: number;
7529
+ }
7530
+
7311
7531
  export { Link }
7312
7532
 
7313
7533
  export declare interface ListOptions<TItem> {
@@ -8603,6 +8823,68 @@ export declare interface OpenModalOptions {
8603
8823
  /** The operators a field offers. */
8604
8824
  export declare function operatorsFor(field: FilterField): FilterOperator[];
8605
8825
 
8826
+ /**
8827
+ * @tempest-limits file-lines — parsing a session description, merging one
8828
+ * `fmtp` line and inserting a missing one are the same pass over the same
8829
+ * grammar; split apart, each half is a parser of half an SDP.
8830
+ */
8831
+ /** What an Opus `fmtp` line can be asked to carry. Every field is optional. */
8832
+ export declare interface OpusProfile {
8833
+ /**
8834
+ * Ceiling the encoder is asked to respect, in bits per second.
8835
+ *
8836
+ * This describes what we want **to receive**. To cap what we *send*, use
8837
+ * `setSenderBitrate` — in a mesh that is the one that matters, because the
8838
+ * uplink carries one copy per participant.
8839
+ */
8840
+ maxAverageBitrate?: number;
8841
+ /** Highest sample rate worth decoding, in Hz. `48000` for full band. */
8842
+ maxPlaybackRate?: number;
8843
+ /**
8844
+ * Two channels instead of one.
8845
+ *
8846
+ * Sets `stereo` **and** `sprop-stereo`, which point in opposite directions:
8847
+ * `stereo=1` asks the *remote* to send two channels, `sprop-stereo=1`
8848
+ * announces that *we* will. Setting only one leaves the link asymmetric,
8849
+ * which is the recurring reason "I asked for stereo and got mono".
8850
+ */
8851
+ stereo?: boolean;
8852
+ /**
8853
+ * In-band forward error correction (`useinbandfec`).
8854
+ *
8855
+ * Rebuilds a lost packet from the next one, which keeps speech intelligible
8856
+ * on a lossy link — and smears music, since it spends bitrate on redundancy
8857
+ * instead of detail.
8858
+ */
8859
+ fec?: boolean;
8860
+ /**
8861
+ * Discontinuous transmission (`usedtx`): stop sending during silence.
8862
+ *
8863
+ * Saves uplink in a mesh, at the cost of clipping the first instant after a
8864
+ * pause. Wrong for music and for a shared screen, where the quiet passages
8865
+ * are content.
8866
+ */
8867
+ dtx?: boolean;
8868
+ /** Constant bitrate (`cbr`). Off by default, as Opus intends. */
8869
+ cbr?: boolean;
8870
+ /**
8871
+ * Any other `fmtp` key, merged verbatim.
8872
+ *
8873
+ * The escape hatch for a parameter this type does not model. Values are
8874
+ * written as given; a key with an empty string is emitted as a bare flag.
8875
+ */
8876
+ extra?: Record<string, string>;
8877
+ }
8878
+
8879
+ /**
8880
+ * Profiles to apply, keyed by audio m-line index (`0`, `1`, …) or by `mid`.
8881
+ *
8882
+ * Position and `mid` can be mixed in one object. A key that matches nothing is
8883
+ * ignored rather than an error — an SDP is negotiated, and a slot that was not
8884
+ * offered this time is normal.
8885
+ */
8886
+ export declare type OpusProfileMap = Record<string | number, OpusProfile>;
8887
+
8606
8888
  /**
8607
8889
  * First sequential step that clears 2:1 against the chart surface.
8608
8890
  *
@@ -9675,7 +9957,7 @@ export declare function range(start: number, end: number, step?: number): number
9675
9957
  * stays accessible and works with keyboards/screen readers without
9676
9958
  * heavyweight positioning libs. The active fill is positioned via percentages.
9677
9959
  */
9678
- export declare function RangeSlider({ value, onChange, min, max, step, label, helperText, disabled, formatValue, className, }: RangeSliderProps): JSX.Element;
9960
+ export declare function RangeSlider({ value, onChange, min, max, step, label, helperText, disabled, formatValue, "aria-label": ariaLabel, className, }: RangeSliderProps): JSX.Element;
9679
9961
 
9680
9962
  export declare interface RangeSliderProps {
9681
9963
  value: RangeValue;
@@ -9688,6 +9970,14 @@ export declare interface RangeSliderProps {
9688
9970
  disabled?: boolean;
9689
9971
  /** Formatter for the value badge next to the label. Defaults to `min – max`. */
9690
9972
  formatValue?: (value: RangeValue) => string;
9973
+ /**
9974
+ * Accessible name for the pair, for when the visible `label` block does not fit.
9975
+ *
9976
+ * Each thumb still gets its own suffixed name — `"Preço (mínimo)"` and
9977
+ * `"Preço (máximo)"` — because a screen reader user moving between the two
9978
+ * needs to know which end they are on. Takes precedence over `label`.
9979
+ */
9980
+ "aria-label"?: string;
9691
9981
  className?: string;
9692
9982
  }
9693
9983
 
@@ -10578,6 +10868,56 @@ export declare interface SequentialScaleOptions {
10578
10868
  */
10579
10869
  export declare function setAudioOutput(element: HTMLMediaElement | null, sinkId: string): Promise<boolean>;
10580
10870
 
10871
+ /**
10872
+ * Cap what one sender transmits, in bits per second.
10873
+ *
10874
+ * This is the other half of the pair that confuses people: an Opus `fmtp` line
10875
+ * describes what we want **to receive**, while this is what limits what we
10876
+ * **send**. Both are needed, and in a mesh topology this one matters more,
10877
+ * because the uplink carries one copy of the stream per participant.
10878
+ *
10879
+ * The read-modify-write is not ceremony. `setParameters` only accepts the very
10880
+ * object `getParameters` handed back — a freshly built one is rejected — and a
10881
+ * sender that has not negotiated yet reports **no** encodings at all, so writing
10882
+ * to `encodings[0]` without checking throws on exactly the call that sets the
10883
+ * cap before the first offer.
10884
+ *
10885
+ * @param sender - The `RTCRtpSender` to cap, from `pc.getSenders()` or
10886
+ * `transceiver.sender`.
10887
+ * @param maxBitrate - Ceiling in bits per second, or `null` to lift the cap.
10888
+ * @returns `false` when the browser refused the change, which happens when the
10889
+ * sender has no track or the transceiver is gone. Playback continues
10890
+ * uncapped — a call that keeps running beats one that throws over a bitrate.
10891
+ *
10892
+ * @example
10893
+ * const sender = pc.getSenders().find((s) => s.track?.kind === "audio");
10894
+ * if (sender) await setSenderBitrate(sender, 48_000);
10895
+ */
10896
+ export declare function setSenderBitrate(sender: RTCRtpSender, maxBitrate: number | null): Promise<boolean>;
10897
+
10898
+ /**
10899
+ * Set a local description, falling back to the untouched one if it is refused.
10900
+ *
10901
+ * Chrome has been tightening what `setLocalDescription` accepts from edited SDP,
10902
+ * and there is no way to know in advance. Without a fallback the call dies
10903
+ * instead of merely losing the profile — which is the wrong trade by a wide
10904
+ * margin: worse audio beats no audio.
10905
+ *
10906
+ * @param connection - The peer connection.
10907
+ * @param description - The description from `createOffer` / `createAnswer`.
10908
+ * @param profiles - Passed straight to {@link tuneOpus}.
10909
+ * @returns `"tuned"` when the rewritten SDP was accepted, `"original"` when the
10910
+ * fallback was used — worth reporting, because it means the profile silently
10911
+ * did not apply.
10912
+ * @throws Whatever `setLocalDescription` throws for the original description: at
10913
+ * that point the failure is not about the rewrite and the caller has to know.
10914
+ *
10915
+ * @example
10916
+ * const applied = await setTunedLocalDescription(pc, await pc.createOffer(), profiles);
10917
+ * if (applied === "original") logger.warn("opus profile refused by the browser");
10918
+ */
10919
+ export declare function setTunedLocalDescription(connection: RTCPeerConnection, description: RTCSessionDescriptionInit, profiles: OpusProfile | OpusProfileMap): Promise<TunedDescriptionResult>;
10920
+
10581
10921
  /** Imperative handle over a pool of short sound effects. */
10582
10922
  export declare interface SfxPool {
10583
10923
  /** Play a clip, allocating and caching its element on first use. */
@@ -10920,7 +11260,7 @@ export declare function sleep(ms: number): Promise<void>;
10920
11260
  * accessible (keyboard + screen reader) with no positioning libs. The active
10921
11261
  * fill is a percentage-width bar. For a two-thumb range, use `RangeSlider`.
10922
11262
  */
10923
- export declare function Slider({ value, onChange, min, max, step, label, helperText, disabled, formatValue, className, }: SliderProps): JSX.Element;
11263
+ export declare function Slider({ value, onChange, min, max, step, label, helperText, disabled, formatValue, "aria-label": ariaLabel, className, }: SliderProps): JSX.Element;
10924
11264
 
10925
11265
  export declare interface SliderProps {
10926
11266
  /** Current value. */
@@ -10935,6 +11275,17 @@ export declare interface SliderProps {
10935
11275
  disabled?: boolean;
10936
11276
  /** Formatter for the value badge next to the label. Defaults to the raw number. */
10937
11277
  formatValue?: (value: number) => string;
11278
+ /**
11279
+ * Accessible name, for when the visible `label` block does not fit.
11280
+ *
11281
+ * A slider in a one-line footer, a table cell or a toolbar has no room for the
11282
+ * label row above the track, and without this every such control announces
11283
+ * itself as "Slider" — several on the same screen become indistinguishable to a
11284
+ * screen reader. Takes precedence over `label`; wrapping the field in an outer
11285
+ * `<label>` does not work, because an explicit `aria-label` on the input wins
11286
+ * the accessible-name precedence order.
11287
+ */
11288
+ "aria-label"?: string;
10938
11289
  className?: string;
10939
11290
  }
10940
11291
 
@@ -12380,6 +12731,42 @@ export declare interface TruncateTextProps extends HTMLAttributes<HTMLDivElement
12380
12731
  children: ReactNode;
12381
12732
  }
12382
12733
 
12734
+ /** Which description a peer connection actually accepted. */
12735
+ export declare type TunedDescriptionResult = "tuned" | "original";
12736
+
12737
+ /**
12738
+ * Apply Opus profiles to the audio m-lines of a session description.
12739
+ *
12740
+ * Audio over WebRTC is mono and narrow by default, and the only place that is
12741
+ * corrected is the SDP — which is why shared-screen audio famously sounds like a
12742
+ * telephone: music and video inherit the speech profile (mono, ~32 kbps, FEC on,
12743
+ * DTX gating the quiet passages) and no high-level API lets you change it.
12744
+ *
12745
+ * Deliberately **without** built-in presets: which values to use is the
12746
+ * consumer's call — voice in a mesh does not want what system audio wants — and
12747
+ * a preset table is the kind of thing that has no business inside a dependency.
12748
+ * What lives here is the parsing, merging and insertion, which is where the long
12749
+ * tail is. Getting any of it wrong degrades silently: nobody sees an exception,
12750
+ * the audio is just worse.
12751
+ *
12752
+ * @param sdp - The description from `createOffer` or `createAnswer`.
12753
+ * @param profiles - One {@link OpusProfile} for every audio m-line, or an
12754
+ * {@link OpusProfileMap} keyed by audio m-line index or by `mid`.
12755
+ * @returns The rewritten SDP, with CRLF line endings as RFC 4566 requires.
12756
+ * Untouched when there is no Opus, when no profile matches, or when a profile
12757
+ * asks for nothing.
12758
+ *
12759
+ * @example
12760
+ * const tuned = tuneOpus(offer.sdp, {
12761
+ * 0: { maxAverageBitrate: 48_000, stereo: false, fec: true, dtx: true },
12762
+ * 1: { maxAverageBitrate: 192_000, stereo: true, fec: false, dtx: false },
12763
+ * });
12764
+ *
12765
+ * @example
12766
+ * const tuned = tuneOpus(offer.sdp, { stereo: true, dtx: false });
12767
+ */
12768
+ export declare function tuneOpus(sdp: string, profiles: OpusProfile | OpusProfileMap): string;
12769
+
12383
12770
  /**
12384
12771
  * Clock label for a turn — the time, not a relative phrase.
12385
12772
  *
@@ -12640,6 +13027,31 @@ export declare interface UseAsyncResult<T> {
12640
13027
  */
12641
13028
  export declare function useAudio(): UseAudioResult;
12642
13029
 
13030
+ /**
13031
+ * Keep one {@link AudioBus} alive for as long as the component is mounted.
13032
+ *
13033
+ * The bus is built on the first render and closed on unmount, which matters more
13034
+ * than it looks: browsers cap the number of live `AudioContext`s (Chrome allows
13035
+ * around six), so a bus leaked on unmount eventually breaks every later one on
13036
+ * the page.
13037
+ *
13038
+ * Options are read once. A bus is a device route and a mixing graph, not a
13039
+ * render output — rebuilding it because a prop changed would drop every attached
13040
+ * source mid-sentence. Change gain and output through the bus itself.
13041
+ *
13042
+ * @param options - See {@link AudioBusOptions}. Read on the first render only.
13043
+ * @returns The bus, stable for the component's lifetime.
13044
+ *
13045
+ * @example
13046
+ * const bus = useAudioBus({ maxGain: 3 });
13047
+ *
13048
+ * useEffect(() => {
13049
+ * const handle = bus.attach(stream, { gain: 1 });
13050
+ * return () => handle.stop();
13051
+ * }, [bus, stream]);
13052
+ */
13053
+ export declare function useAudioBus(options?: AudioBusOptions): AudioBus;
13054
+
12643
13055
  /**
12644
13056
  * Record the given stream, with a clock, a level meter and a state machine.
12645
13057
  *
@@ -15105,11 +15517,13 @@ export { useWatch }
15105
15517
  * for the host component and tears it down on unmount.
15106
15518
  *
15107
15519
  * Every callback is read through a ref, so `onOpen` / `onMessage` / `onClose` /
15108
- * `onError` always run the latest closure an inline arrow function is fine
15109
- * and never reopens the socket. Connection-shaping options (`protocols`,
15110
- * `maxRetries`, `initialBackoff`, `maxBackoff`, `pingInterval`,
15111
- * `queueWhileClosed`) are baked into the connection, so changing one reopens
15112
- * it with the new value rather than being silently ignored.
15520
+ * `onError` / `onReconnecting` / `onReconnected` / `onLost` always run the
15521
+ * latest closure — an inline arrow function is fine and never reopens the
15522
+ * socket. Connection-shaping options (`protocols`, `maxRetries`,
15523
+ * `initialBackoff`, `maxBackoff`, `jitter`, `handshakeTimeout`,
15524
+ * `silenceTimeout`, `waitForOnline`, `pingInterval`, `queueWhileClosed`) are
15525
+ * baked into the connection, so changing one reopens it with the new value
15526
+ * rather than being silently ignored.
15113
15527
  *
15114
15528
  * @param url - Full ws:// or wss:// URL.
15115
15529
  * @param options - Connection configuration and callbacks.
@@ -15138,6 +15552,13 @@ export declare interface UseWebSocketResult<T> {
15138
15552
  send: (payload: string | Blob | BufferSource) => boolean;
15139
15553
  /** Force a reconnect, resetting the retry counter. */
15140
15554
  reconnect: () => void;
15555
+ /**
15556
+ * Change the silence watchdog at runtime, in ms. `0` disables it.
15557
+ *
15558
+ * For a server that announces its own heartbeat interval in the first frame,
15559
+ * so the tolerated silence is not hard-coded on both ends.
15560
+ */
15561
+ setSilenceTimeout: (ms: number) => void;
15141
15562
  }
15142
15563
 
15143
15564
  /**
@@ -15797,10 +16218,38 @@ export declare interface WebSocketController {
15797
16218
  close: (code?: number, reason?: string) => void;
15798
16219
  /** Force an immediate reconnect, resetting the retry counter. */
15799
16220
  reconnect: () => void;
16221
+ /**
16222
+ * Change the silence watchdog at runtime, in ms. `0` disables it.
16223
+ *
16224
+ * For the common case where the server announces its heartbeat interval in
16225
+ * the first frame, so the tolerated silence is not hard-coded on both ends:
16226
+ *
16227
+ * ```ts
16228
+ * onMessage: ({ data }) => {
16229
+ * if (data.type === "welcome") socket.setSilenceTimeout(data.heartbeat_seconds * 2500);
16230
+ * }
16231
+ * ```
16232
+ */
16233
+ setSilenceTimeout: (ms: number) => void;
16234
+ /**
16235
+ * Resolves on the first successful open, rejects when the socket is lost
16236
+ * before ever opening.
16237
+ *
16238
+ * Joining and dropping are different events: a call that never connected has
16239
+ * to be reported, while one that dropped mid-session should reconnect
16240
+ * quietly. Await this for the join, handle
16241
+ * {@link CreateWebSocketOptions.onLost} for the drop. Pair it with
16242
+ * `maxRetries: 0` when the first attempt should fail fast instead of
16243
+ * spending the whole schedule on a server that is not there.
16244
+ */
16245
+ opened: Promise<void>;
15800
16246
  /** Current connection status. */
15801
16247
  readonly status: WebSocketStatus;
15802
16248
  }
15803
16249
 
16250
+ /** Why a socket stopped trying to come back. */
16251
+ export declare type WebSocketLostReason = "rejected" | "exhausted";
16252
+
15804
16253
  export declare interface WebSocketMessage<T> {
15805
16254
  /** Parsed payload — JSON-decoded when possible, raw string otherwise. */
15806
16255
  data: T;
@@ -15808,12 +16257,6 @@ export declare interface WebSocketMessage<T> {
15808
16257
  raw: MessageEvent;
15809
16258
  }
15810
16259
 
15811
- /**
15812
- * @tempest-limits file-lines, function-lines — reconnect with backoff, heartbeat,
15813
- * the send queue that survives a disconnect and the listener set that must be re-
15814
- * attached to each new socket — one connection's lifetime, one closure. The queue
15815
- * and the reconnect timer are the same decision seen twice.
15816
- */
15817
16260
  export declare type WebSocketStatus = "idle" | "connecting" | "open" | "closing" | "closed" | "error";
15818
16261
 
15819
16262
  export declare type WeekStart = 0 | 1;