1
2
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { readerFromStreamReader } from "https://deno.land/std@0.223.0/io/mod.ts";
import { httpClient } from "https://esm.town/v/pomdtr/http_client";
import { disposable } from "https://esm.town/v/postpostscript/disposable";
export const workerURL = new URL(import.meta.url);
workerURL.searchParams.set("worker", "1");
export async function fetchWorker(opts: {
url: string;
handler?: string;
}) {
const worker = disposable(
new Worker(workerURL.toString(), {
type: "module",
}),
(worker) => worker.terminate(),
);
// wait for worker setup to finish
const { resolve, promise } = Promise.withResolvers();
worker.onmessage = resolve;
worker.postMessage({
code: "setup",
...opts,
});
await promise;
const resolvers: {
[id: string]: (value: Response) => void;
} = {};
worker.onmessage = (e) => {
const {
id,
response: {
status,
headers,
body,
},
} = e.data;
const response = new Response(body, {
status,
headers,
});
resolvers[id](response);
};
return {
fetch: async (input: URL | RequestInfo, init?: RequestInit) => {
const req = new Request(input, init);
const body: ArrayBuffer | null = req.body
? await req.blob().then(blob => blob.arrayBuffer())
: null;
const id = crypto.randomUUID();
const { resolve, promise } = Promise.withResolvers<Response>();
resolvers[id] = resolve;
worker.postMessage({
code: "request",
id,
request: {
url: req.url,
body,
init: {
method: req.method,
headers: Object.fromEntries(req.headers.entries()),
},
},
});
return promise;
},
instance: worker,
terminate: () => worker.terminate(),
[Symbol.dispose]: () => worker.terminate(),
};
}
export function setupWorker() {
let handler: (req: Request) => Promise<Response>;
self.onmessage = async (e) => {
if (e.data.code === "setup") {
const module = await import(e.data.url);
handler = module[e.data.handler ?? "default"];
self.postMessage({
code: "ready",
});
}
if (e.data.code === "request") {
const {
id,