@statewalker/webrun-http-browser 0.3.2 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +321 -50
  3. package/demo/demo-1.html +109 -194
  4. package/demo/demo-2.html +119 -580
  5. package/dist/core/data-calls.d.ts +5 -0
  6. package/dist/core/data-calls.d.ts.map +1 -0
  7. package/dist/core/data-channels.d.ts +17 -0
  8. package/dist/core/data-channels.d.ts.map +1 -0
  9. package/dist/core/index.d.ts +6 -0
  10. package/dist/core/index.d.ts.map +1 -0
  11. package/dist/core/message-target.d.ts +16 -0
  12. package/dist/core/message-target.d.ts.map +1 -0
  13. package/dist/core/registry.d.ts +18 -0
  14. package/dist/core/registry.d.ts.map +1 -0
  15. package/dist/http/http-send-recieve.d.ts +23 -0
  16. package/dist/http/http-send-recieve.d.ts.map +1 -0
  17. package/dist/http/index.d.ts +4 -0
  18. package/dist/http/index.d.ts.map +1 -0
  19. package/dist/index.d.ts +4 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +2541 -807
  22. package/dist/relay/index-sw.d.ts +7 -0
  23. package/dist/relay/index-sw.d.ts.map +1 -0
  24. package/dist/relay/index.d.ts +69 -0
  25. package/dist/relay/index.d.ts.map +1 -0
  26. package/dist/relay/split-service-url.d.ts +13 -0
  27. package/dist/relay/split-service-url.d.ts.map +1 -0
  28. package/dist/relay-sw.d.ts +2 -0
  29. package/dist/relay-sw.d.ts.map +1 -0
  30. package/dist/relay-sw.js +878 -0
  31. package/dist/sw/http-sw-dispatcher.d.ts +28 -0
  32. package/dist/sw/http-sw-dispatcher.d.ts.map +1 -0
  33. package/dist/sw/index.d.ts +3 -0
  34. package/dist/sw/index.d.ts.map +1 -0
  35. package/dist/sw/sw-dispatcher.d.ts +74 -0
  36. package/dist/sw/sw-dispatcher.d.ts.map +1 -0
  37. package/dist/sw-worker.d.ts +2 -0
  38. package/dist/sw-worker.d.ts.map +1 -0
  39. package/dist/sw-worker.js +813 -0
  40. package/dist/sw.d.ts +2 -0
  41. package/dist/sw.d.ts.map +1 -0
  42. package/dist/sw.js +1076 -0
  43. package/package.json +50 -37
  44. package/public/index.html +61 -97
  45. package/public/index.js +7 -4
  46. package/public/sw-worker.js +4 -0
  47. package/public-relay/heartbeat.js +4 -3
  48. package/public-relay/relay-sw.js +4 -6
  49. package/public-relay/relay.html +16 -11
  50. package/src/core/data-calls.ts +46 -0
  51. package/src/core/data-channels.ts +224 -0
  52. package/src/core/index.ts +9 -0
  53. package/src/core/message-target.ts +18 -0
  54. package/src/core/registry.ts +54 -0
  55. package/src/http/http-send-recieve.ts +81 -0
  56. package/src/http/index.ts +7 -0
  57. package/src/index.ts +3 -0
  58. package/src/relay/index-sw.ts +145 -0
  59. package/src/relay/index.ts +261 -0
  60. package/src/relay/split-service-url.ts +30 -0
  61. package/src/relay-sw.ts +7 -0
  62. package/src/sw/http-sw-dispatcher.ts +122 -0
  63. package/src/sw/index.ts +2 -0
  64. package/src/sw/sw-dispatcher.ts +307 -0
  65. package/src/sw-worker.ts +7 -0
  66. package/src/sw.ts +1 -0
  67. package/CHANGELOG.md +0 -1
  68. package/demo/demo-3.html +0 -167
  69. package/dist/index-sw-umd.js +0 -798
  70. package/dist/index-sw-umd.min.js +0 -2
  71. package/dist/index-sw.js +0 -791
  72. package/dist/index-sw.min.js +0 -2
  73. package/dist/index-umd.js +0 -853
  74. package/dist/index-umd.min.js +0 -2
  75. package/dist/index.min.js +0 -2
  76. package/index.js +0 -1
  77. package/src/core/data-calls.js +0 -36
  78. package/src/core/data-channels.js +0 -192
  79. package/src/core/data-send-recieve.js +0 -28
  80. package/src/core/errors.js +0 -13
  81. package/src/core/index.js +0 -4
  82. package/src/http/HttpError.js +0 -59
  83. package/src/http/http-send-recieve.js +0 -40
  84. package/src/http/http-stubs.js +0 -135
  85. package/src/http/index.js +0 -3
  86. package/src/http/readable-streams.js +0 -33
  87. package/src/index.js +0 -7
  88. package/src/relay/index-sw.js +0 -216
  89. package/src/relay/index.js +0 -263
  90. package/src/relay/splitServiceUrl.js +0 -24
  91. package/src/sw/http-sw-dispatcher.js +0 -128
  92. package/src/sw/sw-dispatcher.js +0 -264
