Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@sanity/comlink

Package Overview
Dependencies
Maintainers
56
Versions
92
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@sanity/comlink - npm Package Compare versions

Comparing version 0.0.1 to 0.0.2-canary.0

2

dist/index.js

@@ -1,1 +0,1 @@

import{v4 as e}from"uuid";import{fromEventObservable as t,setup as s,sendParent as n,assign as a,fromCallback as r,enqueueActions as o,assertEvent as c,raise as i,createActor as d,emit as u}from"xstate";import{defer as p,fromEvent as l,filter as g,map as m,pipe as h,bufferCount as f,concatMap as y,take as b}from"rxjs";const v=(e=[],t={})=>({context:s})=>{const{count:n,matches:a=!0,responseType:r="message.received"}=t;return{count:n,domain:s.domain,from:s.connectTo,matches:a,responseType:r,target:s.target,to:s.name,type:e}},q=p((()=>l(window,"message"))),x=t((({input:e})=>{return q.pipe(g((e=>t=>{const{data:s}=t,n=Array.isArray(e.type)?e.type:[e.type];return(e.matches?n.includes(s.type):!n.includes(s.type))&&s.domain===e.domain&&s.from===e.from&&s.to===e.to&&(!e.target||t.source===e.target)})(e)),m((t=e.responseType,e=>({type:t,message:e}))),e.count?h(f(e.count),y((e=>e)),b(e.count)):h());var t})),k="sanity/channels",T="channel/response",E="channel/heartbeat",I="channel/disconnect",S="channel/handshake/syn",w="channel/handshake/syn-ack",R="channel/handshake/ack",$=()=>s({types:{},actors:{listen:t((({input:e})=>l(window,"message").pipe(g((t=>t.data.type===T&&t.data.responseTo===e.requestId&&!!t.source&&e.sources.has(t.source))),b(e.sources.size))))},actions:{"send message":({context:e},t)=>{const{sources:s,origin:n}=e,{message:a}=t;s.forEach((e=>{e.postMessage(a,{targetOrigin:n})}))},"on success":n((({context:e,self:t})=>(e.response&&e.resolvable?.resolve(e.response),{type:"request.success",requestId:t.id,response:e.response,responseTo:e.responseTo}))),"on fail":n((({context:e,self:t})=>(console.warn(`Received no response to message '${e.type}' on client '${e.from}' (ID: '${e.id}').`),e.resolvable?.reject(new Error("No response received")),{type:"request.failed",requestId:t.id})))},guards:{expectsResponse:({context:e})=>e.expectResponse},delays:{initialTimeout:0,responseTimeout:1e3}}).createMachine({context:({input:t})=>({connectionId:t.connectionId,data:t.data,domain:t.domain,expectResponse:t.expectResponse??!1,from:t.from,id:`msg-${e()}`,origin:t.origin,resolvable:t.resolvable,response:null,responseTo:t.responseTo,sources:"size"in t.sources?t.sources:new Set([t.sources]),to:t.to,type:t.type}),initial:"idle",states:{idle:{after:{initialTimeout:"sending"}},sending:{entry:{type:"send message",params:({context:e})=>{const{connectionId:t,data:s,domain:n,from:a,id:r,responseTo:o,to:c,type:i}=e;return{message:{connectionId:t,data:s,domain:n,from:a,id:r,to:c,type:i,responseTo:o}}}},always:[{guard:"expectsResponse",target:"awaiting"},"success"]},awaiting:{invoke:{src:"listen",input:({context:e})=>({requestId:e.id,sources:e.sources})},after:{responseTimeout:"failed"},on:{message:{actions:a({response:({event:e})=>e.data.data,responseTo:({event:e})=>e.data.responseTo}),target:"success"}}},failed:{type:"final",entry:"on fail"},success:{type:"final",entry:"on success"}},output:({context:e,self:t})=>({requestId:t.id,response:e.response,responseTo:e.responseTo})}),A=r((({sendBack:e,input:t})=>{const s=()=>{e(t.event)};t.immediate&&s();const n=setInterval(s,t.interval);return()=>{clearInterval(n)}})),M=()=>s({types:{},actors:{requestMachine:$(),listen:x,sendBackAtInterval:A},actions:{"buffer message":o((({enqueue:e})=>{e.assign({buffer:({event:e,context:t})=>(c(e,"post"),[...t.buffer,e.data])}),e.emit((({event:e})=>(c(e,"post"),{type:"_buffer.added",message:e.data})))})),"create request":a({requests:({context:t,event:s,spawn:n})=>{c(s,"request");const a=(Array.isArray(s.data)?s.data:[s.data]).map((s=>{const a=`req-${e()}`;return n("requestMachine",{id:a,input:{connectionId:t.connectionId,data:s.data,domain:t.domain,expectResponse:s.expectResponse,from:t.name,origin:t.origin,responseTo:s.responseTo,sources:t.target,to:t.connectTo,type:s.type}})}));return[...t.requests,...a]}}),"emit received message":o((({enqueue:e})=>{e.emit((({event:e})=>(c(e,"message.received"),{type:"_message",message:e.message.data}))),e.emit((({event:e})=>(c(e,"message.received"),{type:e.message.data.type,message:e.message.data})))})),"flush buffer":o((({enqueue:e})=>{e.raise((({context:e})=>({type:"request",data:e.buffer.map((({data:e,type:t})=>({data:e,type:t})))}))),e.emit((({context:e})=>({type:"_buffer.flushed",messages:e.buffer}))),e.assign({buffer:[]})})),post:i((({event:e})=>(c(e,"post"),{type:"request",data:{data:e.data.data,expectResponse:!0,type:e.data.type}}))),"remove request":a({requests:({context:e,event:t})=>(c(t,["request.success","request.failed"]),e.requests.filter((e=>e.id!==t.requestId)))}),respond:i((({event:e})=>(c(e,"response"),{type:"request",data:{data:e.data,type:T,responseTo:e.respondTo}}))),"send handshake ack":i({type:"request",data:{type:R}}),"send disconnect":i((()=>({type:"request",data:{type:I}}))),"send handshake syn":i({type:"request",data:{type:S}}),"set target":a({target:({event:e})=>(c(e,"target.set"),e.target)})},guards:{"has target":({context:e})=>!!e.target,"should send heartbeats":({context:e})=>e.heartbeat}}).createMachine({id:"channel",context:({input:t})=>({id:t.id||`${t.name}-${e()}`,buffer:[],connectionId:`cnx-${e()}`,connectTo:t.connectTo,domain:t.domain??k,heartbeat:t.heartbeat??!1,name:t.name,origin:t.origin,requests:[],target:t.target}),on:{"target.set":{actions:"set target"},"request.success":{actions:"remove request"},"request.failed":{actions:"remove request"}},initial:"idle",states:{idle:{on:{connect:{target:"handshaking",guard:"has target"},post:{actions:"buffer message"}}},handshaking:{invoke:[{src:"sendBackAtInterval",id:"sendSyn",input:()=>({event:{type:"syn"},interval:500,immediate:!0})},{src:"listen",input:e=>v(w,{count:1})(e)}],on:{syn:{actions:"send handshake syn"},request:{actions:"create request"},post:{actions:"buffer message"},"message.received":{target:"connected"},disconnect:{target:"disconnected"}},exit:"send handshake ack"},connected:{entry:"flush buffer",invoke:{src:"listen",input:v([T,E],{matches:!1})},on:{post:{actions:"post"},request:{actions:"create request"},response:{actions:"respond"},"message.received":{actions:"emit received message"},disconnect:{target:"disconnected"}},initial:"heartbeat",states:{heartbeat:{initial:"checking",states:{checking:{always:{guard:"should send heartbeats",target:"sending"}},sending:{on:{"request.failed":{target:"#disconnected"}},invoke:{src:"sendBackAtInterval",id:"sendHeartbeat",input:()=>({event:{type:"post",data:{type:E,data:void 0}},interval:2e3,immediate:!1})}}}}}},disconnected:{id:"disconnected",entry:"send disconnect",on:{request:{actions:"create request"},post:{actions:"buffer message"},connect:{target:"handshaking",guard:"has target"}}}}}),_=t=>{const s=M(),n=t.id||`${t.name}-${e()}`,a=d(s,{input:{...t,id:n}}),r=()=>{a.stop()};return{actor:a,connect:()=>{a.send({type:"connect"})},disconnect:()=>{a.send({type:"disconnect"})},id:n,name:t.name,machine:s,on:(e,t)=>{const{unsubscribe:s}=a.on(e,(e=>{const s=t(e.message.data);s&&a.send({type:"response",respondTo:e.message.id,data:s})}));return s},onStatus:e=>{const t=a.getSnapshot();let s="string"==typeof t.value?t.value:Object.keys(t.value)[0];const{unsubscribe:n}=a.subscribe((t=>{const n="string"==typeof t.value?t.value:Object.keys(t.value)[0];s!==n&&(s=n,e(n))}));return n},post:e=>{a.send({type:"post",data:e})},setTarget:e=>{a.send({type:"target.set",target:e})},start:()=>(a.start(),r),stop:r,get target(){return a.getSnapshot().context.target}}},j=()=>{},F=()=>{const e=new Set,t=new Set,s=e=>{e.disconnect(),setTimeout((()=>{e.stop()}),0)};return{addTarget:n=>{if(e.has(n))return j;if(!e.size||!t.size)return e.add(n),t.forEach((e=>{e.channels.forEach((e=>{e.setTarget(n),e.connect()}))})),()=>{e.delete(n),t.forEach((e=>{e.channels.forEach((e=>{e.target===n&&e.disconnect()}))}))};e.add(n);const a=new Set;return t.forEach((e=>{const t=_({...e.input,target:n});a.add(t),e.channels.add(t),e.subscribers.forEach((({type:e,handler:s,unsubscribers:n})=>{n.push(t.on(e,s))})),e.internalEventSubscribers.forEach((({type:e,handler:s,unsubscribers:n})=>{n.push(t.actor.on(e,s).unsubscribe)})),e.statusSubscribers.forEach((({handler:e,unsubscribers:s})=>{s.push(t.onStatus((s=>e({channel:t.id,status:s}))))})),t.start(),t.connect()})),()=>{e.delete(n),a.forEach((e=>{s(e),t.forEach((t=>{t.channels.delete(e)}))}))}},createConnection:s=>{const n={input:s,channels:new Set,internalEventSubscribers:new Set,statusSubscribers:new Set,subscribers:new Set};t.add(n);const{channels:a,internalEventSubscribers:r,statusSubscribers:o,subscribers:c}=n;if(e.size)e.forEach((e=>{const t=_({...s,target:e});a.add(t)}));else{const e=_(s);a.add(e)}const i=()=>{a.forEach((e=>{e.stop()}))},d=()=>{a.forEach((e=>{e.disconnect()}))};return{connect:()=>(a.forEach((e=>{e.connect()})),d),disconnect:d,on:(e,t)=>{const s=[];a.forEach((n=>{s.push(n.on(e,t))}));const n={type:e,handler:t,unsubscribers:s};return c.add(n),()=>{s.forEach((e=>e())),c.delete(n)}},onStatus:e=>{const t=[];a.forEach((s=>{t.push(s.onStatus((t=>e({channel:s.id,status:t}))))}));const s={handler:e,unsubscribers:t};return o.add(s),()=>{t.forEach((e=>e())),o.delete(s)}},onInternalEvent:(e,t)=>{const s=[];a.forEach((n=>{s.push(n.actor.on(e,t).unsubscribe)}));const n={type:e,handler:t,unsubscribers:s};return r.add(n),()=>{s.forEach((e=>e())),r.delete(n)}},post:e=>{a.forEach((t=>{t.post(e)}))},start:()=>(a.forEach((e=>{e.start()})),i),stop:i}},destroy:()=>{t.forEach((({channels:e})=>{e.forEach((t=>{s(t),e.delete(t)}))}))}}},z=()=>s({types:{},actors:{requestMachine:$(),listen:x},actions:{"buffer message":o((({enqueue:e})=>{e.assign({buffer:({event:e,context:t})=>(c(e,"post"),[...t.buffer,{data:e.data,resolvable:e.resolvable}])}),e.emit((({event:e})=>(c(e,"post"),{type:"_buffer.added",message:e.data})))})),"create request":a({requests:({context:t,event:s,spawn:n})=>{c(s,"request");const a=(Array.isArray(s.data)?s.data:[s.data]).map((s=>{const a=`req-${e()}`;return n("requestMachine",{id:a,input:{connectionId:t.connectionId,data:s.data,domain:t.domain,expectResponse:s.expectResponse,from:t.name,origin:t.origin,resolvable:s.resolvable,responseTo:s.responseTo,sources:t.target,to:t.connectTo,type:s.type}})}));return[...t.requests,...a]}}),"emit heartbeat":u((()=>({type:"_heartbeat"}))),"emit received message":o((({enqueue:e})=>{e.emit((({event:e})=>(c(e,"message.received"),{type:"_message",message:e.message.data}))),e.emit((({event:e})=>(c(e,"message.received"),{type:e.message.data.type,message:e.message.data})))})),"flush buffer":o((({enqueue:e})=>{e.raise((({context:e})=>({type:"request",data:e.buffer.map((({data:e,resolvable:t})=>({data:e.data,type:e.type,expectResponse:!!t,resolvable:t})))}))),e.emit((({context:e})=>({type:"_buffer.flushed",messages:e.buffer.map((({data:e})=>e))}))),e.assign({buffer:[]})})),post:i((({event:e})=>(c(e,"post"),{type:"request",data:{data:e.data.data,expectResponse:!!e.resolvable,type:e.data.type,resolvable:e.resolvable}}))),"remove request":a({requests:({context:e,event:t})=>(c(t,["request.success","request.failed"]),e.requests.filter((e=>e.id!==t.requestId)))}),"send response":i((({event:e})=>(c(e,["message.received","heartbeat.received"]),{type:"request",data:{type:T,responseTo:e.message.data.id,data:void 0}}))),"send handshake syn ack":i({type:"request",data:{type:w}}),"set connection config":a({connectionId:({event:e})=>(c(e,"message.received"),e.message.data.connectionId),target:({event:e})=>(c(e,"message.received"),e.message.source||void 0),origin:({event:e})=>(c(e,"message.received"),e.message.origin)})},guards:{hasSource:({context:e})=>null!==e.target}}).createMachine({id:"node",context:({input:e})=>({buffer:[],connectionId:null,connectTo:e.connectTo,domain:e.domain??k,name:e.name,origin:null,requests:[],target:void 0}),on:{"request.success":{actions:"remove request"},"request.failed":{actions:"remove request"}},initial:"idle",states:{idle:{invoke:{src:"listen",id:"listenForHandshakeSyn",input:v(S,{count:1}),onDone:{target:"handshaking",guard:"hasSource"}},on:{"message.received":{actions:"set connection config"},post:{actions:"buffer message"}}},handshaking:{entry:"send handshake syn ack",invoke:[{src:"listen",id:"listenForHandshakeAck",input:v(R,{count:1}),onDone:"connected"},{src:"listen",id:"listenForDisconnect",input:v([I],{count:1,responseType:"disconnect"})}],on:{request:{actions:"create request"},post:{actions:"buffer message"},disconnect:{target:"idle"}}},connected:{entry:"flush buffer",invoke:[{src:"listen",id:"listenForMessages",input:v([T,E],{matches:!1})},{src:"listen",id:"listenForHeartbeats",input:v([E],{responseType:"heartbeat.received"})},{src:"listen",id:"listenForDisconnect",input:v([I],{count:1,responseType:"disconnect"})}],on:{request:{actions:"create request"},post:{actions:"post"},disconnect:{target:"idle"},"message.received":{actions:["send response","emit received message"]},"heartbeat.received":{actions:["send response","emit heartbeat"]}}}}}),D=e=>{const t=z(),s=d(t,{input:e}),n=()=>{s.stop()};return{actor:s,fetch:e=>{const t=Promise.withResolvers();return s.send({type:"post",data:e,resolvable:t}),t.promise},machine:t,on:(e,t)=>{const{unsubscribe:n}=s.on(e,(e=>{t(e.message.data)}));return n},onStatus:e=>{const t=s.getSnapshot();let n="string"==typeof t.value?t.value:Object.keys(t.value)[0];const{unsubscribe:a}=s.subscribe((t=>{const s="string"==typeof t.value?t.value:Object.keys(t.value)[0];n!==s&&(n=s,e(s))}));return a},post:e=>{s.send({type:"post",data:e})},start:()=>(s.start(),n),stop:n}};export{E as MSG_HEARTBEAT,T as MSG_RESPONSE,_ as createChannel,M as createChannelMachine,F as createController,D as createNode,z as createNodeMachine,$ as createRequestMachine};//# sourceMappingURL=index.js.map
import{v4 as e}from"uuid";import{fromEventObservable as t,setup as s,sendTo as n,assign as a,fromCallback as r,enqueueActions as o,assertEvent as c,raise as i,stopChild as d,createActor as u,emit as p}from"xstate";import{defer as l,fromEvent as g,map as f,pipe as m,filter as h,bufferCount as b,concatMap as y,take as v,EMPTY as q,takeUntil as k}from"rxjs";const x=e=>({context:t})=>{const{count:s,include:n,exclude:a,responseType:r="message.received"}=e;return{count:s,domain:t.domain,from:t.connectTo,include:n?Array.isArray(n)?n:[n]:[],exclude:a?Array.isArray(a)?a:[a]:[],responseType:r,target:t.target,to:t.name}},T=l((()=>g(window,"message"))),E=e=>t((({input:t})=>{return T.pipe(e?f(e):m(),h((e=>t=>{const{data:s}=t;return(!e.include.length||e.include.includes(s.type))&&(!e.exclude.length||!e.exclude.includes(s.type))&&s.domain===e.domain&&s.from===e.from&&s.to===e.to&&(!e.target||t.source===e.target)})(t)),f((s=t.responseType,e=>({type:s,message:e}))),t.count?m(b(t.count),y((e=>e)),v(t.count)):m());var s})),I="sanity/comlink",w=1e3,S=1e3,R=500,O="comlink/response",$="comlink/heartbeat",A="comlink/disconnect",B="comlink/handshake/syn",M="comlink/handshake/syn-ack",j="comlink/handshake/ack",_=[B,M,j],z=[O,A,$,..._],D=()=>s({types:{},actors:{listen:t((({input:e})=>{const t=e.signal?g(e.signal,"abort").pipe((s=`Request ${e.requestId} aborted`,e=>e.pipe(v(1),f((()=>{throw new Error(s)}))))):q;var s;return g(window,"message").pipe(h((t=>t.data?.type===O&&t.data?.responseTo===e.requestId&&!!t.source&&e.sources.has(t.source))),v(e.sources.size),k(t))}))},actions:{"send message":({context:e},t)=>{const{sources:s,targetOrigin:n}=e,{message:a}=t;s.forEach((e=>{e.postMessage(a,{targetOrigin:n})}))},"on success":n((({context:e})=>e.parentRef),(({context:e,self:t})=>(e.response&&e.resolvable?.resolve(e.response),{type:"request.success",requestId:t.id,response:e.response,responseTo:e.responseTo}))),"on fail":n((({context:e})=>e.parentRef),(({context:e,self:t})=>(console.warn(`Received no response to message '${e.type}' on client '${e.from}' (ID: '${e.id}').`),e.resolvable?.reject(new Error("No response received")),{type:"request.failed",requestId:t.id}))),"on abort":n((({context:e})=>e.parentRef),(({context:e,self:t})=>(e.resolvable?.reject(new Error("Request aborted")),{type:"request.aborted",requestId:t.id})))},guards:{expectsResponse:({context:e})=>e.expectResponse},delays:{initialTimeout:0,responseTimeout:1e3}}).createMachine({context:({input:t})=>({connectionId:t.connectionId,data:t.data,domain:t.domain,expectResponse:t.expectResponse??!1,from:t.from,id:`msg-${e()}`,parentRef:t.parentRef,resolvable:t.resolvable,response:null,responseTo:t.responseTo,signal:t.signal,sources:t.sources instanceof Set?t.sources:new Set([t.sources]),targetOrigin:t.targetOrigin,to:t.to,type:t.type}),initial:"idle",on:{abort:".aborted"},states:{idle:{after:{initialTimeout:[{target:"sending"}]}},sending:{entry:{type:"send message",params:({context:e})=>{const{connectionId:t,data:s,domain:n,from:a,id:r,responseTo:o,to:c,type:i}=e;return{message:{connectionId:t,data:s,domain:n,from:a,id:r,to:c,type:i,responseTo:o}}}},always:[{guard:"expectsResponse",target:"awaiting"},"success"]},awaiting:{invoke:{id:"listen for response",src:"listen",input:({context:e})=>({requestId:e.id,sources:e.sources,signal:e.signal}),onError:"aborted"},after:{responseTimeout:"failed"},on:{message:{actions:a({response:({event:e})=>e.data.data,responseTo:({event:e})=>e.data.responseTo}),target:"success"}}},failed:{type:"final",entry:"on fail"},success:{type:"final",entry:"on success"},aborted:{type:"final",entry:"on abort"}},output:({context:e,self:t})=>({requestId:t.id,response:e.response,responseTo:e.responseTo})}),C=r((({sendBack:e,input:t})=>{const s=()=>{e(t.event)};t.immediate&&s();const n=setInterval(s,t.interval);return()=>{clearInterval(n)}})),N=()=>s({types:{},actors:{requestMachine:D(),listen:E(),sendBackAtInterval:C},actions:{"buffer message":o((({enqueue:e})=>{e.assign({buffer:({event:e,context:t})=>(c(e,"post"),[...t.buffer,e.data])}),e.emit((({event:e})=>(c(e,"post"),{type:"_buffer.added",message:e.data})))})),"create request":a({requests:({context:t,event:s,self:n,spawn:a})=>{c(s,"request");const r=(Array.isArray(s.data)?s.data:[s.data]).map((s=>{const r=`req-${e()}`;return a("requestMachine",{id:r,input:{connectionId:t.connectionId,data:s.data,domain:t.domain,expectResponse:s.expectResponse,from:t.name,parentRef:n,responseTo:s.responseTo,sources:t.target,targetOrigin:t.targetOrigin,to:t.connectTo,type:s.type}})}));return[...t.requests,...r]}}),"emit received message":o((({enqueue:e})=>{e.emit((({event:e})=>(c(e,"message.received"),{type:"_message",message:e.message.data}))),e.emit((({event:e})=>(c(e,"message.received"),{type:e.message.data.type,message:e.message.data})))})),"flush buffer":o((({enqueue:e})=>{e.raise((({context:e})=>({type:"request",data:e.buffer.map((({data:e,type:t})=>({data:e,type:t})))}))),e.emit((({context:e})=>({type:"_buffer.flushed",messages:e.buffer}))),e.assign({buffer:[]})})),post:i((({event:e})=>(c(e,"post"),{type:"request",data:{data:e.data.data,expectResponse:!0,type:e.data.type}}))),"remove request":o((({context:e,enqueue:t,event:s})=>{c(s,["request.success","request.failed","request.aborted"]),d(s.requestId),t.assign({requests:e.requests.filter((({id:e})=>e!==s.requestId))})})),respond:i((({event:e})=>(c(e,"response"),{type:"request",data:{data:e.data,type:O,responseTo:e.respondTo}}))),"send handshake ack":i({type:"request",data:{type:j}}),"send disconnect":i((()=>({type:"request",data:{type:A}}))),"send handshake syn":i({type:"request",data:{type:B}}),"set target":a({target:({event:e})=>(c(e,"target.set"),e.target)})},guards:{"has target":({context:e})=>!!e.target,"should send heartbeats":({context:e})=>e.heartbeat}}).createMachine({id:"channel",context:({input:t})=>({id:t.id||`${t.name}-${e()}`,buffer:[],connectionId:`cnx-${e()}`,connectTo:t.connectTo,domain:t.domain??I,heartbeat:t.heartbeat??!1,name:t.name,requests:[],target:t.target,targetOrigin:t.targetOrigin}),on:{"target.set":{actions:"set target"},"request.success":{actions:"remove request"},"request.failed":{actions:"remove request"}},initial:"idle",states:{idle:{on:{connect:{target:"handshaking",guard:"has target"},post:{actions:"buffer message"}}},handshaking:{invoke:[{id:"send syn",src:"sendBackAtInterval",input:()=>({event:{type:"syn"},interval:500,immediate:!0})},{id:"listen for handshake",src:"listen",input:e=>x({include:M,count:1})(e)}],on:{syn:{actions:"send handshake syn"},request:{actions:"create request"},post:{actions:"buffer message"},"message.received":{target:"connected"},disconnect:{target:"disconnected"}},exit:"send handshake ack"},connected:{entry:"flush buffer",invoke:{id:"listen for messages",src:"listen",input:x({exclude:[O,$]})},on:{post:{actions:"post"},request:{actions:"create request"},response:{actions:"respond"},"message.received":{actions:"emit received message"},disconnect:{target:"disconnected"}},initial:"heartbeat",states:{heartbeat:{initial:"checking",states:{checking:{always:{guard:"should send heartbeats",target:"sending"}},sending:{on:{"request.failed":{target:"#disconnected"}},invoke:{id:"send heartbeat",src:"sendBackAtInterval",input:()=>({event:{type:"post",data:{type:$,data:void 0}},interval:2e3,immediate:!1})}}}}}},disconnected:{id:"disconnected",entry:"send disconnect",on:{request:{actions:"create request"},post:{actions:"buffer message"},connect:{target:"handshaking",guard:"has target"}}}}}),P=(t,s=N())=>{const n=t.id||`${t.name}-${e()}`,a=u(s,{input:{...t,id:n}}),r=()=>{a.stop()};return{actor:a,connect:()=>{a.send({type:"connect"})},disconnect:()=>{a.send({type:"disconnect"})},id:n,name:t.name,machine:s,on:(e,t)=>{const{unsubscribe:s}=a.on(e,(async e=>{const s=await t(e.message.data);s&&a.send({type:"response",respondTo:e.message.id,data:s})}));return s},onStatus:e=>{const t=a.getSnapshot();let s="string"==typeof t.value?t.value:Object.keys(t.value)[0];const{unsubscribe:n}=a.subscribe((t=>{const n="string"==typeof t.value?t.value:Object.keys(t.value)[0];s!==n&&(s=n,e(n))}));return n},post:e=>{a.send({type:"post",data:e})},setTarget:e=>{a.send({type:"target.set",target:e})},start:()=>(a.start(),r),stop:r,get target(){return a.getSnapshot().context.target}}},F=()=>{},G=e=>{const{targetOrigin:t}=e,s=new Set,n=new Set,a=e=>{e.disconnect(),setTimeout((()=>{e.stop()}),0)};return{addTarget:e=>{if(s.has(e))return F;if(!s.size||!n.size)return s.add(e),n.forEach((t=>{t.channels.forEach((t=>{t.setTarget(e),t.connect()}))})),()=>{s.delete(e),n.forEach((t=>{t.channels.forEach((t=>{t.target===e&&t.disconnect()}))}))};s.add(e);const r=new Set;return n.forEach((s=>{const n=P({...s.input,target:e,targetOrigin:t},s.machine);r.add(n),s.channels.add(n),s.subscribers.forEach((({type:e,handler:t,unsubscribers:s})=>{s.push(n.on(e,t))})),s.internalEventSubscribers.forEach((({type:e,handler:t,unsubscribers:s})=>{s.push(n.actor.on(e,t).unsubscribe)})),s.statusSubscribers.forEach((({handler:e,unsubscribers:t})=>{t.push(n.onStatus((t=>e({channel:n.id,status:t}))))})),n.start(),n.connect()})),()=>{s.delete(e),r.forEach((e=>{a(e),n.forEach((t=>{t.channels.delete(e)}))}))}},createConnection:(e,a=N())=>{const r={channels:new Set,input:e,internalEventSubscribers:new Set,machine:a,statusSubscribers:new Set,subscribers:new Set};n.add(r);const{channels:o,internalEventSubscribers:c,statusSubscribers:i,subscribers:d}=r;if(s.size)s.forEach((s=>{const n=P({...e,target:s,targetOrigin:t},a);o.add(n),n.start(),n.connect()}));else{const s=P({...e,targetOrigin:t},a);o.add(s)}const u=()=>{o.forEach((e=>{e.stop()}))},p=()=>{o.forEach((e=>{e.disconnect()}))};return{connect:()=>(o.forEach((e=>{e.connect()})),p),disconnect:p,on:(e,t)=>{const s=[];o.forEach((n=>{s.push(n.on(e,t))}));const n={type:e,handler:t,unsubscribers:s};return d.add(n),()=>{s.forEach((e=>e())),d.delete(n)}},onStatus:e=>{const t=[];o.forEach((s=>{t.push(s.onStatus((t=>e({channel:s.id,status:t}))))}));const s={handler:e,unsubscribers:t};return i.add(s),()=>{t.forEach((e=>e())),i.delete(s)}},onInternalEvent:(e,t)=>{const s=[];o.forEach((n=>{s.push(n.actor.on(e,t).unsubscribe)}));const n={type:e,handler:t,unsubscribers:s};return c.add(n),()=>{s.forEach((e=>e())),c.delete(n)}},post:e=>{o.forEach((t=>{t.post(e)}))},start:()=>(o.forEach((e=>{e.start()})),u),stop:u}},destroy:()=>{n.forEach((({channels:e})=>{e.forEach((t=>{a(t),e.delete(t)}))}))}}},H=()=>s({types:{},actors:{requestMachine:D(),listen:E()},actions:{"buffer incoming message":a({handshakeBuffer:({event:e,context:t})=>(c(e,"message.received"),[...t.handshakeBuffer,e])}),"buffer message":o((({enqueue:e})=>{e.assign({buffer:({event:e,context:t})=>(c(e,"post"),[...t.buffer,{data:e.data,resolvable:e.resolvable,signal:e.signal}])}),e.emit((({event:e})=>(c(e,"post"),{type:"_buffer.added",message:e.data})))})),"create request":a({requests:({context:t,event:s,self:n,spawn:a})=>{c(s,"request");const r=(Array.isArray(s.data)?s.data:[s.data]).map((s=>{const r=`req-${e()}`;return a("requestMachine",{id:r,input:{connectionId:t.connectionId,data:s.data,domain:t.domain,expectResponse:s.expectResponse,from:t.name,parentRef:n,resolvable:s.resolvable,responseTo:s.responseTo,sources:t.target,targetOrigin:t.targetOrigin,to:t.connectTo,type:s.type,signal:s.signal}})}));return[...t.requests,...r]}}),"emit heartbeat":p((()=>({type:"_heartbeat"}))),"emit received message":o((({enqueue:e})=>{e.emit((({event:e})=>(c(e,"message.received"),{type:"_message",message:e.message.data}))),e.emit((({event:e})=>(c(e,"message.received"),{type:e.message.data.type,message:e.message.data})))})),"flush buffer":o((({enqueue:e})=>{e.raise((({context:e})=>({type:"request",data:e.buffer.map((({data:e,resolvable:t,signal:s})=>({data:e.data,type:e.type,expectResponse:!!t,resolvable:t,signal:s})))}))),e.emit((({context:e})=>({type:"_buffer.flushed",messages:e.buffer.map((({data:e})=>e))}))),e.assign({buffer:[]})})),"flush handshake buffer":o((({context:e,enqueue:t})=>{e.handshakeBuffer.forEach((e=>t.raise(e))),t.assign({handshakeBuffer:[]})})),post:i((({event:e})=>(c(e,"post"),{type:"request",data:{data:e.data.data,expectResponse:!!e.resolvable,type:e.data.type,resolvable:e.resolvable,signal:e.signal}}))),"remove request":o((({context:e,enqueue:t,event:s})=>{c(s,["request.success","request.failed","request.aborted"]),d(s.requestId),t.assign({requests:e.requests.filter((({id:e})=>e!==s.requestId))})})),"send response":i((({event:e})=>(c(e,["message.received","heartbeat.received"]),{type:"request",data:{type:O,responseTo:e.message.data.id,data:void 0}}))),"send handshake syn ack":i({type:"request",data:{type:M}}),"set connection config":a({connectionId:({event:e})=>(c(e,"message.received"),e.message.data.connectionId),target:({event:e})=>(c(e,"message.received"),e.message.source||void 0),targetOrigin:({event:e})=>(c(e,"message.received"),e.message.origin)})},guards:{hasSource:({context:e})=>null!==e.target}}).createMachine({id:"node",context:({input:e})=>({buffer:[],connectionId:null,connectTo:e.connectTo,domain:e.domain??I,handshakeBuffer:[],name:e.name,requests:[],target:void 0,targetOrigin:null}),on:{"request.success":{actions:"remove request"},"request.failed":{actions:"remove request"},"request.aborted":{actions:"remove request"}},initial:"idle",states:{idle:{invoke:{id:"listen for handshake syn",src:"listen",input:x({include:B,count:1}),onDone:{target:"handshaking",guard:"hasSource"}},on:{"message.received":{actions:"set connection config"},post:{actions:"buffer message"}}},handshaking:{entry:"send handshake syn ack",invoke:[{id:"listen for handshake ack",src:"listen",input:x({include:j,count:1}),onDone:"connected"},{id:"listen for disconnect",src:"listen",input:x({include:A,count:1,responseType:"disconnect"})},{id:"listen for messages",src:"listen",input:x({exclude:[A,j,$,O]})}],on:{request:{actions:"create request"},post:{actions:"buffer message"},"message.received":{actions:"buffer incoming message"},disconnect:{target:"idle"}}},connected:{entry:["flush handshake buffer","flush buffer"],invoke:[{id:"listen for messages",src:"listen",input:x({exclude:[O,$]})},{id:"listen for heartbeat",src:"listen",input:x({include:$,responseType:"heartbeat.received"})},{id:"listen for disconnect",src:"listen",input:x({include:A,count:1,responseType:"disconnect"})}],on:{request:{actions:"create request"},post:{actions:"post"},disconnect:{target:"idle"},"message.received":{actions:["send response","emit received message"]},"heartbeat.received":{actions:["send response","emit heartbeat"]}}}}}),J=(e,t=H())=>{const s=u(t,{input:e}),n=()=>{s.stop()};return{actor:s,fetch:(e,t)=>{const n=Promise.withResolvers();return s.send({type:"post",data:e,resolvable:n,signal:t?.signal}),n.promise},machine:t,on:(e,t)=>{const{unsubscribe:n}=s.on(e,(e=>{t(e.message.data)}));return n},onStatus:e=>{const t=s.getSnapshot();let n="string"==typeof t.value?t.value:Object.keys(t.value)[0];const{unsubscribe:a}=s.subscribe((t=>{const s="string"==typeof t.value?t.value:Object.keys(t.value)[0];n!==s&&(n=s,e(s))}));return a},post:e=>{s.send({type:"post",data:e})},start:()=>(s.start(),n),stop:n}};export{I as DOMAIN,R as HANDSHAKE_INTERVAL,_ as HANDSHAKE_MSG_TYPES,S as HEARTBEAT_INTERVAL,z as INTERNAL_MSG_TYPES,A as MSG_DISCONNECT,j as MSG_HANDSHAKE_ACK,B as MSG_HANDSHAKE_SYN,M as MSG_HANDSHAKE_SYN_ACK,$ as MSG_HEARTBEAT,O as MSG_RESPONSE,w as RESPONSE_TIMEOUT,P as createChannel,N as createChannelMachine,G as createController,E as createListenLogic,J as createNode,H as createNodeMachine,D as createRequestMachine};//# sourceMappingURL=index.js.map
{
"name": "@sanity/comlink",
"version": "0.0.1",
"version": "0.0.2-canary.0",
"keywords": [

@@ -40,41 +40,5 @@ "sanity.io",

"eslintConfig": {
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 2018,
"sourceType": "module"
},
"plugins": [
"@typescript-eslint",
"simple-import-sort",
"prettier"
],
"extends": [
"eslint:recommended",
"plugin:prettier/recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
"@repo/eslint-config"
],
"rules": {
"no-console": "error",
"no-warning-comments": [
"warn",
{
"location": "start",
"terms": [
"todo",
"@todo",
"fixme"
]
}
],
"@typescript-eslint/explicit-module-boundary-types": "error",
"@typescript-eslint/member-delimiter-style": "off",
"@typescript-eslint/no-empty-interface": "off",
"prettier/prettier": "warn",
"simple-import-sort/exports": "warn",
"simple-import-sort/imports": "warn"
},
"root": true

@@ -88,10 +52,6 @@ },

"devDependencies": {
"@typescript-eslint/eslint-plugin": "^7.18.0",
"@typescript-eslint/parser": "^7.18.0",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-simple-import-sort": "^12.1.1",
"eslint": "^8.57.1",
"typescript": "5.6.2",
"vitest": "^2.0.5",
"vitest": "^2.1.1",
"@repo/eslint-config": "0.0.0",
"@repo/package.config": "0.0.0"

@@ -108,5 +68,5 @@ },

"dev": "pkg build --strict",
"lint": "eslint .",
"lint": "eslint --cache .",
"test": "vitest --pass-with-no-tests --typecheck"
}
}
import {v4 as uuid} from 'uuid'
import {
type ActorRefFrom,
assertEvent,

@@ -8,9 +7,10 @@ assign,

enqueueActions,
type EventObject,
fromCallback,
raise,
setup,
stopChild,
type ActorRefFrom,
type EventObject,
} from 'xstate'
import {listenActor, listenInputFromContext} from './common'
import {createListenLogic, listenInputFromContext} from './common'
import {

@@ -30,7 +30,9 @@ DOMAIN,

BufferFlushedEmitEvent,
Message,
MessageEmitEvent,
ProtocolMessage,
RequestData,
Status,
WithoutResponse,
} from './types'
import type {Message, MessageData, ProtocolMessage} from './types'

