streamlit-nightly 1.52.3.dev20260111__py3-none-any.whl → 1.52.3.dev20260113__py3-none-any.whl

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 (213) hide show
  1. streamlit/__init__.py +1 -1
  2. streamlit/auth_util.py +25 -2
  3. streamlit/cli_util.py +1 -1
  4. streamlit/components/v2/bidi_component/main.py +2 -2
  5. streamlit/connections/snowflake_connection.py +1 -1
  6. streamlit/dataframe_util.py +1 -3
  7. streamlit/elements/arrow.py +5 -1
  8. streamlit/elements/lib/color_util.py +1 -1
  9. streamlit/elements/lib/image_utils.py +1 -1
  10. streamlit/elements/vega_charts.py +4 -1
  11. streamlit/elements/widgets/multiselect.py +1 -1
  12. streamlit/elements/widgets/time_widgets.py +1 -1
  13. streamlit/elements/write.py +1 -2
  14. streamlit/errors.py +2 -0
  15. streamlit/external/langchain/streamlit_callback_handler.py +1 -1
  16. streamlit/proto/Alert_pb2.pyi +31 -31
  17. streamlit/proto/AppPage_pb2.pyi +30 -30
  18. streamlit/proto/ArrowData_pb2.pyi +15 -15
  19. streamlit/proto/ArrowNamedDataSet_pb2.pyi +25 -25
  20. streamlit/proto/ArrowVegaLiteChart_pb2.pyi +45 -45
  21. streamlit/proto/Arrow_pb2.pyi +126 -97
  22. streamlit/proto/AudioInput_pb2.pyi +39 -39
  23. streamlit/proto/Audio_pb2.pyi +39 -39
  24. streamlit/proto/AuthRedirect_pb2.pyi +15 -15
  25. streamlit/proto/AutoRerun_pb2.pyi +18 -18
  26. streamlit/proto/BackMsg_pb2.pyi +64 -64
  27. streamlit/proto/Balloons_pb2.pyi +15 -15
  28. streamlit/proto/BidiComponent_pb2.pyi +100 -100
  29. streamlit/proto/Block_pb2.pyi +295 -264
  30. streamlit/proto/BokehChart_pb2.pyi +21 -21
  31. streamlit/proto/ButtonGroup_pb2.pyi +96 -96
  32. streamlit/proto/ButtonLikeIconPosition_pb2.pyi +12 -12
  33. streamlit/proto/Button_pb2.pyi +63 -50
  34. streamlit/proto/CameraInput_pb2.pyi +34 -34
  35. streamlit/proto/ChatInput_pb2.pyi +63 -63
  36. streamlit/proto/Checkbox_pb2.pyi +49 -49
  37. streamlit/proto/ClientState_pb2.pyi +85 -85
  38. streamlit/proto/Code_pb2.pyi +41 -28
  39. streamlit/proto/ColorPicker_pb2.pyi +43 -43
  40. streamlit/proto/Common_pb2.pyi +175 -175
  41. streamlit/proto/Components_pb2.pyi +110 -110
  42. streamlit/proto/DataFrame_pb2.pyi +209 -209
  43. streamlit/proto/DateInput_pb2.pyi +59 -59
  44. streamlit/proto/DateTimeInput_pb2.pyi +62 -62
  45. streamlit/proto/DeckGlJsonChart_pb2.pyi +91 -56
  46. streamlit/proto/Delta_pb2.pyi +44 -44
  47. streamlit/proto/DocString_pb2.pyi +51 -51
  48. streamlit/proto/DownloadButton_pb2.pyi +59 -59
  49. streamlit/proto/Element_pb2.pyi +319 -319
  50. streamlit/proto/Empty_pb2.pyi +10 -10
  51. streamlit/proto/Exception_pb2.pyi +37 -37
  52. streamlit/proto/Favicon_pb2.pyi +15 -15
  53. streamlit/proto/FileUploader_pb2.pyi +49 -49
  54. streamlit/proto/ForwardMsg_pb2.pyi +176 -170
  55. streamlit/proto/GapSize_pb2.pyi +23 -23
  56. streamlit/proto/GitInfo_pb2.pyi +37 -37
  57. streamlit/proto/GraphVizChart_pb2.pyi +38 -25
  58. streamlit/proto/Heading_pb2.pyi +30 -30
  59. streamlit/proto/HeightConfig_pb2.pyi +31 -31
  60. streamlit/proto/Html_pb2.pyi +18 -18
  61. streamlit/proto/IFrame_pb2.pyi +76 -47
  62. streamlit/proto/Image_pb2.pyi +49 -36
  63. streamlit/proto/Json_pb2.pyi +25 -25
  64. streamlit/proto/LabelVisibilityMessage_pb2.pyi +18 -18
  65. streamlit/proto/LinkButton_pb2.pyi +43 -43
  66. streamlit/proto/Logo_pb2.pyi +24 -24
  67. streamlit/proto/Markdown_pb2.pyi +30 -30
  68. streamlit/proto/Metric_pb2.pyi +59 -59
  69. streamlit/proto/MetricsEvent_pb2.pyi +171 -171
  70. streamlit/proto/MultiSelect_pb2.pyi +72 -66
  71. streamlit/proto/NamedDataSet_pb2.pyi +25 -25
  72. streamlit/proto/Navigation_pb2.pyi +35 -35
  73. streamlit/proto/NewSession_pb2.pyi +511 -498
  74. streamlit/proto/NumberInput_pb2.pyi +79 -79
  75. streamlit/proto/PageConfig_pb2.pyi +71 -71
  76. streamlit/proto/PageInfo_pb2.pyi +15 -15
  77. streamlit/proto/PageLink_pb2.pyi +47 -47
  78. streamlit/proto/PageNotFound_pb2.pyi +15 -15
  79. streamlit/proto/PageProfile_pb2.pyi +85 -85
  80. streamlit/proto/PagesChanged_pb2.pyi +19 -19
  81. streamlit/proto/ParentMessage_pb2.pyi +15 -15
  82. streamlit/proto/PlotlyChart_pb2.pyi +79 -64
  83. streamlit/proto/Progress_pb2.pyi +18 -18
  84. streamlit/proto/Radio_pb2.pyi +62 -62
  85. streamlit/proto/RootContainer_pb2.pyi +12 -12
  86. streamlit/proto/Selectbox_pb2.pyi +80 -70
  87. streamlit/proto/SessionEvent_pb2.pyi +27 -27
  88. streamlit/proto/SessionStatus_pb2.pyi +18 -18
  89. streamlit/proto/Skeleton_pb2.pyi +25 -25
  90. streamlit/proto/Slider_pb2.pyi +74 -74
  91. streamlit/proto/Snow_pb2.pyi +15 -15
  92. streamlit/proto/Space_pb2.pyi +10 -10
  93. streamlit/proto/Spinner_pb2.pyi +21 -21
  94. streamlit/proto/TextAlignmentConfig_pb2.pyi +18 -18
  95. streamlit/proto/TextArea_pb2.pyi +72 -59
  96. streamlit/proto/TextInput_pb2.pyi +67 -67
  97. streamlit/proto/Text_pb2.pyi +18 -18
  98. streamlit/proto/TimeInput_pb2.pyi +52 -52
  99. streamlit/proto/Toast_pb2.pyi +25 -25
  100. streamlit/proto/Transient_pb2.pyi +19 -19
  101. streamlit/proto/VegaLiteChart_pb2.pyi +32 -32
  102. streamlit/proto/Video_pb2.pyi +65 -65
  103. streamlit/proto/WidgetStates_pb2.pyi +91 -85
  104. streamlit/proto/WidthConfig_pb2.pyi +31 -31
  105. streamlit/proto/openmetrics_data_model_pb2.pyi +269 -269
  106. streamlit/runtime/app_session.py +1 -1
  107. streamlit/runtime/credentials.py +2 -2
  108. streamlit/runtime/metrics_util.py +3 -3
  109. streamlit/runtime/secrets.py +1 -1
  110. streamlit/runtime/stats.py +1 -3
  111. streamlit/static/index.html +1 -1
  112. streamlit/static/manifest.json +296 -296
  113. streamlit/static/static/js/{ErrorOutline.esm.D0HiUB0L.js → ErrorOutline.esm.BjVqd_6R.js} +1 -1
  114. streamlit/static/static/js/{FileDownload.esm.BuUS-pfi.js → FileDownload.esm.DJCSsghl.js} +1 -1
  115. streamlit/static/static/js/{FileHelper.Pf8URFng.js → FileHelper.C---TH7o.js} +1 -1
  116. streamlit/static/static/js/{FormClearHelper.By4vKj6A.js → FormClearHelper.C-6BC487.js} +1 -1
  117. streamlit/static/static/js/{InputInstructions.BiaGyIXk.js → InputInstructions.sxc3InCI.js} +1 -1
  118. streamlit/static/static/js/{Particles.2-EdjYhR.js → Particles.S8yD7iW-.js} +1 -1
  119. streamlit/static/static/js/{ProgressBar.Dgbh0B0d.js → ProgressBar.BiYsyZCC.js} +1 -1
  120. streamlit/static/static/js/{StreamlitSyntaxHighlighter.DSl8Wr3R.js → StreamlitSyntaxHighlighter.9jZF8jX1.js} +1 -1
  121. streamlit/static/static/js/{TableChart.esm.MOwyTUPh.js → TableChart.esm.BdA4Q1rZ.js} +1 -1
  122. streamlit/static/static/js/{Toolbar.CowuXIFr.js → Toolbar.B9DaaDfN.js} +1 -1
  123. streamlit/static/static/js/{WidgetLabelHelpIconInline.BdGIJQe4.js → WidgetLabelHelpIconInline.DxODTLS2.js} +1 -1
  124. streamlit/static/static/js/{base-input.CHPo5oJ1.js → base-input.Gf1cKuQR.js} +1 -1
  125. streamlit/static/static/js/{checkbox.Dkt2TQVS.js → checkbox.CnoNruf3.js} +1 -1
  126. streamlit/static/static/js/{createDownloadLinkElement.BaE-_v8I.js → createDownloadLinkElement.B48AepiL.js} +1 -1
  127. streamlit/static/static/js/{data-grid-overlay-editor.C1ncL-Nr.js → data-grid-overlay-editor.Cmdq9aqU.js} +1 -1
  128. streamlit/static/static/js/{downloader.yaq2AzD9.js → downloader.CQLoQdMX.js} +1 -1
  129. streamlit/static/static/js/{embed.DJJvCVz2.js → embed.oKwocwU8.js} +1 -1
  130. streamlit/static/static/js/{es6.D2jK98VU.js → es6.BRxlY_y5.js} +2 -2
  131. streamlit/static/static/js/{formatNumber.Cxr2q_Sk.js → formatNumber.DaagZyZe.js} +1 -1
  132. streamlit/static/static/js/{iconPosition.5dHEZYw2.js → iconPosition.Q3hNvmK4.js} +1 -1
  133. streamlit/static/static/js/{iframeResizer.contentWindow.Cedt4qbc.js → iframeResizer.contentWindow.B6EBvI9L.js} +1 -1
  134. streamlit/static/static/js/{index.DaITTdfQ.js → index.19_qtO6t.js} +1 -1
  135. streamlit/static/static/js/{index._nL4Yjdr.js → index.43b777iP.js} +1 -1
  136. streamlit/static/static/js/{index.P-CMMGUY.js → index.B03eQZoH.js} +1 -1
  137. streamlit/static/static/js/{index.D2EVLt1U.js → index.B9kZB0o1.js} +1 -1
  138. streamlit/static/static/js/{index.BkDplL5I.js → index.BAI9aHCq.js} +1 -1
  139. streamlit/static/static/js/{index.CT9jvPcD.js → index.BF23fbfs.js} +1 -1
  140. streamlit/static/static/js/{index.TO9vodwr.js → index.BGBTkulf.js} +1 -1
  141. streamlit/static/static/js/{index.01VsD2h1.js → index.BRfGUOQ-.js} +5 -5
  142. streamlit/static/static/js/{index.D6ea3OJl.js → index.BVT89mQw.js} +1 -1
  143. streamlit/static/static/js/{index.BHMoYAbd.js → index.BXEC4cf3.js} +1 -1
  144. streamlit/static/static/js/{index.B6EliwN_.js → index.BbSFVZ3p.js} +1 -1
  145. streamlit/static/static/js/{index.B7EzT2pL.js → index.BkSwGJoh.js} +1 -1
  146. streamlit/static/static/js/{index.B6Uhb_NP.js → index.BnfTPrHb.js} +1 -1
  147. streamlit/static/static/js/{index.qzz9PjCO.js → index.BoX8d5rK.js} +1 -1
  148. streamlit/static/static/js/{index.Bb9kjc_v.js → index.Boa0Egng.js} +1 -1
  149. streamlit/static/static/js/{index.CjQo7CUO.js → index.BzwlrgZO.js} +1 -1
  150. streamlit/static/static/js/{index.Ba6hzYdl.js → index.C0fSEz-3.js} +1 -1
  151. streamlit/static/static/js/{index.B2TDaHdI.js → index.CCFwVy90.js} +1 -1
  152. streamlit/static/static/js/{index.Dt0Psatx.js → index.CCQ5p_WC.js} +1 -1
  153. streamlit/static/static/js/{index.DeGjj5Xy.js → index.CFCBhOfx.js} +1 -1
  154. streamlit/static/static/js/{index.DredtYc0.js → index.CIbgt5wY.js} +1 -1
  155. streamlit/static/static/js/{index.CD8IIWcc.js → index.CJ4oJe0V.js} +1 -1
  156. streamlit/static/static/js/{index.6_D2Y2jA.js → index.CP-hoxJM.js} +1 -1
  157. streamlit/static/static/js/{index.BXCQzqUL.js → index.CSfsEKCF.js} +1 -1
  158. streamlit/static/static/js/{index.C8PH2B2k.js → index.CVlg41MB.js} +1 -1
  159. streamlit/static/static/js/{index.BVit6ClT.js → index.CYE7b5Du.js} +1 -1
  160. streamlit/static/static/js/{index.DKUtJ1wC.js → index.Ca7MUNWJ.js} +1 -1
  161. streamlit/static/static/js/index.CrPjcPY1.js +1 -0
  162. streamlit/static/static/js/{index.BMPclSge.js → index.CvB9JBqS.js} +5 -5
  163. streamlit/static/static/js/{index.BCCeRfnu.js → index.CvIqsWy1.js} +1 -1
  164. streamlit/static/static/js/{index.wLJVkoPD.js → index.D1pK_Vw2.js} +1 -1
  165. streamlit/static/static/js/{index.B0GsKOuI.js → index.D6X2coHR.js} +1 -1
  166. streamlit/static/static/js/{index.B4x2O71H.js → index.DGYHxruh.js} +1 -1
  167. streamlit/static/static/js/{index.DcKOiCiE.js → index.DJ7P09eb.js} +1 -1
  168. streamlit/static/static/js/{index.CcHnYd9w.js → index.Dh5SAThV.js} +1 -1
  169. streamlit/static/static/js/{index.BFopzcDu.js → index.Fu73QtkD.js} +1 -1
  170. streamlit/static/static/js/{index.CIlqaESj.js → index.KN1VmyYN.js} +1 -1
  171. streamlit/static/static/js/{index.B9DrCSR6.js → index.KtjGDGY5.js} +1 -1
  172. streamlit/static/static/js/{index.DLB_Wwth.js → index.OpATzEaW.js} +1 -1
  173. streamlit/static/static/js/{index.CcJEaOpw.js → index.QHnxuesF.js} +1 -1
  174. streamlit/static/static/js/{index.1djeb6e0.js → index.QTaWooav.js} +1 -1
  175. streamlit/static/static/js/{index.BgVtKHgk.js → index.WXybx2Xq.js} +1 -1
  176. streamlit/static/static/js/{index.DtGneC7j.js → index.Xg-Qttib.js} +1 -1
  177. streamlit/static/static/js/{index.Dewn3Ni9.js → index.j4fnjyHo.js} +1 -1
  178. streamlit/static/static/js/{index.CAobVzMK.js → index.na9UBuse.js} +1 -1
  179. streamlit/static/static/js/{index.D2v1x0i_.js → index.pU9mQeVC.js} +1 -1
  180. streamlit/static/static/js/{index.DbTMA1_Q.js → index.slgxPafU.js} +1 -1
  181. streamlit/static/static/js/{index.DozBVd6-.js → index.whRT3Vm3.js} +1 -1
  182. streamlit/static/static/js/{input.27t-DftI.js → input.CPzINTl-.js} +1 -1
  183. streamlit/static/static/js/{main.BEfv2Y8-.js → main.DSPn8dUe.js} +1 -1
  184. streamlit/static/static/js/{memory.CaZBVQ_1.js → memory.CfD8IGoU.js} +1 -1
  185. streamlit/static/static/js/{number-overlay-editor.CAIp-3oo.js → number-overlay-editor.4Ae0qegV.js} +1 -1
  186. streamlit/static/static/js/{pandasStylerUtils.BY9qaz81.js → pandasStylerUtils.D2EjZ7k6.js} +1 -1
  187. streamlit/static/static/js/{sandbox.BJUaaWFJ.js → sandbox.C6vcPIm0.js} +1 -1
  188. streamlit/static/static/js/{styled-components.DQsMkvXn.js → styled-components.BBmp8buj.js} +1 -1
  189. streamlit/static/static/js/{throttle.DSR3q89S.js → throttle.BPcPpy-S.js} +1 -1
  190. streamlit/static/static/js/{timepicker.gie5YwtP.js → timepicker.ryzkTs2C.js} +1 -1
  191. streamlit/static/static/js/{toConsumableArray.C9lVwnAo.js → toConsumableArray.Dg1nDaB_.js} +1 -1
  192. streamlit/static/static/js/uniqueId.BFHzT5KQ.js +1 -0
  193. streamlit/static/static/js/{useBasicWidgetState.DrTKs46R.js → useBasicWidgetState.A4U5lzAm.js} +1 -1
  194. streamlit/static/static/js/{useIntlLocale.CmSionuT.js → useIntlLocale.DWJgLlNz.js} +1 -1
  195. streamlit/static/static/js/{useTextInputAutoExpand.D7lViJSu.js → useTextInputAutoExpand.BrBonw8t.js} +1 -1
  196. streamlit/static/static/js/{useUpdateUiValue.Ct3CJQBQ.js → useUpdateUiValue.BkOWyNVX.js} +1 -1
  197. streamlit/static/static/js/{useWaveformController.D-KQLpLI.js → useWaveformController.CBlvXlgZ.js} +1 -1
  198. streamlit/static/static/js/{withCalculatedWidth.CD0pPoZr.js → withCalculatedWidth.D4cpOyNe.js} +1 -1
  199. streamlit/static/static/js/{withFullScreenWrapper.Ch22PgdD.js → withFullScreenWrapper.BMim3w94.js} +1 -1
  200. streamlit/testing/v1/app_test.py +1 -1
  201. streamlit/user_info.py +6 -4
  202. streamlit/web/server/browser_websocket_handler.py +2 -2
  203. streamlit/web/server/oauth_authlib_routes.py +97 -20
  204. streamlit/web/server/starlette/starlette_routes.py +1 -3
  205. streamlit/web/server/stats_request_handler.py +1 -3
  206. {streamlit_nightly-1.52.3.dev20260111.dist-info → streamlit_nightly-1.52.3.dev20260113.dist-info}/METADATA +1 -1
  207. {streamlit_nightly-1.52.3.dev20260111.dist-info → streamlit_nightly-1.52.3.dev20260113.dist-info}/RECORD +211 -211
  208. streamlit/static/static/js/index.i_eQw7NS.js +0 -1
  209. streamlit/static/static/js/uniqueId.BdEQNrWF.js +0 -1
  210. {streamlit_nightly-1.52.3.dev20260111.data → streamlit_nightly-1.52.3.dev20260113.data}/scripts/streamlit.cmd +0 -0
  211. {streamlit_nightly-1.52.3.dev20260111.dist-info → streamlit_nightly-1.52.3.dev20260113.dist-info}/WHEEL +0 -0
  212. {streamlit_nightly-1.52.3.dev20260111.dist-info → streamlit_nightly-1.52.3.dev20260113.dist-info}/entry_points.txt +0 -0
  213. {streamlit_nightly-1.52.3.dev20260111.dist-info → streamlit_nightly-1.52.3.dev20260113.dist-info}/top_level.txt +0 -0
