@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
package/demo/demo-1.html CHANGED
@@ -1,199 +1,114 @@
1
- <!DOCTYPE HTML>
2
- <html>
3
-
4
- <head>
5
- <meta charset="utf-8" />
6
- <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
7
- <meta name="viewport" content="width=device-width, initial-scale=1" />
8
- </head>
9
-
10
- <body>
11
- <h1>Dynamic Site</h1>
12
- <p>This demo shows how to launch a dynamic site containing the following parts:</p>
13
- <ul>
14
- <li><code>/index.html</code> - the main page referencing a CSS and a java script files. Note that the javascript is
15
- imported using the standard ESM <code>import</code> notation</li>
16
- <li><code>/index.css</code> - styles for the HTML page.</li>
17
- <li><code>/index.js</code> - the main application code. This script listens the input box and sent its content to
18
- the server-side API.</li>
19
- <li><code>/api/:name</code> - dynamic server-side endpoint running responding to GET HTTP requests from the client.
20
- This endpoint returns JSON object with a greeting message using the transmitted name with the current time.
21
- The name of the user is loaded from the URL.
22
-
23
- <p>Example of the server response:</p>
24
- <pre>
25
- {
26
- "name" : "John",
27
- "time" : "11:02:59",
28
- "milliseconds" : "785"
29
- }
30
- </pre>
31
- </li>
32
- </ul>
33
- <div id="view"></div>
34
-
35
- <script type="module">
36
- import * as WebRunHttp from "https://unpkg.com/@statewalker/webrun-http-browser@0.3/dist/index.js";
37
- import { Hono } from "https://unpkg.com/hono@3.5/dist/index.js";
38
- import mime from "https://esm.sh/mime-types";
39
-
40
- Promise.resolve().then(main).catch(console.error);
41
- async function main() {
42
- // Load a Hono request router:
43
- const router = getRouter();
44
-
45
- // Create an HTTP Server with the specified name.
46
- // It uses the given Hono router to dispatch requests
47
- // between endpoints.
48
- const serviceBaseUrl = await startHttpService({
49
- serviceKey: "MY_SITE",
50
- router
51
- })
52
- const siteUrl = `${serviceBaseUrl}/`;
53
-
54
- // Now we can visualize the site in an iframe iframe:
55
- const container = document.querySelector("#view");
56
- const iframe = document.createElement("iframe");
57
- iframe.width = "100%";
58
- iframe.height = "500px";
59
- iframe.src = siteUrl;
60
- container.appendChild(iframe);
61
-
62
- // We also append a reference to this site.
63
- // It allows to open the site in a separate window:
64
- const a = document.createElement("a");
65
- a.target = "_blank";
66
- a.href = siteUrl;
67
- a.innerText = `Open "~MY_SITE/index.html" in a new window.`;
68
- container.insertBefore(a, iframe);
69
- }
70
-
71
- async function startHttpService({
72
- serviceKey,
73
- router
74
- }) {
75
- // Step 1: Start a ServiceWorker and open a MessageChannel used to recieve HTTP requests and send responses:
76
- const connection = await WebRunHttp.newRemoteRelayChannel();
77
-
78
- // Step 2: Define an HTTP handler
79
- const serviceBaseUrl = `${connection.baseUrl}~${serviceKey}`;
80
- const app = new Hono({
81
- getPath: (req) => req.url.substring(serviceBaseUrl.length)
82
- });
83
- // Add the router
84
- app.route("/", router);
85
- const httpHandler = (request) => app.fetch(request);
86
-
87
- // Step 3: Instantiate a "server" using the communcation channel with the ServiceWorker:
88
- const close = await WebRunHttp.initHttpService(httpHandler, {
89
- key: serviceKey, // Service prefix
90
- port: connection.port
91
- });
92
-
93
- return serviceBaseUrl;
94
- }
95
-
96
- function getRouter() {
97
- const router = new Hono();
98
-
99
- // Server-side REST API handler:
100
- router.get("/api/:name", (c) => {
101
- const { name } = c.req.param()
102
- const date = new Date();
103
- const response = {
104
- message: `Hello ${name}!`,
105
- time: date.toLocaleTimeString(),
106
- milliseconds: date.getMilliseconds()
107
- }
108
- return c.json(response);
109
- });
110
-
111
- // Static files: an object with path names and the corresponding content
112
- const files = getStaticFiles();
113
- // Register these files with a basic dispatcher
114
- // returning the file content to the caller:
115
- router.get("/*", newStaticFilesDispatcher(files))
116
-
117
- return router;
118
- }
119
-
120
- function newStaticFilesDispatcher(files) {
121
- return function showStaticFiles(context) {
122
- let { url, path } = context.req;
123
- path = path.replace(/#.*$/, "");
124
- if (path.match(/\/$/)) {
125
- path = path + "index.html";
126
- }
127
- const result = files[path];
128
- if (!result) {
129
- return context.notFound();
130
- }
131
- const mimeType = mime.lookup(path) || "application/octet-stream";
132
- context.header("Content-Type", mimeType);
133
- context.status(201);
134
- if (typeof result === "object") {
135
- return context.json(result);
136
- } else {
137
- return context.body(result);
138
- }
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>webrun-http-browser — dynamic site demo (relay)</title>
7
+ <style>
8
+ body { font-family: system-ui, sans-serif; margin: 2rem; max-width: 60rem; }
9
+ iframe { width: 100%; height: 22rem; border: 1px solid #e5e5e5; }
10
+ code { background: #f4f4f5; padding: 0 0.25rem; border-radius: 0.2rem; }
11
+ </style>
12
+ </head>
13
+ <body>
14
+ <h1>Dynamic in-browser site (relay mode)</h1>
15
+ <p>
16
+ Registers a tiny site under the service key <code>MY_SITE</code> on the
17
+ relay ServiceWorker, then embeds <code>~MY_SITE/index.html</code> in an
18
+ iframe. The “server” is a request router running entirely in this tab.
19
+ </p>
20
+ <div id="view"></div>
21
+
22
+ <script type="module">
23
+ import { Hono } from "https://esm.sh/hono@4.9.10";
24
+ import * as WebRunHttp from "../dist/index.js";
25
+
26
+ const main = async () => {
27
+ const SERVICE_KEY = "MY_SITE";
28
+ const connection = await WebRunHttp.newRemoteRelayChannel();
29
+ const serviceBaseUrl = `${connection.baseUrl}~${SERVICE_KEY}`;
30
+
31
+ const router = getRouter();
32
+ const app = new Hono({ getPath: (req) => req.url.substring(serviceBaseUrl.length) });
33
+ app.route("/", router);
34
+
35
+ await WebRunHttp.initHttpService((req) => app.fetch(req), {
36
+ key: SERVICE_KEY,
37
+ port: connection.port,
38
+ });
39
+
40
+ const siteUrl = `${serviceBaseUrl}/`;
41
+ const view = document.querySelector("#view");
42
+ const link = document.createElement("a");
43
+ link.href = siteUrl;
44
+ link.target = "_blank";
45
+ link.textContent = `Open ${siteUrl} in a new tab`;
46
+ view.appendChild(link);
47
+
48
+ const iframe = document.createElement("iframe");
49
+ iframe.src = siteUrl;
50
+ view.appendChild(iframe);
139
51
  };
140
- }
141
-
142
- function getStaticFiles() {
143
- return {
144
- "/index.css": `
145
- html, body {
146
- padding: 0;
147
- margin: 0;
148
- }
149
- h1 {
150
- color : navy;
151
- }
152
- `,
153
52
 
53
+ function getRouter() {
54
+ const router = new Hono();
55
+ router.get("/api/:name", (c) => {
56
+ const { name } = c.req.param();
57
+ const date = new Date();
58
+ return c.json({
59
+ message: `Hello ${name}!`,
60
+ time: date.toLocaleTimeString(),
61
+ milliseconds: date.getMilliseconds(),
62
+ });
63
+ });
64
+ const files = getStaticFiles();
65
+ router.get("/*", (c) => {
66
+ let path = c.req.path.replace(/#.*$/, "");
67
+ if (path.endsWith("/")) path += "index.html";
68
+ const body = files[path];
69
+ if (!body) return c.notFound();
70
+ const contentType = path.endsWith(".html")
71
+ ? "text/html"
72
+ : path.endsWith(".js")
73
+ ? "text/javascript"
74
+ : path.endsWith(".css")
75
+ ? "text/css"
76
+ : "text/plain";
77
+ c.header("Content-Type", contentType);
78
+ return c.body(body);
79
+ });
80
+ return router;
81
+ }
154
82
 
155
- "/index.js": `
156
- document.addEventListener("DOMContentLoaded", () => {
157
- const input = document.querySelector("#name");
158
- input.addEventListener("input", (ev) => {
159
- ev.preventDefault();
160
- ev.stopPropagation();
161
- updateName();
162
- })
163
- updateName();
164
- async function updateName() {
165
- const name = input.value;
166
- const res = await fetch("./api/" + encodeURIComponent(name));
167
- const { message, time, milliseconds } = await res.json();
168
- const view = document.querySelector("#messages");
169
- view.innerHTML = "<div>" + message + "</div><div>Current time is " + time + " (and " + milliseconds + " milliseconds).</div>";
170
- }
171
- })
172
- `,
173
- "/index.html": `<!DOCTYPE HTML>
174
- <html>
175
- <head>
176
- <meta charset="utf-8" />
177
- <meta http-equiv="content-type" content="text/html; charset=utf-8" />
178
- <meta name="viewport" content="width=device-width, initial-scale=1" />
179
- <link rel="stylesheet" href="./index.css" />
180
- </head>
181
- <body>
182
- <h1>In-Browser Dynamic Site</h1>
183
- <div>
184
- Please enter your name:
185
- <input type="text" id="name" value="John">
186
- </div>
187
- <p>Message from the server:</p>
188
- <div id="messages">
189
- </div>
190
- <script type="module" src="./index.js"><\/script>
191
- </body>
192
- </html>
193
- `
83
+ function getStaticFiles() {
84
+ return {
85
+ "/index.css": `
86
+ body { font-family: system-ui, sans-serif; margin: 1rem; }
87
+ h2 { color: navy; }`,
88
+ "/index.js": `
89
+ document.addEventListener("DOMContentLoaded", () => {
90
+ const input = document.querySelector("#name");
91
+ const view = document.querySelector("#messages");
92
+ const update = async () => {
93
+ const res = await fetch("./api/" + encodeURIComponent(input.value));
94
+ const { message, time, milliseconds } = await res.json();
95
+ view.innerHTML = "<div>" + message + "</div>" +
96
+ "<div>Current time: " + time + " (" + milliseconds + "ms)</div>";
97
+ };
98
+ input.addEventListener("input", update);
99
+ update();
100
+ });`,
101
+ "/index.html": '<!DOCTYPE html><html><head><meta charset="utf-8">' +
102
+ '<link rel="stylesheet" href="./index.css">' +
103
+ '</head><body><h2>In-browser dynamic site</h2>' +
104
+ '<label>Name: <input id="name" value="World"></label>' +
105
+ '<div id="messages"></div>' +
106
+ // Split the closing tag so the outer HTML parser doesn't end the script tag early.
107
+ `<script type="module" src="./index.js"></scr${"ipt>"}</body></html>`,
108
+ };
194
109
  }
195
- }
196
- </script>
197
- </body>
198
110
 
199
- </html>
111
+ main().catch(console.error);
112
+ </script>
113
+ </body>
114
+ </html>