-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathendpoint.ts
116 lines (95 loc) · 3.17 KB
/
endpoint.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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import { getUncompressedSnippetString } from "@tscircuit/create-snippet-url"
import { CircuitRunner } from "@tscircuit/eval/eval"
import { circuitJsonPreviewHtml } from "./circuit-json-preview-html"
import { getHtmlForGeneratedUrlPage } from "./get-html-for-generated-url-page"
import { getIndexPageHtml } from "./get-index-page-html"
import { getErrorSvg } from "./getErrorSvg"
type Result<T, E = Error> = [T, null] | [null, E]
async function unwrapPromise<T>(promise: Promise<T>): Promise<Result<T>> {
return promise
.then<[T, null]>((data) => [data, null])
.catch<[null, Error]>((err) => [null, err])
}
function unwrapSyncError<T>(fn: () => T): Result<T> {
try {
return [fn(), null]
} catch (err) {
return [null, err as Error]
}
}
export default async (req: Request) => {
const url = new URL(req.url.replace("/api", "/"))
const host = `${url.protocol}//${url.host}`
if (url.pathname === "/health") {
return new Response(JSON.stringify({ ok: true }))
}
if (url.pathname === "/generate_url") {
const code = url.searchParams.get("code")
return new Response(await getHtmlForGeneratedUrlPage(code!, host), {
headers: { "Content-Type": "text/html" },
})
}
if (url.pathname === "/" && !url.searchParams.get("code")) {
return new Response(getIndexPageHtml(), {
headers: { "Content-Type": "text/html" },
})
}
const rawCode = url.searchParams.get("code")
if (!rawCode) {
return new Response(
JSON.stringify({ ok: false, error: "No code parameter provided" }),
{ status: 400 },
)
}
const gzipPrefix = "data:application/gzip;base64,"
const normalizedCode = rawCode.startsWith(gzipPrefix)
? rawCode
: gzipPrefix + rawCode
const [userCode, userCodeErr] = unwrapSyncError(() =>
getUncompressedSnippetString(normalizedCode),
)
if (userCodeErr) {
return errorResponse(userCodeErr)
}
const worker = new CircuitRunner()
const [, executeError] = await unwrapPromise(
worker.executeWithFsMap({
fsMap: {
"entrypoint.tsx": `
import UserComponents from "./UserCode.tsx";
const hasBoard = ${userCode.includes("<board").toString()};
circuit.add(
hasBoard ? (
<UserComponents />
) : (
<board>
<UserComponents name="U1" />
</board>
)
);
`,
"UserCode.tsx": userCode,
},
entrypoint: "entrypoint.tsx",
}),
)
if (executeError) return errorResponse(executeError)
const [, renderError] = await unwrapPromise(worker.renderUntilSettled())
if (renderError) return errorResponse(renderError)
const [circuitJson, jsonError] = await unwrapPromise(worker.getCircuitJson())
if (jsonError) return errorResponse(jsonError)
if (circuitJson) {
const html = await circuitJsonPreviewHtml(circuitJson as any)
return new Response(html, {
headers: { "Content-Type": "text/html" },
})
}
}
function errorResponse(err: Error) {
return new Response(getErrorSvg(err.message), {
headers: {
"Content-Type": "image/svg+xml",
"Cache-Control": "public, max-age=86400, s-maxage=86400",
},
})
}