@@ -1,2 +0,0 @@
1
- // @statewalker/webrun-http-browser v0.3.2 https://github.com/statewalker/statewalker-webrun-http-browser Copyright 2023 Mikhail Kotelnikov
2
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(((e="undefined"!=typeof globalThis?globalThis:e||self).statewalker=e.statewalker||{},e.statewalker["webrun-http-browser"]=e.statewalker["webrun-http-browser"]||{}))}(this,(function(e){"use strict";function t(e){return Object.assign({message:e,stack:e.stack},e)}function n(e){return"string"==typeof e&&(e={message:e}),Object.assign(new Error(e.message),e)}async function r(e,t,r,...o){return new Promise(((a,s)=>{const c=new MessageChannel;c.port1.onmessage=e=>{const{result:t,error:r}=e.data;r?s(n(r)):a(t)},e.postMessage({type:t,params:r},[c.port2,...o])}))}function o(e,n,r){const o=async e=>{if(!e.data||e.data.type!==n)return;const[o,...a]=e.ports;let s={};try{const t=e.data.params;s.result=await r(e,t,...a)}catch(e){s.error=t(e)}o.postMessage(s)};e.addEventListener("message",o);try{e.start&&e.start()}catch(e){}return()=>e.removeEventListener("message",o)}function a(e=console.error){let t=0;const n={},r=r=>{const o=t++;return n[o]=Object.assign((function(t){try{return delete n[o],!t&&r&&r()}catch(t){e(t)}}),{action:r})},o=e=>Object.values(n).forEach((t=>t.action===e&&t(!0))),a=()=>Object.values(n).forEach((e=>e()));return Object.assign([r,a,o],{register:r,clear:a,unregister:o})}async function*s(e){yield*async function*(e,t=[]){let n,r,o=async(e,n,o)=>{const a={error:e,value:n,done:o};return a.promise=new Promise((e=>a.notify=e)),await t.push(a),r&&r(),r=null,a.promise};const a=e=>o(void 0,e,!1),s=()=>o(void 0,void 0,!0),c=e=>o(e,void 0,!0),i=e(Object.assign([a,s,c],{next:a,complete:s,error:c}));let l;try{for(;;)if(l=await t.shift(),l)try{if(l.error)throw l.error;if(l.done)break;yield l.value}finally{l.notify(!0)}else await(n=r?n:new Promise((e=>r=e)))}finally{for(r&&r(),o=()=>!1,"function"==typeof i&&await i();l=await t.shift();)l.notify(!1)}}((t=>e((async({done:e=!0,value:n,error:r}={})=>{r?await t.error(r):e?await t.complete():await t.next(n)}))))}async function c(e,t){let n;try{for await(let n of t)await e({done:!1,value:n})}catch(e){n=e}finally{await e({done:!0,error:n})}}async function*i(e,t,n={}){const r=new MessageChannel;e.postMessage({type:"START_CALL",params:n},[r.port2]);const o=u(r.port1);try{await o.start(),o.sendAll(t),yield*o.recieveAll()}finally{await o.close()}}function l(e,t){const n=async e=>{const{type:n,params:r}=e.data||{};if("START_CALL"!==n)return;const o=u(e.ports[0]);try{await o.start();const e=o.recieveAll(),n=await t(e,r);await o.sendAll(n)}finally{await o.close()}};e.addEventListener("message",n);try{e.start&&e.start()}catch(e){}return()=>e.removeEventListener("message",n)}function u(e){let t=[],n=[];const r=async e=>{for(let n of t)await n(e)},o=d({port:e,handler:r});return{start:()=>o.start(),close:async()=>{await r({done:!0}),[...n].forEach((e=>e.return&&e.return())),await o.close()},recieveAll:async function*(){yield*s((e=>(t.push(e),()=>t=t.filter((t=>t!==e)))))},sendAll:async function(e){await c(o.invoke,async function*(){try{n.push(e),yield*e}finally{n=n.filter((t=>t!==e))}}())}}}function d({port:e,handler:r=(()=>{throw new Error("Handler not implemented")}),onError:o=console.error,newCallId:a=(()=>d.__counter=(d.__counter||0)+1)}){const s="REQUEST",c="RESPONSE",i="message",l={},u=async o=>{const a=o.data||{},{type:i,callId:u}=a;if(i===s)try{const{request:t}=a;let n=await r(t,...o.ports||[]);const[s,...i]=Array.isArray(n)?n:void 0!==n?[n]:[];e.postMessage({type:c,callId:u,response:s},i)}catch(n){e.postMessage({type:c,callId:u,error:t(n)})}else if(i===c){const{callId:e,response:t,error:r}=a,o=l[e];delete l[e],o&&(r?o.reject(n(r)):o.resolve(t))}};return{start:async()=>{try{e.addEventListener(i,u),e.start&&await e.start()}catch(e){o(e)}},close:async()=>{try{e.removeEventListener(i,u),e.close&&await e.close()}catch(e){o(e)}},invoke:async function(t={},...n){const r=a();return new Promise(((o,a)=>{try{l[r]={resolve:o,reject:a},e.postMessage({type:s,callId:r,request:t},n)}catch(e){a(e),delete t[r]}}))}}}function f(e){return new ReadableStream({type:"bytes",async pull(t){let n=!1;try{for(;;){const n=await e.next();if(!n||n.done)break;t.enqueue(await n.value)}}catch(e){n=!0,t.error(e)}finally{!n&&t.close()}}})}async function*p(e){const t=await e.getReader();let n,r;for(;({done:n,value:r}=await t.read())&&!n;)yield await r}function y(e){return async t=>{const n=[...(t=await t).headers].map((([e,t])=>[e,t])),r=["url","method","mode","credentials","cache","redirect","referrer","referrerPolicy","integrity","keepalive"].reduce(((e,n)=>{const r=t[n];return void 0!==r&&(e[n]=r),e}),{headers:n}),o=t.body?p(t.body):[],a=await e({options:r,content:o});let s=null,c={};if(a){c=a.options;const e=a.content;"HEAD"!==r.method&&"OPTIONS"!==r.method?s=f(e):e&&e.return&&e.return()}else c={status:404,statusText:"Error 404: Not Found"};return new Response(s,c)}}function w(e){return async t=>{const{options:n,content:r}=await t;let o;const{url:a,mode:s,headers:c=[]}=n,i=new Headers;for(let[e,t]of c)i.append(e,t);delete n.mode,delete n.url,"GET"!==n.method&&"HEAD"!==n.method&&"OPTIONS"!==n.method?(o=f(r),n.duplex="half"):r&&r.return&&r.return();const l=new Request(a,{...n,headers:i,body:o}),u=await e(l);return{options:{status:u.status,statusText:u.statusText,headers:Object.fromEntries([...u.headers])},content:await p(await u.body)}}}async function*m(e){const{options:t,content:n}=await e,r=new TextEncoder;yield r.encode(JSON.stringify(t)),yield*n}async function h(e){e=await e;const{done:t,value:n}=await e.next();let r={};if(!t&&n){const e=(new TextDecoder).decode(n);r=JSON.parse(e)}return{options:r,content:e}}function g(e,t){const n=w(t);return l(e,(e=>m(n(h(e)))))}async function v(e,t){const n=y((async t=>await h(i(e,m(t)))));return await n(t)}function b(){const e=new MessageChannel;return e.port1.onmessage=e=>{navigator.serviceWorker.controller.postMessage(e.data,e.ports)},navigator.serviceWorker.addEventListener("message",(t=>{e.port1.postMessage(t.data,t.ports)})),e.port2}async function E({swUrl:e,scopeUrl:t,type:n}){await navigator.serviceWorker.register(e,{type:n,scope:t});const r=await async function(){return await new Promise((e=>{const t=navigator.serviceWorker;if(t.controller)e(t.controller);else{const n=()=>{e(t.controller),t.removeEventListener("controllerchange",n),t.oncontrollerchange=null};t.addEventListener("controllerchange",n),t.oncontrollerchange=n}}))}();return await async function(e){const t=()=>"activated"===e.state;await new Promise((async n=>{t()?n():e.onstatechange=()=>{t()&&(e.onstatechange=null,n())}}))}(r),r}async function R({key:e,communicationPort:t,...n}){const o=new MessageChannel;return await r(t,"CONNECT",{key:e,...n},o.port2)?o.port1:(o.port1.close(),o.port2.close(),null)}async function k({key:e,handler:t,communicationPort:n}){const[s,c]=a();return await r(n,"REGISTER",{key:e}),s((()=>r(n,"UNREGISTER",{key:e}))),s(o(n,"CONNECT",t)),c}e.callChannel=r,e.callHttpService=async function(e,{key:t,port:n}){const r=await R({key:t,communicationPort:n});return await v(r,e)},e.deserializeError=n,e.fromReadableStream=p,e.getRelayWindowMessageHandler=function({swUrl:e=new URL("./index-sw.js","undefined"==typeof document&&"undefined"==typeof location?new(require("url").URL)("file:"+__filename).href:"undefined"==typeof document?location.href:document.currentScript&&document.currentScript.src||new URL("index-umd.min.js",document.baseURI).href)+"",scopeUrl:t=new URL("../","undefined"==typeof document&&"undefined"==typeof location?new(require("url").URL)("file:"+__filename).href:"undefined"==typeof document?location.href:document.currentScript&&document.currentScript.src||new URL("index-umd.min.js",document.baseURI).href)+""}={}){let n;return async r=>{if("CONNECT"===r.data.type){const o=(r.ports||[])[0];if(n)return void o.close();n=o,await E({swUrl:e,scopeUrl:t});const a=b();a.onmessage=e=>{n.postMessage(e.data,e.ports)},n.onmessage=e=>{a.postMessage(e.data,e.ports)}}}},e.handleChannelCalls=o,e.handleHttpRequests=g,e.handleStreams=l,e.initHttpService=async function(e,{key:t,port:n}){return await k({key:t,communicationPort:n,handler:async(t,n,r)=>(g(r,e),!0)})},e.initServiceWorker=E,e.initServiceWorker1=async function({swUrl:e,scopeUrl:t,type:n}){const{installing:r,waiting:o,active:a}=await navigator.serviceWorker.register(e,{scope:t});(r||o||a).addEventListener("statechange",(e=>{console.log("state",e.target.state)}));const s=navigator.serviceWorker;await new Promise((e=>{if(s.controller)e();else{const t=()=>{e(),s.removeEventListener("controllerchange",t),s.oncontrollerchange=null};s.addEventListener("controllerchange",t),s.oncontrollerchange=t}}));const c=s.controller,i=()=>"activated"===c.state;return await new Promise((async e=>{i()?e(c):c.onstatechange=()=>{i()&&(c.onstatechange=null,e(c))}}))},e.initializeConnection=R,e.newHttpClientStub=y,e.newHttpServerStub=w,e.newInvokationChannel=d,e.newRegistry=a,e.newRemoteRelayChannel=async function({baseUrl:e=new URL("../public-relay/","undefined"==typeof document&&"undefined"==typeof location?new(require("url").URL)("file:"+__filename).href:"undefined"==typeof document?location.href:document.currentScript&&document.currentScript.src||new URL("index-umd.min.js",document.baseURI).href),url:t=new URL("relay.html",e),container:n=document.body}={}){const r=new MessageChannel,{iframe:o,promise:a}=await async function(e){const t=document.createElement("iframe");return t.src=e,Object.assign(t.style,{padding:0,margin:0,border:"none",outline:"none",width:"100%",height:"100%"}),{iframe:t,promise:new Promise(((e,n)=>{try{t.onerror=n,t.onload=()=>e(t)}catch(e){n(e)}}))}}(t);return Object.assign(o.style,{position:"fixed",width:"1px",height:"1px",top:"-1000",left:"-1000",display:"block",opacity:"0",border:"none",outline:"none"}),n.appendChild(o),a.then((()=>{o.contentWindow.postMessage({type:"CONNECT"},"*",[r.port1])})),{baseUrl:e,port:r.port2,close:()=>{o.parentElement&&o.parentElement.removeChild(o),r.port1.close(),r.port2.close()}}},e.newServiceWorkerPort=b,e.recieveData=s,e.registerConnectionsHandler=k,e.sendData=c,e.sendHttpRequest=v,e.sendStream=i,e.serializeError=t,e.splitServiceUrl=function(e,t="~"){let n="",r="",o=e+"";const a=o.indexOf(t);let s="";return a>=0&&(s=o.substring(0,a+t.length),o.substring(a+t.length).replace(/^([^\/]+)/,((e,t)=>(s+=e,s.length<o.length&&(s+="/"),n=t,r=o.substring(s.length),"")))),{url:e,key:n,baseUrl:s,path:r}},e.toReadableStream=f}));
package/dist/index.min.js DELETED
@@ -1,2 +0,0 @@
1
- // @statewalker/webrun-http-browser v0.3.2 https://github.com/statewalker/statewalker-webrun-http-browser Copyright 2023 Mikhail Kotelnikov
2
- function e(e){return Object.assign({message:e,stack:e.stack},e)}function t(e){return"string"==typeof e&&(e={message:e}),Object.assign(new Error(e.message),e)}async function n(e,n,r,...a){return new Promise(((o,s)=>{const c=new MessageChannel;c.port1.onmessage=e=>{const{result:n,error:r}=e.data;r?s(t(r)):o(n)},e.postMessage({type:n,params:r},[c.port2,...a])}))}function r(t,n,r){const a=async t=>{if(!t.data||t.data.type!==n)return;const[a,...o]=t.ports;let s={};try{const e=t.data.params;s.result=await r(t,e,...o)}catch(t){s.error=e(t)}a.postMessage(s)};t.addEventListener("message",a);try{t.start&&t.start()}catch(e){}return()=>t.removeEventListener("message",a)}function a(e=console.error){let t=0;const n={},r=r=>{const a=t++;return n[a]=Object.assign((function(t){try{return delete n[a],!t&&r&&r()}catch(t){e(t)}}),{action:r})},a=e=>Object.values(n).forEach((t=>t.action===e&&t(!0))),o=()=>Object.values(n).forEach((e=>e()));return Object.assign([r,o,a],{register:r,clear:o,unregister:a})}async function*o(e){yield*async function*(e,t=[]){let n,r,a=async(e,n,a)=>{const o={error:e,value:n,done:a};return o.promise=new Promise((e=>o.notify=e)),await t.push(o),r&&r(),r=null,o.promise};const o=e=>a(void 0,e,!1),s=()=>a(void 0,void 0,!0),c=e=>a(e,void 0,!0),i=e(Object.assign([o,s,c],{next:o,complete:s,error:c}));let l;try{for(;;)if(l=await t.shift(),l)try{if(l.error)throw l.error;if(l.done)break;yield l.value}finally{l.notify(!0)}else await(n=r?n:new Promise((e=>r=e)))}finally{for(r&&r(),a=()=>!1,"function"==typeof i&&await i();l=await t.shift();)l.notify(!1)}}((t=>e((async({done:e=!0,value:n,error:r}={})=>{r?await t.error(r):e?await t.complete():await t.next(n)}))))}async function s(e,t){let n;try{for await(let n of t)await e({done:!1,value:n})}catch(e){n=e}finally{await e({done:!0,error:n})}}async function*c(e,t,n={}){const r=new MessageChannel;e.postMessage({type:"START_CALL",params:n},[r.port2]);const a=l(r.port1);try{await a.start(),a.sendAll(t),yield*a.recieveAll()}finally{await a.close()}}function i(e,t){const n=async e=>{const{type:n,params:r}=e.data||{};if("START_CALL"!==n)return;const a=l(e.ports[0]);try{await a.start();const e=a.recieveAll(),n=await t(e,r);await a.sendAll(n)}finally{await a.close()}};e.addEventListener("message",n);try{e.start&&e.start()}catch(e){}return()=>e.removeEventListener("message",n)}function l(e){let t=[],n=[];const r=async e=>{for(let n of t)await n(e)},a=u({port:e,handler:r});return{start:()=>a.start(),close:async()=>{await r({done:!0}),[...n].forEach((e=>e.return&&e.return())),await a.close()},recieveAll:async function*(){yield*o((e=>(t.push(e),()=>t=t.filter((t=>t!==e)))))},sendAll:async function(e){await s(a.invoke,async function*(){try{n.push(e),yield*e}finally{n=n.filter((t=>t!==e))}}())}}}function u({port:n,handler:r=(()=>{throw new Error("Handler not implemented")}),onError:a=console.error,newCallId:o=(()=>u.__counter=(u.__counter||0)+1)}){const s="REQUEST",c="RESPONSE",i="message",l={},d=async a=>{const o=a.data||{},{type:i,callId:u}=o;if(i===s)try{const{request:e}=o;let t=await r(e,...a.ports||[]);const[s,...i]=Array.isArray(t)?t:void 0!==t?[t]:[];n.postMessage({type:c,callId:u,response:s},i)}catch(t){n.postMessage({type:c,callId:u,error:e(t)})}else if(i===c){const{callId:e,response:n,error:r}=o,a=l[e];delete l[e],a&&(r?a.reject(t(r)):a.resolve(n))}};return{start:async()=>{try{n.addEventListener(i,d),n.start&&await n.start()}catch(e){a(e)}},close:async()=>{try{n.removeEventListener(i,d),n.close&&await n.close()}catch(e){a(e)}},invoke:async function(e={},...t){const r=o();return new Promise(((a,o)=>{try{l[r]={resolve:a,reject:o},n.postMessage({type:s,callId:r,request:e},t)}catch(t){o(t),delete e[r]}}))}}}function d(e){return new ReadableStream({type:"bytes",async pull(t){let n=!1;try{for(;;){const n=await e.next();if(!n||n.done)break;t.enqueue(await n.value)}}catch(e){n=!0,t.error(e)}finally{!n&&t.close()}}})}async function*y(e){const t=await e.getReader();let n,r;for(;({done:n,value:r}=await t.read())&&!n;)yield await r}function p(e){return async t=>{const n=[...(t=await t).headers].map((([e,t])=>[e,t])),r=["url","method","mode","credentials","cache","redirect","referrer","referrerPolicy","integrity","keepalive"].reduce(((e,n)=>{const r=t[n];return void 0!==r&&(e[n]=r),e}),{headers:n}),a=t.body?y(t.body):[],o=await e({options:r,content:a});let s=null,c={};if(o){c=o.options;const e=o.content;"HEAD"!==r.method&&"OPTIONS"!==r.method?s=d(e):e&&e.return&&e.return()}else c={status:404,statusText:"Error 404: Not Found"};return new Response(s,c)}}function w(e){return async t=>{const{options:n,content:r}=await t;let a;const{url:o,mode:s,headers:c=[]}=n,i=new Headers;for(let[e,t]of c)i.append(e,t);delete n.mode,delete n.url,"GET"!==n.method&&"HEAD"!==n.method&&"OPTIONS"!==n.method?(a=d(r),n.duplex="half"):r&&r.return&&r.return();const l=new Request(o,{...n,headers:i,body:a}),u=await e(l);return{options:{status:u.status,statusText:u.statusText,headers:Object.fromEntries([...u.headers])},content:await y(await u.body)}}}async function*f(e){const{options:t,content:n}=await e,r=new TextEncoder;yield r.encode(JSON.stringify(t)),yield*n}async function g(e){e=await e;const{done:t,value:n}=await e.next();let r={};if(!t&&n){const e=(new TextDecoder).decode(n);r=JSON.parse(e)}return{options:r,content:e}}function m(e,t){const n=w(t);return i(e,(e=>f(n(g(e)))))}async function h(e,t){const n=p((async t=>await g(c(e,f(t)))));return await n(t)}function v(e,t="~"){let n="",r="",a=e+"";const o=a.indexOf(t);let s="";return o>=0&&(s=a.substring(0,o+t.length),a.substring(o+t.length).replace(/^([^\/]+)/,((e,t)=>(s+=e,s.length<a.length&&(s+="/"),n=t,r=a.substring(s.length),"")))),{url:e,key:n,baseUrl:s,path:r}}function E(){const e=new MessageChannel;return e.port1.onmessage=e=>{navigator.serviceWorker.controller.postMessage(e.data,e.ports)},navigator.serviceWorker.addEventListener("message",(t=>{e.port1.postMessage(t.data,t.ports)})),e.port2}async function b({swUrl:e,scopeUrl:t,type:n}){const{installing:r,waiting:a,active:o}=await navigator.serviceWorker.register(e,{scope:t});(r||a||o).addEventListener("statechange",(e=>{console.log("state",e.target.state)}));const s=navigator.serviceWorker;await new Promise((e=>{if(s.controller)e();else{const t=()=>{e(),s.removeEventListener("controllerchange",t),s.oncontrollerchange=null};s.addEventListener("controllerchange",t),s.oncontrollerchange=t}}));const c=s.controller,i=()=>"activated"===c.state;return await new Promise((async e=>{i()?e(c):c.onstatechange=()=>{i()&&(c.onstatechange=null,e(c))}}))}async function k({swUrl:e,scopeUrl:t,type:n}){await navigator.serviceWorker.register(e,{type:n,scope:t});const r=await async function(){return await new Promise((e=>{const t=navigator.serviceWorker;if(t.controller)e(t.controller);else{const n=()=>{e(t.controller),t.removeEventListener("controllerchange",n),t.oncontrollerchange=null};t.addEventListener("controllerchange",n),t.oncontrollerchange=n}}))}();return await async function(e){const t=()=>"activated"===e.state;await new Promise((async n=>{t()?n():e.onstatechange=()=>{t()&&(e.onstatechange=null,n())}}))}(r),r}async function O(e,{key:t,port:n}){return await U({key:t,communicationPort:n,handler:async(t,n,r)=>(m(r,e),!0)})}async function L(e,{key:t,port:n}){const r=await P({key:t,communicationPort:n});return await h(r,e)}function T({swUrl:e=new URL("./index-sw.js",import.meta.url)+"",scopeUrl:t=new URL("../",import.meta.url)+""}={}){let n;return async r=>{if("CONNECT"===r.data.type){const a=(r.ports||[])[0];if(n)return void a.close();n=a,await k({swUrl:e,scopeUrl:t});const o=E();o.onmessage=e=>{n.postMessage(e.data,e.ports)},n.onmessage=e=>{o.postMessage(e.data,e.ports)}}}}async function C({baseUrl:e=new URL("../public-relay/",import.meta.url),url:t=new URL("relay.html",e),container:n=document.body}={}){const r=new MessageChannel,{iframe:a,promise:o}=await async function(e){const t=document.createElement("iframe");return t.src=e,Object.assign(t.style,{padding:0,margin:0,border:"none",outline:"none",width:"100%",height:"100%"}),{iframe:t,promise:new Promise(((e,n)=>{try{t.onerror=n,t.onload=()=>e(t)}catch(e){n(e)}}))}}(t);return Object.assign(a.style,{position:"fixed",width:"1px",height:"1px",top:"-1000",left:"-1000",display:"block",opacity:"0",border:"none",outline:"none"}),n.appendChild(a),o.then((()=>{a.contentWindow.postMessage({type:"CONNECT"},"*",[r.port1])})),{baseUrl:e,port:r.port2,close:()=>{a.parentElement&&a.parentElement.removeChild(a),r.port1.close(),r.port2.close()}}}async function P({key:e,communicationPort:t,...r}){const a=new MessageChannel;return await n(t,"CONNECT",{key:e,...r},a.port2)?a.port1:(a.port1.close(),a.port2.close(),null)}async function U({key:e,handler:t,communicationPort:o}){const[s,c]=a();return await n(o,"REGISTER",{key:e}),s((()=>n(o,"UNREGISTER",{key:e}))),s(r(o,"CONNECT",t)),c}export{n as callChannel,L as callHttpService,t as deserializeError,y as fromReadableStream,T as getRelayWindowMessageHandler,r as handleChannelCalls,m as handleHttpRequests,i as handleStreams,O as initHttpService,k as initServiceWorker,b as initServiceWorker1,P as initializeConnection,p as newHttpClientStub,w as newHttpServerStub,u as newInvokationChannel,a as newRegistry,C as newRemoteRelayChannel,E as newServiceWorkerPort,o as recieveData,U as registerConnectionsHandler,s as sendData,h as sendHttpRequest,c as sendStream,e as serializeError,v as splitServiceUrl,d as toReadableStream};
package/index.js DELETED
@@ -1 +0,0 @@
1
- export * from './src/index.js';
@@ -1,36 +0,0 @@
1
- import { deserializeError, serializeError } from "./errors.js";
2
-
3
- export async function callChannel(mainChannel, callType, params, ...transfers) {
4
- return new Promise((resolve, reject) => {
5
- const channel = new MessageChannel();
6
- channel.port1.onmessage = (ev) => {
7
- const { result, error } = ev.data;
8
- if (error) reject(deserializeError(error));
9
- else resolve(result);
10
- };
11
- mainChannel.postMessage({ type: callType, params }, [
12
- channel.port2,
13
- ...transfers,
14
- ]);
15
- });
16
- }
17
-
18
- export function handleChannelCalls(mainChannel, callType, handler) {
19
- const messageListener = async (event) => {
20
- if (!event.data || event.data.type !== callType) return;
21
- const [port, ...transfers] = event.ports;
22
- let response = {};
23
- try {
24
- const params = event.data.params;
25
- response.result = await handler(event, params, ...transfers);
26
- } catch (error) {
27
- response.error = serializeError(error);
28
- }
29
- port.postMessage(response);
30
- };
31
- mainChannel.addEventListener("message", messageListener);
32
- try {
33
- mainChannel.start && mainChannel.start();
34
- } catch (e) {}
35
- return () => mainChannel.removeEventListener("message", messageListener);
36
- }
@@ -1,192 +0,0 @@
1
- import { deserializeError, serializeError } from "./errors.js";
2
- import { recieveData, sendData } from "./data-send-recieve.js";
3
-
4
- export async function* sendStream(communicationPort, input, params = {}) {
5
- const messageChannel = new MessageChannel();
6
- communicationPort.postMessage({ type: "START_CALL", params }, [
7
- messageChannel.port2,
8
- ]);
9
-
10
- const channel = newChannel(messageChannel.port1);
11
- try {
12
- await channel.start();
13
- channel.sendAll(input);
14
- yield* channel.recieveAll();
15
- } finally {
16
- await channel.close();
17
- }
18
- }
19
-
20
- export function handleStreams(communicationPort, handler) {
21
- const listener = async (event) => {
22
- const { type, params } = event.data || {};
23
- if (type !== "START_CALL") return;
24
- const port = event.ports[0];
25
- const channel = newChannel(port);
26
- try {
27
- await channel.start();
28
- const input = channel.recieveAll();
29
- const response = await handler(input, params);
30
- await channel.sendAll(response);
31
- } finally {
32
- await channel.close();
33
- }
34
- };
35
- communicationPort.addEventListener("message", listener);
36
- try {
37
- communicationPort.start && communicationPort.start();
38
- } catch (e) {}
39
- return () => communicationPort.removeEventListener("message", listener);
40
- }
41
-
42
- /**
43
- * This method creates and returns methods allowing to send and recieve data over the specified port.
44
- * The main characteristics of the returned methods is that they properly manage backpressure - sender
45
- * iterators are waiting to send the next value until the previous one is consumed on the other side.
46
- * @param {*} port
47
- * @returns an object with the following methods:
48
- * * `start` - starts the connection over the specified port
49
- * * `close`- stops all iterators and closes the port
50
- * * `recieveAll() : AsyncIterator` - returns an AsyncIterator over all values send by the peer
51
- * * `sendAll(it : AsyncIterator) : Promise<any>` - sends all values defined by the given
52
- * AsyncIterator to the peer
53
- */
54
- function newChannel(port) {
55
- let listeners = [];
56
- let iterators = [];
57
-
58
- const notifyAll = async (data) => {
59
- for (let listener of listeners) {
60
- await listener(data);
61
- }
62
- };
63
- const channel = newInvokationChannel({
64
- port,
65
- handler: notifyAll,
66
- });
67
-
68
- const start = () => channel.start();
69
-
70
- const close = async () => {
71
- await notifyAll({ done: true });
72
- [...iterators].forEach((it) => it.return && it.return());
73
- await channel.close();
74
- };
75
-
76
- async function* recieveAll() {
77
- yield* recieveData((listener) => {
78
- listeners.push(listener);
79
- return () => listeners = listeners.filter((l) => l !== listener);
80
- });
81
- }
82
-
83
- async function sendAll(it) {
84
- await sendData(
85
- channel.invoke,
86
- (async function* () {
87
- try {
88
- iterators.push(it);
89
- yield* it;
90
- } finally {
91
- iterators = iterators.filter((i) => i !== it);
92
- }
93
- })(),
94
- );
95
- }
96
- return {
97
- start,
98
- close,
99
- recieveAll,
100
- sendAll,
101
- };
102
- }
103
-
104
- export function newInvokationChannel({
105
- port,
106
- handler = () => {
107
- throw new Error("Handler not implemented");
108
- },
109
- onError = console.error,
110
- newCallId = () =>
111
- newInvokationChannel.__counter = (newInvokationChannel.__counter || 0) + 1,
112
- }) {
113
- const MESSAGE_TYPE_REQUEST = "REQUEST";
114
- const MESSAGE_TYPE_RESPONSE = "RESPONSE";
115
- const EVENT_MESSAGE = "message";
116
-
117
- const requests = {};
118
- const listener = async (event) => {
119
- const data = event.data || {};
120
- const { type, callId } = data;
121
- if (type === MESSAGE_TYPE_REQUEST) {
122
- try {
123
- const { request } = data;
124
- let result = await handler(request, ...(event.ports || []));
125
- const [response, ...transfers] = Array.isArray(result)
126
- ? result
127
- : result !== undefined
128
- ? [result]
129
- : [];
130
- port.postMessage(
131
- { type: MESSAGE_TYPE_RESPONSE, callId, response },
132
- transfers,
133
- );
134
- } catch (error) {
135
- port.postMessage({
136
- type: MESSAGE_TYPE_RESPONSE,
137
- callId,
138
- error: serializeError(error),
139
- });
140
- }
141
- } else if (type === MESSAGE_TYPE_RESPONSE) {
142
- const { callId, response, error } = data;
143
- const request = requests[callId];
144
- delete requests[callId];
145
- if (request) {
146
- error
147
- ? request.reject(deserializeError(error))
148
- : request.resolve(response);
149
- }
150
- }
151
- };
152
-
153
- const start = async () => {
154
- try {
155
- port.addEventListener(EVENT_MESSAGE, listener);
156
- port.start && await port.start();
157
- } catch (e) {
158
- onError(e);
159
- }
160
- };
161
-
162
- const close = async () => {
163
- try {
164
- port.removeEventListener(EVENT_MESSAGE, listener);
165
- port.close && await port.close();
166
- } catch (e) {
167
- onError(e);
168
- }
169
- };
170
-
171
- const invoke = async function (request = {}, ...transfers) {
172
- const callId = newCallId();
173
- return new Promise((resolve, reject) => {
174
- try {
175
- requests[callId] = { resolve, reject };
176
- port.postMessage(
177
- { type: MESSAGE_TYPE_REQUEST, callId, request },
178
- transfers,
179
- );
180
- } catch (error) {
181
- reject(error);
182
- delete request[callId];
183
- }
184
- });
185
- };
186
-
187
- return {
188
- start,
189
- close,
190
- invoke,
191
- };
192
- }
@@ -1,28 +0,0 @@
1
- import { iterate } from "@statewalker/utils";
2
-
3
- export async function* recieveData(onMessage) {
4
- yield* iterate((iterator) => {
5
- return onMessage(async ({ done = true, value, error } = {}) => {
6
- if (error) {
7
- await iterator.error(error);
8
- } else if (done) {
9
- await iterator.complete();
10
- } else {
11
- await iterator.next(value);
12
- }
13
- });
14
- });
15
- }
16
-
17
- export async function sendData(send, it) {
18
- let error;
19
- try {
20
- for await (let value of it) {
21
- await send({ done: false, value });
22
- }
23
- } catch (err) {
24
- error = err;
25
- } finally {
26
- await send({ done: true, error });
27
- }
28
- }
@@ -1,13 +0,0 @@
1
- export function serializeError(error) {
2
- return Object.assign({
3
- message: error,
4
- stack: error.stack,
5
- }, error);
6
- }
7
-
8
- export function deserializeError(error) {
9
- if (typeof error === "string") {
10
- error = { message: error };
11
- }
12
- return Object.assign(new Error(error.message), error);
13
- }
package/src/core/index.js DELETED
@@ -1,4 +0,0 @@
1
- export * from "./data-calls.js";
2
- export * from "./data-channels.js";
3
- export * from "./data-send-recieve.js";
4
- export * from "./errors.js";
@@ -1,59 +0,0 @@
1
- export class HttpError extends Error {
2
- constructor(options) {
3
- super(options.message);
4
- this.status = options.status;
5
- this.statusText = options.statusText;
6
- }
7
- getResponseOptions(options = {}) {
8
- return Object.assign(this.toJson(), options);
9
- }
10
- toJson() {
11
- return {
12
- status: this.status,
13
- statusText: this.statusText,
14
- message: this.message,
15
- };
16
- }
17
-
18
- static fromError(error) {
19
- if (!(error instanceof HttpError)) {
20
- error = new HttpError(Object.assign({
21
- status: 500,
22
- statusText: "Bad Request",
23
- reason: error.message,
24
- }));
25
- }
26
- return error;
27
- }
28
-
29
- static errorResourceNotFound(options = {}) {
30
- return new HttpError({
31
- status: 404,
32
- statusText: "Error 404: Resource not found",
33
- ...options,
34
- });
35
- }
36
- static errorForbidden(options = {}) {
37
- return new HttpError({
38
- status: 403,
39
- statusText: "Error 403: Forbidden",
40
- ...options,
41
- });
42
- }
43
-
44
- static errorResourceGone(options = {}) {
45
- return new HttpError({
46
- status: 410,
47
- statusText: "Error 410: Resource Gone",
48
- ...options,
49
- });
50
- }
51
-
52
- static errorInternalError(options) {
53
- return new HttpError({
54
- ...options,
55
- status: 500,
56
- statusText: "Error 500: Internal error",
57
- });
58
- }
59
- }
@@ -1,40 +0,0 @@
1
- import { handleStreams, sendStream } from "../core/data-channels.js";
2
- import { newHttpClientStub, newHttpServerStub } from "./http-stubs.js";
3
-
4
- async function* httpToIterator(params) {
5
- const { options, content } = await params;
6
- const encoder = new TextEncoder();
7
- yield encoder.encode(JSON.stringify(options));
8
- yield* content;
9
- }
10
-
11
- async function httpFromIterator(it) {
12
- it = await it;
13
- const { done, value } = await it.next();
14
- let options = {};
15
- if (!done && value) {
16
- const decoder = new TextDecoder();
17
- const str = decoder.decode(value);
18
- options = JSON.parse(str);
19
- }
20
- return {
21
- options,
22
- content: it,
23
- };
24
- }
25
-
26
- export function handleHttpRequests(communicationPort, handler) {
27
- const serverStub = newHttpServerStub(handler);
28
- return handleStreams(communicationPort, (it) => {
29
- return httpToIterator(serverStub(httpFromIterator(it)));
30
- });
31
- }
32
-
33
- export async function sendHttpRequest(communicationPort, request) {
34
- const clientStub = newHttpClientStub(async (req) => {
35
- return await httpFromIterator(
36
- sendStream(communicationPort, httpToIterator(req)),
37
- );
38
- });
39
- return await clientStub(request);
40
- }
@@ -1,135 +0,0 @@
1
- import { fromReadableStream, toReadableStream } from "./readable-streams.js";
2
-
3
- /**
4
- * This method returns an HTTP handlers transforming
5
- * HTTP Request instances to binary representations and
6
- * sending them to a transport layer.
7
- * Results of these transport ivokations are deserialized
8
- * as meaningful Response instances and returned back to the caller.
9
- *
10
- * The specified `send` method is used to dispatch serialized
11
- * requests to return the serialized remote results.
12
- * This transport method accepts and returns objects with
13
- * the same structure:
14
- * * `options` - contains serialized request or response parameters
15
- * * `content` - an async iterator over binary blocks for
16
- * the request or response
17
- *
18
- * @param {*} send transport function accepting serialized requests
19
- * and returning back serialized responses
20
- * @returns an async handler accepting standard
21
- * HTTP `Request` instances and returning `Response` instances
22
- */
23
- export function newHttpClientStub(send) {
24
- return async (request) => {
25
- request = await request;
26
- const fields = [
27
- "url",
28
- "method",
29
- "mode",
30
- "credentials",
31
- "cache",
32
- "redirect",
33
- "referrer",
34
- "referrerPolicy",
35
- "integrity",
36
- "keepalive"
37
- ];
38
- const headers = [...request.headers].map(([key, value]) => {
39
- return [key, value]
40
- });
41
- const requestOptions = fields.reduce((options, key) => {
42
- const val = request[key];
43
- if (val !== undefined) options[key] = val;
44
- return options;
45
- }, {
46
- headers
47
- });
48
- const requestContent = (request.body)
49
- ? fromReadableStream(request.body)
50
- : [];
51
- const result = await send({
52
- options: requestOptions,
53
- content: requestContent,
54
- });
55
- let responseBody = null;
56
- let responseOptions = {};
57
- if (!result) {
58
- responseOptions = {
59
- status: 404,
60
- statusText: "Error 404: Not Found",
61
- };
62
- } else {
63
- responseOptions = result.options;
64
- const responseContent = result.content;
65
- if (
66
- requestOptions.method !== "HEAD" &&
67
- requestOptions.method !== "OPTIONS"
68
- ) {
69
- responseBody = toReadableStream(responseContent);
70
- } else if (responseContent && responseContent.return) {
71
- responseContent.return();
72
- }
73
- }
74
- return new Response(responseBody, responseOptions);
75
- };
76
- }
77
-
78
- /**
79
- * This method returns the server-side call handler transforming
80
- * serialized requests to HTTP Request instances, delegating
81
- * their handing to the given `handler` method. This handler
82
- * should handle the HTTP request and return a valid Response instance.
83
- * The resulting instance is serialized as an object with the same
84
- * structure as the initial serialized request:
85
- * - `options` - contains serialized request or response parameters
86
- * - `content` - an async iterator over binary blocks for
87
- * the request or response
88
- * @param {*} handler this handler method accepts standard HTTP Request
89
- * and returns back an HTTP Response instance
90
- * @returns a method deserializing HTTP requests and returning back
91
- * serialized HTTP responses
92
- */
93
- export function newHttpServerStub(handler) {
94
- return async (params) => {
95
- const {
96
- options: requestOptions,
97
- content: requestContent,
98
- } = await params;
99
- let requestBody = undefined;
100
- const { url, mode, headers = [] } = requestOptions;
101
- const requestHeaders = new Headers()
102
- for (let [key, value] of headers) {
103
- requestHeaders.append(key, value);
104
- }
105
- delete requestOptions.mode;
106
- delete requestOptions.url;
107
- if (
108
- requestOptions.method !== "GET" &&
109
- requestOptions.method !== "HEAD" &&
110
- requestOptions.method !== "OPTIONS"
111
- ) {
112
- requestBody = toReadableStream(requestContent);
113
- requestOptions.duplex = "half";
114
- } else if (requestContent && requestContent.return) {
115
- requestContent.return();
116
- }
117
- const request = new Request(url, {
118
- ...requestOptions,
119
- headers: requestHeaders,
120
- // duplex: 'full',
121
- body: requestBody,
122
- });
123
- const response = await handler(request);
124
- const responseOptions = {
125
- status: response.status,
126
- statusText: response.statusText,
127
- headers: Object.fromEntries([...response.headers]),
128
- };
129
- const responseContent = await fromReadableStream(await response.body);
130
- return {
131
- options: responseOptions,
132
- content: responseContent,
133
- };
134
- };
135
- }
package/src/http/index.js DELETED
@@ -1,3 +0,0 @@
1
- export * from "./http-send-recieve.js";
2
- export * from "./http-stubs.js";
3
- export * from "./readable-streams.js";
@@ -1,33 +0,0 @@
1
- export function toReadableStream(it) {
2
- return new ReadableStream({
3
- type: "bytes",
4
- async pull(controller) {
5
- let handled = false;
6
- try {
7
- while (true) {
8
- const slot = await it.next();
9
- if (!slot || slot.done) {
10
- break;
11
- }
12
- controller.enqueue(await slot.value);
13
- }
14
- } catch (error) {
15
- handled = true;
16
- controller.error(error);
17
- } finally {
18
- !handled && controller.close();
19
- }
20
- },
21
- });
22
- }
23
-
24
- export async function* fromReadableStream(stream) {
25
- const reader = await stream.getReader();
26
- let done, value;
27
- while (({ done, value } = await reader.read())) {
28
- if (done) {
29
- break;
30
- }
31
- yield await value;
32
- }
33
- }
package/src/index.js DELETED
@@ -1,7 +0,0 @@
1
- export * from "./core/index.js"
2
- export * from "./http/index.js";
3
- // export * from "./sw/index.js";
4
- export * from "./relay/index.js";
5
-
6
- import { newRegistry } from "@statewalker/utils";
7
- export { newRegistry };