@@ -40,2 +42,8 @@ /**

*/
export type ChannelActorLogic<R extends Message, S extends Message> = ReturnType<
typeof createChannelMachine<R, S>
>
/**
* @public
*/
export type ChannelActor<R extends Message, S extends Message> = ActorRefFrom<

@@ -57,5 +65,5 @@ ReturnType<typeof createChannelMachine<R, S>>

type: T,
handler: (event: U['data']) => U['response'],
handler: (event: U['data']) => Promise<U['response']> | U['response'],
) => () => void
onStatus: (handler: (status: string) => void) => () => void
onStatus: (handler: (status: Status) => void) => () => void
post: (data: WithoutResponse<S>) => void

@@ -77,4 +85,4 @@ setTarget: (target: MessageEventSource) => void

id?: string
origin: string
target?: MessageEventSource
targetOrigin: string
}

@@ -112,2 +120,8 @@

types: {} as {
children: {
'listen for handshake': 'listen'
'listen for messages': 'listen'
'send heartbeat': 'sendBackAtInterval'
'send syn': 'sendBackAtInterval'
}
context: {

@@ -121,5 +135,5 @@ buffer: Array<V>

name: string
origin: string
requests: Array<RequestActorRef<S>>
target: MessageEventSource | undefined
targetOrigin: string
}

@@ -137,2 +151,3 @@ emitted:

| {type: 'response'; respondTo: string; data: Pick<S, 'response'>}
| {type: 'request.aborted'; requestId: string}
| {type: 'request.failed'; requestId: string}

@@ -142,3 +157,3 @@ | {

requestId: string
response: MessageData | null
response: S['response'] | null
responseTo: string | undefined

@@ -153,3 +168,3 @@ }

requestMachine: createRequestMachine<S>(),
listen: listenActor,
listen: createListenLogic(),
sendBackAtInterval,

@@ -174,3 +189,3 @@ },

