-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathruntime.ts
91 lines (79 loc) · 2.46 KB
/
runtime.ts
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
// copied from https://github.com/honojs/hono/blob/80c7e225af5fd8f92b3a69015fe78c546b678ba9/src/helper/adapter/index.ts#L45 under MIT License.
// deno-lint-ignore-file no-explicit-any
/**
* @module
* Adapter Helper for Hono.
*/
export type Runtime =
| "node"
| "deno"
| "bun"
| "workerd"
| "fastly"
| "edge-light"
| "other";
const knownUserAgents: Partial<Record<Runtime, string>> = {
deno: "Deno",
bun: "Bun",
workerd: "Cloudflare-Workers",
node: "Node.js",
};
export const getRuntimeKey = (): Runtime => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const global = globalThis as any;
// check if the current runtime supports navigator.userAgent
const userAgentSupported = typeof navigator !== "undefined" &&
typeof navigator.userAgent === "string";
// if supported, check the user agent
if (userAgentSupported) {
for (const [runtimeKey, userAgent] of Object.entries(knownUserAgents)) {
if (checkUserAgentEquals(userAgent)) {
return runtimeKey as Runtime;
}
}
}
// check if running on Edge Runtime
if (typeof global?.EdgeRuntime === "string") {
return "edge-light";
}
// check if running on Fastly
if (global?.fastly !== undefined) {
return "fastly";
}
// userAgent isn't supported before Node v21.1.0; so fallback to the old way
if (global?.process?.release?.name === "node") {
return "node";
}
// couldn't detect the runtime
return "other";
};
const checkUserAgentEquals = (platform: string): boolean => {
const userAgent = navigator.userAgent;
return userAgent.startsWith(platform);
};
export const upgradeWebSocket = (
req: Request,
): { socket: WebSocket; response: Response } => {
if (getRuntimeKey() === "deno") {
return Deno.upgradeWebSocket(req);
}
// @ts-ignore: WebSocketPair is not part of the global scope
const webSocketPair = new WebSocketPair();
const [client, server] = Object.values(webSocketPair);
// @ts-ignore: WebSocketPair is not part of the global scope
const originalAccept = server.accept.bind(server);
// @ts-ignore: WebSocketPair is not part of the global scope
server.accept = () => {
originalAccept();
// @ts-ignore: WebSocketPair is not part of the global scope
server.dispatchEvent(new Event("open"));
};
return {
socket: server as WebSocket,
response: new Response(null, {
status: 101,
// @ts-ignore: webSocket is not part of the Response type
webSocket: client,
}),
};
};