@@ -1 +1 @@
1
- import{l as Z,r as i,aR as M,ab as $,aS as O}from"./index.01VsD2h1.js";async function q(l,e=16e3){if(!l||l.size===0)throw new Error("Invalid or empty blob provided");if(!window.AudioContext)throw new Error("AudioContext not supported in this browser");const o=new AudioContext;try{const n=await l.arrayBuffer(),r=await o.decodeAudioData(n),d=e??r.sampleRate,s=await J(r,d);return K(s,d)}finally{o.close()}}async function J(l,e){const{duration:o,numberOfChannels:n,sampleRate:r}=l,d=Math.ceil(o*e);if(!window.OfflineAudioContext)throw new Error("OfflineAudioContext not supported");const s=new OfflineAudioContext(1,d,e),p=s.createBufferSource();if(p.buffer=l,n>1){const h=s.createChannelSplitter(n),m=s.createChannelMerger(1);p.connect(h);for(let c=0;c<n;c++){const u=s.createGain();u.gain.value=1/n,h.connect(u,c),u.connect(m,0,0)}m.connect(s.destination)}else p.connect(s.destination);p.start(0);try{return await s.startRendering()}catch(h){throw new Error(`Failed to resample audio from ${r}Hz to ${e}Hz: ${h instanceof Error?h.message:String(h)}`)}}function K(l,e){const n=l.length,r=n*2+44,d=new ArrayBuffer(r),s=new DataView(d),p=l.getChannelData(0),h=(c,u)=>{for(let y=0;y<u.length;y++)s.setUint8(c+y,u.charCodeAt(y))};h(0,"RIFF"),s.setUint32(4,r-8,!0),h(8,"WAVE"),h(12,"fmt "),s.setUint32(16,16,!0),s.setUint16(20,1,!0),s.setUint16(22,1,!0),s.setUint32(24,e,!0),s.setUint32(28,e*2,!0),s.setUint16(32,2,!0),s.setUint16(34,16,!0),h(36,"data"),s.setUint32(40,n*2,!0);let m=44;for(let c=0;c<n;c++){const u=Math.max(-1,Math.min(1,p[c]));s.setInt16(m,u*32767,!0),m+=2}return new Blob([d],{type:"audio/wav"})}class W{constructor(){this.wavesurfer=null,this.currentBlobUrl=null,this.events={},this.isPlaying=!1}initialize(e){this.wavesurfer=e,this.setupEventListeners()}setupEventListeners(){this.wavesurfer&&(this.teardownEventListeners(),this.handleTimeUpdate=e=>{this.events.onTimeUpdate?.(e*1e3)},this.handlePause=()=>{this.isPlaying=!1,this.events.onPause?.()},this.handlePlay=()=>{this.isPlaying=!0,this.events.onPlay?.()},this.handleFinish=()=>{this.isPlaying=!1,this.events.onFinish?.()},this.handleReady=()=>{this.events.onReady?.()},this.handleError=e=>{const o=e instanceof Error?e:new Error(String(e));this.events.onError?.(o)},this.wavesurfer.on("timeupdate",this.handleTimeUpdate),this.wavesurfer.on("pause",this.handlePause),this.wavesurfer.on("play",this.handlePlay),this.wavesurfer.on("finish",this.handleFinish),this.wavesurfer.on("ready",this.handleReady),this.wavesurfer.on("error",this.handleError))}setEventHandlers(e){this.events=e}async load(e){if(!this.wavesurfer)throw new Error("WaveSurfer not initialized");this.cleanupPreviousUrl();let o,n=null;try{if(e instanceof Blob)n=URL.createObjectURL(e),o=n;else if(e instanceof ArrayBuffer){const r=new Blob([e]);n=URL.createObjectURL(r),o=n}else o=e;this.currentBlobUrl=n,await this.wavesurfer.load(o)}catch(r){throw this.cleanupPreviousUrl(),r}}async play(){if(!this.wavesurfer)throw new Error("WaveSurfer not initialized");await this.wavesurfer.play()}pause(){this.wavesurfer&&this.wavesurfer.pause()}getDuration(){return this.wavesurfer?this.wavesurfer.getDuration()*1e3:0}getCurrentTime(){return this.wavesurfer?this.wavesurfer.getCurrentTime()*1e3:0}getIsPlaying(){return this.isPlaying}seekToStart(){this.wavesurfer&&this.wavesurfer.seekTo(0)}cleanupPreviousUrl(){this.currentBlobUrl&&(URL.revokeObjectURL(this.currentBlobUrl),this.currentBlobUrl=null)}destroy(){this.pause(),this.cleanupPreviousUrl(),this.wavesurfer&&(this.teardownEventListeners(),this.wavesurfer.empty(),this.wavesurfer=null),this.events={},this.isPlaying=!1,this.handleTimeUpdate=void 0,this.handlePause=void 0,this.handlePlay=void 0,this.handleFinish=void 0,this.handleReady=void 0,this.handleError=void 0}teardownEventListeners(){this.wavesurfer&&(this.handleTimeUpdate&&(this.wavesurfer.un("timeupdate",this.handleTimeUpdate),this.handleTimeUpdate=void 0),this.handlePause&&(this.wavesurfer.un("pause",this.handlePause),this.handlePause=void 0),this.handlePlay&&(this.wavesurfer.un("play",this.handlePlay),this.handlePlay=void 0),this.handleFinish&&(this.wavesurfer.un("finish",this.handleFinish),this.handleFinish=void 0),this.handleReady&&(this.wavesurfer.un("ready",this.handleReady),this.handleReady=void 0),this.handleError&&(this.wavesurfer.un("error",this.handleError),this.handleError=void 0))}}function I(l){return l.name==="NotAllowedError"||l.name==="PermissionDeniedError"||l.message?.toLowerCase().includes("permission denied")}class Q{constructor(e={}){this.wavesurfer=null,this.recordPlugin=null,this.isRecording=!1,this.recordEndResolve=null,this.recordEndReject=null,this.events={},this.options=e}initialize(e,o){this.wavesurfer=e;try{const n={renderRecordedAudio:!1,mimeType:"audio/webm"};this.recordPlugin=e.registerPlugin(o.create(n)),this.setupEventListeners()}catch(n){const r=n instanceof Error?n:new Error(String(n));throw I(r)?(this.events.onPermissionDenied?.(),new Error("Microphone permission denied")):(this.events.onError?.(r),r)}}setupEventListeners(){this.recordPlugin&&(this.recordPlugin.on("record-start",()=>{this.isRecording=!0,this.events.onRecordStart?.()}),this.recordPlugin.on("record-end",e=>{this.isRecording=!1,this.events.onRecordEnd?.(e),this.recordEndResolve&&e&&e.size>0?(this.recordEndResolve(e),this.recordEndResolve=null,this.recordEndReject=null):this.recordEndReject?(this.recordEndReject(new Error("Invalid or empty recording")),this.recordEndResolve=null,this.recordEndReject=null):(this.recordEndResolve=null,this.recordEndReject=null)}),this.recordPlugin.on("record-progress",e=>{this.events.onRecordProgress?.(e)}))}setEventHandlers(e){this.events=e}async startRecording(){if(!this.recordPlugin)throw new Error("Record plugin not initialized");if(this.isRecording)return;const e=typeof this.options.sampleRate=="number"?this.options.sampleRate:void 0,o={};e!==void 0&&(o.sampleRate={ideal:e}),await this.startRecordingWithConstraints(o,e!==void 0)}async startRecordingWithConstraints(e,o){if(!this.recordPlugin)throw new Error("Record plugin not initialized");try{const n=Object.keys(e).length?e:void 0;await this.recordPlugin.startRecording(n)}catch(n){const r=n instanceof Error?n:new Error(String(n));if(I(r))throw this.events.onPermissionDenied?.(),new Error("Microphone permission denied");if(o&&(r.name==="OverconstrainedError"||r.name==="NotReadableError")){this.options.sampleRate=void 0,await this.startRecordingWithConstraints({},!1);return}throw this.events.onError?.(r),r}}async stopRecording(){if(!this.recordPlugin||!this.isRecording)throw new Error("Not currently recording");try{return await new Promise((e,o)=>{this.recordEndResolve=e,this.recordEndReject=o,this.recordPlugin?.stopRecording()})}catch(e){const o=e instanceof Error?e:new Error(String(e));throw this.events.onError?.(o),o}}cancelRecording(){this.recordPlugin&&this.isRecording&&(this.recordPlugin.stopRecording(),this.isRecording=!1,this.recordEndResolve=null,this.recordEndReject=null)}destroy(){this.cancelRecording(),this.recordPlugin&&(this.recordPlugin.destroy(),this.recordPlugin=null),this.wavesurfer=null,this.events={}}}const X=4,Y=4,ee=8,re=0,te=16e3;function se({containerRef:l,sampleRate:e,events:o,waveformPadding:n=0}){const r=Z(),[d,s]=i.useState("idle"),[p,h]=i.useState(null),[m,c]=i.useState(!1),u=i.useRef(null),y=i.useRef(null),a=i.useRef(null),f=i.useRef(o),U=i.useRef(!1),D=i.useRef(!1),E=i.useRef(new Set),P=i.useRef(!1),b=e===void 0?te:e,A=i.useCallback(()=>{E.current.clear(),c(!1),y.current&&(y.current.destroy(),y.current=null),a.current&&(a.current.destroy(),a.current=null),u.current&&(u.current.destroy(),u.current=null),U.current=!1,P.current=!1,s("idle"),h(null)},[]),x=i.useCallback(()=>{const t=Array.from(E.current);E.current.clear(),t.forEach(w=>{w.resolve()})},[]),_=i.useCallback(t=>{c(!1);const w=Array.from(E.current);E.current.clear(),w.forEach(v=>{v.reject(t)})},[]),T=i.useCallback(t=>{const w={onPlay:()=>{c(!0),f.current.onPlaybackPlay?.()},onPause:()=>{c(!1),f.current.onPlaybackPause?.()},onFinish:()=>{c(!1),f.current.onPlaybackFinish?.()},onReady:()=>{x()},onError:v=>{c(!1),_(v),f.current.onError?.(v)}};t.setEventHandlers(w)},[x,_]);i.useEffect(()=>{f.current=o,a.current&&T(a.current)},[o,T]);const S=i.useCallback(async()=>{if(!(U.current||D.current||!l.current)){D.current=!0;try{const[t,w]=await Promise.all([M(()=>import("./wavesurfer.esm.D1Sty35j.js"),[],import.meta.url),M(()=>import("./record.DytFsBUt.js"),[],import.meta.url)]),v=t.default,B=w.default,k=v.create({container:l.current,waveColor:r.colors.primary,progressColor:r.colors.bodyText,height:n>0?$(r.sizes.largestElementHeight)-2*n:"auto",barWidth:X,barGap:Y,barRadius:ee,cursorWidth:re,interact:!0});u.current=k,P.current=!1;const C=new Q({sampleRate:b});C.initialize(k,B),C.setEventHandlers({onRecordProgress:R=>{f.current.onProgressMs?.(R)},onPermissionDenied:()=>{f.current.onPermissionDenied(),s("idle")},onError:R=>{f.current.onError(R),s("idle")}}),y.current=C;const g=new W;g.initialize(k),a.current=g,T(g),U.current=!0}catch(t){const w=t instanceof Error?t:new Error(String(t));f.current.onError?.(w)}finally{D.current=!1}}},[l,r,b,T,n]);i.useEffect(()=>(S(),()=>{A()}),[A,S]),i.useEffect(()=>{const t=u.current;if(t){if(d==="recording"){t.setOptions({waveColor:r.colors.primary,progressColor:r.colors.primary});return}if(P.current){t.setOptions({interact:!0,waveColor:O(r.colors.fadedText40,r.colors.secondaryBg),progressColor:r.colors.bodyText});return}t.setOptions({waveColor:r.colors.primary,progressColor:r.colors.bodyText})}},[d,r.colors.bodyText,r.colors.fadedText40,r.colors.primary,r.colors.secondaryBg]);const F=i.useCallback(async()=>{if(d!=="recording"){if(U.current||await S(),!y.current)throw new Error("Record backend not initialized");u.current&&u.current.setOptions({waveColor:r.colors.primary,progressColor:r.colors.primary}),P.current=!1,await y.current.startRecording(),s("recording"),h(null),c(!1),f.current.onRecordStart?.()}},[d,S,r.colors.primary]),L=i.useCallback(()=>{a.current&&u.current&&(a.current.destroy(),a.current=new W,a.current.initialize(u.current),E.current.clear(),c(!1),T(a.current)),P.current=!1},[T]),z=i.useCallback(()=>{a.current?.seekToStart(),c(!1),P.current=!0,u.current&&u.current.setOptions({interact:!0,waveColor:O(r.colors.fadedText40,r.colors.secondaryBg),progressColor:r.colors.bodyText})},[r.colors.bodyText,r.colors.fadedText40,r.colors.secondaryBg]),H=i.useCallback(async()=>{if(d!=="recording")throw new Error("Not currently recording");if(!y.current||!a.current)throw new Error("Backends not initialized");try{const t=await y.current.stopRecording();h(t),await new Promise((k,C)=>{if(!a.current){C(new Error("Player not initialized"));return}const g={resolve:()=>{E.current.delete(g),k()},reject:R=>{E.current.delete(g),C(R)}};E.current.add(g),a.current.load(t).catch(R=>{E.current.delete(g),C(R instanceof Error?R:new Error(String(R)))})}),s("idle"),c(!1),z();const v={durationMs:a.current?.getDuration()??0,sampleRate:typeof b=="number"?b:null,mimeType:t.type||"audio/webm",size:t.size},B={blob:t,meta:v};return f.current.onRecordReady?.(t),B}catch(t){const w=t instanceof Error?t:new Error(String(t));return c(!1),s("idle"),f.current.onError(w),{blob:new Blob,meta:{durationMs:0,sampleRate:null,mimeType:"audio/webm",size:0}}}},[d,z,b]),j=i.useCallback(async t=>{const w=t??p;if(!w){const v=new Error("No recorded audio to approve");f.current.onError(v);return}try{const v=await q(w,b);await f.current.onApprove?.(v),h(null),s("idle")}catch(v){const B=v instanceof Error?v:new Error(String(v));f.current.onError(B)}},[p,b]),N=i.useCallback(()=>{d==="recording"&&y.current?.cancelRecording(),L(),h(null),s("idle"),c(!1),P.current=!1,f.current.onCancel?.()},[d,L]),V=i.useMemo(()=>({isPlaying:()=>a.current?.getIsPlaying()??!1,play:async()=>{if(!a.current)throw new Error("Player not initialized");await a.current.play()},pause:()=>{a.current?.pause()},load:async t=>{if(U.current||await S(),!a.current)throw new Error("Player not initialized");await a.current.load(t),z()},getCurrentTimeMs:()=>a.current?.getCurrentTime()??0,getDurationMs:()=>a.current?.getDuration()??0}),[z,S]),G=i.useCallback(t=>{f.current=t},[]);return i.useEffect(()=>()=>{A()},[A]),{state:d,isPlaybackPlaying:m,mountRef:l,start:F,stop:H,approve:j,cancel:N,destroy:A,playback:V,setEventHandlers:G}}export{se as u};
1
+ import{l as Z,r as i,aR as M,ab as $,aS as O}from"./index.BRfGUOQ-.js";async function q(l,e=16e3){if(!l||l.size===0)throw new Error("Invalid or empty blob provided");if(!window.AudioContext)throw new Error("AudioContext not supported in this browser");const o=new AudioContext;try{const n=await l.arrayBuffer(),r=await o.decodeAudioData(n),d=e??r.sampleRate,s=await J(r,d);return K(s,d)}finally{o.close()}}async function J(l,e){const{duration:o,numberOfChannels:n,sampleRate:r}=l,d=Math.ceil(o*e);if(!window.OfflineAudioContext)throw new Error("OfflineAudioContext not supported");const s=new OfflineAudioContext(1,d,e),p=s.createBufferSource();if(p.buffer=l,n>1){const h=s.createChannelSplitter(n),m=s.createChannelMerger(1);p.connect(h);for(let c=0;c<n;c++){const u=s.createGain();u.gain.value=1/n,h.connect(u,c),u.connect(m,0,0)}m.connect(s.destination)}else p.connect(s.destination);p.start(0);try{return await s.startRendering()}catch(h){throw new Error(`Failed to resample audio from ${r}Hz to ${e}Hz: ${h instanceof Error?h.message:String(h)}`)}}function K(l,e){const n=l.length,r=n*2+44,d=new ArrayBuffer(r),s=new DataView(d),p=l.getChannelData(0),h=(c,u)=>{for(let y=0;y<u.length;y++)s.setUint8(c+y,u.charCodeAt(y))};h(0,"RIFF"),s.setUint32(4,r-8,!0),h(8,"WAVE"),h(12,"fmt "),s.setUint32(16,16,!0),s.setUint16(20,1,!0),s.setUint16(22,1,!0),s.setUint32(24,e,!0),s.setUint32(28,e*2,!0),s.setUint16(32,2,!0),s.setUint16(34,16,!0),h(36,"data"),s.setUint32(40,n*2,!0);let m=44;for(let c=0;c<n;c++){const u=Math.max(-1,Math.min(1,p[c]));s.setInt16(m,u*32767,!0),m+=2}return new Blob([d],{type:"audio/wav"})}class W{constructor(){this.wavesurfer=null,this.currentBlobUrl=null,this.events={},this.isPlaying=!1}initialize(e){this.wavesurfer=e,this.setupEventListeners()}setupEventListeners(){this.wavesurfer&&(this.teardownEventListeners(),this.handleTimeUpdate=e=>{this.events.onTimeUpdate?.(e*1e3)},this.handlePause=()=>{this.isPlaying=!1,this.events.onPause?.()},this.handlePlay=()=>{this.isPlaying=!0,this.events.onPlay?.()},this.handleFinish=()=>{this.isPlaying=!1,this.events.onFinish?.()},this.handleReady=()=>{this.events.onReady?.()},this.handleError=e=>{const o=e instanceof Error?e:new Error(String(e));this.events.onError?.(o)},this.wavesurfer.on("timeupdate",this.handleTimeUpdate),this.wavesurfer.on("pause",this.handlePause),this.wavesurfer.on("play",this.handlePlay),this.wavesurfer.on("finish",this.handleFinish),this.wavesurfer.on("ready",this.handleReady),this.wavesurfer.on("error",this.handleError))}setEventHandlers(e){this.events=e}async load(e){if(!this.wavesurfer)throw new Error("WaveSurfer not initialized");this.cleanupPreviousUrl();let o,n=null;try{if(e instanceof Blob)n=URL.createObjectURL(e),o=n;else if(e instanceof ArrayBuffer){const r=new Blob([e]);n=URL.createObjectURL(r),o=n}else o=e;this.currentBlobUrl=n,await this.wavesurfer.load(o)}catch(r){throw this.cleanupPreviousUrl(),r}}async play(){if(!this.wavesurfer)throw new Error("WaveSurfer not initialized");await this.wavesurfer.play()}pause(){this.wavesurfer&&this.wavesurfer.pause()}getDuration(){return this.wavesurfer?this.wavesurfer.getDuration()*1e3:0}getCurrentTime(){return this.wavesurfer?this.wavesurfer.getCurrentTime()*1e3:0}getIsPlaying(){return this.isPlaying}seekToStart(){this.wavesurfer&&this.wavesurfer.seekTo(0)}cleanupPreviousUrl(){this.currentBlobUrl&&(URL.revokeObjectURL(this.currentBlobUrl),this.currentBlobUrl=null)}destroy(){this.pause(),this.cleanupPreviousUrl(),this.wavesurfer&&(this.teardownEventListeners(),this.wavesurfer.empty(),this.wavesurfer=null),this.events={},this.isPlaying=!1,this.handleTimeUpdate=void 0,this.handlePause=void 0,this.handlePlay=void 0,this.handleFinish=void 0,this.handleReady=void 0,this.handleError=void 0}teardownEventListeners(){this.wavesurfer&&(this.handleTimeUpdate&&(this.wavesurfer.un("timeupdate",this.handleTimeUpdate),this.handleTimeUpdate=void 0),this.handlePause&&(this.wavesurfer.un("pause",this.handlePause),this.handlePause=void 0),this.handlePlay&&(this.wavesurfer.un("play",this.handlePlay),this.handlePlay=void 0),this.handleFinish&&(this.wavesurfer.un("finish",this.handleFinish),this.handleFinish=void 0),this.handleReady&&(this.wavesurfer.un("ready",this.handleReady),this.handleReady=void 0),this.handleError&&(this.wavesurfer.un("error",this.handleError),this.handleError=void 0))}}function I(l){return l.name==="NotAllowedError"||l.name==="PermissionDeniedError"||l.message?.toLowerCase().includes("permission denied")}class Q{constructor(e={}){this.wavesurfer=null,this.recordPlugin=null,this.isRecording=!1,this.recordEndResolve=null,this.recordEndReject=null,this.events={},this.options=e}initialize(e,o){this.wavesurfer=e;try{const n={renderRecordedAudio:!1,mimeType:"audio/webm"};this.recordPlugin=e.registerPlugin(o.create(n)),this.setupEventListeners()}catch(n){const r=n instanceof Error?n:new Error(String(n));throw I(r)?(this.events.onPermissionDenied?.(),new Error("Microphone permission denied")):(this.events.onError?.(r),r)}}setupEventListeners(){this.recordPlugin&&(this.recordPlugin.on("record-start",()=>{this.isRecording=!0,this.events.onRecordStart?.()}),this.recordPlugin.on("record-end",e=>{this.isRecording=!1,this.events.onRecordEnd?.(e),this.recordEndResolve&&e&&e.size>0?(this.recordEndResolve(e),this.recordEndResolve=null,this.recordEndReject=null):this.recordEndReject?(this.recordEndReject(new Error("Invalid or empty recording")),this.recordEndResolve=null,this.recordEndReject=null):(this.recordEndResolve=null,this.recordEndReject=null)}),this.recordPlugin.on("record-progress",e=>{this.events.onRecordProgress?.(e)}))}setEventHandlers(e){this.events=e}async startRecording(){if(!this.recordPlugin)throw new Error("Record plugin not initialized");if(this.isRecording)return;const e=typeof this.options.sampleRate=="number"?this.options.sampleRate:void 0,o={};e!==void 0&&(o.sampleRate={ideal:e}),await this.startRecordingWithConstraints(o,e!==void 0)}async startRecordingWithConstraints(e,o){if(!this.recordPlugin)throw new Error("Record plugin not initialized");try{const n=Object.keys(e).length?e:void 0;await this.recordPlugin.startRecording(n)}catch(n){const r=n instanceof Error?n:new Error(String(n));if(I(r))throw this.events.onPermissionDenied?.(),new Error("Microphone permission denied");if(o&&(r.name==="OverconstrainedError"||r.name==="NotReadableError")){this.options.sampleRate=void 0,await this.startRecordingWithConstraints({},!1);return}throw this.events.onError?.(r),r}}async stopRecording(){if(!this.recordPlugin||!this.isRecording)throw new Error("Not currently recording");try{return await new Promise((e,o)=>{this.recordEndResolve=e,this.recordEndReject=o,this.recordPlugin?.stopRecording()})}catch(e){const o=e instanceof Error?e:new Error(String(e));throw this.events.onError?.(o),o}}cancelRecording(){this.recordPlugin&&this.isRecording&&(this.recordPlugin.stopRecording(),this.isRecording=!1,this.recordEndResolve=null,this.recordEndReject=null)}destroy(){this.cancelRecording(),this.recordPlugin&&(this.recordPlugin.destroy(),this.recordPlugin=null),this.wavesurfer=null,this.events={}}}const X=4,Y=4,ee=8,re=0,te=16e3;function se({containerRef:l,sampleRate:e,events:o,waveformPadding:n=0}){const r=Z(),[d,s]=i.useState("idle"),[p,h]=i.useState(null),[m,c]=i.useState(!1),u=i.useRef(null),y=i.useRef(null),a=i.useRef(null),f=i.useRef(o),U=i.useRef(!1),D=i.useRef(!1),E=i.useRef(new Set),P=i.useRef(!1),b=e===void 0?te:e,A=i.useCallback(()=>{E.current.clear(),c(!1),y.current&&(y.current.destroy(),y.current=null),a.current&&(a.current.destroy(),a.current=null),u.current&&(u.current.destroy(),u.current=null),U.current=!1,P.current=!1,s("idle"),h(null)},[]),x=i.useCallback(()=>{const t=Array.from(E.current);E.current.clear(),t.forEach(w=>{w.resolve()})},[]),_=i.useCallback(t=>{c(!1);const w=Array.from(E.current);E.current.clear(),w.forEach(v=>{v.reject(t)})},[]),T=i.useCallback(t=>{const w={onPlay:()=>{c(!0),f.current.onPlaybackPlay?.()},onPause:()=>{c(!1),f.current.onPlaybackPause?.()},onFinish:()=>{c(!1),f.current.onPlaybackFinish?.()},onReady:()=>{x()},onError:v=>{c(!1),_(v),f.current.onError?.(v)}};t.setEventHandlers(w)},[x,_]);i.useEffect(()=>{f.current=o,a.current&&T(a.current)},[o,T]);const S=i.useCallback(async()=>{if(!(U.current||D.current||!l.current)){D.current=!0;try{const[t,w]=await Promise.all([M(()=>import("./wavesurfer.esm.D1Sty35j.js"),[],import.meta.url),M(()=>import("./record.DytFsBUt.js"),[],import.meta.url)]),v=t.default,B=w.default,k=v.create({container:l.current,waveColor:r.colors.primary,progressColor:r.colors.bodyText,height:n>0?$(r.sizes.largestElementHeight)-2*n:"auto",barWidth:X,barGap:Y,barRadius:ee,cursorWidth:re,interact:!0});u.current=k,P.current=!1;const C=new Q({sampleRate:b});C.initialize(k,B),C.setEventHandlers({onRecordProgress:R=>{f.current.onProgressMs?.(R)},onPermissionDenied:()=>{f.current.onPermissionDenied(),s("idle")},onError:R=>{f.current.onError(R),s("idle")}}),y.current=C;const g=new W;g.initialize(k),a.current=g,T(g),U.current=!0}catch(t){const w=t instanceof Error?t:new Error(String(t));f.current.onError?.(w)}finally{D.current=!1}}},[l,r,b,T,n]);i.useEffect(()=>(S(),()=>{A()}),[A,S]),i.useEffect(()=>{const t=u.current;if(t){if(d==="recording"){t.setOptions({waveColor:r.colors.primary,progressColor:r.colors.primary});return}if(P.current){t.setOptions({interact:!0,waveColor:O(r.colors.fadedText40,r.colors.secondaryBg),progressColor:r.colors.bodyText});return}t.setOptions({waveColor:r.colors.primary,progressColor:r.colors.bodyText})}},[d,r.colors.bodyText,r.colors.fadedText40,r.colors.primary,r.colors.secondaryBg]);const F=i.useCallback(async()=>{if(d!=="recording"){if(U.current||await S(),!y.current)throw new Error("Record backend not initialized");u.current&&u.current.setOptions({waveColor:r.colors.primary,progressColor:r.colors.primary}),P.current=!1,await y.current.startRecording(),s("recording"),h(null),c(!1),f.current.onRecordStart?.()}},[d,S,r.colors.primary]),L=i.useCallback(()=>{a.current&&u.current&&(a.current.destroy(),a.current=new W,a.current.initialize(u.current),E.current.clear(),c(!1),T(a.current)),P.current=!1},[T]),z=i.useCallback(()=>{a.current?.seekToStart(),c(!1),P.current=!0,u.current&&u.current.setOptions({interact:!0,waveColor:O(r.colors.fadedText40,r.colors.secondaryBg),progressColor:r.colors.bodyText})},[r.colors.bodyText,r.colors.fadedText40,r.colors.secondaryBg]),H=i.useCallback(async()=>{if(d!=="recording")throw new Error("Not currently recording");if(!y.current||!a.current)throw new Error("Backends not initialized");try{const t=await y.current.stopRecording();h(t),await new Promise((k,C)=>{if(!a.current){C(new Error("Player not initialized"));return}const g={resolve:()=>{E.current.delete(g),k()},reject:R=>{E.current.delete(g),C(R)}};E.current.add(g),a.current.load(t).catch(R=>{E.current.delete(g),C(R instanceof Error?R:new Error(String(R)))})}),s("idle"),c(!1),z();const v={durationMs:a.current?.getDuration()??0,sampleRate:typeof b=="number"?b:null,mimeType:t.type||"audio/webm",size:t.size},B={blob:t,meta:v};return f.current.onRecordReady?.(t),B}catch(t){const w=t instanceof Error?t:new Error(String(t));return c(!1),s("idle"),f.current.onError(w),{blob:new Blob,meta:{durationMs:0,sampleRate:null,mimeType:"audio/webm",size:0}}}},[d,z,b]),j=i.useCallback(async t=>{const w=t??p;if(!w){const v=new Error("No recorded audio to approve");f.current.onError(v);return}try{const v=await q(w,b);await f.current.onApprove?.(v),h(null),s("idle")}catch(v){const B=v instanceof Error?v:new Error(String(v));f.current.onError(B)}},[p,b]),N=i.useCallback(()=>{d==="recording"&&y.current?.cancelRecording(),L(),h(null),s("idle"),c(!1),P.current=!1,f.current.onCancel?.()},[d,L]),V=i.useMemo(()=>({isPlaying:()=>a.current?.getIsPlaying()??!1,play:async()=>{if(!a.current)throw new Error("Player not initialized");await a.current.play()},pause:()=>{a.current?.pause()},load:async t=>{if(U.current||await S(),!a.current)throw new Error("Player not initialized");await a.current.load(t),z()},getCurrentTimeMs:()=>a.current?.getCurrentTime()??0,getDurationMs:()=>a.current?.getDuration()??0}),[z,S]),G=i.useCallback(t=>{f.current=t},[]);return i.useEffect(()=>()=>{A()},[A]),{state:d,isPlaybackPlaying:m,mountRef:l,start:F,stop:H,approve:j,cancel:N,destroy:A,playback:V,setEventHandlers:G}}export{se as u};
@@ -1 +1 @@
1
- import{h as l,k as h,j as s,d as n}from"./index.01VsD2h1.js";const o=t=>{const a=e=>{const{width:i,elementRef:c}=h();return s(n,{ref:c,children:s(t,{...e,width:i})})};return a.displayName=`withCalculatedWidth(${t.displayName||t.name})`,l(a,t)};export{o as w};
1
+ import{h as l,k as h,j as s,d as n}from"./index.BRfGUOQ-.js";const o=t=>{const a=e=>{const{width:i,elementRef:c}=h();return s(n,{ref:c,children:s(t,{...e,width:i})})};return a.displayName=`withCalculatedWidth(${t.displayName||t.name})`,l(a,t)};export{o as w};
@@ -1 +1 @@
1
- import{r as n,F as f,b7 as p,b8 as h,l as x,k as y,j as i,h as g}from"./index.01VsD2h1.js";const m=n.createContext(null);m.displayName="ElementFullscreenContext";const w=f("div",{target:"e5bcvgj0"})(({theme:e,isExpanded:t})=>({width:"100%",height:"100%",...t?{position:"fixed",top:0,left:0,bottom:0,right:0,background:e.colors.bgColor,zIndex:e.zIndices.fullscreenWrapper,padding:e.spacing.md,paddingTop:e.sizes.fullScreenHeaderHeight,overflow:"auto",display:"flex",alignItems:"center",justifyContent:"center"}:{}})),C=()=>{const{setFullScreen:e}=n.useContext(p),[t,s]=n.useState(!1),{fullHeight:a,fullWidth:c}=h(),l=n.useCallback(r=>{s(r),e(r)},[e]),u=n.useCallback(()=>{document.body.style.overflow="hidden",l(!0)},[l]),o=n.useCallback(()=>{document.body.style.overflow="unset",l(!1)},[l]),d=n.useCallback(r=>{r.keyCode===27&&t&&o()},[o,t]);return n.useEffect(()=>(document.addEventListener("keydown",d,!1),()=>{document.removeEventListener("keydown",d,!1)}),[d]),n.useMemo(()=>({expanded:t,zoomIn:u,zoomOut:o,fullHeight:a,fullWidth:c}),[t,u,o,a,c])},F=({children:e})=>{const t=x(),{expanded:s,fullHeight:a,fullWidth:c,zoomIn:l,zoomOut:u}=C(),{width:o,elementRef:d}=y(),r=n.useMemo(()=>({width:s?c:o,height:s?a:void 0,expanded:s,expand:l,collapse:u}),[s,a,c,o,l,u]);return i(m.Provider,{value:r,children:i(w,{ref:d,isExpanded:s,"data-testid":"stFullScreenFrame",theme:t,children:e})})};function S(e){const t=s=>i(F,{children:i(e,{...s})});return t.displayName=`withFullScreenWrapper(${e.displayName||e.name})`,g(t,e)}export{m as E,S as w};
1
+ import{r as n,F as f,b7 as p,b8 as h,l as x,k as y,j as i,h as g}from"./index.BRfGUOQ-.js";const m=n.createContext(null);m.displayName="ElementFullscreenContext";const w=f("div",{target:"e5bcvgj0"})(({theme:e,isExpanded:t})=>({width:"100%",height:"100%",...t?{position:"fixed",top:0,left:0,bottom:0,right:0,background:e.colors.bgColor,zIndex:e.zIndices.fullscreenWrapper,padding:e.spacing.md,paddingTop:e.sizes.fullScreenHeaderHeight,overflow:"auto",display:"flex",alignItems:"center",justifyContent:"center"}:{}})),C=()=>{const{setFullScreen:e}=n.useContext(p),[t,s]=n.useState(!1),{fullHeight:a,fullWidth:c}=h(),l=n.useCallback(r=>{s(r),e(r)},[e]),u=n.useCallback(()=>{document.body.style.overflow="hidden",l(!0)},[l]),o=n.useCallback(()=>{document.body.style.overflow="unset",l(!1)},[l]),d=n.useCallback(r=>{r.keyCode===27&&t&&o()},[o,t]);return n.useEffect(()=>(document.addEventListener("keydown",d,!1),()=>{document.removeEventListener("keydown",d,!1)}),[d]),n.useMemo(()=>({expanded:t,zoomIn:u,zoomOut:o,fullHeight:a,fullWidth:c}),[t,u,o,a,c])},F=({children:e})=>{const t=x(),{expanded:s,fullHeight:a,fullWidth:c,zoomIn:l,zoomOut:u}=C(),{width:o,elementRef:d}=y(),r=n.useMemo(()=>({width:s?c:o,height:s?a:void 0,expanded:s,expand:l,collapse:u}),[s,a,c,o,l,u]);return i(m.Provider,{value:r,children:i(w,{ref:d,isExpanded:s,"data-testid":"stFullScreenFrame",theme:t,children:e})})};function S(e){const t=s=>i(F,{children:i(e,{...s})});return t.displayName=`withFullScreenWrapper(${e.displayName||e.name})`,g(t,e)}export{m as E,S as w};
@@ -218,7 +218,7 @@ class AppTest:
218
218
 
