@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.
- package/LICENSE +1 -1
- package/README.md +321 -50
- package/demo/demo-1.html +109 -194
- package/demo/demo-2.html +119 -580
- package/dist/core/data-calls.d.ts +5 -0
- package/dist/core/data-calls.d.ts.map +1 -0
- package/dist/core/data-channels.d.ts +17 -0
- package/dist/core/data-channels.d.ts.map +1 -0
- package/dist/core/index.d.ts +6 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/message-target.d.ts +16 -0
- package/dist/core/message-target.d.ts.map +1 -0
- package/dist/core/registry.d.ts +18 -0
- package/dist/core/registry.d.ts.map +1 -0
- package/dist/http/http-send-recieve.d.ts +23 -0
- package/dist/http/http-send-recieve.d.ts.map +1 -0
- package/dist/http/index.d.ts +4 -0
- package/dist/http/index.d.ts.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2541 -807
- package/dist/relay/index-sw.d.ts +7 -0
- package/dist/relay/index-sw.d.ts.map +1 -0
- package/dist/relay/index.d.ts +69 -0
- package/dist/relay/index.d.ts.map +1 -0
- package/dist/relay/split-service-url.d.ts +13 -0
- package/dist/relay/split-service-url.d.ts.map +1 -0
- package/dist/relay-sw.d.ts +2 -0
- package/dist/relay-sw.d.ts.map +1 -0
- package/dist/relay-sw.js +878 -0
- package/dist/sw/http-sw-dispatcher.d.ts +28 -0
- package/dist/sw/http-sw-dispatcher.d.ts.map +1 -0
- package/dist/sw/index.d.ts +3 -0
- package/dist/sw/index.d.ts.map +1 -0
- package/dist/sw/sw-dispatcher.d.ts +74 -0
- package/dist/sw/sw-dispatcher.d.ts.map +1 -0
- package/dist/sw-worker.d.ts +2 -0
- package/dist/sw-worker.d.ts.map +1 -0
- package/dist/sw-worker.js +813 -0
- package/dist/sw.d.ts +2 -0
- package/dist/sw.d.ts.map +1 -0
- package/dist/sw.js +1076 -0
- package/package.json +50 -37
- package/public/index.html +61 -97
- package/public/index.js +7 -4
- package/public/sw-worker.js +4 -0
- package/public-relay/heartbeat.js +4 -3
- package/public-relay/relay-sw.js +4 -6
- package/public-relay/relay.html +16 -11
- package/src/core/data-calls.ts +46 -0
- package/src/core/data-channels.ts +224 -0
- package/src/core/index.ts +9 -0
- package/src/core/message-target.ts +18 -0
- package/src/core/registry.ts +54 -0
- package/src/http/http-send-recieve.ts +81 -0
- package/src/http/index.ts +7 -0
- package/src/index.ts +3 -0
- package/src/relay/index-sw.ts +145 -0
- package/src/relay/index.ts +261 -0
- package/src/relay/split-service-url.ts +30 -0
- package/src/relay-sw.ts +7 -0
- package/src/sw/http-sw-dispatcher.ts +122 -0
- package/src/sw/index.ts +2 -0
- package/src/sw/sw-dispatcher.ts +307 -0
- package/src/sw-worker.ts +7 -0
- package/src/sw.ts +1 -0
- package/CHANGELOG.md +0 -1
- package/demo/demo-3.html +0 -167
- package/dist/index-sw-umd.js +0 -798
- package/dist/index-sw-umd.min.js +0 -2
- package/dist/index-sw.js +0 -791
- package/dist/index-sw.min.js +0 -2
- package/dist/index-umd.js +0 -853
- package/dist/index-umd.min.js +0 -2
- package/dist/index.min.js +0 -2
- package/index.js +0 -1
- package/src/core/data-calls.js +0 -36
- package/src/core/data-channels.js +0 -192
- package/src/core/data-send-recieve.js +0 -28
- package/src/core/errors.js +0 -13
- package/src/core/index.js +0 -4
- package/src/http/HttpError.js +0 -59
- package/src/http/http-send-recieve.js +0 -40
- package/src/http/http-stubs.js +0 -135
- package/src/http/index.js +0 -3
- package/src/http/readable-streams.js +0 -33
- package/src/index.js +0 -7
- package/src/relay/index-sw.js +0 -216
- package/src/relay/index.js +0 -263
- package/src/relay/splitServiceUrl.js +0 -24
- package/src/sw/http-sw-dispatcher.js +0 -128
- package/src/sw/sw-dispatcher.js +0 -264
package/demo/demo-1.html
CHANGED
|
@@ -1,199 +1,114 @@
|
|
|
1
|
-
<!DOCTYPE
|
|
2
|
-
<html>
|
|
3
|
-
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
<
|
|
14
|
-
<
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
<
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
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
|
-
|
|
111
|
+
main().catch(console.error);
|
|
112
|
+
</script>
|
|
113
|
+
</body>
|
|
114
|
+
</html>
|