@statewalker/webrun-http-browser 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- // @statewalker/webrun-http-browser v0.1.0 https://github.com/statewalker/statewalker-webrun-http-browser Copyright 2023 Mikhail Kotelnikov
1
+ // @statewalker/webrun-http-browser v0.2.1 https://github.com/statewalker/statewalker-webrun-http-browser Copyright 2023 Mikhail Kotelnikov
2
2
  function serializeError(error) {
3
3
  return Object.assign({
4
4
  message: error,
@@ -199,7 +199,10 @@ function newChannel(port) {
199
199
  await listener(data);
200
200
  }
201
201
  };
202
- const channel = newInvokationChannel(port, notifyAll);
202
+ const channel = newInvokationChannel({
203
+ port,
204
+ handler: notifyAll,
205
+ });
203
206
 
204
207
  const start = () => channel.start();
205
208
 
@@ -237,15 +240,20 @@ function newChannel(port) {
237
240
  };
238
241
  }
239
242
 
240
- function newInvokationChannel(port, handler = () => {
241
- throw new Error("Handler not implemented");
243
+ function newInvokationChannel({
244
+ port,
245
+ handler = () => {
246
+ throw new Error("Handler not implemented");
247
+ },
248
+ onError = console.error,
249
+ newCallId = () =>
250
+ newInvokationChannel.__counter = (newInvokationChannel.__counter || 0) + 1,
242
251
  }) {
243
252
  const MESSAGE_TYPE_REQUEST = "REQUEST";
244
253
  const MESSAGE_TYPE_RESPONSE = "RESPONSE";
245
254
  const EVENT_MESSAGE = "message";
246
255
 
247
256
  const requests = {};
248
- let requestCounter = 0;
249
257
  const listener = async (event) => {
250
258
  const data = event.data || {};
251
259
  const { type, callId } = data;
@@ -282,17 +290,25 @@ function newInvokationChannel(port, handler = () => {
282
290
  };
283
291
 
284
292
  const start = async () => {
285
- port.addEventListener(EVENT_MESSAGE, listener);
286
- await port.start();
293
+ try {
294
+ port.addEventListener(EVENT_MESSAGE, listener);
295
+ port.start && await port.start();
296
+ } catch (e) {
297
+ onError(e);
298
+ }
287
299
  };
288
300
 
289
301
  const close = async () => {
290
- port.removeEventListener(EVENT_MESSAGE, listener);
291
- await port.close();
302
+ try {
303
+ port.removeEventListener(EVENT_MESSAGE, listener);
304
+ port.close && await port.close();
305
+ } catch (e) {
306
+ onError(e);
307
+ }
292
308
  };
293
309
 
294
310
  const invoke = async function (request = {}, ...transfers) {
295
- const callId = ++requestCounter;
311
+ const callId = newCallId();
296
312
  return new Promise((resolve, reject) => {
297
313
  try {
298
314
  requests[callId] = { resolve, reject };
@@ -511,435 +527,284 @@ async function sendHttpRequest(communicationPort, request) {
511
527
  return await clientStub(request);
512
528
  }
513
529
 
514
- function promisifyRequest(request) {
515
- return new Promise((resolve, reject) => {
516
- // @ts-ignore - file size hacks
517
- request.oncomplete = request.onsuccess = () => resolve(request.result);
518
- // @ts-ignore - file size hacks
519
- request.onabort = request.onerror = () => reject(request.error);
520
- });
521
- }
522
- function createStore(dbName, storeName) {
523
- const request = indexedDB.open(dbName);
524
- request.onupgradeneeded = () => request.result.createObjectStore(storeName);
525
- const dbp = promisifyRequest(request);
526
- return (txMode, callback) => dbp.then((db) => callback(db.transaction(storeName, txMode).objectStore(storeName)));
527
- }
528
- let defaultGetStoreFunc;
529
- function defaultGetStore() {
530
- if (!defaultGetStoreFunc) {
531
- defaultGetStoreFunc = createStore('keyval-store', 'keyval');
532
- }
533
- return defaultGetStoreFunc;
534
- }
535
- /**
536
- * Get a value by its key.
537
- *
538
- * @param key
539
- * @param customStore Method to get a custom store. Use with caution (see the docs).
540
- */
541
- function get(key, customStore = defaultGetStore()) {
542
- return customStore('readonly', (store) => promisifyRequest(store.get(key)));
543
- }
544
- /**
545
- * Set a value with a key.
546
- *
547
- * @param key
548
- * @param value
549
- * @param customStore Method to get a custom store. Use with caution (see the docs).
550
- */
551
- function set(key, value, customStore = defaultGetStore()) {
552
- return customStore('readwrite', (store) => {
553
- store.put(value, key);
554
- return promisifyRequest(store.transaction);
555
- });
556
- }
557
-
558
- class SwPortHandler {
559
- constructor(options) {
560
- this.options = options;
561
- if (!this.key) throw new Error("Key is not defined.");
562
- if (!this.scope) throw new Error("Scope is not defined");
563
- }
564
-
565
- get key() {
566
- return this.options.key;
530
+ function splitServiceUrl(url, separator = "~") {
531
+ let key = "";
532
+ let path = "";
533
+ let str = url + "";
534
+ const idx = str.indexOf(separator);
535
+ let baseUrl = "";
536
+ if (idx >= 0) {
537
+ baseUrl = str.substring(0, idx + separator.length);
538
+ str.substring(idx + separator.length)
539
+ .replace(/^([^\/]+)/, (match, $1) => {
540
+ baseUrl += match;
541
+ if (baseUrl.length < str.length) baseUrl += "/";
542
+ key = $1;
543
+ path = str.substring(baseUrl.length);
544
+ return "";
545
+ });
567
546
  }
547
+ return {
548
+ url,
549
+ key,
550
+ baseUrl,
551
+ path,
552
+ };
553
+ }
568
554
 
569
- get scope() {
570
- return this.options.scope || new URL("./", this.serviceWorkerUrl).pathname;
571
- }
555
+ function newServiceWorkerPort() {
556
+ // Bind the service worker to
557
+ const channel = new MessageChannel();
558
+ channel.port1.onmessage = (event) => {
559
+ navigator.serviceWorker.controller.postMessage(event.data, event.ports);
560
+ };
561
+ navigator.serviceWorker.addEventListener("message", (event) => {
562
+ channel.port1.postMessage(event.data, event.ports);
563
+ });
564
+ return channel.port2;
565
+ }
572
566
 
573
- get rootUrl() {
574
- return new URL(this.scope, import.meta.url);
575
- }
567
+ async function initServiceWorker1({ swUrl, scopeUrl, type }) {
568
+ const {
569
+ installing,
570
+ waiting,
571
+ active,
572
+ } = await navigator.serviceWorker.register(swUrl, {
573
+ // type: "module",
574
+ scope: scopeUrl,
575
+ });
576
+ (installing || waiting || active).addEventListener("statechange", (e) => {
577
+ console.log("state", e.target.state);
578
+ });
576
579
 
577
- get serviceWorkerUrl() {
578
- if (!this._serviceWorkerUrl) {
579
- let url = this.options.serviceWorkerUrl
580
- ? new URL(this.options.serviceWorkerUrl)
581
- : new URL("./index-sw.js", this.rootUrl);
582
- this._serviceWorkerUrl = url + "";
580
+ const serviceWorker = navigator.serviceWorker;
581
+ await new Promise((resolve) => {
582
+ // Resolve right away if this page is already controlled.
583
+ if (serviceWorker.controller) {
584
+ resolve();
585
+ } else {
586
+ const onChange = () => {
587
+ resolve();
588
+ serviceWorker.removeEventListener("controllerchange", onChange);
589
+ serviceWorker.oncontrollerchange = null;
590
+ };
591
+ serviceWorker.addEventListener("controllerchange", onChange);
592
+ serviceWorker.oncontrollerchange = onChange;
583
593
  }
584
- return this._serviceWorkerUrl;
585
- }
586
-
587
- async _newCommunicationChannel() {
588
- const messageChannel = new MessageChannel();
589
- return [messageChannel.port1, messageChannel.port2];
590
- }
591
-
592
- async _setCommunicationPort(port) {
593
- await this.options.bindPort(port);
594
- }
595
-
596
- async _updateCommunicationChannel() {
597
- // console.log("[_updateCommunicationChannel]", this._serviceWorker);
598
- if (!this._serviceWorker) return;
599
- const [port1, port2] = await this._newCommunicationChannel();
600
- await this._setCommunicationPort(port1);
601
- await callChannel(
602
- this._serviceWorker,
603
- "UPDATE_COMMUNICATION_PORT",
604
- this._getRegistrationInfo(),
605
- port2,
606
- );
607
- }
608
-
609
- _getRegistrationInfo() {
610
- return { key: this.key };
611
- }
612
-
613
- /**
614
- * Starts the server.
615
- */
616
- async start() {
617
- return this._registrationPromise = this._registrationPromise ||
618
- (async () => {
619
- const [register, cleanup] = newRegistry();
620
- this._cleanupRegistrations = cleanup;
621
- register(() => this._cleanupRegistrations = null);
622
- const registration = await navigator.serviceWorker.register(
623
- this.serviceWorkerUrl,
624
- {
625
- // type: "module",
626
- scope: this.scope,
627
- },
628
- );
629
- register(() => registration.unregister());
630
-
631
- // (example: when the service worker is the same but it is waked up/activated after an idle period)
632
- register(
633
- handleChannelCalls(
634
- navigator.serviceWorker,
635
- "UPDATE_COMMUNICATION_PORT",
636
- async (event, params, port) => {
637
- console.log("[UPDATE_COMMUNICATION_PORT]", port);
638
- this._setCommunicationPort(port);
639
- return this._getRegistrationInfo();
640
- },
641
- ),
642
- );
643
-
644
- this._serviceWorker = await getServiceWorkerController();
645
- await awaitServiceWorkerActivation(this._serviceWorker);
646
- await this._updateCommunicationChannel();
647
-
648
- async function getServiceWorkerController() {
649
- return await new Promise((resolve) => {
650
- // Resolve right away if this page is already controlled.
651
- const serviceWorker = navigator.serviceWorker;
652
- if (serviceWorker.controller) {
653
- resolve(serviceWorker.controller);
654
- } else {
655
- const onChange = () => {
656
- resolve(serviceWorker.controller);
657
- serviceWorker.removeEventListener("controllerchange", onChange);
658
- serviceWorker.oncontrollerchange = null;
659
- };
660
- serviceWorker.addEventListener("controllerchange", onChange);
661
- serviceWorker.oncontrollerchange = onChange;
662
- }
663
- });
664
- }
665
-
666
- // ------------------------------
667
- // Await until the service is ready
668
- async function awaitServiceWorkerActivation(worker) {
669
- const isActivated = () => worker.state === "activated";
670
- await new Promise(async (resolve) => {
671
- if (isActivated()) resolve();
672
- else {
673
- worker.onstatechange = () => {
674
- if (!isActivated()) return;
675
- worker.onstatechange = null;
676
- resolve();
677
- };
678
- }
679
- });
680
- }
681
- })();
682
- }
683
-
684
- /**
685
- * Stops the server and removes associated handlers.
686
- */
687
- async stop() {
688
- if (this._cleanupRegistrations) this._cleanupRegistrations();
689
- const registrations = await navigator.serviceWorker.getRegistrations();
690
- for (let registration of registrations) {
691
- try {
692
- await registration.unregister();
693
- } catch (error) {
694
- console.log("Service Worker registration failed: ", error);
695
- }
594
+ });
595
+ const worker = serviceWorker.controller;
596
+ const isActivated = () => worker.state === "activated";
597
+ return await new Promise(async (resolve) => {
598
+ if (isActivated()) resolve(worker);
599
+ else {
600
+ worker.onstatechange = () => {
601
+ if (!isActivated()) return;
602
+ worker.onstatechange = null;
603
+ resolve(worker);
604
+ };
696
605
  }
697
- }
606
+ });
698
607
  }
699
608
 
700
- class SwPortDispatcher {
701
- constructor({ self, log }) {
702
- this.self = self;
703
- this.log = log;
704
- // Contains mapping between path prefixes and clientIds
705
- this.handlersIndex = new Map();
706
- }
707
-
708
- get scope() {
709
- return new URL("./", import.meta.url) + "";
710
- }
711
-
712
- async loadChannelInfo(key) {
713
- await this._checkActivation();
714
- let result;
715
- for (let channelInfo of this.handlersIndex.values()) {
716
- if (channelInfo.key !== key) continue;
717
- const clientId = channelInfo.clientId;
718
- const client = await self.clients.get(clientId);
719
- if (!client) {
720
- // Client gone. Remove the corresponding handlers from the index.
721
- this.handlersIndex.delete(clientId);
722
- throw Object.assign(new Error("Error 410: Resource Gone"), {
723
- status: 410,
724
- });
609
+ async function initServiceWorker({ swUrl, scopeUrl, type }) {
610
+ await navigator.serviceWorker.register(swUrl, {
611
+ type,
612
+ scope: scopeUrl,
613
+ });
614
+ const worker = await getServiceWorkerController();
615
+ await awaitServiceWorkerActivation(worker);
616
+ return worker;
617
+
618
+ async function getServiceWorkerController() {
619
+ return await new Promise((resolve) => {
620
+ // Resolve right away if this page is already controlled.
621
+ const serviceWorker = navigator.serviceWorker;
622
+ if (serviceWorker.controller) {
623
+ resolve(serviceWorker.controller);
624
+ } else {
625
+ const onChange = () => {
626
+ resolve(serviceWorker.controller);
627
+ serviceWorker.removeEventListener("controllerchange", onChange);
628
+ serviceWorker.oncontrollerchange = null;
629
+ };
630
+ serviceWorker.addEventListener("controllerchange", onChange);
631
+ serviceWorker.oncontrollerchange = onChange;
725
632
  }
726
- result = channelInfo;
727
- break;
728
- }
729
- return result;
730
- }
731
-
732
- start() {
733
- this._cleanup = handleChannelCalls(
734
- this.self,
735
- "UPDATE_COMMUNICATION_PORT",
736
- async (event, channelInfo, port) => {
737
- const clientId = event.source.id;
738
- this.log("[UPDATE_COMMUNICATION_PORT]", clientId, channelInfo);
739
- await this._updateChannelInfo({ ...channelInfo, port, clientId });
740
- return { ...channelInfo };
741
- },
742
- );
743
- this.self.onmessage = () => {};
744
-
745
- this.self.addEventListener("install", (event) => {
746
- this.log("Skip waiting on install.", event);
747
- this.self.skipWaiting();
748
- });
749
-
750
- this.self.addEventListener("activate", async (event) => {
751
- this.log(
752
- "Claim control over all clients.",
753
- event,
754
- clients,
755
- this.self.clients,
756
- );
757
- event.waitUntil((async () => {
758
- await this.self.clients.claim();
759
- await this._checkActivation();
760
- })());
761
633
  });
762
634
  }
763
635
 
764
- async stop() {
765
- if (this._cleanup) {
766
- await this._cleanup();
767
- this._cleanup = undefined;
768
- }
769
- }
770
-
771
- async _checkActivation() {
772
- return this._activationPromise = this._activationPromise ||
773
- this._activate();
636
+ // ------------------------------
637
+ // Await until the service is ready
638
+ async function awaitServiceWorkerActivation(worker) {
639
+ const isActivated = () => worker.state === "activated";
640
+ await new Promise(async (resolve) => {
641
+ if (isActivated()) resolve();
642
+ else {
643
+ worker.onstatechange = () => {
644
+ if (!isActivated()) return;
645
+ worker.onstatechange = null;
646
+ resolve();
647
+ };
648
+ }
649
+ });
774
650
  }
651
+ }
775
652
 
776
- async _activate() {
777
- this.log("[checkActivation]");
778
- let clientsIndex = await this._loadClientIds();
779
- for (let [clientId, client] of clientsIndex.entries()) {
780
- const messageChannel = new MessageChannel();
781
- const port = messageChannel.port1;
782
- const channelInfo = await callChannel(
783
- client,
784
- "UPDATE_COMMUNICATION_PORT",
785
- {},
786
- messageChannel.port2,
787
- );
788
- await this._updateChannelInfo({ ...channelInfo, port, clientId });
789
- }
790
- }
653
+ async function initHttpService(handler, {
654
+ key,
655
+ port,
656
+ }) {
657
+ return await registerConnectionsHandler({
658
+ key,
659
+ communicationPort: port,
660
+ handler: async (event, data, callPort) => {
661
+ handleHttpRequests(callPort, handler);
662
+ return true;
663
+ },
664
+ });
665
+ }
791
666
 
792
- async _updateChannelInfo(channelInfo) {
793
- this.log("[updateClientInfo]", channelInfo);
794
- this.handlersIndex.set(channelInfo.clientId, channelInfo);
795
- await this._updateClientIds([]);
796
- }
667
+ async function callHttpService(request, {
668
+ key,
669
+ port,
670
+ }) {
671
+ const callPort = await initializeConnection({
672
+ key,
673
+ communicationPort: port,
674
+ });
675
+ const result = await sendHttpRequest(callPort, request);
676
+ return result;
677
+ }
797
678
 
798
- async _loadClientIds() {
799
- const clientIds = new Set((await get("clientIds")) || []);
800
- return await this._updateClientIds(clientIds);
801
- }
679
+ function getRelayWindowMessageHandler({
680
+ swUrl = new URL("./index-sw.js", import.meta.url) + "",
681
+ scopeUrl = new URL("../", import.meta.url) + "",
682
+ } = {}) {
683
+ let externalPort;
684
+ return async (ev) => {
685
+ if (ev.data.type === "CONNECT") {
686
+ const newExternalPort = (ev.ports || [])[0];
687
+ if (externalPort) {
688
+ newExternalPort.close();
689
+ return;
690
+ }
691
+ externalPort = newExternalPort;
692
+ await initServiceWorker({
693
+ swUrl,
694
+ scopeUrl,
695
+ });
696
+ const serviceWorkerPort = newServiceWorkerPort();
697
+ serviceWorkerPort.onmessage = (event) => {
698
+ externalPort.postMessage(event.data, event.ports);
699
+ };
802
700
 
803
- async _updateClientIds(clientIds) {
804
- clientIds = new Set(clientIds);
805
- for (let clientId of this.handlersIndex.keys()) {
806
- clientIds.add(clientId);
807
- }
808
- const index = new Map();
809
- for (let clientId of clientIds) {
810
- const client = await this.self.clients.get(clientId);
811
- if (client) index.set(clientId, client);
812
- else this.handlersIndex.delete(clientId);
701
+ externalPort.onmessage = (event) => {
702
+ serviceWorkerPort.postMessage(event.data, event.ports);
703
+ };
813
704
  }
814
- await set("clientIds", [...index.keys()].sort());
815
- return index;
816
- }
705
+ };
817
706
  }
818
707
 
819
- class SwHttpAdapter extends SwPortHandler {
820
- constructor(options) {
821
- super(options);
822
- this._handlers = new Map();
823
- }
824
-
825
- async _setCommunicationPort(port) {
826
- if (this._cleanupRequestChannel) {
827
- this._cleanupRequestChannel();
828
- }
829
- this._cleanupRequestChannel = handleHttpRequests(
830
- port,
831
- this._handleHttpRequest.bind(this),
708
+ async function newRemoteRelayChannel({
709
+ baseUrl = new URL("../public-relay/", import.meta.url),
710
+ url = new URL("relay.html", baseUrl),
711
+ container = document.body,
712
+ } = {}) {
713
+ const messageChannel = new MessageChannel();
714
+ const { iframe, promise } = await newIFrame(url);
715
+ Object.assign(iframe.style, {
716
+ // height: "100px"
717
+ position: "fixed",
718
+ width: "1px",
719
+ height: "1px",
720
+ top: "-1000",
721
+ left: "-1000",
722
+ display: "block",
723
+ opacity: "0",
724
+ border: "none",
725
+ outline: "none",
726
+ });
727
+ container.appendChild(iframe);
728
+ promise.then(() => {
729
+ iframe.contentWindow.postMessage(
730
+ {
731
+ type: "CONNECT",
732
+ },
733
+ "*",
734
+ [messageChannel.port1],
832
735
  );
833
- }
834
-
835
- async _handleHttpRequest(request) {
836
- const requestUrl = request.url;
837
- let handler;
838
- for (let entry of this._handlers.entries()) {
839
- const [urlPrefix] = entry;
840
- if (requestUrl.indexOf(urlPrefix) === 0) {
841
- handler = entry[1];
842
- break;
843
- }
844
- }
845
- return !handler
846
- ? new Response(null, {
847
- status: 404,
848
- statusMessage: "Error 404: Not found",
849
- })
850
- : handler(request);
851
- }
736
+ });
737
+ return {
738
+ port: messageChannel.port2,
739
+ close: () => {
740
+ container.parentElement && container.parentElement.removeChild(container);
741
+ messageChannel.port1.close();
742
+ messageChannel.port2.close();
743
+ },
744
+ };
852
745
 
853
- /**
854
- * Registers the given request handler.
855
- * @param {string} prefix unique base URL prefix used to register the specified handler
856
- * @param {*} handler the request handler
857
- * @return {string} full URL of the resulting endpoint
858
- */
859
- async register(prefix, handler) {
860
- prefix = "./" + (prefix || "").replace(/^[\.\/]+/, "");
861
- const rootUrl = this.rootUrl;
862
- const baseUrl = new URL(prefix, rootUrl) + "";
863
- this._handlers.set(baseUrl, handler);
746
+ async function newIFrame(url) {
747
+ const iframe = document.createElement("iframe");
748
+ iframe.src = url;
749
+ Object.assign(iframe.style, {
750
+ padding: 0,
751
+ margin: 0,
752
+ border: "none",
753
+ outline: "none",
754
+ width: "100%",
755
+ height: "100%",
756
+ });
864
757
  return {
865
- baseUrl,
866
- prefix,
867
- async remove() {
868
- this._handlers.delete(baseUrl);
869
- },
758
+ iframe,
759
+ promise: new Promise((resolve, reject) => {
760
+ try {
761
+ iframe.onerror = reject;
762
+ iframe.onload = () => resolve(iframe);
763
+ } catch (error) {
764
+ reject(error);
765
+ }
766
+ }),
870
767
  };
871
768
  }
872
769
  }
770
+ // -------------------------------------------------------
873
771
 
874
- class SwHttpDispatcher extends SwPortDispatcher {
875
- constructor(options) {
876
- super(options);
877
- }
878
-
879
- start() {
880
- super.start();
881
- this.self.addEventListener("fetch", this._handleFetchEvent.bind(this));
882
- }
883
-
884
- _handleFetchEvent(event) {
885
- event.respondWith((async () => {
886
- const request = event.request;
887
- try {
888
- const requestUrl = request.url;
889
- const rootUrl = this.scope;
890
- let channelInfo;
891
- if (requestUrl.indexOf(rootUrl) === 0) {
892
- const key = requestUrl
893
- .substring(rootUrl.length)
894
- .replace(/^\/?([^\/]+).*$/, "$1");
895
- // console.log(`* rootUrl="${rootUrl}" requestUrl="${requestUrl}" key="${key}"`);
896
- channelInfo = await this.loadChannelInfo(key);
897
- }
898
- if (channelInfo && channelInfo.port) {
899
- return await sendHttpRequest(channelInfo.port, request);
900
- } else {
901
- const newRequest = new Request(requestUrl, {
902
- method: request.method,
903
- headers: request.headers,
904
- body: request.body,
905
- referrer: request.referrer,
906
- referrerPolicy: request.referrerPolicy,
907
- // mode: request.mode,
908
- credentials: request.credentials,
909
- cache: request.cache,
910
- redirect: request.redirect,
911
- integrity: request.integrity,
912
- });
913
- return await fetch(newRequest);
914
- }
915
-
916
- // const requestUrl = request.url;
917
- // let url = requestUrl.replace(
918
- // /^.*\/[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}(.*)$/,
919
- // "$1",
920
- // );
921
- // if (url !== requestUrl) {
922
- // url = new URL(
923
- // "/packages/webrun-http-browser/src" + url,
924
- // self.location.href,
925
- // );
926
- // }
927
- } catch (error) {
928
- console.error(error);
929
- return new Response(null, {
930
- status: 500,
931
- statusText: "Error 500: Internal error",
932
- });
933
- }
934
- })());
935
- }
772
+ async function initializeConnection({
773
+ key,
774
+ communicationPort,
775
+ ...options
776
+ }) {
777
+ const channel = new MessageChannel();
778
+ const accepted = await callChannel(
779
+ communicationPort,
780
+ "CONNECT",
781
+ { key, ...options },
782
+ channel.port2,
783
+ );
784
+ if (!accepted) {
785
+ channel.port1.close();
786
+ channel.port2.close();
787
+ return null;
788
+ }
789
+ return channel.port1;
936
790
  }
937
- function startHttpDispatcher({ self, log }) {
938
- const dispatcher = new SwHttpDispatcher({ self, log });
939
- dispatcher.start();
940
- return () => {
941
- dispatcher.stop();
942
- };
791
+
792
+ async function registerConnectionsHandler({
793
+ key,
794
+ handler,
795
+ communicationPort,
796
+ }) {
797
+ const [register, cleanup] = newRegistry();
798
+ await callChannel(communicationPort, "REGISTER", { key });
799
+ register(() => callChannel(communicationPort, "UNREGISTER", { key }));
800
+ register(
801
+ handleChannelCalls(
802
+ communicationPort,
803
+ "CONNECT",
804
+ handler,
805
+ ),
806
+ );
807
+ return cleanup;
943
808
  }
944
809
 
945
- export { SwHttpAdapter, SwHttpDispatcher, SwPortDispatcher, SwPortHandler, callChannel, deserializeError, fromReadableStream, handleChannelCalls, handleHttpRequests, handleStreams, newChannel, newHttpClientStub, newHttpServerStub, newInvokationChannel, newRegistry, recieveData, sendData, sendHttpRequest, sendStream, serializeError, startHttpDispatcher, toReadableStream };
810
+ export { callChannel, callHttpService, deserializeError, fromReadableStream, getRelayWindowMessageHandler, handleChannelCalls, handleHttpRequests, handleStreams, initHttpService, initServiceWorker, initServiceWorker1, initializeConnection, newHttpClientStub, newHttpServerStub, newInvokationChannel, newRegistry, newRemoteRelayChannel, newServiceWorkerPort, recieveData, registerConnectionsHandler, sendData, sendHttpRequest, sendStream, serializeError, splitServiceUrl, toReadableStream };