219
219
  path = Path(TMP_DIR.name, script_name)
220
220
  aligned_script = textwrap.dedent(script)
221
- path.write_text(aligned_script)
221
+ path.write_text(aligned_script, encoding="utf-8")
222
222
  return AppTest(
223
223
  str(path), default_timeout=default_timeout, args=args, kwargs=kwargs
224
224
  )
streamlit/user_info.py CHANGED
@@ -301,8 +301,9 @@ def logout() -> None:
301
301
  """Logout the current user.
302
302
 
303
303
  This command removes the user's information from ``st.user``,
304
- deletes their identity cookie, and redirects them back to your app's home
305
- page. This creates a new session.
304
+ deletes their identity cookie, and redirects them to perform a proper
305
+ logout from the OAuth provider (if available) before returning to your
306
+ app's home page. This creates a new session.
306
307
 
307
308
  If the user has multiple sessions open in the same browser,
308
309
  ``st.user`` will not be cleared in any other session.
@@ -311,8 +312,9 @@ def logout() -> None:
311
312
  ``st.logout()`` within that session to update ``st.user``.
312
313
 
313
314
  .. Note::
314
- This does not log the user out of their underlying account from the
315
- identity provider.
315
+ If the OAuth provider supports OIDC end_session_endpoint in their
316
+ server metadata, the user will be logged out from the identity provider
317
+ as well. If not available, only local logout is performed.
316
318
 
317
319
  Example
318
320
  -------
@@ -247,9 +247,9 @@ class BrowserWebSocketHandler(WebSocketHandler, SessionClient):
247
247
  # See the NOTE in the docstring of the `select_subprotocol` method above
248
248
  # for a detailed explanation of why this is done.
249
249
  existing_session_id = ws_protocols[2]
250
- except KeyError:
250
+ except (KeyError, json.JSONDecodeError):
251
251
  # Just let existing_session_id=None if we run into any error while trying to
252
- # extract it from the Sec-Websocket-Protocol header.
252
+ # extract it from the Sec-Websocket-Protocol header or parsing cookie JSON.
253
253
  pass
254
254
 
255
255
  # Map in any user-configured headers. Note that these override anything coming
@@ -13,8 +13,9 @@
13
13
  # limitations under the License.
14
14
  from __future__ import annotations
15
15
 
16
+ import json
16
17
  from typing import Any, Final, cast
17
- from urllib.parse import urlparse
18
+ from urllib.parse import urlencode, urlparse
18
19
 
19
20
  import tornado.web
20
21
 
@@ -23,6 +24,8 @@ from streamlit.auth_util import (
23
24
  clear_cookie_and_chunks,
24
25
  decode_provider_token,
25
26
  generate_default_provider_section,
27
+ get_cookie_with_chunks,
28
+ get_redirect_uri,
26
29
  get_secrets_auth_section,
27
30
  set_cookie_with_chunks,
28
31
  )
@@ -41,7 +44,7 @@ def create_oauth_client(provider: str) -> tuple[TornadoOAuth2App, str]:
41
44
  """Create an OAuth client for the given provider based on secrets.toml configuration."""
42
45
  auth_section = get_secrets_auth_section()
43
46
  if auth_section:
44
- redirect_uri = auth_section.get("redirect_uri", None)
47
+ redirect_uri = get_redirect_uri(auth_section) or "/"
45
48
  config = auth_section.to_dict()
46
49
  else:
47
50
  config = {}
@@ -169,16 +172,99 @@ class AuthLoginHandler(AuthHandlerMixin, tornado.web.RequestHandler):
169
172
  class AuthLogoutHandler(AuthHandlerMixin, tornado.web.RequestHandler):
170
173
  def get(self) -> None:
171
174
  self.clear_auth_cookie()
172
- self.redirect_to_base()
175
+
176
+ provider_logout_url = self._get_provider_logout_url()
177
+ if provider_logout_url:
178
+ self.redirect(provider_logout_url)
179
+ else:
180
+ self.redirect_to_base()
181
+
182
+ def _get_redirect_uri(self) -> str | None:
183
+ auth_section = get_secrets_auth_section()
184
+ if not auth_section:
185
+ return None
186
+
187
+ redirect_uri = get_redirect_uri(auth_section)
188
+ if not redirect_uri:
189
+ return None
190
+
191
+ if not redirect_uri.endswith("/oauth2callback"):
192
+ _LOGGER.warning("Redirect URI does not end with /oauth2callback")
193
+ return None
194
+
195
+ return redirect_uri
196
+
197
+ def _get_provider_logout_url(self) -> str | None:
198
+ """Get the OAuth provider's logout URL from OIDC metadata."""
199
+ cookie_value = get_cookie_with_chunks(self._get_signed_cookie, AUTH_COOKIE_NAME)
200
+
201
+ if not cookie_value:
202
+ return None
203
+
204
+ try:
205
+ user_info = json.loads(cookie_value)
206
+ provider = user_info.get("provider")
207
+ if not provider:
208
+ return None
209
+
210
+ client, _ = create_oauth_client(provider)
211
+
212
+ metadata = client.load_server_metadata()
213
+ end_session_endpoint = metadata.get("end_session_endpoint")
214
+
215
+ if not end_session_endpoint:
216
+ _LOGGER.info("No end_session_endpoint found for provider %s", provider)
217
+ return None
218
+
219
+ # Use redirect_uri (i.e. /oauth2callback) for post_logout_redirect_uri
220
+ # This is safer than redirecting to root as some providers seem to
221
+ # require url to be in a whitelist /oauth2callback should be whitelisted
222
+ redirect_uri = self._get_redirect_uri()
223
+ if redirect_uri is None:
224
+ _LOGGER.info("Redirect url could not be determined")
225
+ return None
226
+
227
+ logout_params = {
228
+ "client_id": client.client_id,
229
+ "post_logout_redirect_uri": redirect_uri,
230
+ }
231
+
232
+ # Add id_token_hint to logout params if it is available
233
+ tokens_cookie_value = get_cookie_with_chunks(
234
+ self._get_signed_cookie, TOKENS_COOKIE_NAME
235
+ )
236
+ if tokens_cookie_value:
237
+ try:
238
+ tokens = json.loads(tokens_cookie_value)
239
+ id_token = tokens.get("id_token")
240
+ if id_token:
241
+ logout_params["id_token_hint"] = id_token
242
+ except (json.JSONDecodeError, TypeError):
243
+ _LOGGER.exception(
244
+ "Error, invalid tokens cookie value.",
245
+ )
246
+ return None
247
+
248
+ return f"{end_session_endpoint}?{urlencode(logout_params)}"
249
+
250
+ except Exception as e:
251
+ _LOGGER.warning("Failed to get provider logout URL: %s", e)
252
+ return None
173
253
 