'create request': assign({
requests: ({context, event, spawn}) => {
requests: ({context, event, self, spawn}) => {
assertEvent(event, 'request')

@@ -188,5 +203,6 @@ const arr = Array.isArray(event.data) ? event.data : [event.data]

from: context.name,
origin: context.origin,
parentRef: self,
responseTo: request.responseTo,
sources: context.target!,
targetOrigin: context.targetOrigin,
to: context.connectTo,

@@ -243,7 +259,6 @@ type: request.type,

}),
'remove request': assign({
requests: ({context, event}) => {
assertEvent(event, ['request.success', 'request.failed'])
return context.requests.filter((request) => request.id !== event.requestId)
},
'remove request': enqueueActions(({context, enqueue, event}) => {
assertEvent(event, ['request.success', 'request.failed', 'request.aborted'])
stopChild(event.requestId)
enqueue.assign({requests: context.requests.filter(({id}) => id !== event.requestId)})
}),

@@ -287,3 +302,3 @@ 'respond': raise(({event}) => {

}).createMachine({
/** @xstate-layout N4IgpgJg5mDOIC5QGMAWBDAdpsAbAxLAPYCuATsmAHSxgAuA2gAwC6ioADkbAJZ09FM7EAA9EAdnFMqAJgCs4gBwA2RTMVqAzNoA0IAJ6IZTaQE4mymQBYrc7TYCM4qwF8XetFhwEyYAI4kcHQ0JMiUsLDMbEggXLz8gsJiCM6msppMVuYyznKKTnqGCA4WVLaaDhmmTpma+W4eGNh4+L4BQVQAZug8uJBRwnF8AkIxyeJycmXiOUxODlbKGVaFiA4yDSCezbhUPBB9+MiCOMiMrIPcw4lja3MyVMpWFnLWS6Z1DqspJVTiDio6qZ5DIKqZNttvHsDmB8HFztFOFcEqNQMlFBU-gpFCYZDJTFZFM5vsomGlxMpJnMbMZ6u4tk0oU0ILAMABrHiYKCEfSYAYxIYopJrDLiKiaOQOZTSuTS0lPb6yh4UyaKOSLSUS1z0yF4KjM1noDlc1r+QKwBGXeIjYXFTTWcVWOpWBwfJ1S76LZTi9Yu7Q45TAykQxl6g3sznc+H8pHWm5okUyByyJgVFSEmxO76aQNUNUfcSmKQLJwbHWh3bho2R-AAWzgsHQMCovkoPAAbv0LgLkTbbsVMmkNOo7HjM4pPeYqHN1UTTGpKSqQ14w1gWRGTRAeLBjs0zjHYr346I1oSqK6S9VTE8mIpr98AbLHkTCcoHA51XjweWV7td6c6EgOFuEtHs41RE8EDkJgHkmDV7UsRRbGUb5TDyR5rDVJCJjyTRlx2Kh-zAM4gLac1QNja4IOSKxxE0KhJTQ+072UYtpW+dNz3+f4YOxD4HHwqEiJIiBTVgLhMFoA9BT7BMECyaQFCsUEcnnJZJk0b4KXJAEll9HIiUEvVhMA0T6wiJtqFbMAOy7RFD3A20bEUKhTGBV1r1dRYnBQgxTzxBilA-YEpCYf5tUaX9CJOYjTPwLcdxi-du0ooV+xKdZHmeSk3k0D58gfJNvVJKUqlsPFpSMv8ktM-UwHQMg6AAI3q4I0GI41uWko9qMQe0HjqHIKTqBCYMK6pxXUEtJiLKVlCq6K91q1B6salr0GCWhMC3E0yI6bpejsq0qNtDKHhvHLFjyz5Cspc8ZyeQtaJzOQFoSkzSLNIJusc9LMm9NR8nyedvImB81SmDNlIpKQZEqn8CPemqgOjFKHJOv6nWfCY30qUkcwfCY0lTSowsJSQ3zwhGoSRpbPpMn6MbkmZirc6xnDVQsFnB0oAWcCkshmPEy3pTAiAgOBhF1XBjrSuS8m+dQBrkAt1WgwlZSpyKCP2PpZdkyCiQeAl3IJeQWJWPyfmTJMVFqUECRghaq06-Xj2SX0pjfGZXiQkw5hJJ5ZF0i9M3fBaPogN3eoHXyigysUwpxCY7zyTWI+RiA6oa5rWuj071QfJwxWxW9LGgosFAzums5WnP1ralbkFdsCmcg4wZEKjRAvyd9lMpeHtaEzPs7W1qaDAbbI3z-t1WTTQnXed8woUL4rfWO6k7JJhoNdMm3u3SOZ7ks6speXL8rX+O0O9VXaLVIbKjcNwgA */
/** @xstate-layout N4IgpgJg5mDOIC5QGMAWBDAdpsAbAxAC7oBOMhAdLGIQNoAMAuoqAA4D2sAloV+5ixAAPRAHZRAJgoAWABz0ArHICMy2QGZZCgJwAaEAE9EE+tIrb6ANgkLl46fTuj1AXxf60WHARJgAjgCucJSwAcjIcLAMzEggHNy8-IIiCKLS2hQS6qb2yurisrL6RgjK9LIyCuqq0g7WstZuHhjYePi+gcEUAGboXLiQ0YLxPHwCsSmiCgoykpayDtqS6trqxYjKEk0gnq24FFwQA-jI-DjIdEzDnKNJExuOZpZ12eq29OrSCuupypYUojUaTKCnm5Wk2123gORzA+HilxibBuiXGoBSGnUAIU4gU9FWamUtR+lmUM1EllBEkslMUEnpkJa0JaEFgGAA1lxMFB8LADJghrERqjkhtshk3mTtNo5OpqpYfqCKhTptoqpY1WUtu4dky8BQWWz0Jzue1-EFYIjrgkxqLSupqRRPpoPqJtLI0hIioZENJJE7NnJ8ZYHVk1YyvPrDRyuTyEYLkTa7uixVlMh81KGFhS1j6EPkZlpVjTphr8mkI3sDVhWTHTQBbSLoGAUXwRLgAN0GVyFKNt91KimUFEKXvKC2s9R+6X+jipnzJeSqEJ1UKjNaNJp5EC4sFOrQuCbifeTwg2cgoym0RPxDtqkj0eaB9Ao8zSolMEivZVcq71+33c5CEgeFOCtXskzRM8EDxKRpmkSw3QJbQsmpH5tHmV8JHSbJpDsakV2aSMALOMALhAjoLXAxNbiglI-SxWw1Vw0QNDw0Qfg9KQ7EJSxHHxApK2hQCyOAiAzVgDhMGoI9hX7FMEHSF8cWkelpHURCbBsb481xAEgT9BQJCmWQsiE-URPI8TG1gWBmzAVsyLATtuyRY9ILtWoKmlL82Kqd0tAVJ91LMHFZDKIkVlkNVZHMkiDzE-Adz3UjDx7GiRQHCKnheD53k+HSSkDDIwpBVTqQwuKKEssSDTAUhCAAI3qyg0DIrd8Fkk86MQUMnVM+RynoegTDJH48hGp0vR-FDRqqKqasgOqGua9AQjATAd1NSiul6fpXOtWi7Wy19cslD4vnG7IX3oVjVDUVYEJQqrksW8SdstLqPKy0wKgG1RhtMWogqKhoMjkWp6XxUyFBe3c3tAz70vco6fq+V8PTkGUFzdQqNnELEM2yClrwwzQ4ZShKQJqr7UYU98AS0W9pT4z5pHG0yXwMkNNTyGk3B1TB2AgOBBDXXBDsyhSFG9EovQqN5i1JeRcKqw4Bkl+ToMx8x0j+EaqQ9XMSkBURMgMkEwQWKro2NWNNdPFJAzN0lJGM4slDxhBEJfXyplBd03wW1KxIdnrBxBh4JAyW75C8rJpmDqmIGWkgmpasPjqUcaHooMLHA0uU1UkJOgKW1B6rT1bWor5At0zgcTAkK7hrz1irB0D8cW0UvRPLyv07WqgNq2qAG+l9SnXUz0UOXD5xuMs3Y4+DVJBX7UiKrV6Q8gcfoJO54rFefLLqfJYX1WKYNLxL4NO1NwgA */
id: 'channel',

@@ -298,5 +313,5 @@ context: ({input}) => ({

name: input.name,
origin: input.origin,
requests: [],
target: input.target,
targetOrigin: input.targetOrigin,
}),

@@ -330,4 +345,4 @@ on: {

{
id: 'send syn',
src: 'sendBackAtInterval',
id: 'sendSyn',
input: () => ({

@@ -340,5 +355,7 @@ event: {type: 'syn'},

{
id: 'listen for handshake',
src: 'listen',
input: (input) =>
listenInputFromContext(MSG_HANDSHAKE_SYN_ACK, {
listenInputFromContext({
include: MSG_HANDSHAKE_SYN_ACK,
count: 1,

@@ -377,4 +394,7 @@ })(input),

invoke: {
id: 'listen for messages',
src: 'listen',
input: listenInputFromContext([MSG_RESPONSE, MSG_HEARTBEAT], {matches: false}),
input: listenInputFromContext({
exclude: [MSG_RESPONSE, MSG_HEARTBEAT],
}),
},

@@ -416,4 +436,4 @@ on: {

invoke: {
id: 'send heartbeat',
src: 'sendBackAtInterval',
id: 'sendHeartbeat',
input: () => ({

@@ -457,5 +477,4 @@ event: {type: 'post', data: {type: MSG_HEARTBEAT, data: undefined}},

input: ChannelInput,
machine: ChannelActorLogic<R, S> = createChannelMachine<R, S>(),
): Channel<R, S> => {
const machine = createChannelMachine<R, S>()
const id = input.id || `${input.name}-${uuid()}`

@@ -468,3 +487,3 @@ const actor = createActor(machine, {

type: T,
handler: (event: U['data']) => U['response'],
handler: (event: U['data']) => Promise<U['response']> | U['response'],
) => {

@@ -474,4 +493,4 @@ const {unsubscribe} = actor.on(

type,
(event: {type: T; message: ProtocolMessage<U>}) => {
const response = handler(event.message.data)
async (event: {type: T; message: ProtocolMessage<U>}) => {
const response = await handler(event.message.data)
if (response) {

@@ -493,5 +512,5 @@ actor.send({type: 'response', respondTo: event.message.id, data: response})

const onStatus = (handler: (status: string) => void) => {
const onStatus = (handler: (status: Status) => void) => {
const currentSnapshot = actor.getSnapshot()
let currentStatus: string | undefined =
let currentStatus: Status =
typeof currentSnapshot.value === 'string'

@@ -502,3 +521,4 @@ ? currentSnapshot.value

const {unsubscribe} = actor.subscribe((state) => {
const status = typeof state.value === 'string' ? state.value : Object.keys(state.value)[0]
const status: Status =
typeof state.value === 'string' ? state.value : Object.keys(state.value)[0]
if (currentStatus !== status) {

@@ -505,0 +525,0 @@ currentStatus = status

import {bufferCount, concatMap, defer, filter, fromEvent, map, pipe, take} from 'rxjs'
import {fromEventObservable} from 'xstate'
import type {ListenInput, ProtocolMessage} from './types'

@@ -8,4 +7,16 @@

(
type: string | string[] = [],
options: {matches?: boolean; count?: number; responseType?: string} = {},
config: (
| {
include: string | string[]
exclude?: string | string[]
}
| {
include?: string | string[]
exclude: string | string[]
}
) & {
matches?: boolean
count?: number
responseType?: string
},
) =>

@@ -24,3 +35,3 @@ <

}): ListenInput => {
const {count, matches = true, responseType = 'message.received'} = options
const {count, include, exclude, responseType = 'message.received'} = config
return {

@@ -30,7 +41,7 @@ count,

from: context.connectTo,
matches,
include: include ? (Array.isArray(include) ? include : [include]) : [],
exclude: exclude ? (Array.isArray(exclude) ? exclude : [exclude]) : [],
responseType,
target: context.target,
to: context.name,
type,
}

@@ -43,5 +54,5 @@ }

const {data} = event
const types = Array.isArray(input.type) ? input.type : [input.type]
return (
(input.matches ? types.includes(data.type) : !types.includes(data.type)) &&
(input.include.length ? input.include.includes(data.type) : true) &&
(input.exclude.length ? !input.exclude.includes(data.type) : true) &&
data.domain === input.domain &&

@@ -65,14 +76,22 @@ data.from === input.from &&

export const listenActor = fromEventObservable(({input}: {input: ListenInput}) => {
return messageEvents$.pipe(
filter(listenFilter(input)),
map(eventToMessage(input.responseType)),
input.count
? pipe(
bufferCount(input.count),
concatMap((arr) => arr),
take(input.count),
)
: pipe(),
)
})
/**
* @public
*/
export const createListenLogic = (
compatMap?: (event: MessageEvent<ProtocolMessage>) => MessageEvent<ProtocolMessage>,
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
) =>
fromEventObservable(({input}: {input: ListenInput}) => {
return messageEvents$.pipe(
compatMap ? map(compatMap) : pipe(),
filter(listenFilter(input)),
map(eventToMessage(input.responseType)),
input.count
? pipe(
bufferCount(input.count),
concatMap((arr) => arr),
take(input.count),
)
: pipe(),
)
})
import type {MessageType} from './types'
/** @internal */
export const DOMAIN = 'sanity/channels'
export const DOMAIN = 'sanity/comlink'

@@ -18,3 +18,3 @@ /** @internal */

*/
export const MSG_RESPONSE = 'channel/response'
export const MSG_RESPONSE = 'comlink/response'

@@ -24,15 +24,15 @@ /**

*/
export const MSG_HEARTBEAT = 'channel/heartbeat'
export const MSG_HEARTBEAT = 'comlink/heartbeat'
/** @internal */
export const MSG_DISCONNECT = 'channel/disconnect'
export const MSG_DISCONNECT = 'comlink/disconnect'
/** @internal */
export const MSG_HANDSHAKE_SYN = 'channel/handshake/syn'
export const MSG_HANDSHAKE_SYN = 'comlink/handshake/syn'
/** @internal */
export const MSG_HANDSHAKE_SYN_ACK = 'channel/handshake/syn-ack'
export const MSG_HANDSHAKE_SYN_ACK = 'comlink/handshake/syn-ack'
/** @internal */
export const MSG_HANDSHAKE_ACK = 'channel/handshake/ack'
export const MSG_HANDSHAKE_ACK = 'comlink/handshake/ack'

@@ -39,0 +39,0 @@ /** @internal */

@@ -1,6 +0,18 @@

import {type Channel, type ChannelInput, createChannel} from './channel'
import {type InternalEmitEvent, type Message, type WithoutResponse} from './types'
import {
createChannel,
createChannelMachine,
type Channel,
type ChannelActorLogic,
type ChannelInput,
} from './channel'
import {type InternalEmitEvent, type Message, type StatusEvent, type WithoutResponse} from './types'
export type ConnectionInput = Omit<ChannelInput, 'target'>
/**
* @public
*/
export type ConnectionInput = Omit<ChannelInput, 'target' | 'targetOrigin'>
/**
* @public
*/
export interface ConnectionInstance<R extends Message, S extends Message> {

@@ -11,4 +23,4 @@ connect: () => () => void

type: T,
handler: (event: U['data']) => U['response'],
) => void
handler: (event: U['data']) => Promise<U['response']> | U['response'],
) => () => void
onInternalEvent: <

@@ -20,4 +32,4 @@ T extends InternalEmitEvent<R, S>['type'],

handler: (event: U) => void,
) => void
onStatus: (handler: (event: {channel: string; status: string}) => void) => void
) => () => void
onStatus: (handler: (event: StatusEvent) => void) => void
post: (data: WithoutResponse<S>) => void

@@ -35,2 +47,3 @@ start: () => () => void

input: ConnectionInput,
machine?: ChannelActorLogic<R, S>,
) => ConnectionInstance<R, S>

@@ -52,4 +65,5 @@ destroy: () => void

}>
machine: ChannelActorLogic<R, S>
statusSubscribers: Set<{
handler: (event: {channel: string; status: string}) => void
handler: (event: StatusEvent) => void
unsubscribers: Array<() => void>

@@ -59,3 +73,3 @@ }>

type: R['type']
handler: (event: R['data']) => R['response']
handler: (event: R['data']) => Promise<R['response']> | R['response']
unsubscribers: Array<() => void>

@@ -70,3 +84,4 @@ }>

*/
export const createController = (): Controller => {
export const createController = (input: {targetOrigin: string}): Controller => {
const {targetOrigin} = input
const targets = new Set<MessageEventSource>()

@@ -76,3 +91,3 @@ const connections = new Set<Connection>()

const addTarget = (target: MessageEventSource) => {
// If the target has already been added, return just return a noop cleanup
// If the target has already been added, return just a noop cleanup
if (targets.has(target)) {

@@ -115,6 +130,10 @@ return noop

connections.forEach((connection) => {
const channel = createChannel({
...connection.input,
target,
})
const channel = createChannel(
{
...connection.input,
target,
targetOrigin,
},
connection.machine,
)

@@ -162,8 +181,10 @@ targetChannels.add(channel)

const createConnection = <R extends Message, S extends Message>(
input: ChannelInput,
input: ConnectionInput,
machine: ChannelActorLogic<R, S> = createChannelMachine<R, S>(),
): ConnectionInstance<R, S> => {
const connection: Connection<R, S> = {
channels: new Set(),
input,
channels: new Set(),
internalEventSubscribers: new Set(),
machine,
statusSubscribers: new Set(),

@@ -181,15 +202,21 @@ subscribers: new Set(),

targets.forEach((target) => {
const channel = createChannel<R, S>({
...input,
target,
})
const channel = createChannel<R, S>(
{
...input,
target,
targetOrigin,
},
machine,
)
channels.add(channel)
channel.start()
channel.connect()
})
} else {
// If targets have not been added yet, create a channel without a target
const channel = createChannel<R, S>(input)
const channel = createChannel<R, S>({...input, targetOrigin}, machine)
channels.add(channel)
}
const post = (data: WithoutResponse<S>) => {
const post: ConnectionInstance<R, S>['post'] = (data) => {
channels.forEach((channel) => {

@@ -200,6 +227,3 @@ channel.post(data)

const on = <T extends R['type'], U extends Extract<R, {type: T}>>(
type: T,
handler: (event: U['data']) => U['response'],
) => {
const on: ConnectionInstance<R, S>['on'] = (type, handler) => {
const unsubscribers: Array<() => void> = []

@@ -239,3 +263,3 @@ channels.forEach((channel) => {

const onStatus = (handler: (event: {channel: string; status: string}) => void) => {
const onStatus = (handler: (event: StatusEvent) => void) => {
const unsubscribers: Array<() => void> = []

@@ -242,0 +266,0 @@ channels.forEach((channel) => {

export {
type Channel,
type ChannelActor,
type ChannelActorLogic,
type ChannelInput,

@@ -8,3 +9,4 @@ createChannel,

} from './channel'
export {MSG_HEARTBEAT, MSG_RESPONSE} from './constants'
export {createListenLogic} from './common'
export * from './constants'
export {

@@ -16,3 +18,10 @@ type ConnectionInput,

} from './controller'
export {createNode, createNodeMachine, type Node, type NodeActor, type NodeInput} from './node'
export {
createNode,
createNodeMachine,
type Node,
type NodeActor,
type NodeActorLogic,
type NodeInput,
} from './node'
export {createRequestMachine, type RequestActorRef, type RequestMachineContext} from './request'

@@ -22,5 +31,8 @@ export type {

BufferFlushedEmitEvent,
DisconnectMessage,
HandshakeMessageType,
HeartbeatEmitEvent,
HeartbeatMessage,
InternalEmitEvent,
InternalMessageType,
ListenInput,

@@ -34,3 +46,5 @@ Message,

ResponseMessage,
Status,
StatusEvent,
WithoutResponse,
} from './types'
import {v4 as uuid} from 'uuid'
import {
type ActorRefFrom,
assertEvent,

@@ -11,5 +10,6 @@ assign,

setup,
stopChild,
type ActorRefFrom,
} from 'xstate'
import {listenActor, listenInputFromContext} from './common'
import {createListenLogic, listenInputFromContext} from './common'
import {

@@ -29,7 +29,10 @@ DOMAIN,

HeartbeatEmitEvent,
HeartbeatMessage,
Message,
MessageEmitEvent,
ProtocolMessage,
RequestData,
Status,
WithoutResponse,
} from './types'
import type {HeartbeatMessage, Message, ProtocolMessage} from './types'

@@ -48,4 +51,4 @@ /**

*/
export type NodeActor<R extends Message, U extends Message> = ActorRefFrom<
ReturnType<typeof createNodeMachine<R, U>>
export type NodeActorLogic<R extends Message, S extends Message> = ReturnType<
typeof createNodeMachine<R, S>
>

@@ -56,2 +59,7 @@

*/
export type NodeActor<R extends Message, S extends Message> = ActorRefFrom<NodeActorLogic<R, S>>
/**
* @public
*/
export type Node<R extends Message, S extends Message> = {

@@ -61,4 +69,5 @@ actor: NodeActor<R, S>

data: U,
) => S extends U ? (S['type'] extends T ? S['response'] : never) : never
machine: ReturnType<typeof createNodeMachine<R, S>>
options?: {signal?: AbortSignal},
) => S extends U ? (S['type'] extends T ? Promise<S['response']> : never) : never
machine: NodeActorLogic<R, S>
on: <T extends R['type'], U extends Extract<R, {type: T}>>(

@@ -68,3 +77,3 @@ type: T,

) => () => void
onStatus: (handler: (status: string) => void) => () => void
onStatus: (handler: (status: Status) => void) => () => void
post: (data: WithoutResponse<S>) => void

@@ -86,11 +95,30 @@ start: () => () => void

types: {} as {
children: {
'listen for disconnect': 'listen'
'listen for handshake ack': 'listen'
'listen for handshake syn': 'listen'
'listen for heartbeat': 'listen'
'listen for messages': 'listen'
}
context: {
buffer: Array<{data: V; resolvable?: PromiseWithResolvers<S['response']>}>
buffer: Array<{
data: V
resolvable?: PromiseWithResolvers<S['response']>
signal?: AbortSignal
}>
connectionId: string | null
connectTo: string
domain: string
// The handshake buffer is a workaround to maintain backwards
// compatibility with the Sanity channels package, which may incorrectly
// send buffered messages _before_ it completes the handshake (i.e.
// sends an ack message). It should be removed in the next major.
handshakeBuffer: Array<{
type: 'message.received'
message: MessageEvent<ProtocolMessage<R>>
}>
name: string
origin: string | null
requests: Array<RequestActorRef<S>>
target: MessageEventSource | undefined
targetOrigin: string | null
}

@@ -106,6 +134,17 @@ emitted:

| {type: 'message.received'; message: MessageEvent<ProtocolMessage<R>>}
| {type: 'post'; data: V; resolvable?: PromiseWithResolvers<S['response']>}
| {
type: 'post'
data: V
resolvable?: PromiseWithResolvers<S['response']>
signal?: AbortSignal
}
| {type: 'request.aborted'; requestId: string}
| {type: 'request.failed'; requestId: string}
| {type: 'request.success'; requestId: string}
| {type: 'request'; data: RequestData<S> | RequestData<S>[]}
| {
type: 'request.success'
requestId: string
response: S['response'] | null
responseTo: string | undefined
}
| {type: 'request'; data: RequestData<S> | RequestData<S>[]} // @todo align with 'post' type
input: NodeInput

@@ -115,5 +154,11 @@ },

requestMachine: createRequestMachine<S>(),
listen: listenActor,
listen: createListenLogic(),
},
actions: {
'buffer incoming message': assign({
handshakeBuffer: ({event, context}) => {
assertEvent(event, 'message.received')
return [...context.handshakeBuffer, event]
},
}),
'buffer message': enqueueActions(({enqueue}) => {

@@ -123,3 +168,10 @@ enqueue.assign({

assertEvent(event, 'post')
return [...context.buffer, {data: event.data, resolvable: event.resolvable}]
return [
...context.buffer,
{
data: event.data,
resolvable: event.resolvable,
signal: event.signal,
},
]
},

@@ -136,3 +188,3 @@ })

'create request': assign({
requests: ({context, event, spawn}) => {
requests: ({context, event, self, spawn}) => {
assertEvent(event, 'request')

@@ -150,8 +202,10 @@ const arr = Array.isArray(event.data) ? event.data : [event.data]

from: context.name,
origin: context.origin!,
parentRef: self,
resolvable: request.resolvable,
responseTo: request.responseTo,
sources: context.target!,
targetOrigin: context.targetOrigin!,
to: context.connectTo,
type: request.type,
signal: request.signal,
},

@@ -188,3 +242,3 @@ })

type: 'request',
data: context.buffer.map(({data, resolvable}) => ({
data: context.buffer.map(({data, resolvable, signal}) => ({
data: data.data,

@@ -194,2 +248,3 @@ type: data.type,

resolvable,
signal,
})),

@@ -207,2 +262,8 @@ }))

}),
'flush handshake buffer': enqueueActions(({context, enqueue}) => {
context.handshakeBuffer.forEach((event) => enqueue.raise(event))
enqueue.assign({
handshakeBuffer: [],
})
}),
'post': raise(({event}) => {

@@ -217,10 +278,10 @@ assertEvent(event, 'post')

resolvable: event.resolvable,
signal: event.signal,
},
}
}),
'remove request': assign({
requests: ({context, event}) => {
assertEvent(event, ['request.success', 'request.failed'])
return context.requests.filter((request) => request.id !== event.requestId)
},
'remove request': enqueueActions(({context, enqueue, event}) => {
assertEvent(event, ['request.success', 'request.failed', 'request.aborted'])
stopChild(event.requestId)
enqueue.assign({requests: context.requests.filter(({id}) => id !== event.requestId)})
}),

@@ -234,3 +295,2 @@ 'send response': raise(({event}) => {

responseTo: event.message.data.id,
// @todo Do nodes need to support responses?
data: undefined,

@@ -253,3 +313,3 @@ },

},
origin: ({event}) => {
targetOrigin: ({event}) => {
assertEvent(event, 'message.received')

@@ -271,6 +331,7 @@ return event.message.origin

domain: input.domain ?? DOMAIN,
handshakeBuffer: [],
name: input.name,
origin: null,
requests: [],
target: undefined,
targetOrigin: null,
}),

@@ -284,2 +345,5 @@ on: {

},
'request.aborted': {
actions: 'remove request',
},
},

@@ -290,5 +354,8 @@ initial: 'idle',

invoke: {
id: 'listen for handshake syn',
src: 'listen',
id: 'listenForHandshakeSyn',
input: listenInputFromContext(MSG_HANDSHAKE_SYN, {count: 1}),
input: listenInputFromContext({
include: MSG_HANDSHAKE_SYN,
count: 1,
}),
onDone: {

@@ -312,11 +379,15 @@ target: 'handshaking',

{
id: 'listen for handshake ack',
src: 'listen',
id: 'listenForHandshakeAck',
input: listenInputFromContext(MSG_HANDSHAKE_ACK, {count: 1}),
input: listenInputFromContext({
include: MSG_HANDSHAKE_ACK,
count: 1,
}),
onDone: 'connected',
},
{
id: 'listen for disconnect',
src: 'listen',
id: 'listenForDisconnect',
input: listenInputFromContext([MSG_DISCONNECT], {
input: listenInputFromContext({
include: MSG_DISCONNECT,
count: 1,

@@ -326,11 +397,21 @@ responseType: 'disconnect',

},
{
id: 'listen for messages',
src: 'listen',
input: listenInputFromContext({
exclude: [MSG_DISCONNECT, MSG_HANDSHAKE_ACK, MSG_HEARTBEAT, MSG_RESPONSE],
}),
},
],
on: {
request: {
'request': {
actions: 'create request',
},
post: {
'post': {
actions: 'buffer message',
},
disconnect: {
'message.received': {
actions: 'buffer incoming message',
},
'disconnect': {
target: 'idle',

@@ -341,18 +422,24 @@ },

connected: {
entry: 'flush buffer',
entry: ['flush handshake buffer', 'flush buffer'],
invoke: [
{
id: 'listen for messages',
src: 'listen',
id: 'listenForMessages',
input: listenInputFromContext([MSG_RESPONSE, MSG_HEARTBEAT], {matches: false}),
input: listenInputFromContext({
exclude: [MSG_RESPONSE, MSG_HEARTBEAT],
}),
},
{
id: 'listen for heartbeat',
src: 'listen',
id: 'listenForHeartbeats',
input: listenInputFromContext([MSG_HEARTBEAT], {responseType: 'heartbeat.received'}),
input: listenInputFromContext({
include: MSG_HEARTBEAT,
responseType: 'heartbeat.received',
}),
},
{
id: 'listen for disconnect',
src: 'listen',
id: 'listenForDisconnect',
input: listenInputFromContext([MSG_DISCONNECT], {
input: listenInputFromContext({
include: MSG_DISCONNECT,
count: 1,

@@ -389,5 +476,6 @@ responseType: 'disconnect',

*/
export const createNode = <R extends Message, S extends Message>(input: NodeInput): Node<R, S> => {
const machine = createNodeMachine<R, S>()
export const createNode = <R extends Message, S extends Message>(
input: NodeInput,
machine: NodeActorLogic<R, S> = createNodeMachine<R, S>(),
): Node<R, S> => {
const actor = createActor(machine, {

@@ -411,9 +499,10 @@ input,

const onStatus = (handler: (status: string) => void) => {
const onStatus = (handler: (status: Status) => void) => {
const snapshot = actor.getSnapshot()
let currentStatus: string | undefined =
let currentStatus: Status =
typeof snapshot.value === 'string' ? snapshot.value : Object.keys(snapshot.value)[0]
const {unsubscribe} = actor.subscribe((state) => {
const status = typeof state.value === 'string' ? state.value : Object.keys(state.value)[0]
const status: Status =
typeof state.value === 'string' ? state.value : Object.keys(state.value)[0]
if (currentStatus !== status) {

@@ -431,5 +520,10 @@ currentStatus = status

const fetch = (data: WithoutResponse<S>) => {
const fetch = (data: WithoutResponse<S>, options?: {signal?: AbortSignal}) => {
const resolvable = Promise.withResolvers<S['response']>()
actor.send({type: 'post', data, resolvable})
actor.send({
type: 'post',
data,
resolvable,
signal: options?.signal,
})
return resolvable.promise as never

@@ -436,0 +530,0 @@ }

@@ -1,8 +0,24 @@

import {filter, fromEvent, take} from 'rxjs'
import {EMPTY, filter, fromEvent, map, Observable, take, takeUntil} from 'rxjs'
import {v4 as uuid} from 'uuid'
import {type ActorRefFrom, assign, fromEventObservable, sendParent, setup} from 'xstate'
import {
assign,
fromEventObservable,
sendTo,
setup,
type ActorRefFrom,
type AnyActorRef,
} from 'xstate'
import {MSG_RESPONSE, RESPONSE_TIMEOUT} from './constants'
import type {Message, MessageData, MessageType, ProtocolMessage, ResponseMessage} from './types'
const throwOnEvent =
<T>(message?: string) =>
(source: Observable<T>) =>
source.pipe(
take(1),
map(() => {
throw new Error(message)
}),
)
/**

@@ -18,7 +34,9 @@ * @public

id: string
origin: string
parentRef: AnyActorRef
resolvable: PromiseWithResolvers<S['response']> | undefined
response: S['response'] | null
responseTo: string | undefined
signal: AbortSignal | undefined
sources: Set<MessageEventSource>
targetOrigin: string
to: string

@@ -44,6 +62,11 @@ type: MessageType

types: {} as {
children: {
'listen for response': 'listen'
}
context: RequestMachineContext<S>
// @todo Should response types be specified?
events: {type: 'message'; data: ProtocolMessage<ResponseMessage>}
events: {type: 'message'; data: ProtocolMessage<ResponseMessage>} | {type: 'abort'}
emitted:
| {type: 'request.failed'; requestId: string}
| {type: 'request.aborted'; requestId: string}
| {

@@ -55,3 +78,2 @@ type: 'request.success'

}
| {type: 'request.failed'; requestId: string}
input: {

@@ -63,23 +85,46 @@ connectionId: string

from: string
origin: string
parentRef: AnyActorRef
resolvable?: PromiseWithResolvers<S['response']>
responseTo?: string
resolvable?: PromiseWithResolvers<S['response']>
signal?: AbortSignal
sources: Set<MessageEventSource> | MessageEventSource
targetOrigin: string
to: string
type: S['type']
}
output: {
requestId: string
response: S['response'] | null
responseTo: string | undefined
}
},
actors: {
listen: fromEventObservable(
({input}: {input: {requestId: string; sources: Set<MessageEventSource>}}) =>
fromEvent<MessageEvent<ProtocolMessage<ResponseMessage>>>(window, 'message').pipe(
filter(
(event) =>
event.data.type === MSG_RESPONSE &&
event.data.responseTo === input.requestId &&
!!event.source &&
input.sources.has(event.source),
),
({
input,
}: {
input: {
requestId: string
sources: Set<MessageEventSource>
signal?: AbortSignal
}
}) => {
const abortSignal$ = input.signal
? fromEvent(input.signal, 'abort').pipe(
throwOnEvent(`Request ${input.requestId} aborted`),
)
: EMPTY
const messageFilter = (event: MessageEvent<ProtocolMessage<ResponseMessage>>) =>
event.data?.type === MSG_RESPONSE &&
event.data?.responseTo === input.requestId &&
!!event.source &&
input.sources.has(event.source)
return fromEvent<MessageEvent<ProtocolMessage<ResponseMessage>>>(window, 'message').pipe(
filter(messageFilter),
take(input.sources.size),
),
takeUntil(abortSignal$),
)
},
),

@@ -89,28 +134,41 @@ },

'send message': ({context}, params: {message: ProtocolMessage}) => {
const {sources, origin} = context
const {sources, targetOrigin} = context
const {message} = params
sources.forEach((source) => {
source.postMessage(message, {targetOrigin: origin})
source.postMessage(message, {targetOrigin})
})
},
'on success': sendParent(({context, self}) => {
if (context.response) {
context.resolvable?.resolve(context.response)
}
return {
type: 'request.success',
requestId: self.id,
response: context.response,
responseTo: context.responseTo,
}
}),
'on fail': sendParent(({context, self}) => {
// eslint-disable-next-line no-console
console.warn(
`Received no response to message '${context.type}' on client '${context.from}' (ID: '${context.id}').`,
)
context.resolvable?.reject(new Error('No response received'))
return {type: 'request.failed', requestId: self.id}
}),
'on success': sendTo(
({context}) => context.parentRef,
({context, self}) => {
if (context.response) {
context.resolvable?.resolve(context.response)
}
return {
type: 'request.success',
requestId: self.id,
response: context.response,
responseTo: context.responseTo,
}
},
),
'on fail': sendTo(
({context}) => context.parentRef,
({context, self}) => {
// eslint-disable-next-line no-console
console.warn(
`Received no response to message '${context.type}' on client '${context.from}' (ID: '${context.id}').`,
)
context.resolvable?.reject(new Error('No response received'))
return {type: 'request.failed', requestId: self.id}
},
),
'on abort': sendTo(
({context}) => context.parentRef,
({context, self}) => {
context.resolvable?.reject(new Error('Request aborted'))
return {type: 'request.aborted', requestId: self.id}
},
),
},

@@ -125,3 +183,3 @@ guards: {

}).createMachine({
/** @xstate-layout N4IgpgJg5mDOIC5QAoC2BDAxgCwJYDswBKAOlwgBswBiAD1gBd0GwT0AzFgJ2QNwdzoKAFVyowAewCuDItTRY8hUuSoBtAAwBdRKAAOE2P1wT8ukLUQBGAEwBWEnY3ONAZlc2XATjtWANCAAntYaAGwkLs5ergAsAOxeMVahcQC+qQEKOATEJLBg+BAEUNSaOkggBkYCpuaWCL4aJFYaVnZxABwd7lYxbnEBwQj2TfGhdilJYXE2cTHpmRjZynkFRfglalbl+obGtRX1jc2t7V09fa4DQYheNiQxXk9eHXFxbl7JVgsgWUq56AA7uhjBtqOJYLB0DAyuYqvszIdEF0rA84qFQo87LM4lY8YNEDY8RFIi1bFYvM40hlfkt-qQgSCBGD6EwWGxOGAeFw4AZ8PlROJpLJ5HScgzgaCoLCKvCaojQPUUWiMVicXj-DcEK4NHEHnZXOTQhSbKENDFQukafgJBA4OY-uK4Xt5XVEABaUIEhCekmRf0uamLRTisiUMDO6omBUWRAxGzeloOf1zcZ2C2vH6Olb5QrFSMIt3DLx6ryhV6hGwl3xWDwxb0dVGPZ7vDHvGKGrNilaMqUF11IhC4vVuWsUg2m5IJrU2ewkWfjUJXWI2eN2OxdkMrdggqgQfvRostN4kT5TaK9WwY702Rskd6G1yY3VXGIbmnZ3KwKSYTBweCyi6h6DsepaXhoF5JKaXpaneTguDYrgdI8dbUukQA */
/** @xstate-layout N4IgpgJg5mDOIC5QAoC2BDAxgCwJYDswBKAOlwgBswBiAD1gBd0GwT0AzFgJ2QNwdzoKAFVyowAewCuDItTRY8hUuSoBtAAwBdRKAAOE2P1wT8ukLUQBGAEwBWEgBYAnK+eOAzB7sB2DzY8rABoQAE9rDQc3V0cNTw8fAA4NHwBfVJCFHAJiElgwfAgCKGpNHSQQAyMBU3NLBDsrDxI7DTaAjQA2OOcNDxDwhHsNJx9Ou0TOq2cJxP9HdMyMbOU8gqL8ErUrcv1DY1qK+sbm1vaPLp6+gcRnGydo9wDGycWQLKVc9AB3dGNN6jiWCwdAwMrmKoHMxHRCJRKOEiJHwuZKBZwXKzBMKIGyYkhtAkXOweTqOHw2RJvD45Ug-P4CAH0JgsNicMA8LhwAz4fKicTSWTyZafWm-f5QcEVSE1aGgepwhFIlF9aYYrGDC4+JzEppjGzOUkeGbpDIgfASCBwczU5QQ-YyuqIAC0nRuCBd+IJXu9KSpwppZEoYDt1RMsosiEcNjdVjiJEeGisiSTHkcVgWpptuXyhWKIahjqGzi1BqRJINnVcdkcbuTLS9VYC8ISfsUAbp4vzDphCHJIyjBvJNlxNmRNexQ3sJGH43GPj8jWJrZWuXYfyoEC7YcLsbrgRsjkcvkmdgNbopVhIPhVfnsh8ClMz-tWsCkmEwcHgUvt257u8v+6Hse4xnhOdZnImVidPqCRNB4JqpEAA */
context: ({input}) => {

@@ -135,7 +193,9 @@ return {

id: `msg-${uuid()}`,
origin: input.origin,
parentRef: input.parentRef,
resolvable: input.resolvable,
response: null,
responseTo: input.responseTo,
sources: 'size' in input.sources ? input.sources : new Set([input.sources]),
signal: input.signal,
sources: input.sources instanceof Set ? input.sources : new Set([input.sources]),
targetOrigin: input.targetOrigin,
to: input.to,

@@ -146,6 +206,13 @@ type: input.type,

initial: 'idle',
on: {
abort: '.aborted',
},
states: {
idle: {
after: {
initialTimeout: 'sending',
initialTimeout: [
{
target: 'sending',
},
],
},

@@ -181,2 +248,3 @@ },

invoke: {
id: 'listen for response',
src: 'listen',

@@ -186,3 +254,5 @@ input: ({context}) => ({

sources: context.sources,
signal: context.signal,
}),
onError: 'aborted',
},

@@ -210,2 +280,6 @@ after: {

},
aborted: {
type: 'final',
entry: 'on abort',
},
},

@@ -212,0 +286,0 @@ output: ({context, self}) => {

@@ -1,2 +0,9 @@

import type {MSG_HEARTBEAT, MSG_RESPONSE} from './constants'
import {
MSG_DISCONNECT,
MSG_HANDSHAKE_ACK,
MSG_HANDSHAKE_SYN,
MSG_HANDSHAKE_SYN_ACK,
MSG_HEARTBEAT,
type MSG_RESPONSE,
} from './constants'

@@ -6,2 +13,12 @@ /**

*/
export type Status = string // @todo strongly type these
/**
* @public
*/
export type StatusEvent = {channel: string; status: Status}
/**
* @public
*/
export type MessageType = string

@@ -32,2 +49,3 @@

resolvable?: PromiseWithResolvers<S['response']>
signal?: AbortSignal
}

@@ -44,10 +62,10 @@

export interface ListenInput {
count?: number
domain: string
exclude: string[]
from: string
to: string
type: string | string[]
matches: boolean
count?: number
include: string[]
responseType: string
target: MessageEventSource | undefined
to: string
}

@@ -123,1 +141,28 @@

}
/**
* @internal
*/
export interface DisconnectMessage {
type: typeof MSG_DISCONNECT
data: undefined
}
/**
* @internal
*/
export type HandshakeMessageType =
| typeof MSG_HANDSHAKE_ACK
| typeof MSG_HANDSHAKE_SYN
| typeof MSG_HANDSHAKE_SYN_ACK
/**
* @internal
*/
export type InternalMessageType =
| typeof MSG_DISCONNECT
| typeof MSG_HANDSHAKE_ACK
| typeof MSG_HANDSHAKE_SYN
| typeof MSG_HANDSHAKE_SYN_ACK
| typeof MSG_HEARTBEAT
| typeof MSG_RESPONSE

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc