@marimo-team/frontend 0.25.3-dev80 → 0.25.3-dev82
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.
- package/dist/assets/{CellStatus-cD3S0wEA.js → CellStatus-DXroYLOP.js} +1 -1
- package/dist/assets/{ErrorBoundary-DJhsFCsX.js → ErrorBoundary-DaQ9THH_.js} +2 -2
- package/dist/assets/{JsonOutput-Pm6OCP3J.js → JsonOutput-VxzHyItt.js} +1 -1
- package/dist/assets/{MarimoErrorOutput-DlEjLCZ-.js → MarimoErrorOutput-D-hLaDA-.js} +1 -1
- package/dist/assets/{RenderHTML-CfQ6i3QV.js → RenderHTML-DjOEZL25.js} +1 -1
- package/dist/assets/{RunButton-DvuvkgrG.js → RunButton-CuhNTo5_.js} +1 -1
- package/dist/assets/{add-cell-with-ai-By51zSlC.js → add-cell-with-ai-BbVntTh7.js} +1 -1
- package/dist/assets/{add-connection-dialog-D7EYSraq.js → add-connection-dialog-Qf63aKV6.js} +1 -1
- package/dist/assets/{agent-panel-aCWa3Yai.js → agent-panel-DMOfF3qF.js} +1 -1
- package/dist/assets/{ai-model-dropdown-bwTRyFn4.js → ai-model-dropdown-B15l0R62.js} +2 -2
- package/dist/assets/{app-config-button-DGhsM0xw.js → app-config-button-BIMB8qjD.js} +1 -1
- package/dist/assets/{blob-e6VlOmQP.js → blob-De9GR2s6.js} +1 -1
- package/dist/assets/{cell-editor-M8dEnDzk.js → cell-editor-Di0cSFhC.js} +32 -11
- package/dist/assets/{cell-link-DFqfW-Ym.js → cell-link-DR3W2HC7.js} +1 -1
- package/dist/assets/{cells-T9_Y4Jlv.js → cells-styV7IX8.js} +6 -6
- package/dist/assets/{chat-display-DXn2Yrjr.js → chat-display-BzdYdN39.js} +1 -1
- package/dist/assets/{chat-panel-D3iUyZId.js → chat-panel-De3YzkSF.js} +1 -1
- package/dist/assets/{chat-ui-YuJtv3UJ.js → chat-ui-NTNapdtP.js} +1 -1
- package/dist/assets/{code-visibility-CV3S4xuf.js → code-visibility-csc3tgA0.js} +1 -1
- package/dist/assets/{column-preview-C6uXRJry.js → column-preview-DkH-oD8f.js} +1 -1
- package/dist/assets/{command-palette-CGNUQdgW.js → command-palette-Dg_xstl0.js} +1 -1
- package/dist/assets/{common-DeeLgjWQ.js → common-D7VAS6rd.js} +1 -1
- package/dist/assets/{components-DyAF3_Nf.js → components-CNmvC781.js} +1 -1
- package/dist/assets/config-BQT0uYUo.js +1 -0
- package/dist/assets/{config-CjQ4WJnJ.js → config-BbRbT9Ww.js} +1 -1
- package/dist/assets/{datasource-gqFgG9Qd.js → datasource-C3yfeDa2.js} +1 -1
- package/dist/assets/{dependency-graph-panel-B3T9kSTs.js → dependency-graph-panel-CjoA6L0w.js} +1 -1
- package/dist/assets/{documentation-panel-BBpGbT-f.js → documentation-panel-DHWFOiG1.js} +1 -1
- package/dist/assets/{download-C8Gw-D0Y.js → download-BrCpRZKN.js} +1 -1
- package/dist/assets/{edit-page-CBftLPze.js → edit-page-BPMo_x-T.js} +4 -4
- package/dist/assets/{error-entries-uyqOG5tg.js → error-entries-BkEAmmnD.js} +1 -1
- package/dist/assets/{error-panel-Cli5zPWi.js → error-panel-BhTfPA_i.js} +1 -1
- package/dist/assets/feedback-button-BAcClv7c.js +1 -0
- package/dist/assets/{feedback-button-CvrwBGr7.js → feedback-button-D9InK87G.js} +1 -1
- package/dist/assets/{file-explorer-panel-BSU5ultY.js → file-explorer-panel-BSd_ZbUC.js} +1 -1
- package/dist/assets/{file-name-input-CDrRlIiX.js → file-name-input-RHURglL_.js} +1 -1
- package/dist/assets/{floating-outline-GQD9km0W.js → floating-outline-Cm49rYYe.js} +1 -1
- package/dist/assets/{gallery-page-B-5H1fEt.js → gallery-page-DdMdOtdv.js} +1 -1
- package/dist/assets/{glide-data-editor-B1kpoetH.js → glide-data-editor-eiSlEUyR.js} +1 -1
- package/dist/assets/{home-page-3qsPTb4v.js → home-page-DwWvBB0R.js} +1 -1
- package/dist/assets/{hooks-BrFYiTJS.js → hooks-CHeUZHPp.js} +1 -1
- package/dist/assets/{index-D0IWODMU.js → index-DckSn2w6.js} +8 -8
- package/dist/assets/{layout-CGC8ajpe.js → layout-_lp06T0C.js} +3 -3
- package/dist/assets/{logs-panel-CdUc5vtA.js → logs-panel-CAAk72Gb.js} +1 -1
- package/dist/assets/{markdown-renderer-pKc_bFac.js → markdown-renderer-CAyCgogC.js} +1 -1
- package/dist/assets/{name-cell-input-csH3Cy54.js → name-cell-input-DA8hU9XT.js} +1 -1
- package/dist/assets/{outline-panel-DhsHYTuo.js → outline-panel-Cc5oQ4LL.js} +1 -1
- package/dist/assets/{packages-panel-BtkXVz3L.js → packages-panel-DTfKez6I.js} +1 -1
- package/dist/assets/{panel-accordion-state-Bco6nsUI.js → panel-accordion-state-BZHex38W.js} +1 -1
- package/dist/assets/panels-DU-SaRHy.js +105 -0
- package/dist/assets/{process-output-B2-bT4cq.js → process-output-CrDc_O1D.js} +1 -1
- package/dist/assets/{readonly-code-display-Dsp6vWPh.js → readonly-code-display-BR-_jUj8.js} +1 -1
- package/dist/assets/{readonly-python-code-B81AjzXM.js → readonly-python-code-D7jcy9ds.js} +1 -1
- package/dist/assets/{reveal-component-Cxo3hLGA.js → reveal-component-eLftBwOe.js} +1 -1
- package/dist/assets/{run-page-CLP1s8uX.js → run-page-mURyATDJ.js} +1 -1
- package/dist/assets/{runtime-details-state-CznIe40L.js → runtime-details-state-hb7A1jgR.js} +1 -1
- package/dist/assets/{scratchpad-panel-yHIW63VQ.js → scratchpad-panel-B_gEnoqj.js} +1 -1
- package/dist/assets/{session-panel-C7-wmZhc.js → session-panel-DmDjaPsN.js} +1 -1
- package/dist/assets/{snippets-panel-BARpOPyS.js → snippets-panel-o9KL5jMi.js} +1 -1
- package/dist/assets/state-BkAqJoW7.js +3 -0
- package/dist/assets/{state-Bye6rCo4.js → state-Os7LSUUZ.js} +1 -1
- package/dist/assets/{terminal-Bhcn_y1N.js → terminal-BI85khrS.js} +1 -1
- package/dist/assets/{tracing-DDohxo24.js → tracing-AsNGuDsh.js} +1 -1
- package/dist/assets/{tracing-panel-DYhGDAo5.js → tracing-panel-CBcmea6L.js} +2 -2
- package/dist/assets/{tree-actions-Cb-nUK1F.js → tree-actions-Cx5EDpA6.js} +1 -1
- package/dist/assets/{useAddCell-Bielffe0.js → useAddCell-uJJYtgwa.js} +1 -1
- package/dist/assets/{useBoolean-CMgj9hnq.js → useBoolean-8wlrTeus.js} +1 -1
- package/dist/assets/{useCellActionButton-DAcQhse_.js → useCellActionButton-CmQ-OcPa.js} +1 -1
- package/dist/assets/{useDeleteCell-BV4VemCv.js → useDeleteCell-CXgOCDqY.js} +1 -1
- package/dist/assets/{useDependencyPanelTab-PtXIVh53.js → useDependencyPanelTab-Ch6gm7uM.js} +1 -1
- package/dist/assets/{useInstallPackage-C7neMPwh.js → useInstallPackage-CYQoMdMQ.js} +1 -1
- package/dist/assets/{useNotebookActions-DZBB98fP.js → useNotebookActions-DGShHZ_1.js} +1 -1
- package/dist/assets/{useRunCells-BFeZMi7f.js → useRunCells-DAfDmOMC.js} +1 -1
- package/dist/assets/{useSplitCell-DllkNFke.js → useSplitCell-NLULgcq7.js} +1 -1
- package/dist/assets/{vega-component-D7JFthDD.js → vega-component-BKJU3uaB.js} +1 -1
- package/dist/index.html +24 -24
- package/package.json +1 -1
- package/src/core/host/AGENTS.md +6 -5
- package/src/core/host/__tests__/notebook-client.test.ts +368 -350
- package/src/core/host/connection.ts +1 -40
- package/src/core/host/notebook-client.ts +129 -186
- package/src/core/wasm/bridge.ts +0 -8
- package/src/core/websocket/__tests__/connection-state.test.ts +0 -12
- package/src/core/websocket/__tests__/useNotebookClient.hook.test.tsx +133 -59
- package/src/core/websocket/__tests__/useNotebookSession.hook.test.tsx +152 -250
- package/src/core/websocket/connection-state.ts +0 -10
- package/src/core/websocket/transports/__tests__/notebook.test.ts +502 -0
- package/src/core/websocket/transports/notebook.ts +213 -0
- package/src/core/websocket/useNotebookClient.ts +28 -17
- package/dist/assets/config-DzdxZb17.js +0 -1
- package/dist/assets/feedback-button-DknbRCN_.js +0 -1
- package/dist/assets/panels-D1i80TGn.js +0 -107
- package/dist/assets/state-BRYi026f.js +0 -3
- package/dist/assets/ws-BXWY541V.js +0 -22
- package/src/core/host/__tests__/events.test.ts +0 -49
- package/src/core/host/events.ts +0 -68
- package/src/core/websocket/__tests__/createConnectionTransport.test.ts +0 -49
- package/src/core/websocket/transports/__tests__/basic.test.ts +0 -275
- package/src/core/websocket/transports/__tests__/sse.test.ts +0 -352
- package/src/core/websocket/transports/__tests__/transport.test.ts +0 -308
- package/src/core/websocket/transports/__tests__/ws.test.ts +0 -125
- package/src/core/websocket/transports/basic.ts +0 -102
- package/src/core/websocket/transports/create.ts +0 -31
- package/src/core/websocket/transports/sse.ts +0 -320
- package/src/core/websocket/transports/transport.ts +0 -50
- package/src/core/websocket/transports/ws.ts +0 -98
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import{r as e}from"./useEvent-Dfcbgjhg.js";import{$n as t,La as n,Pa as r,Qn as i,_o as a,oi as o,vo as s,x as c,za as l}from"./cells-T9_Y4Jlv.js";import{t as u}from"./get-DjNf4SIX.js";import{t as d}from"./debounce-aFmHgJZY.js";import{E as f}from"./config-DGX7JYor.js";import{t as p}from"./_baseSet-Bpdo9AvU.js";import{g as m,v as h}from"./useEventListener-CjDeLqFC.js";import{t as g}from"./invariant-Ci2dTZ72.js";import{s as _}from"./config-CjQ4WJnJ.js";import{d as v,v as y}from"./session-B8Y-GJnS.js";import{N as ee,O as b,c as x,l as S,n as te}from"./config-DzdxZb17.js";import{c as ne,o as C}from"./state-DaWgt-rn.js";import{c as w,o as re}from"./markdown-renderer-pKc_bFac.js";import{w as ie}from"./write-secret-modal-7DzehGyr.js";import{t as ae}from"./use-toast-Wu434mLr.js";import{t as oe}from"./preload-helper-uBIymjUX.js";import{r as se}from"./strings-C25fhMR_.js";import{t as T}from"./requests-lt0JK8Jt.js";import{t as ce}from"./Deferred-CrTnjj37.js";import{t as le}from"./uuid-k9DpjH68.js";import{n as ue}from"./RenderHTML-CfQ6i3QV.js";import{t as de}from"./useRunCells-BFeZMi7f.js";import{r as fe,t as pe}from"./blob-e6VlOmQP.js";import{f as me}from"./useInstallPackage-C7neMPwh.js";import{n as he,t as ge}from"./share-BZW3tzEX.js";import{i as E,r as _e,t as ve}from"./events-CbeVJ6OD.js";function D(e,t,n){return e==null?e:p(e,t,n)}function O(e,t){if(e.origin===globalThis.origin)return new Worker(e.href,{...t,type:`module`});let n=`import ${JSON.stringify(e.href)}`,r=globalThis.origin===`null`?`data:application/javascript,${encodeURIComponent(n)}`:URL.createObjectURL(new Blob([n],{type:`application/javascript`}));try{return new Worker(r,{...t,type:`module`})}finally{r.startsWith(`blob:`)&&URL.revokeObjectURL(r)}}function k(e){return e.assetUrl,e}var A=class{subscriptions=new Map;addSubscription(e,t){this.subscriptions.has(e)||this.subscriptions.set(e,new Set),this.subscriptions.get(e)?.add(t)}removeSubscription(e,t){this.subscriptions.get(e)?.delete(t)}notify(e,t){for(let n of this.subscriptions.get(e)??[])n(t)}},j=class e{subscriptions=new A;producer;static withProducerCallback(t){return new e(t)}static empty(){return new e}constructor(e){this.producer=e}startProducer(){this.producer&&this.producer(e=>{this.subscriptions.notify(`message`,e)})}connect(){return new Promise(e=>setTimeout(e,0)).then(()=>{this.subscriptions.notify(`open`,new Event(`open`))})}get readyState(){return WebSocket.OPEN}reconnect(e,t){this.close(),this.connect()}close(){this.subscriptions.notify(`close`,new Event(`close`))}send(e){return this.subscriptions.notify(`message`,new MessageEvent(`message`,{data:e})),Promise.resolve()}addEventListener(e,t){this.subscriptions.addSubscription(e,t),e===`open`&&t(new Event(`open`)),e===`message`&&this.startProducer()}removeEventListener(e,t){this.subscriptions.removeSubscription(e,t)}},ye=1e10,be=1e3;function M(e,t){let n=e.map(e=>`"${e}"`).join(`, `);return Error(`This RPC instance cannot ${t} because the transport did not provide one or more of these methods: ${n}`)}function xe(e={}){let t={};function n(e){t=e}let r={};function i(e){r.unregisterHandler&&r.unregisterHandler(),r=e,r.registerHandler?.(x)}let a;function o(e){if(typeof e==`function`){a=e;return}a=(t,n)=>{let r=e[t];if(r)return r(n);let i=e._;if(!i)throw Error(`The requested method has no handler: ${t}`);return i(t,n)}}let{maxRequestTime:s=be}=e;e.transport&&i(e.transport),e.requestHandler&&o(e.requestHandler),e._debugHooks&&n(e._debugHooks);let c=0;function l(){return c<=ye?++c:c=0}let u=new Map,d=new Map;function f(e,...n){let i=n[0];return new Promise((n,a)=>{if(!r.send)throw M([`send`],`make requests`);let o=l(),c={type:`request`,id:o,method:e,params:i};u.set(o,{resolve:n,reject:a}),s!==1/0&&d.set(o,setTimeout(()=>{d.delete(o),a(Error(`RPC request timed out.`))},s)),t.onSend?.(c),r.send(c)})}let p=new Proxy(f,{get:(e,t,n)=>t in e?Reflect.get(e,t,n):e=>f(t,e)}),m=p;function h(e,...n){let i=n[0];if(!r.send)throw M([`send`],`send messages`);let a={type:`message`,id:e,payload:i};t.onSend?.(a),r.send(a)}let g=new Proxy(h,{get:(e,t,n)=>t in e?Reflect.get(e,t,n):e=>h(t,e)}),_=g,v=new Map,y=new Set;function ee(e,t){if(!r.registerHandler)throw M([`registerHandler`],`register message listeners`);if(e===`*`){y.add(t);return}v.has(e)||v.set(e,new Set),v.get(e)?.add(t)}function b(e,t){if(e===`*`){y.delete(t);return}v.get(e)?.delete(t),v.get(e)?.size===0&&v.delete(e)}async function x(e){if(t.onReceive?.(e),!(`type`in e))throw Error(`Message does not contain a type.`);if(e.type===`request`){if(!r.send||!a)throw M([`send`,`requestHandler`],`handle requests`);let{id:n,method:i,params:o}=e,s;try{s={type:`response`,id:n,success:!0,payload:await a(i,o)}}catch(e){if(!(e instanceof Error))throw e;s={type:`response`,id:n,success:!1,error:e.message}}t.onSend?.(s),r.send(s);return}if(e.type===`response`){let t=d.get(e.id);t!=null&&clearTimeout(t);let{resolve:n,reject:r}=u.get(e.id)??{};e.success?n?.(e.payload):r?.(Error(e.error));return}if(e.type===`message`){for(let t of y)t(e.id,e.payload);let t=v.get(e.id);if(!t)return;for(let n of t)n(e.payload);return}throw Error(`Unexpected RPC message type: ${e.type}`)}return{setTransport:i,setRequestHandler:o,request:p,requestProxy:m,send:g,sendProxy:_,addMessageListener:ee,removeMessageListener:b,proxy:{send:_,request:m},_setDebugHooks:n}}function Se(e){return xe(e)}var N=`[transport-id]`;function Ce(e,t){let{transportId:n}=t;return n==null?e:{[N]:n,data:e}}function we(e,t){let{transportId:n,filter:r}=t,i=r?.();if(n!=null&&i!=null)throw Error("Cannot use both `transportId` and `filter` at the same time");let a=e;if(n){if(e[N]!==n)return[!0];a=e.data}return i===!1?[!0]:[!1,a]}function Te(e,t={}){let{transportId:n,filter:r,remotePort:i}=t,a=e,o=i??e,s;return{send(e){o.postMessage(Ce(e,{transportId:n}))},registerHandler(e){s=t=>{let i=t.data,[a,o]=we(i,{transportId:n,filter:()=>r?.(t)});a||e(o)},a.addEventListener(`message`,s)},unregisterHandler(){s&&a.removeEventListener(`message`,s)}}}function Ee(e,t){return Te(e,t)}var De=`::controller`,Oe=`marimo-transport`;function P(e){return Se({transport:Ee(e,{transportId:Oe}),maxRequestTime:2e4,_debugHooks:{onSend:e=>{m.debug(`[rpc] Parent -> Worker`,e)},onReceive:e=>{m.debug(`[rpc] Worker -> Parent`,e)}}})}function F(){let e=document.querySelector(`marimo-wasm`),t=e=>{try{return e?new URL(e,document.baseURI).href:void 0}catch{return}};return{version:ne(),pyodideIndexUrl:t(e?.dataset.pyodideIndexUrl),pyodideLockfileUrl:t(e?.dataset.pyodideLockfileUrl),pypiIndexUrl:t(e?.dataset.pypiIndexUrl)?.replaceAll(`%7Bpackage_name%7D`,`{package_name}`)}}var I=he(),L=`marimo:file`,R=new r(null),ke={saveFile(e){R.set(L,e)},readFile(){return R.get(L)}},Ae={saveFile(e){s.setCodeForHash((0,I.compressToEncodedURIComponent)(e))},readFile(){let e=s.getCodeFromHash()||s.getCodeFromSearchParam();return e?(0,I.decompressFromEncodedURIComponent)(e):null}},je={saveFile(e){},readFile(){let e=document.querySelector(`marimo-code`);return e?decodeURIComponent(e.textContent||``).trim():null}},Me={saveFile(e){},readFile(){if(window.location.hostname!==`marimo.app`)return null;let e=new URL(`export_demos/wasm-intro.py`,document.baseURI);return fetch(e.toString()).then(e=>e.ok?e.text():null).catch(()=>null)}},Ne={saveFile(e){},readFile(){return e.get(n)??null}},Pe={saveFile(e){},readFile(){return[`import marimo`,`app = marimo.App()`,``,`@app.cell`,`def __():`,` return`,``,`if __name__ == "__main__":`,` app.run()`].join(`
|
|
2
|
-
`)}},z=class{stores;constructor(e){this.stores=e}insert(e,t){this.stores.splice(e,0,t)}saveFile(e){this.stores.forEach(t=>t.saveFile(e))}readFile(){for(let e of this.stores){let t=e.readFile();if(t)return t}return null}},B=new z([Ne,je,Ae]),V=new z([ke,Me,Pe]),Fe=new URL(`save-worker-BbUSwZRG.js`,import.meta.url).href,Ie=new URL(`worker-DTQ7oH2A.js`,import.meta.url).href,H=class t{static get INSTANCE(){let e=`_marimo_private_PyodideBridge`;return window[e]||(window[e]=new t),window[e]}rpc;saveRpc;pendingSessionSave=Promise.resolve();interruptBuffer;messageConsumer;initialized=new ce;getSaveWorker(){if(v()===`read`)return m.debug(`Using partially disabled SaveWorker in read-mode`),{readFile:h,readNotebook:async()=>await B.readFile()??``,saveNotebook:h};let e=F(),t=P(O(new URL(Fe,import.meta.url),{name:Re()}));return t.send.bootstrap(e),t.proxy.request}constructor(){if(!ee())return;let t=F(),n=O(new URL(Ie,import.meta.url),{name:Re()});this.rpc=P(n),this.rpc.send.bootstrap(t),this.rpc.addMessageListener(`ready`,()=>{this.startSession()}),this.rpc.addMessageListener(`initialized`,()=>{this.saveRpc=this.getSaveWorker(),this.setInterruptBuffer(),e.set(C,{kind:`ready`}),this.initialized.resolve()}),this.rpc.addMessageListener(`initializingMessage`,({message:t})=>{e.get(C).kind===`loading`&&e.set(C,{kind:`loading`,message:t})}),this.rpc.addMessageListener(`initializedError`,({error:t})=>{if(this.initialized.status===`resolved`){m.error(t),ae({title:`Error initializing`,description:t,variant:`danger`});return}e.set(C,{kind:`error`,message:t}),this.initialized.reject(Error(t))}),this.rpc.addMessageListener(`kernelMessage`,({message:e})=>{this.messageConsumer?.(new MessageEvent(`message`,{data:e}))})}async startSession(){let t=await B.readFile(),n=await V.readFile(),r=e.get(l)??s.getFilename(),i=e.get(f),a={},o=new URLSearchParams(window.location.search);for(let e of o.keys()){let t=o.getAll(e);a[e]=t.length===1?t[0]:t}await this.rpc.proxy.request.startSession({queryParameters:a,code:t||n||``,filename:r,userConfig:{...i,runtime:{...i.runtime,auto_instantiate:v()===`read`||i.runtime.auto_instantiate}}})}setInterruptBuffer(){crossOriginIsolated?(this.interruptBuffer=new Uint8Array(new SharedArrayBuffer(1)),this.rpc.proxy.request.setInterruptBuffer(this.interruptBuffer)):m.warn(`Not running in a secure context; interrupts are not available.`)}attachMessageConsumer(e){this.messageConsumer=e,this.rpc.proxy.send.consumerReady({})}sendRename=async({filename:e})=>e===null?null:(s.setFilename(e),await this.rpc.proxy.request.bridge({functionName:`rename_file`,payload:e}),null);sendSave=async e=>{if(!this.saveRpc)return m.warn(`Save RPC not initialized`),null;let t=this.saveRpc.saveNotebook(e);this.pendingSessionSave=this.pendingSessionSave.catch(()=>void 0).then(async()=>{await t,await this.rpc.proxy.request.saveNotebook(e)}),this.pendingSessionSave.catch(e=>{m.error(e)}),await t;let n=await this.readCode();return n.contents&&(B.saveFile(n.contents),V.saveFile(n.contents)),null};sendCopy=async()=>{h()};sendStdin=async e=>(await this.rpc.proxy.request.bridge({functionName:`put_input`,payload:e.text}),null);sendPdb=async()=>{h()};sendSetBreakpoints=async()=>{h()};sendRun=async e=>(await this.rpc.proxy.request.loadPackages(e.codes.join(`
|
|
3
|
-
`)),await this.putControlRequest({type:`execute-cells`,...e}),null);sendRunScratchpad=async e=>(await this.rpc.proxy.request.loadPackages(e.code),await this.putControlRequest({type:`execute-scratchpad`,...e}),null);sendInterrupt=async()=>(this.interruptBuffer!==void 0&&(this.interruptBuffer[0]=2),null);sendShutdown=async()=>(window.close(),null);sendFormat=async e=>await this.rpc.proxy.request.bridge({functionName:`format`,payload:e});sendDeleteCell=async e=>(await this.putControlRequest({type:`delete-cell`,...e}),null);sendInstallMissingPackages=async e=>(this.putControlRequest({type:`install-packages`,...e}),null);sendCodeCompletionRequest=async t=>(e.get(c)||await this.rpc.proxy.request.bridge({functionName:`code_complete`,payload:t}),null);saveUserConfig=async e=>(await this.rpc.proxy.request.bridge({functionName:`save_user_config`,payload:e}),_.post(`/kernel/save_user_config`,e,{baseUrl:`/`}).catch(e=>(m.error(e),null)));saveAppConfig=async e=>(await this.rpc.proxy.request.bridge({functionName:`save_app_config`,payload:e}),null);saveCellConfig=async e=>(await this.putControlRequest({type:`update-cell-config`,...e}),null);sendRestart=async()=>{let e=await this.readCode();return e.contents&&(B.saveFile(e.contents),V.saveFile(e.contents)),me(),null};readCode=async()=>this.saveRpc?{contents:await this.saveRpc.readNotebook()}:(m.warn(`Save RPC not initialized`),{contents:``});readSnippets=async()=>await this.rpc.proxy.request.bridge({functionName:`read_snippets`,payload:void 0});openFile=async({path:e})=>{let t=ge({code:null,baseUrl:window.location.origin});return window.open(t,`_blank`),null};sendListFiles=async e=>await this.rpc.proxy.request.bridge({functionName:`list_files`,payload:e});getFileRoots=async()=>await this.rpc.proxy.request.bridge({functionName:`file_roots`,payload:void 0});sendSearchFiles=async e=>await this.rpc.proxy.request.bridge({functionName:`search_files`,payload:e});sendComponentValues=async e=>(await this.putControlRequest({type:`update-ui-element`,...e,token:le()}),null);sendInstantiate=async e=>null;sendFunctionRequest=async e=>(await this.putControlRequest({type:`invoke-function`,...e}),null);sendCreateFileOrFolder=async e=>{let t=null;return e.file&&(t=(await fe(e.file)).split(`,`)[1]??``),await this.rpc.proxy.request.bridge({functionName:`create_file_or_directory`,payload:{path:e.path,type:e.type,name:e.name,contents:t}})};sendDeleteFileOrFolder=async e=>await this.rpc.proxy.request.bridge({functionName:`delete_file_or_directory`,payload:e});sendCopyFileOrFolder=async e=>await this.rpc.proxy.request.bridge({functionName:`copy_file_or_directory`,payload:e});sendRenameFileOrFolder=async e=>await this.rpc.proxy.request.bridge({functionName:`move_file_or_directory`,payload:e});sendUpdateFile=async e=>await this.rpc.proxy.request.bridge({functionName:`update_file`,payload:e});sendFileDetails=async e=>await this.rpc.proxy.request.bridge({functionName:`file_details`,payload:e});exportAsHTML=async e=>(await this.pendingSessionSave,await this.rpc.proxy.request.bridge({functionName:`export_html`,payload:k(e)}));exportAsMarkdown=async e=>(await this.pendingSessionSave,await this.rpc.proxy.request.bridge({functionName:`export_markdown`,payload:e}));exportAsScript=async e=>(await this.pendingSessionSave,await this.rpc.proxy.request.bridge({functionName:`export_script`,payload:e}));previewDatasetColumn=async e=>(await this.putControlRequest({type:`preview-dataset-column`,...e}),null);previewSQLTable=async e=>(await this.putControlRequest({type:`preview-sql-table`,...e}),null);previewSQLTableList=async e=>(await this.putControlRequest({type:`list-sql-tables`,...e}),null);previewSQLSchemaList=async e=>(await this.putControlRequest({type:`list-sql-schemas`,...e}),null);previewDataSourceConnection=async e=>(await this.putControlRequest({type:`list-data-source-connection`,...e}),null);validateSQL=async e=>(await this.putControlRequest({type:`validate-sql`,...e}),null);sendModelValue=async e=>(await this.putControlRequest({type:`model`,...e}),null);sendDocumentTransaction=()=>Promise.resolve(null);addPackage=async e=>this.rpc.proxy.request.addPackage(e);removePackage=async e=>this.rpc.proxy.request.removePackage(e);getPackageList=async()=>await this.rpc.proxy.request.listPackages();getSandbox=async()=>({backend:null,manifest:null,filename:null});updateManifest=async()=>{throw Error(`Sandboxes are not supported in WebAssembly`)};syncSandbox=async()=>{throw Error(`Sandboxes are not supported in WebAssembly`)};getDependencyTree=async()=>({tree:{dependencies:[],name:``,tags:[],version:null},context:{kind:`package-manager`,name:`micropip`}});listSecretKeys=async e=>(await this.putControlRequest({type:`list-secret-keys`,...e}),null);discoverDataSources=async e=>(await this.putControlRequest({type:`discover-data-sources`,...e}),null);getUsageStats=h;getEnvironmentInfo=async()=>await this.rpc.proxy.request.bridge({functionName:`get_environment_info`,payload:void 0});openTutorial=h;getRecentFiles=h;getWorkspaceFiles=h;getRunningNotebooks=h;shutdownSession=h;getExportAvailability=h;installExportRequirements=h;exportAsIPYNB=h;exportAsPDF=h;autoExportAsHTML=h;autoExportAsMarkdown=h;autoExportAsIPYNB=h;updateCellOutputs=h;writeSecret=h;invokeAiTool=h;clearCache=h;getCacheInfo=h;listStorageEntries=h;downloadStorage=h;async putControlRequest(e){await this.rpc.proxy.request.bridge({functionName:`put_control_request`,payload:e})}};function Le(){return j.withProducerCallback(e=>{H.INSTANCE.attachMessageConsumer(e)})}function Re(){return`marimo${typeof window<`u`&&window.__MARIMO_HAS_WASM_CONTROLLER__===!0?De:``}`}function ze(e=x()){let t=window.fetch;return window.fetch=async(n,r)=>{let i=n instanceof Request?n.url:n.toString();if(i.startsWith(`data:`))return t(n,r);try{let a=W(i,e);if(a){let e=await(await t(a)).arrayBuffer();return new Response(e,{headers:{"Content-Type":Be(i)}})}return t(n,r)}catch(e){return m.error(`Error parsing URL`,e),t(n,r)}},()=>{window.fetch=t}}function Be(e){return e.endsWith(`.csv`)?`text/csv`:e.endsWith(`.json`)?`application/json`:e.endsWith(`.txt`)?`text/plain`:`application/octet-stream`}function Ve(e,t=x()){let n=e.http.bind(e),r=e.load.bind(e);return e.http=async e=>{let r=W(e,t);if(r)return await window.fetch(r).then(e=>e.text());try{return await n(e)}catch(t){if(e.startsWith(`data:`))return await window.fetch(e).then(e=>e.text());throw t}},e.load=async e=>{let n=W(e,t);if(n)return await window.fetch(n).then(e=>e.text());try{return await r(e)}catch(t){if(e.startsWith(`data:`))return await window.fetch(e).then(e=>e.text());throw t}},()=>{e.http=n,e.load=r}}function U(e){return e.startsWith(`.`)?e.slice(1):e}function He(e,t=x()){let n=W(e,t);if(!n)return e;let r=pe(n);return URL.createObjectURL(r)}function W(e,t){let n=document.baseURI;n.startsWith(`blob:`)&&(n=n.replace(`blob:`,``));let r=new URL(e,n).pathname,i=Ue(e),a=Ue(r);return t[e]||t[U(e)]||t[r]||t[U(r)]||i&&t[i]||a&&t[a]}function Ue(e){let t=e.indexOf(`/@file/`);return t===-1?null:e.slice(t)}function G(e,t){return{get(t){return e.get(t)},set(t,n){e.set(t,n)},save_changes(){e.save_changes()},send:e.send.bind(e),on(n,r){t.aborted||(e.on(n,r),t.addEventListener(`abort`,()=>e.off(n,r),{once:!0}))},off(t,n){e.off(t??null,n??null)},widget_manager:{async get_model(n){return G(await e.widget_manager.get_model(n),t)}}}}function K(e){return typeof e==`string`&&e.length>0}function We(e){if(typeof e==`string`&&e.startsWith(`anywidget:`)){let t=e.slice(10);if(K(t))return t}throw Error(`[anywidget] Invalid widget reference: ${JSON.stringify(e)}`)}function Ge(e,t){return{async getModel(n){let r=We(n);return G(await e.getModel(r),t)},async getWidget(n){let r=We(n),i=await e.getWidget(r);return{exports:i.exports,async render({el:e,signal:n}){await i.render({el:e,signal:n??t})}}}}}var Ke=Symbol(`marimo`);function q(e){return e[Ke]}var qe=class e{#e=`change`;#t;#n;#r;#i={};static _modelManager;constructor(e,t,n){this.#n=e,this.#r=t,this.#t=new Set,n&&n.addEventListener(`abort`,()=>{m.debug(`[Model] Signal aborted, clearing all listeners`),this.#i={}})}[Ke]={updateAndEmitDiffs:e=>this.#o(e),emitCustomMessage:(e,t)=>this.#s(e,t)};off(e,t){if(!e){this.#i={};return}if(!t){this.#i[e]=new Set;return}this.#i[e]?.delete(t)}send(e,t,n){let r=(n??[]).map(e=>e instanceof ArrayBuffer?new DataView(e):new DataView(e.buffer,e.byteOffset,e.byteLength));return this.#r.sendCustomMessage(e,r).then(()=>t?.())}widget_manager={async get_model(t){let n=await e._modelManager.getModel(t);if(!n)throw Error(`Model not found with id: ${t}. This is likely because the model was not registered.`);return n}};get(e){return this.#n[e]}set(e,t){this.#n={...this.#n,[e]:t},this.#t.add(e),this.#a(`change:${e}`,t),this.#c()}save_changes(){if(this.#t.size===0)return;let e=Object.fromEntries([...this.#t].map(e=>[e,this.#n[e]]));this.#t.clear(),this.#r.sendUpdate(e)}on(e,t,n){let r=n?.signal;r?.aborted||(this.#i[e]||(this.#i[e]=new Set),this.#i[e].add(t),r?.addEventListener(`abort`,()=>this.off(e,t),{once:!0}))}#a(e,t){let n=this.#i[e];if(n)for(let e of[...n])try{e(t)}catch(e){m.error(`Error emitting event`,e)}}#o(e){e!=null&&Object.keys(e).forEach(t=>{let n=t;this.#t.delete(n),this.#n[n]!==e[n]&&(this.#n={...this.#n,[n]:e[n]},this.#a(`change:${n}`,e[n]),this.#c())})}#s(e,t=[]){let n=this.#i[`msg:custom`];if(n)for(let r of[...n])try{r(e.content,t)}catch(e){m.error(`Error emitting event`,e)}}#c=d(()=>{let e=this.#i[this.#e];if(e)for(let t of[...e])try{t()}catch(e){m.error(`Error emitting event`,e)}},0)};function Je(e){return typeof e==`function`}function Ye(e){return typeof e==`function`}function Xe(e){return t(e)&&(Je(e.render)||Ye(e.initialize))}function Ze(e){return typeof e==`function`||Xe(e)}function Qe(e){return t(e)&&Ze(e.default)}var $e=new Set,et=new WeakMap;function tt(e,n){if(Qe(e))return e.default;if(!t(e)||e.default!==void 0)return null;let r=Je(e.render)?e.render:void 0,i=Ye(e.initialize)?e.initialize:void 0;if(r===void 0&&i===void 0)return null;let a=et.get(e);if(a)return a;$e.has(n)||($e.add(n),m.warn(`Anywidget module at ${n} uses deprecated top-level named exports (\`render\`/\`initialize\`). Per the AFM spec, use a default export instead: \`export default { render }\`. See https://anywidget.dev/en/afm/`));let o={render:r,initialize:i};return et.set(e,o),o}function nt(e,n){let r=`https://anywidget.dev/en/afm/`,a=t(e)&&i(e,`render`),o=t(e)&&i(e,`initialize`);if(t(e)&&e.default!==void 0)return Error(`Anywidget module at ${n} has an invalid default export. Expected a factory function or an object with \`render\` or \`initialize\`. See ${r}`);if(a||o){let e=[a?"`render`":null,o?"`initialize`":null].filter(Boolean).join(` and `),t=[a?`render`:null,o?`initialize`:null].filter(e=>e!==null),i=`export default { ${t.join(`, `)} }`,s=t.length===1?`export function ${t[0]}`:`named export function ...`;return Error(`Anywidget module at ${n} uses named exports (${e}). Per the AFM spec, use a default export instead: \`${i}\` (not \`${s}\`). See ${r}`)}return Error(`Anywidget module at ${n} is missing a default export. Per the AFM spec, use \`export default { render }\` or \`export default async () => ({ render })\`. See ${r}`)}function rt(e){return typeof e!=`string`||e.length===0?!1:!!(/^(\.?\/)?@file\/[^?#]+$/.test(e)||at(e))}function it(){return e.get(de)||ue()}function at(e){return e.startsWith(`data:text/javascript;base64,`)||e.startsWith(`data:application/javascript;base64,`)||e.startsWith(`data:text/css;base64,`)?it():!1}var ot={invoke:async()=>{let e=`anywidget.invoke not supported in marimo. Please file an issue at https://github.com/marimo-team/marimo/issues`;throw m.warn(e),Error(e)}};function st(e){if(typeof AbortSignal.any==`function`)return AbortSignal.any(e);let t=new AbortController;for(let n of e){if(n.aborted)return t.abort(n.reason),t.signal;n.addEventListener(`abort`,()=>t.abort(n.reason),{once:!0})}return t.signal}var ct=class{#e=new Map;getModule(e){let{jsUrl:t,jsHash:n,kernelAuthored:r=!1,lifetime:i}=e,a=this.#e.get(n);if(!a){let e={references:0,dispose:()=>void 0,promise:this.#t(t,{kernelAuthored:r}).then(({module:t,dispose:n})=>(e.dispose=n,t),t=>{throw this.#e.get(n)===e&&this.#e.delete(n),t})};this.#e.set(n,e),a=e}let o=a;o.references+=1;let s=()=>{--o.references,o.references===0&&o.promise.then(()=>{o.dispose(),o.dispose=()=>void 0},()=>void 0)};return i?.aborted?s():i?.addEventListener(`abort`,s,{once:!0}),o.promise}invalidate(e){this.#e.delete(e)}async#t(e,t={}){if(!(rt(e)||t.kernelAuthored===!0&&/^(https?:|data:)/.test(e)))throw Error(`Refusing to load anywidget module from untrusted URL: ${String(e)}`);let n=te(e).toString(),r=S()?He(n):n,i=()=>{r!==n&&URL.revokeObjectURL(r)};try{return{module:await oe(()=>import(r),[],import.meta.url),dispose:i}}catch(e){throw i(),e}}};function J(e){return typeof e==`function`}async function Y(e,t){try{await e()}catch(e){m.warn(`[WidgetBinding] ${t} cleanup failed`,e)}}var lt=class e{#e;#t;#n;#r;#i;#a=new Set;#o=new Set;#s;constructor(e){this.#t=e.widget,this.#n=e.model,this.#r=e.exports,this.#e=e.controller,this.#i=e.createHost,this.#s=e.onDestroy}static async create({widgetDef:t,model:n,createHost:r,controller:i=new AbortController,onDestroy:a}){let o=i.signal,s;try{let c=typeof t==`function`?await t():t;if(o.aborted)throw Error(`[anywidget] binding destroyed`);let l=Promise.resolve(c.initialize?.({model:G(n,o),experimental:ot,signal:o}));s=l.then(async e=>{o.aborted&&J(e)&&await Y(e,`late initialize`)}).catch(()=>void 0);let u=await Promise.race([l,new Promise((e,t)=>{let n=()=>t(Error(`[anywidget] binding destroyed`));if(o.aborted){n();return}o.addEventListener(`abort`,n,{once:!0})})]);if(o.aborted)throw Error(`[anywidget] binding destroyed`);let d,f;J(u)?(f=u,d=void 0):d=typeof u==`object`&&u?u:void 0;let p=new e({widget:c,model:n,exports:d,controller:i,createHost:r,onDestroy:a});return f&&o.addEventListener(`abort`,()=>void p.#l(f,`initialize`),{once:!0}),p}catch(e){throw s?s.then(()=>a?.()):a?.(),e}}get exports(){return this.#r}async createView(e,t){let n=this.#c(e,t);this.#o.add(n);try{await n}finally{this.#o.delete(n)}}async#c(e,t){let n=this.#t;if(!n.render)return;let r=st([t.signal,this.#e.signal]);if(r.aborted)return;e.el.innerHTML=``;let i=this.#i(r),a=await n.render({model:G(this.#n,r),el:e.el,experimental:ot,signal:r,host:i});if(J(a)){let e=()=>{let e=t.signal.aborted?`view unmount`:`binding destroyed`;return m.debug(`[WidgetBinding] Render cleanup triggered (reason: ${e})`),this.#l(a,`render`)};if(r.aborted){await e();return}r.addEventListener(`abort`,()=>void e(),{once:!0})}}#l(e,t){let n=Y(e,t);return this.#a.add(n),n.finally(()=>this.#a.delete(n)),n}async destroy(){for(m.debug(`[WidgetBinding] Destroying binding generation`),this.#e.abort(),await Promise.allSettled(this.#o);this.#a.size>0;)await Promise.all(this.#a);this.#s?.(),this.#s=void 0}},ut=new ct,dt=class{#e;#t;#n;#r;#i;#a=new AbortController;#o=new ce;#s=new Set;#c=new Map;#l;#u;#d;#f=Promise.resolve();#p=``;constructor(e,t){this.#e=e,this.#t=t.timeout,this.#n=t.isEditMode,this.#r=t.createHost,this.#i=t.onModelTimeout}getModel(){return this.#o.status===`pending`&&!this.#l&&(this.#l=setTimeout(()=>{this.#o.status===`pending`&&(this.#l=void 0,this.#o.reject(Error(`Model not found for key: ${this.#e}`)),this.#i())},this.#t)),this.#o.promise}getModelSync(){return this.#o.status===`resolved`?this.#o.value:void 0}createModel(e){this.#o.status===`pending`&&this.#m(e(this.#a.signal))}setModel(e){this.#o.status===`pending`&&this.#m(e)}#m(e){this.#l&&=(clearTimeout(this.#l),void 0),this.#o.resolve(e);let t=e.get(`_css`);this.#p=typeof t==`string`?t:``,e.on(`change:_css`,e=>{this.#p=typeof e==`string`?e:``;for(let e of this.#c.values())e.update(this.#p)},{signal:this.#a.signal})}setSpec(e){if(!this.#u){this.#u=e;return}this.#n()&&(this.#u=e,this.#d&&this.#d.hash!==e.hash&&this.#v(e))}async getWidget(){return{exports:(await this.#h()).exports,render:async({el:e,signal:t})=>{await this.createView({el:e,signal:t??this.#a.signal})}}}async createView(e){if(e.signal.aborted||this.#a.signal.aborted)return;let t={el:e.el,signal:e.signal};this.#s.add(t),this.#x(t),e.signal.addEventListener(`abort`,()=>this.#s.delete(t),{once:!0}),await this.#b(t)}async#h(){for(;!this.#a.signal.aborted;){let e=await this.getModel(),t=this.#d;if(!t){let n=this.#u;if(!n)throw Error(`[anywidget] No ESM spec for model ${this.#e}: nothing ever provided this widget's code`);t=this.#_(n,e)}try{let e=await t.promise;if(t===this.#d)return e}catch(e){if(!this.#d||t===this.#d)throw e}}throw Error(`[anywidget] widget runtime destroyed`)}async#g(e){let{spec:t,model:n,controller:r}=e,i=new AbortController,a;try{let e=await ut.getModule({jsUrl:t.url,jsHash:t.hash,kernelAuthored:!0,lifetime:i.signal}),n=tt(e,t.url);if(!n)throw ut.invalidate(t.hash),nt(e,t.url);a=n}catch(e){throw i.abort(),e}return lt.create({widgetDef:a,model:n,createHost:this.#r,controller:r,onDestroy:()=>i.abort()})}#_(e,t){let n=new AbortController,r={hash:e.hash,controller:n,promise:this.#g({spec:e,model:t,controller:n})};return r.promise.catch(()=>{this.#d===r&&(this.#d=void 0)}),this.#d=r,r}#v(e){let t=this.#d;if(!t)return;m.debug(`[WidgetRuntime] Hot-swapping generation for model=${this.#e}`);let n=this.#y(t),r=this.getModelSync();if(!r)return;let i=this.#_(e,r);for(let e of this.#s)e.generation=void 0,n.then(()=>this.#b(e,i)).catch(e=>{m.error(`[WidgetRuntime] Error replacing widget view`,e)})}#y(e){e.controller.abort();let t=this.#f.then(async()=>{try{await(await e.promise).destroy()}catch{}});return this.#f=t,t}async#b(e,t){if(e.signal.aborted||this.#a.signal.aborted)return;let n=t??this.#d,r=n?await n.promise:await this.#h(),i=this.#d;if(!(!i||i!==(n??i))&&e.generation!==i){e.generation=i;try{await r.createView({el:e.el},{signal:e.signal})}catch(t){if(i!==this.#d){e.generation=void 0;return}throw t}}}#x(e){let t=e.el.getRootNode();if(!X(t)&&!ft(t))return;let n=this.#c.get(t);n||(n=pt(t,this.#p),this.#c.set(t,n)),n.references+=1;let r=!1;e.signal.addEventListener(`abort`,()=>{if(r)return;r=!0;let e=this.#c.get(t);e&&(--e.references,e.references===0&&(e.dispose(),this.#c.delete(t)))},{once:!0})}dispose(){if(!this.#a.signal.aborted){m.debug(`[WidgetRuntime] Disposing model=${this.#e}`),this.#l&&=(clearTimeout(this.#l),void 0),this.#o.status===`pending`&&(this.#o.promise.catch(()=>void 0),this.#o.reject(Error(`[anywidget] widget runtime destroyed`))),this.#d&&this.#y(this.#d),this.#a.abort(),this.#s.clear();for(let e of this.#c.values())e.dispose();this.#c.clear()}}};function X(e){return e.nodeType===Node.DOCUMENT_NODE}function ft(e){return e.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&`host`in e}function pt(e,t){let n=X(e)?e:e.ownerDocument??document,r=n.defaultView??window;if(`adoptedStyleSheets`in e&&r.CSSStyleSheet!==void 0&&typeof r.CSSStyleSheet.prototype.replaceSync==`function`)try{let n=new r.CSSStyleSheet;return n.replaceSync(t),e.adoptedStyleSheets=[...e.adoptedStyleSheets,n],{references:0,update(e){n.replaceSync(e)},dispose(){e.adoptedStyleSheets=e.adoptedStyleSheets.filter(e=>e!==n)}}}catch{}let i=n.createElement(`style`);return i.textContent=t,X(e)?n.head.append(i):e.append(i),{references:0,update(e){i.textContent=e},dispose(){i.remove()}}}function Z(e,t=[]){let n=[];if(e instanceof DataView)n.push(t);else if(Array.isArray(e))for(let[r,i]of e.entries())n.push(...Z(i,[...t,r]));else if(typeof e==`object`&&e)for(let[r,i]of Object.entries(e))n.push(...Z(i,[...t,r]));return n}function mt(e){let t=Z(e);if(t.length===0)return{state:e,buffers:[],bufferPaths:[]};let n=structuredClone(e),r=[],i=[];for(let a of t){let t=u(e,a);if(t instanceof DataView){let e=w(t);r.push(e),i.push(a),D(n,a,e)}}return{state:n,buffers:r,bufferPaths:i}}function ht(e){let{state:t,bufferPaths:n,buffers:r}=e;if(!n||n.length===0)return t;r&&g(r.length===n.length,`Buffers and buffer paths not the same length`);let i=t;for(let[e,t]of n.entries()){let n=r?.[e];if(n==null){m.warn(`[anywidget] Could not find buffer at path`,t);continue}typeof n==`string`?D(i,t,re(n)):D(i,t,n)}return i}function gt(){let t=e.get(y).mode;return t===`edit`||t===`present`}var Q=new class{#e=new Map;#t;#n;constructor(e=1e4,t=gt){this.#t=e,this.#n=t}#r(e){let t=this.#e.get(e);if(!t){let n=new dt(e,{timeout:this.#t,isEditMode:this.#n,createHost:e=>Ge(this,e),onModelTimeout:()=>{this.#e.get(e)===n&&(n.dispose(),this.#e.delete(e))}});t=n,this.#e.set(e,t)}return t}getModel(e){return this.#r(e).getModel()}getModelSync(e){return this.#e.get(e)?.getModelSync()}createModel(e,t){this.#r(e).createModel(t)}setModel(e,t){this.#r(e).setModel(t)}setSpec(e,t){this.#r(e).setSpec(t)}getWidget(e){return this.#r(e).getWidget()}createView(e){return this.#r(e.modelId).createView(e)}delete(e){let t=this.#e.get(e);t&&(t.dispose(),this.#e.delete(e))}};qe._modelManager=Q;async function _t(e,t){let n=t.model_id;if(!K(n))throw Error(`[anywidget] Invalid model id: ${String(n)}`);let r=t.message,i=(`buffers`in r?r.buffers:[]).map(re);switch(r.method){case`open`:{let{state:t,buffer_paths:a=[]}=r;r.esm_spec&&e.setSpec(n,r.esm_spec);let o=ht({state:t,bufferPaths:a,buffers:i}),s=e.getModelSync(n);if(s){q(s).updateAndEmitDiffs(o);return}e.createModel(n,e=>{let t=S()?{sendUpdate:async()=>void 0,sendCustomMessage:async()=>void 0}:{async sendUpdate(t){if(e.aborted){m.debug(`[Model] sendUpdate suppressed for model=${n} (signal aborted)`);return}let{state:r,buffers:i,bufferPaths:a}=mt(t);await T().sendModelValue({modelId:n,message:{method:`update`,state:r,bufferPaths:a},buffers:i})},async sendCustomMessage(t,r){if(e.aborted){m.debug(`[Model] sendCustomMessage suppressed for model=${n} (signal aborted)`);return}await T().sendModelValue({modelId:n,message:{method:`custom`,content:t},buffers:r.map(w)})}};return new qe(o,t,e)});return}case`custom`:q(await e.getModel(n)).emitCustomMessage({method:`custom`,content:r.content},i);return;case`close`:e.delete(n);return;case`update`:{let{state:t,buffer_paths:a=[]}=r;r.esm_spec&&e.setSpec(n,r.esm_spec);let o=ht({state:t,bufferPaths:a,buffers:i});q(await e.getModel(n)).updateAndEmitDiffs(o);return}default:se(r)}}o(Q,`WIDGET_REGISTRY`);function vt(e){return typeof e!=`object`||!e?!1:`type`in e&&e.type===`marimo-ui-value-update`}var $=class e{entries;static get INSTANCE(){let t=`_marimo_private_UIElementRegistry`;return window[t]||(window[t]=new e),window[t]}constructor(){this.entries=new Map}has(e){return this.entries.has(e)}set(e,t){this.entries.has(e)&&m.debug(`UIElementRegistry overwriting entry for objectId.`,e),this.entries.set(e,{objectId:e,value:t,elements:new Set})}registerInstance(e,t){let n=this.entries.get(e);n===void 0?this.entries.set(e,{objectId:e,value:a(t,this),elements:new Set([t])}):n.elements.add(t)}removeInstance(e,t){let n=this.entries.get(e);n?.elements.has(t)&&n.elements.delete(t)}removeElementsByCell(e){[...this.entries.keys()].filter(t=>t.startsWith(`${e}-`)).forEach(e=>{this.entries.delete(e)})}lookupValue(e){let t=this.entries.get(e);return t===void 0?void 0:t.value}broadcastMessage(e,t,n){let r=this.entries.get(e);if(r===void 0){m.warn(`UIElementRegistry missing entry`,e);return}if(vt(t)){r.value=t.value,r.elements.forEach(e=>{e.dispatchEvent(E.create({bubbles:!1,composed:!0,detail:{value:t.value,element:e}}))});return}r.elements.forEach(r=>{r.dispatchEvent(ve.create({bubbles:!1,composed:!0,detail:{objectId:e,message:t,buffers:n}}))})}broadcastValueUpdate(e,t,n){let r=this.entries.get(t);r===void 0?m.warn(`UIElementRegistry missing entry`,t):(r.value=n,r.elements.forEach(t=>{t!==e&&t.dispatchEvent(E.create({bubbles:!1,composed:!0,detail:{value:n,element:t}}))}),document.dispatchEvent(_e.create({bubbles:!0,composed:!0,detail:{objectId:t}})))}},yt=$.INSTANCE,bt=new ie(`function-call-result`,async(e,t)=>{await T().sendFunctionRequest({functionCallId:e,...t})}),xt=`68px`,St=`288px`,Ct=e=>e?/^\d+$/.test(e)?`${e}px`:e:St,wt=b({isOpen:!0},(e,t)=>{if(!t)return e;switch(t.type){case`toggle`:return{...e,isOpen:t.isOpen??e.isOpen};case`setWidth`:return{...e,width:t.width};default:return e}});export{A as _,$ as a,_t as c,ze as d,Ve as f,j as g,B as h,bt as i,rt as l,Le as m,Ct as n,yt as o,H as p,wt as r,Q as s,xt as t,K as u,k as v,D as y};
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
(!globalThis.EventTarget||!globalThis.Event)&&console.error(`
|
|
2
|
-
PartySocket requires a global 'EventTarget' class to be available!
|
|
3
|
-
You can polyfill this global by adding this to your code before any partysocket imports:
|
|
4
|
-
|
|
5
|
-
\`\`\`
|
|
6
|
-
import 'partysocket/event-target-polyfill';
|
|
7
|
-
\`\`\`
|
|
8
|
-
Please file an issue at https://github.com/partykit/partykit if you're still having trouble.
|
|
9
|
-
`);var e=class extends Event{message;error;constructor(e,t){super(`error`,t),this.message=e.message,this.error=e}},t=class extends Event{code;reason;wasClean=!0;constructor(e=1e3,t=``,n){super(`close`,n),this.code=e,this.reason=t}},n={Event,ErrorEvent:e,CloseEvent:t};function r(e,t){if(!e)throw Error(t)}function i(e){return new e.constructor(e.type,e)}function a(n){return`data`in n?new MessageEvent(n.type,n):`code`in n||`reason`in n?new t(n.code||1999,n.reason||`unknown reason`,n):`error`in n?new e(n.error,n):new Event(n.type,n)}var o=typeof process<`u`&&process.versions?.node!==void 0,s=typeof navigator<`u`&&navigator.product===`ReactNative`,c=o||s?a:i,l={maxReconnectionDelay:1e4,minReconnectionDelay:3e3,minUptime:5e3,reconnectionDelayGrowFactor:1.3,connectionTimeout:4e3,maxRetries:1/0,maxEnqueuedMessages:1/0,startClosed:!1,debug:!1},u=!1;function d(){}var f=class e extends EventTarget{_ws;_retryCount=-1;_uptimeTimeout;_connectTimeout;_shouldReconnect=!0;_connectLock=!1;_binaryType=`blob`;_closeCalled=!1;_didWarnAboutClosedSend=!1;_messageQueue=[];_debugLogger=console.log.bind(console);_url;_protocols;_options;constructor(e,t,n={}){super(),this._url=e,this._protocols=t,this._options=n,this._options.startClosed&&(this._shouldReconnect=!1),this._options.debugLogger&&(this._debugLogger=this._options.debugLogger),this._connect()}static get CONNECTING(){return 0}static get OPEN(){return 1}static get CLOSING(){return 2}static get CLOSED(){return 3}get CONNECTING(){return e.CONNECTING}get OPEN(){return e.OPEN}get CLOSING(){return e.CLOSING}get CLOSED(){return e.CLOSED}get binaryType(){return this._ws?this._ws.binaryType:this._binaryType}set binaryType(e){this._binaryType=e,this._ws&&(this._ws.binaryType=e)}get retryCount(){return Math.max(this._retryCount,0)}get bufferedAmount(){return this._messageQueue.reduce((e,t)=>(typeof t==`string`?e+=t.length:t instanceof Blob?e+=t.size:e+=t.byteLength,e),0)+(this._ws?this._ws.bufferedAmount:0)}get extensions(){return this._ws?this._ws.extensions:``}get protocol(){return this._ws?this._ws.protocol:``}get readyState(){return this._closeCalled?e.CLOSED:this._ws?this._ws.readyState:this._options.startClosed?e.CLOSED:e.CONNECTING}get url(){return this._ws?this._ws.url:``}get shouldReconnect(){return this._shouldReconnect}onclose=null;onerror=null;onmessage=null;onopen=null;close(e=1e3,t){if(this._closeCalled=!0,this._shouldReconnect=!1,this._clearTimeouts(),!this._ws){this._debug(`close enqueued: no ws instance`);return}if(this._ws.readyState===this.CLOSED||this._ws.readyState===this.CLOSING){this._debug(`close: already closing or closed`);return}this._disconnect(e,t)}reconnect(e,t){this._shouldReconnect=!0,this._closeCalled=!1,this._didWarnAboutClosedSend=!1,this._retryCount=-1,!this._ws||this._ws.readyState===this.CLOSED||this._ws.readyState===this.CLOSING||this._disconnect(e,t),this._connect()}send(e){if(this._ws&&this._ws.readyState===this.OPEN)return this._debug(`send`,e),this._ws.send(e),!0;this._closeCalled&&!this._didWarnAboutClosedSend&&(this._didWarnAboutClosedSend=!0,console.warn(`ReconnectingWebSocket: send() was called after close(). The message has been buffered, but it will only be delivered if reconnect() is called on this socket. If this socket has been discarded, the message is lost — this usually means a stale socket reference is being used.`));let{maxEnqueuedMessages:t=l.maxEnqueuedMessages}=this._options;return this._messageQueue.length<t&&(this._debug(`enqueue`,e),this._messageQueue.push(e)),!1}drainQueuedMessages(){let e=this._messageQueue;return this._messageQueue=[],e}_debug(...e){this._options.debug&&this._debugLogger(`RWS>`,...e)}_getNextDelay(){let{reconnectionDelayGrowFactor:e=l.reconnectionDelayGrowFactor,minReconnectionDelay:t=l.minReconnectionDelay,maxReconnectionDelay:n=l.maxReconnectionDelay}=this._options,r=0;return this._retryCount>0&&(r=t*e**(this._retryCount-1),r>n&&(r=n)),this._debug(`next delay`,r),r}_wait(){return new Promise(e=>{setTimeout(e,this._getNextDelay())})}_getNextProtocols(e){if(!e)return Promise.resolve(null);if(typeof e==`string`||Array.isArray(e))return Promise.resolve(e);if(typeof e==`function`){let t=e();if(!t)return Promise.resolve(null);if(typeof t==`string`||Array.isArray(t))return Promise.resolve(t);if(t.then)return t}throw Error(`Invalid protocols`)}_getNextUrl(e){if(typeof e==`string`)return Promise.resolve(e);if(typeof e==`function`){let t=e();if(typeof t==`string`)return Promise.resolve(t);if(t.then)return t}throw Error(`Invalid URL`)}_connect(){if(this._connectLock||!this._shouldReconnect)return;this._connectLock=!0;let{maxRetries:e=l.maxRetries,connectionTimeout:t=l.connectionTimeout}=this._options;if(this._retryCount>=e){this._debug(`max retries reached`,this._retryCount,`>=`,e),this._connectLock=!1;return}this._retryCount++,this._debug(`connect`,this._retryCount),this._removeListeners(),this._wait().then(()=>Promise.all([this._getNextUrl(this._url),this._getNextProtocols(this._protocols||null)])).then(([e,n])=>{if(this._closeCalled){this._connectLock=!1;return}!this._options.WebSocket&&typeof WebSocket>`u`&&!u&&(console.error(`‼️ No WebSocket implementation available. You should define options.WebSocket.
|
|
10
|
-
|
|
11
|
-
For example, if you're using node.js, run \`npm install ws\`, and then in your code:
|
|
12
|
-
|
|
13
|
-
import PartySocket from 'partysocket';
|
|
14
|
-
import WS from 'ws';
|
|
15
|
-
|
|
16
|
-
const partysocket = new PartySocket({
|
|
17
|
-
host: "127.0.0.1:1999",
|
|
18
|
-
room: "test-room",
|
|
19
|
-
WebSocket: WS
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
`),u=!0);let r=this._options.WebSocket||WebSocket;this._debug(`connect`,{url:e,protocols:n}),this._ws=n?new r(e,n):new r(e),this._ws.binaryType=this._binaryType,this._connectLock=!1,this._addListeners(),this._connectTimeout=setTimeout(()=>this._handleTimeout(),t)}).catch(e=>{this._connectLock=!1,this._handleError(new n.ErrorEvent(Error(e.message),this))})}_handleTimeout(){this._debug(`timeout event`),this._handleError(new n.ErrorEvent(Error(`TIMEOUT`),this))}_disconnect(e=1e3,t){if(this._clearTimeouts(),this._ws){this._removeListeners();try{(this._ws.readyState===this.OPEN||this._ws.readyState===this.CONNECTING)&&this._ws.close(e,t),this._handleClose(new n.CloseEvent(e,t,this))}catch{}}}_acceptOpen(){this._debug(`accept open`),this._retryCount=0}_handleOpen=e=>{this._debug(`open event`);let{minUptime:t=l.minUptime}=this._options;clearTimeout(this._connectTimeout),this._uptimeTimeout=setTimeout(()=>this._acceptOpen(),t),r(this._ws,`WebSocket is not defined`),this._ws.binaryType=this._binaryType,this._messageQueue.forEach(e=>{this._ws?.send(e)}),this._messageQueue=[],this.onopen&&this.onopen(e),this.dispatchEvent(c(e))};_handleMessage=e=>{this._debug(`message event`),this.onmessage&&this.onmessage(e),this.dispatchEvent(c(e))};_handleError=e=>{this._debug(`error event`,e.message),this._disconnect(void 0,e.message===`TIMEOUT`?`timeout`:void 0),this.onerror&&this.onerror(e),this._debug(`exec error listeners`),this.dispatchEvent(c(e)),this._connect()};_handleClose=e=>{this._debug(`close event`),this._clearTimeouts(),this._options.shouldReconnectOnClose&&!this._options.shouldReconnectOnClose(e)&&(this._shouldReconnect=!1),this._shouldReconnect&&this._connect(),this.onclose&&this.onclose(e),this.dispatchEvent(c(e))};_removeListeners(){this._ws&&(this._debug(`removeListeners`),this._ws.removeEventListener(`open`,this._handleOpen),this._ws.removeEventListener(`close`,this._handleClose),this._ws.removeEventListener(`message`,this._handleMessage),this._ws.removeEventListener(`error`,this._handleError),this._ws.addEventListener(`error`,d))}_addListeners(){this._ws&&(this._debug(`addListeners`),this._ws.addEventListener(`open`,this._handleOpen),this._ws.addEventListener(`close`,this._handleClose),this._ws.addEventListener(`message`,this._handleMessage),this._ws.addEventListener(`error`,this._handleError))}_clearTimeouts(){clearTimeout(this._connectTimeout),clearTimeout(this._uptimeTimeout)}};export{f as t};
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
-
|
|
3
|
-
import { describe, expect, expectTypeOf, it } from "vitest";
|
|
4
|
-
import { z } from "zod";
|
|
5
|
-
import { type NotebookEvent, parseNotebookEvent } from "../events";
|
|
6
|
-
|
|
7
|
-
describe("notebook messages", () => {
|
|
8
|
-
it("normalizes session and host envelopes for native marimo messages", () => {
|
|
9
|
-
const notification = {
|
|
10
|
-
op: "variables",
|
|
11
|
-
variables: [{ name: "x", value: Number.NaN }],
|
|
12
|
-
};
|
|
13
|
-
expectTypeOf<
|
|
14
|
-
Extract<NotebookEvent, { event: "marimo" }>["data"]["marimo"]
|
|
15
|
-
>().toBeUnknown();
|
|
16
|
-
const host = { event: "marimo", data: { marimo: notification } };
|
|
17
|
-
expect(parseNotebookEvent({ data: notification })).toEqual(host);
|
|
18
|
-
expect(parseNotebookEvent({ ...host, id: "42" })).toEqual({
|
|
19
|
-
...host,
|
|
20
|
-
id: "42",
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it("retains unknown event cursors without interpreting their payloads", () => {
|
|
25
|
-
expect(
|
|
26
|
-
parseNotebookEvent({ event: "future", id: "42", data: null }),
|
|
27
|
-
).toEqual({ event: "unknown", name: "future", id: "42" });
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it("decodes known events outside the client's subscription filters", () => {
|
|
31
|
-
const event = {
|
|
32
|
-
event: "run.removed",
|
|
33
|
-
id: "42",
|
|
34
|
-
data: { id: "r1", time: "2026-10-19T12:00:00Z" },
|
|
35
|
-
};
|
|
36
|
-
expect(parseNotebookEvent(event)).toEqual(event);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it.each([
|
|
40
|
-
{ event: "cell", id: "42", data: { cell: { id: "c1" } } },
|
|
41
|
-
{ event: "run.removed", id: "42", data: {} },
|
|
42
|
-
{ event: "ready", data: {} },
|
|
43
|
-
{ event: "marimo", data: {} },
|
|
44
|
-
{},
|
|
45
|
-
null,
|
|
46
|
-
])("rejects malformed known messages: %j", (message) => {
|
|
47
|
-
expect(() => parseNotebookEvent(message)).toThrow(z.ZodError);
|
|
48
|
-
});
|
|
49
|
-
});
|
package/src/core/host/events.ts
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
-
|
|
3
|
-
import { z } from "zod";
|
|
4
|
-
import * as Protocol from "@marimo-team/client/protocol";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Notebook stream events, including native marimo notifications.
|
|
8
|
-
*
|
|
9
|
-
* Known events follow the generated protocol. Unknown events retain their name
|
|
10
|
-
* and cursor so clients can skip them without losing their place in the stream.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
const envelope = z.object({
|
|
14
|
-
event: z.string().min(1),
|
|
15
|
-
data: z.unknown(),
|
|
16
|
-
id: z.string().min(1).optional(),
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
const knownNames = new Set<string>(
|
|
20
|
-
Protocol.Event.options.flatMap((schema) => schema.shape.event.options),
|
|
21
|
-
);
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* A native marimo message carried by a host stream.
|
|
25
|
-
*
|
|
26
|
-
* The protocol leaves extension events to their producer. The payload is
|
|
27
|
-
* passed through for the session handler to interpret.
|
|
28
|
-
*/
|
|
29
|
-
const MarimoEvent = z.object({
|
|
30
|
-
event: z.literal("marimo"),
|
|
31
|
-
id: z.string().min(1).optional(),
|
|
32
|
-
data: z.object({ marimo: z.unknown() }),
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
/** A decoded event, or the name and cursor of an unrecognized event. */
|
|
36
|
-
export type NotebookEvent =
|
|
37
|
-
| Protocol.EventOutput
|
|
38
|
-
| z.output<typeof MarimoEvent>
|
|
39
|
-
| {
|
|
40
|
-
readonly event: "unknown";
|
|
41
|
-
readonly name: string;
|
|
42
|
-
readonly id?: string;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
const sessionEnvelope = z.object({ data: z.unknown() });
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Decode a host event or an in-process WASM `{ data: notification }` message.
|
|
49
|
-
*
|
|
50
|
-
* Throws if the envelope or a known event is malformed. Native notification
|
|
51
|
-
* payloads are passed through for the session handler to interpret.
|
|
52
|
-
*/
|
|
53
|
-
export function parseNotebookEvent(value: unknown): NotebookEvent {
|
|
54
|
-
if (typeof value === "object" && value !== null && !("event" in value)) {
|
|
55
|
-
return {
|
|
56
|
-
event: "marimo",
|
|
57
|
-
data: { marimo: sessionEnvelope.parse(value).data },
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
const parsed = envelope.parse(value);
|
|
61
|
-
if (parsed.event === "marimo") {
|
|
62
|
-
return MarimoEvent.parse(parsed);
|
|
63
|
-
}
|
|
64
|
-
if (knownNames.has(parsed.event)) {
|
|
65
|
-
return Protocol.Event.parse(parsed);
|
|
66
|
-
}
|
|
67
|
-
return { event: "unknown", name: parsed.event, id: parsed.id };
|
|
68
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
-
|
|
3
|
-
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
4
|
-
import { BasicTransport } from "../transports/basic";
|
|
5
|
-
import { SseTransport } from "../transports/sse";
|
|
6
|
-
import { WsTransport } from "../transports/ws";
|
|
7
|
-
import { createConnectionTransport } from "../transports/create";
|
|
8
|
-
|
|
9
|
-
vi.mock("../../wasm/utils", () => ({
|
|
10
|
-
isWasm: () => false,
|
|
11
|
-
}));
|
|
12
|
-
|
|
13
|
-
describe("createConnectionTransport", () => {
|
|
14
|
-
afterEach(() => {
|
|
15
|
-
vi.restoreAllMocks();
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
const options = {
|
|
19
|
-
url: () => "http://localhost/ws",
|
|
20
|
-
headers: () => ({}),
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
it("uses BasicTransport for static notebooks", () => {
|
|
24
|
-
const transport = createConnectionTransport({
|
|
25
|
-
...options,
|
|
26
|
-
static: true,
|
|
27
|
-
transportType: "websocket",
|
|
28
|
-
});
|
|
29
|
-
expect(transport).toBeInstanceOf(BasicTransport);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it("uses WsTransport by default", () => {
|
|
33
|
-
const transport = createConnectionTransport({
|
|
34
|
-
...options,
|
|
35
|
-
static: false,
|
|
36
|
-
transportType: "websocket",
|
|
37
|
-
});
|
|
38
|
-
expect(transport).toBeInstanceOf(WsTransport);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it("uses SseTransport when the transport type is sse", () => {
|
|
42
|
-
const transport = createConnectionTransport({
|
|
43
|
-
...options,
|
|
44
|
-
static: false,
|
|
45
|
-
transportType: "sse",
|
|
46
|
-
});
|
|
47
|
-
expect(transport).toBeInstanceOf(SseTransport);
|
|
48
|
-
});
|
|
49
|
-
});
|
|
@@ -1,275 +0,0 @@
|
|
|
1
|
-
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
-
|
|
3
|
-
import { describe, expect, it, vi } from "vitest";
|
|
4
|
-
import { BasicTransport } from "../basic";
|
|
5
|
-
|
|
6
|
-
describe("BasicTransport", () => {
|
|
7
|
-
describe("close", () => {
|
|
8
|
-
it("should trigger close event", () => {
|
|
9
|
-
const transport = BasicTransport.empty();
|
|
10
|
-
const closeCallback = vi.fn();
|
|
11
|
-
|
|
12
|
-
transport.addEventListener("close", closeCallback);
|
|
13
|
-
transport.close();
|
|
14
|
-
|
|
15
|
-
expect(closeCallback).toHaveBeenCalledTimes(1);
|
|
16
|
-
expect(closeCallback).toHaveBeenCalledWith(expect.any(Event));
|
|
17
|
-
});
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
describe("reconnect", () => {
|
|
21
|
-
it("should trigger close and open events", async () => {
|
|
22
|
-
const transport = BasicTransport.empty();
|
|
23
|
-
const openCallback = vi.fn();
|
|
24
|
-
const closeCallback = vi.fn();
|
|
25
|
-
|
|
26
|
-
transport.addEventListener("open", openCallback);
|
|
27
|
-
transport.addEventListener("close", closeCallback);
|
|
28
|
-
|
|
29
|
-
// Clear the initial open callback
|
|
30
|
-
openCallback.mockClear();
|
|
31
|
-
|
|
32
|
-
transport.reconnect();
|
|
33
|
-
|
|
34
|
-
// Wait for connect to complete
|
|
35
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
36
|
-
|
|
37
|
-
expect(closeCallback).toHaveBeenCalledTimes(1);
|
|
38
|
-
expect(openCallback).toHaveBeenCalledTimes(1);
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
describe("send", () => {
|
|
43
|
-
it("should trigger message event with string data", async () => {
|
|
44
|
-
const transport = BasicTransport.empty();
|
|
45
|
-
const messageCallback = vi.fn();
|
|
46
|
-
|
|
47
|
-
transport.addEventListener("message", messageCallback);
|
|
48
|
-
|
|
49
|
-
transport.send("test message");
|
|
50
|
-
|
|
51
|
-
expect(messageCallback).toHaveBeenCalledTimes(1);
|
|
52
|
-
expect(messageCallback).toHaveBeenCalledWith(
|
|
53
|
-
expect.objectContaining({
|
|
54
|
-
data: "test message",
|
|
55
|
-
}),
|
|
56
|
-
);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it("should trigger message event with ArrayBuffer data", async () => {
|
|
60
|
-
const transport = BasicTransport.empty();
|
|
61
|
-
const messageCallback = vi.fn();
|
|
62
|
-
|
|
63
|
-
transport.addEventListener("message", messageCallback);
|
|
64
|
-
|
|
65
|
-
const buffer = new ArrayBuffer(8);
|
|
66
|
-
transport.send(buffer);
|
|
67
|
-
|
|
68
|
-
expect(messageCallback).toHaveBeenCalledTimes(1);
|
|
69
|
-
expect(messageCallback).toHaveBeenCalledWith(
|
|
70
|
-
expect.objectContaining({
|
|
71
|
-
data: buffer,
|
|
72
|
-
}),
|
|
73
|
-
);
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
describe("addEventListener", () => {
|
|
78
|
-
it("should add open event listener and call it immediately", () => {
|
|
79
|
-
const transport = BasicTransport.empty();
|
|
80
|
-
const callback = vi.fn();
|
|
81
|
-
|
|
82
|
-
transport.addEventListener("open", callback);
|
|
83
|
-
|
|
84
|
-
expect(callback).toHaveBeenCalledTimes(1);
|
|
85
|
-
expect(callback).toHaveBeenCalledWith(expect.any(Event));
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it("should add message event listener and start producer", () => {
|
|
89
|
-
const producer = vi.fn();
|
|
90
|
-
const transport = BasicTransport.withProducerCallback(producer);
|
|
91
|
-
const callback = vi.fn();
|
|
92
|
-
|
|
93
|
-
transport.addEventListener("message", callback);
|
|
94
|
-
|
|
95
|
-
// Producer should be called once
|
|
96
|
-
expect(producer).toHaveBeenCalledTimes(1);
|
|
97
|
-
expect(producer).toHaveBeenCalledWith(expect.any(Function));
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
describe("removeEventListener", () => {
|
|
102
|
-
it("should remove event listener", async () => {
|
|
103
|
-
const transport = BasicTransport.empty();
|
|
104
|
-
const callback = vi.fn();
|
|
105
|
-
|
|
106
|
-
transport.addEventListener("message", callback);
|
|
107
|
-
transport.removeEventListener("message", callback);
|
|
108
|
-
|
|
109
|
-
transport.send("test");
|
|
110
|
-
|
|
111
|
-
expect(callback).not.toHaveBeenCalled();
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
it("should only remove the specific listener", () => {
|
|
115
|
-
const transport = BasicTransport.empty();
|
|
116
|
-
const callback1 = vi.fn();
|
|
117
|
-
const callback2 = vi.fn();
|
|
118
|
-
|
|
119
|
-
transport.addEventListener("close", callback1);
|
|
120
|
-
transport.addEventListener("close", callback2);
|
|
121
|
-
|
|
122
|
-
transport.removeEventListener("close", callback1);
|
|
123
|
-
|
|
124
|
-
transport.close();
|
|
125
|
-
|
|
126
|
-
expect(callback1).not.toHaveBeenCalled();
|
|
127
|
-
expect(callback2).toHaveBeenCalledTimes(1);
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
describe("Producer functionality", () => {
|
|
132
|
-
it("should pass producer callback that triggers message events", () => {
|
|
133
|
-
let producerCallback: ((message: MessageEvent) => void) | undefined;
|
|
134
|
-
const producer = vi.fn((callback) => {
|
|
135
|
-
producerCallback = callback;
|
|
136
|
-
});
|
|
137
|
-
const transport = BasicTransport.withProducerCallback(producer);
|
|
138
|
-
const messageCallback = vi.fn();
|
|
139
|
-
|
|
140
|
-
transport.addEventListener("message", messageCallback);
|
|
141
|
-
|
|
142
|
-
expect(producerCallback).toBeDefined();
|
|
143
|
-
|
|
144
|
-
const testMessage = new MessageEvent("message", { data: "test" });
|
|
145
|
-
producerCallback?.(testMessage);
|
|
146
|
-
|
|
147
|
-
expect(messageCallback).toHaveBeenCalledWith(testMessage);
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it("should handle multiple messages from producer", () => {
|
|
151
|
-
let producerCallback: ((message: MessageEvent) => void) | undefined;
|
|
152
|
-
const producer = vi.fn((callback) => {
|
|
153
|
-
producerCallback = callback;
|
|
154
|
-
});
|
|
155
|
-
const transport = BasicTransport.withProducerCallback(producer);
|
|
156
|
-
const messageCallback = vi.fn();
|
|
157
|
-
|
|
158
|
-
transport.addEventListener("message", messageCallback);
|
|
159
|
-
|
|
160
|
-
producerCallback?.(new MessageEvent("message", { data: "msg1" }));
|
|
161
|
-
producerCallback?.(new MessageEvent("message", { data: "msg2" }));
|
|
162
|
-
producerCallback?.(new MessageEvent("message", { data: "msg3" }));
|
|
163
|
-
|
|
164
|
-
expect(messageCallback).toHaveBeenCalledTimes(3);
|
|
165
|
-
expect(messageCallback).toHaveBeenNthCalledWith(
|
|
166
|
-
1,
|
|
167
|
-
expect.objectContaining({ data: "msg1" }),
|
|
168
|
-
);
|
|
169
|
-
expect(messageCallback).toHaveBeenNthCalledWith(
|
|
170
|
-
2,
|
|
171
|
-
expect.objectContaining({ data: "msg2" }),
|
|
172
|
-
);
|
|
173
|
-
expect(messageCallback).toHaveBeenNthCalledWith(
|
|
174
|
-
3,
|
|
175
|
-
expect.objectContaining({ data: "msg3" }),
|
|
176
|
-
);
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
it("should not start producer if no message listener is added", () => {
|
|
180
|
-
const producer = vi.fn();
|
|
181
|
-
const transport = BasicTransport.withProducerCallback(producer);
|
|
182
|
-
|
|
183
|
-
transport.addEventListener("open", vi.fn());
|
|
184
|
-
transport.addEventListener("close", vi.fn());
|
|
185
|
-
|
|
186
|
-
expect(producer).not.toHaveBeenCalled();
|
|
187
|
-
});
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
describe("Integration scenarios", () => {
|
|
191
|
-
it("should handle complete connection lifecycle", async () => {
|
|
192
|
-
const transport = BasicTransport.empty();
|
|
193
|
-
const openCallback = vi.fn();
|
|
194
|
-
const closeCallback = vi.fn();
|
|
195
|
-
|
|
196
|
-
transport.addEventListener("open", openCallback);
|
|
197
|
-
transport.addEventListener("close", closeCallback);
|
|
198
|
-
|
|
199
|
-
expect(openCallback).toHaveBeenCalledTimes(1);
|
|
200
|
-
|
|
201
|
-
transport.reconnect();
|
|
202
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
203
|
-
expect(openCallback).toHaveBeenCalledTimes(2);
|
|
204
|
-
expect(closeCallback).toHaveBeenCalledTimes(1);
|
|
205
|
-
|
|
206
|
-
transport.close();
|
|
207
|
-
expect(closeCallback).toHaveBeenCalledTimes(2);
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
it("should handle send and receive flow", async () => {
|
|
211
|
-
let producerCallback: ((message: MessageEvent) => void) | undefined;
|
|
212
|
-
const producer = vi.fn((callback) => {
|
|
213
|
-
producerCallback = callback;
|
|
214
|
-
});
|
|
215
|
-
const transport = BasicTransport.withProducerCallback(producer);
|
|
216
|
-
const messageCallback = vi.fn();
|
|
217
|
-
|
|
218
|
-
transport.addEventListener("message", messageCallback);
|
|
219
|
-
|
|
220
|
-
transport.send("outgoing");
|
|
221
|
-
expect(messageCallback).toHaveBeenCalledWith(
|
|
222
|
-
expect.objectContaining({ data: "outgoing" }),
|
|
223
|
-
);
|
|
224
|
-
|
|
225
|
-
messageCallback.mockClear();
|
|
226
|
-
|
|
227
|
-
producerCallback?.(new MessageEvent("message", { data: "incoming" }));
|
|
228
|
-
expect(messageCallback).toHaveBeenCalledWith(
|
|
229
|
-
expect.objectContaining({ data: "incoming" }),
|
|
230
|
-
);
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
it("should maintain separate event queues for different event types", async () => {
|
|
234
|
-
const transport = BasicTransport.empty();
|
|
235
|
-
const openCallback = vi.fn();
|
|
236
|
-
const closeCallback = vi.fn();
|
|
237
|
-
const messageCallback = vi.fn();
|
|
238
|
-
|
|
239
|
-
transport.addEventListener("open", openCallback);
|
|
240
|
-
transport.addEventListener("close", closeCallback);
|
|
241
|
-
transport.addEventListener("message", messageCallback);
|
|
242
|
-
|
|
243
|
-
openCallback.mockClear();
|
|
244
|
-
|
|
245
|
-
transport.reconnect();
|
|
246
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
247
|
-
transport.send("test");
|
|
248
|
-
transport.close();
|
|
249
|
-
|
|
250
|
-
expect(openCallback).toHaveBeenCalledTimes(1);
|
|
251
|
-
expect(messageCallback).toHaveBeenCalledTimes(1);
|
|
252
|
-
expect(closeCallback).toHaveBeenCalledTimes(2);
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
it("should handle rapid reconnections", async () => {
|
|
256
|
-
const transport = BasicTransport.empty();
|
|
257
|
-
const openCallback = vi.fn();
|
|
258
|
-
const closeCallback = vi.fn();
|
|
259
|
-
|
|
260
|
-
transport.addEventListener("open", openCallback);
|
|
261
|
-
transport.addEventListener("close", closeCallback);
|
|
262
|
-
|
|
263
|
-
openCallback.mockClear();
|
|
264
|
-
|
|
265
|
-
transport.reconnect();
|
|
266
|
-
transport.reconnect();
|
|
267
|
-
transport.reconnect();
|
|
268
|
-
|
|
269
|
-
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
270
|
-
|
|
271
|
-
expect(closeCallback).toHaveBeenCalledTimes(3);
|
|
272
|
-
expect(openCallback).toHaveBeenCalledTimes(3);
|
|
273
|
-
});
|
|
274
|
-
});
|
|
275
|
-
});
|