174
254
 
175
255
  class AuthCallbackHandler(AuthHandlerMixin, tornado.web.RequestHandler):
176
256
  async def get(self) -> None:
177
257
  provider = self._get_provider_by_state()
258
+ if provider is None:
259
+ # This could be a logout redirect (no state parameter) or invalid state
260
+ # In both cases, redirect to base
261
+ self.redirect_to_base()
262
+ return
263
+
178
264
  origin = self._get_origin_from_secrets()
179
265
  if origin is None:
180
266
  _LOGGER.error(
181
- "Error, misconfigured origin for `redirect_uri` in secrets. ",
267
+ "Error, misconfigured origin for `redirect_uri` in secrets.",
182
268
  )
183
269
  self.redirect_to_base()
184
270
  return
@@ -200,34 +286,25 @@ class AuthCallbackHandler(AuthHandlerMixin, tornado.web.RequestHandler):
200
286
  self.redirect_to_base()
201
287
  return
202
288
 
203
- if provider is None:
204
- # See https://github.com/streamlit/streamlit/issues/13101
205
- _LOGGER.warning(
206
- "Missing provider for OAuth callback; this often indicates a stale "
207
- "or replayed callback (for example, from browser back/forward "
208
- "navigation).",
209
- )
210
- self.redirect_to_base()
211
- return
212
-
213
289
  client, _ = create_oauth_client(provider)
214
290
  token = client.authorize_access_token(self)
215
291
  user = cast("dict[str, Any]", token.get("userinfo"))
216
292
 
217
- cookie_value = dict(user, origin=origin, is_logged_in=True)
293
+ cookie_value = dict(user, origin=origin, is_logged_in=True, provider=provider)
218
294
  tokens = {k: token[k] for k in ["id_token", "access_token"] if k in token}
219
295
 
220
296
  if user:
221
297
  self.set_auth_cookie(cookie_value, tokens)
222
298
  # Keep tokens in a separate cookie to avoid hitting the size limit
223
299
  else:
224
- _LOGGER.error(
225
- "Error, missing user info.",
226
- )
300
+ _LOGGER.error("Error, missing user info.")
227
301
  self.redirect_to_base()
228
302
 
229
303
  def _get_provider_by_state(self) -> str | None:
230
- state_code_from_url = self.get_argument("state")
304
+ state_code_from_url = self.get_argument("state", None)
305
+ if state_code_from_url is None:
306
+ return None
307
+
231
308
  current_cache_keys = list(auth_cache.get_dict().keys())
232
309
  state_provider_mapping = {}
233
310
  for key in current_cache_keys:
@@ -253,7 +330,7 @@ class AuthCallbackHandler(AuthHandlerMixin, tornado.web.RequestHandler):
253
330
  redirect_uri = None
254
331
  auth_section = get_secrets_auth_section()
255
332
  if auth_section:
256
- redirect_uri = auth_section.get("redirect_uri", None)
333
+ redirect_uri = get_redirect_uri(auth_section)
257
334
 
258
335
  if not redirect_uri:
259
336
  return None
@@ -341,9 +341,7 @@ def create_metrics_routes(runtime: Runtime, base_url: str | None) -> list[BaseRo
341
341
 
342
342
  async def _metrics_endpoint(request: Request) -> Response:
343
343
  requested_families = request.query_params.getlist("families")
344
- stats = runtime.stats_mgr.get_stats(
345
- family_names=requested_families if requested_families else None
346
- )
344
+ stats = runtime.stats_mgr.get_stats(family_names=requested_families or None)
347
345
  accept = request.headers.get("Accept", "")
348
346
  if "application/x-protobuf" in accept:
349
347
  payload = StatsRequestHandler._stats_to_proto(stats).SerializeToString()
@@ -52,9 +52,7 @@ class StatsRequestHandler(tornado.web.RequestHandler):
52
52
  # If no families are specified, all metrics are returned.
53
53
  # Example: /_stcore/metrics?families=session_events_total&families=active_sessions
54
54
  requested_families = self.get_arguments("families")
55
- stats = self._manager.get_stats(
56
- family_names=requested_families if requested_families else None
57
- )
55
+ stats = self._manager.get_stats(family_names=requested_families or None)
58
56
  # If the request asked for protobuf output, we return a serialized
59
57
  # protobuf. Else we return text.
60
58
  if "application/x-protobuf" in self.request.headers.get_list("Accept"):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: streamlit-nightly
3
- Version: 1.52.3.dev20260111
3
+ Version: 1.52.3.dev20260113
4
4
  Summary: A faster way to build and share data apps
5
5
  Home-page: https://streamlit.io
6
6
  Author: Snowflake Inc