diff --git a/api/relay.ts b/api/relay.ts index 553b513..674c6c0 100644 --- a/api/relay.ts +++ b/api/relay.ts @@ -29,7 +29,7 @@ import { createRateLimiter } from "../src/middleware/rate-limiter"; import { logRelayEvent } from "../src/middleware/logger"; import { handleChatCompletion, listModels } from "../src/lib/ai-proxy"; import { handleAnthropicMessages } from "../src/lib/anthropic-proxy"; -import testApiHtmlRaw from "./test-api-content"; +import { getTestPageHtml } from "../src/lib/test-page"; // ─── Configuration ────────────────────────────────────────────────────────────── @@ -42,7 +42,7 @@ const RELAY_VERSION = "1.0.0"; // ─── API Key Authentication ───────────────────────────────────────────────────── -const API_KEY = "sk-dummy-key"; +const API_KEY = process.env.API_KEY ?? "sk-dummy-key"; function requireAuth(req: Request): Response | null { const header = req.headers.get("authorization") ?? req.headers.get("x-api-key") ?? ""; @@ -382,7 +382,7 @@ export default { // Static routes — show index only when no relay target is requested if (url.pathname === "/health") return handleHealth(); if (url.pathname === "/docs" || url.pathname === "/test") { - return new Response(testApiHtmlRaw, { + return new Response(getTestPageHtml(), { headers: { "Content-Type": "text/html; charset=utf-8" }, }); } diff --git a/api/test-api-content.ts b/api/test-api-content.ts index 4cba29d..88378c4 100644 --- a/api/test-api-content.ts +++ b/api/test-api-content.ts @@ -1,2 +1 @@ -export default "\n\n\n \n \n Edge Proxy — API Test\n \n\n\n
\n

Edge Proxy Relay — API Test

\n

Test all proxy endpoints from the browser

\n\n \n
\n
\n AUTH API Key\n \n
\n
\n \n
\n \n \n
\n
\n
\n\n \n
\n
\n GET /health\n \n
\n
\n \n
\n
\n
\n\n \n
\n
\n GET /v1/models\n \n
\n
\n \n
\n
\n
\n\n \n
\n
\n POST /v1/chat/completions\n \n
\n
\n \n \n \n \n \n
\n
\n
\n
\n\n \n
\n
\n POST /v1/messages (Anthropic)\n \n
\n
\n \n \n \n \n \n \n \n
\n
\n
\n
\n\n \n
\n
\n RELAY Generic HTTP Relay\n \n
\n
\n \n \n \n \n \n \n \n \n
\n
\n
\n
\n\n
\n
\n\n\n\n\n"; +export { getTestPageHtml as default } from "../src/lib/test-page"; diff --git a/src/lib/test-page.ts b/src/lib/test-page.ts new file mode 100644 index 0000000..fa017e6 --- /dev/null +++ b/src/lib/test-page.ts @@ -0,0 +1,298 @@ +/** + * Interactive test page HTML — shared across all runtimes. + * + * Uses base64 encoding to avoid template-literal / string-escape issues + * that plague inline HTML in TypeScript files. Decoded once at module + * load and cached. + * + * Compatible with: + * - Bun (native) + * - Node.js (Buffer) + * - Cloudflare Workers (global TextDecoder) + * - Vercel serverless (Bun or Node) + */ + +// ── Embedded HTML (base64-encoded) ───────────────────────────────────────── + +const B64_HTML = + "PCFET0NUWVBFIGh0bWw+CjxodG1sIGxhbmc9ImVuIj4KPGhlYWQ+CiAgPG1ldGEgY2hhcnNldD0iVVRG" + + "LTgiPgogIDxtZXRhIG5hbWU9InZpZXdwb3J0IiBjb250ZW50PSJ3aWR0aD1kZXZpY2Utd2lkdGgsIGlu" + + "aXRpYWwtc2NhbGU9MS4wIj4KICA8dGl0bGU+RWRnZSBQcm94eSDigJQgQVBJIFRlc3Q8L3RpdGxlPgog" + + "IDxzdHlsZT4KICAgICosICo6OmJlZm9yZSwgKjo6YWZ0ZXIgeyBib3gtc2l6aW5nOiBib3JkZXItYm94" + + "OyBtYXJnaW46IDA7IHBhZGRpbmc6IDA7IH0KICAgIGJvZHkgeyBmb250LWZhbWlseTogc3lzdGVtLXVp" + + "LCAtYXBwbGUtc3lzdGVtLCBzYW5zLXNlcmlmOyBiYWNrZ3JvdW5kOiAjMGQxMTE3OyBjb2xvcjogI2Ux" + + "ZTRlODsgcGFkZGluZzogMS41cmVtOyB9CiAgICBtYWluIHsgbWF4LXdpZHRoOiA5NjBweDsgbWFyZ2lu" + + "OiAwIGF1dG87IH0KICAgIGgxIHsgZm9udC1zaXplOiAxLjVyZW07IGNvbG9yOiAjNThhNmZmOyBtYXJn" + + "aW4tYm90dG9tOiAwLjI1cmVtOyB9CiAgICAuc3ViIHsgY29sb3I6ICM4Yjk0OWU7IG1hcmdpbi1ib3R0" + + "b206IDEuNXJlbTsgZm9udC1zaXplOiAwLjlyZW07IH0KICAgIC5jYXJkIHsgYmFja2dyb3VuZDogIzE2" + + "MWIyMjsgYm9yZGVyOiAxcHggc29saWQgIzMwMzYzZDsgYm9yZGVyLXJhZGl1czogOHB4OyBtYXJnaW4t" + + "Ym90dG9tOiAxcmVtOyBvdmVyZmxvdzogaGlkZGVuOyB9CiAgICAuY2FyZC1oZWFkZXIgeyBwYWRkaW5n" + + "OiAwLjc1cmVtIDFyZW07IGJhY2tncm91bmQ6ICMxYzIxMjg7IGJvcmRlci1ib3R0b206IDFweCBzb2xp" + + "ZCAjMzAzNjNkOyBmb250LXdlaWdodDogNjAwOyBjdXJzb3I6IHBvaW50ZXI7IGRpc3BsYXk6IGZsZXg7" + + "IGFsaWduLWl0ZW1zOiBjZW50ZXI7IGdhcDogMC41cmVtOyB1c2VyLXNlbGVjdDogbm9uZTsgfQogICAg" + + "LmNhcmQtaGVhZGVyOmhvdmVyIHsgYmFja2dyb3VuZDogIzIxMjYyZDsgfQogICAgLmNhcmQtaGVhZGVy" + + "IC5tZXRob2QgeyBmb250LXNpemU6IDAuN3JlbTsgcGFkZGluZzogMXB4IDZweDsgYm9yZGVyLXJhZGl1" + + "czogM3B4OyBmb250LXdlaWdodDogNjAwOyB0ZXh0LXRyYW5zZm9ybTogdXBwZXJjYXNlOyB9CiAgICAu" + + "Z2V0IHsgYmFja2dyb3VuZDogIzFmNmZlYjMzOyBjb2xvcjogIzU4YTZmZjsgfQogICAgLnBvc3QgeyBi" + + "YWNrZ3JvdW5kOiAjMjM4NjM2MzM7IGNvbG9yOiAjM2ZiOTUwOyB9CiAgICAuY2FyZC1ib2R5IHsgcGFk" + + "ZGluZzogMXJlbTsgZGlzcGxheTogbm9uZTsgfQogICAgLmNhcmQub3BlbiAuY2FyZC1ib2R5IHsgZGlz" + + "cGxheTogYmxvY2s7IH0KICAgIC5jYXJkLWhlYWRlciAuYXJyb3cgeyBtYXJnaW4tbGVmdDogYXV0bzsg" + + "dHJhbnNpdGlvbjogdHJhbnNmb3JtIC4xNXM7IH0KICAgIC5jYXJkLm9wZW4gLmFycm93IHsgdHJhbnNm" + + "b3JtOiByb3RhdGUoOTBkZWcpOyB9CiAgICBsYWJlbCB7IGRpc3BsYXk6IGJsb2NrOyBmb250LXNpemU6" + + "IDAuOHJlbTsgY29sb3I6ICM4Yjk0OWU7IG1hcmdpbi1ib3R0b206IDAuMjVyZW07IH0KICAgIGlucHV0" + + "LCB0ZXh0YXJlYSwgc2VsZWN0IHsgd2lkdGg6IDEwMCU7IGJhY2tncm91bmQ6ICMwZDExMTc7IGJvcmRl" + + "cjogMXB4IHNvbGlkICMzMDM2M2Q7IGJvcmRlci1yYWRpdXM6IDRweDsgY29sb3I6ICNlMWU0ZTg7IHBh" + + "ZGRpbmc6IDAuNXJlbSAwLjc1cmVtOyBmb250LWZhbWlseTogaW5oZXJpdDsgZm9udC1zaXplOiAwLjly" + + "ZW07IG1hcmdpbi1ib3R0b206IDAuNzVyZW07IH0KICAgIGlucHV0OmZvY3VzLCB0ZXh0YXJlYTpmb2N1" + + "cyB7IGJvcmRlci1jb2xvcjogIzU4YTZmZjsgb3V0bGluZTogbm9uZTsgfQogICAgdGV4dGFyZWEgeyBt" + + "aW4taGVpZ2h0OiA2MHB4OyByZXNpemU6IHZlcnRpY2FsOyBmb250LWZhbWlseTogJ1NGIE1vbm8nLCAn" + + "Q2FzY2FkaWEgQ29kZScsIG1vbm9zcGFjZTsgZm9udC1zaXplOiAwLjhyZW07IH0KICAgIHRleHRhcmVh" + + "LmNvZGUgeyBtaW4taGVpZ2h0OiAxMjBweDsgfQogICAgLnJvdyB7IGRpc3BsYXk6IGZsZXg7IGdhcDog" + + "MC43NXJlbTsgfQogICAgLnJvdyA+ICogeyBmbGV4OiAxOyB9CiAgICAuYnRuIHsgYmFja2dyb3VuZDog" + + "IzIzODYzNjsgY29sb3I6ICNmZmY7IGJvcmRlcjogbm9uZTsgYm9yZGVyLXJhZGl1czogNnB4OyBwYWRk" + + "aW5nOiAwLjVyZW0gMS4yNXJlbTsgZm9udC1zaXplOiAwLjg1cmVtOyBjdXJzb3I6IHBvaW50ZXI7IGZv" + + "bnQtd2VpZ2h0OiA1MDA7IH0KICAgIC5idG46aG92ZXIgeyBiYWNrZ3JvdW5kOiAjMmVhMDQzOyB9CiAg" + + "ICAuYnRuOmRpc2FibGVkIHsgb3BhY2l0eTogMC41OyBjdXJzb3I6IG5vdC1hbGxvd2VkOyB9CiAgICAu" + + "b3V0cHV0IHsgYmFja2dyb3VuZDogIzBkMTExNzsgYm9yZGVyOiAxcHggc29saWQgIzMwMzYzZDsgYm9y" + + "ZGVyLXJhZGl1czogNHB4OyBwYWRkaW5nOiAwLjc1cmVtOyBtYXJnaW4tdG9wOiAwLjVyZW07IH0KICAg" + + "IC5vdXRwdXQgcHJlIHsgZm9udC1mYW1pbHk6ICdTRiBNb25vJywgJ0Nhc2NhZGlhIENvZGUnLCBtb25v" + + "c3BhY2U7IGZvbnQtc2l6ZTogMC43OHJlbTsgd2hpdGUtc3BhY2U6IHByZS13cmFwOyB3b3JkLWJyZWFr" + + "OiBicmVhay1hbGw7IG1heC1oZWlnaHQ6IDMwMHB4OyBvdmVyZmxvdzogYXV0bzsgY29sb3I6ICNjOWQx" + + "ZDk7IH0KICAgIC5vdXRwdXQgLm1ldGEgeyBmb250LXNpemU6IDAuNzVyZW07IGNvbG9yOiAjOGI5NDll" + + "OyBtYXJnaW4tYm90dG9tOiAwLjVyZW07IH0KICAgIC5vdXRwdXQgLm1ldGEgLnN0YXR1cy5vayB7IGNv" + + "bG9yOiAjM2ZiOTUwOyB9CiAgICAub3V0cHV0IC5tZXRhIC5zdGF0dXMuZXJyIHsgY29sb3I6ICNmODUx" + + "NDk7IH0KICAgIC50b2FzdCB7IHBvc2l0aW9uOiBmaXhlZDsgYm90dG9tOiAxLjVyZW07IHJpZ2h0OiAx" + + "LjVyZW07IGJhY2tncm91bmQ6ICMxYzIxMjg7IGJvcmRlcjogMXB4IHNvbGlkICMzMDM2M2Q7IGJvcmRl" + + "ci1yYWRpdXM6IDZweDsgcGFkZGluZzogMC43NXJlbSAxcmVtOyBmb250LXNpemU6IDAuODVyZW07IGRp" + + "c3BsYXk6IG5vbmU7IHotaW5kZXg6IDEwMDsgfQogIDwvc3R5bGU+CjwvaGVhZD4KPGJvZHk+CjxtYWlu" + + "PgogIDxoMT5FZGdlIFByb3h5IFJlbGF5IOKAlCBJbnRlcmFjdGl2ZSBUZXN0PC9oMT4KICA8cCBjbGFz" + + "cz0ic3ViIj5UZXN0IGFsbCBlbmRwb2ludHMgZnJvbSB0aGUgYnJvd3Nlci4gT3BlbiBhIGNhcmQsIGZp" + + "bGwgaW4gdGhlIGZpZWxkcywgYW5kIHJ1bi48L3A+CgogIDxkaXYgY2xhc3M9ImNhcmQgb3BlbiI+CiAg" + + "ICA8ZGl2IGNsYXNzPSJjYXJkLWhlYWRlciI+CiAgICAgIDxzcGFuIGNsYXNzPSJtZXRob2QgZ2V0Ij5B" + + "VVRIPC9zcGFuPiBBUEkgS2V5CiAgICAgIDxzcGFuIGNsYXNzPSJhcnJvdyI+4pa2PC9zcGFuPgogICAg" + + "PC9kaXY+CiAgICA8ZGl2IGNsYXNzPSJjYXJkLWJvZHkiPgogICAgICA8bGFiZWw+QVBJIEtleSAoZGVm" + + "YXVsdDogPGNvZGU+c2stZHVtbXkta2V5PC9jb2RlPik8L2xhYmVsPgogICAgICA8ZGl2IGNsYXNzPSJy" + + "b3ciPgogICAgICAgIDxpbnB1dCB0eXBlPSJ0ZXh0IiBpZD0iYXBpS2V5IiB2YWx1ZT0ic2stZHVtbXkt" + + "a2V5IiAvPgogICAgICAgIDxpbnB1dCB0eXBlPSJ0ZXh0IiBpZD0iYmFzZVVybCIgdmFsdWU9IiIgcGxh" + + "Y2Vob2xkZXI9IihzYW1lIG9yaWdpbiDigJQgYXV0by1kZXRlY3RlZCkiIC8+CiAgICAgIDwvZGl2Pgog" + + "ICAgPC9kaXY+CiAgPC9kaXY+CgogIDxkaXYgY2xhc3M9ImNhcmQgb3BlbiI+CiAgICA8ZGl2IGNsYXNz" + + "PSJjYXJkLWhlYWRlciIgb25jbGljaz0idG9nZ2xlQ2FyZCh0aGlzKSI+CiAgICAgIDxzcGFuIGNsYXNz" + + "PSJtZXRob2QgZ2V0Ij5HRVQ8L3NwYW4+IC9oZWFsdGgKICAgICAgPHNwYW4gY2xhc3M9ImFycm93Ij7i" + + "lrY8L3NwYW4+CiAgICA8L2Rpdj4KICAgIDxkaXYgY2xhc3M9ImNhcmQtYm9keSI+CiAgICAgIDxidXR0" + + "b24gY2xhc3M9ImJ0biIgb25jbGljaz0iY2FsbEhlYWx0aCgpIj5QaW5nIEhlYWx0aDwvYnV0dG9uPgog" + + "ICAgICA8ZGl2IGlkPSJvdXRwdXQtaGVhbHRoIiBjbGFzcz0ib3V0cHV0IiBzdHlsZT0iZGlzcGxheTpu" + + "b25lIj48cHJlPjwvcHJlPjwvZGl2PgogICAgPC9kaXY+CiAgPC9kaXY+CgogIDxkaXYgY2xhc3M9ImNh" + + "cmQgb3BlbiI+CiAgICA8ZGl2IGNsYXNzPSJjYXJkLWhlYWRlciIgb25jbGljaz0idG9nZ2xlQ2FyZCh0" + + "aGlzKSI+CiAgICAgIDxzcGFuIGNsYXNzPSJtZXRob2QgZ2V0Ij5HRVQ8L3NwYW4+IC92MS9tb2RlbHMK" + + "ICAgICAgPHNwYW4gY2xhc3M9ImFycm93Ij7ilrY8L3NwYW4+CiAgICA8L2Rpdj4KICAgIDxkaXYgY2xh" + + "c3M9ImNhcmQtYm9keSI+CiAgICAgIDxidXR0b24gY2xhc3M9ImJ0biIgb25jbGljaz0iY2FsbE1vZGVs" + + "cygpIj5MaXN0IE1vZGVsczwvYnV0dG9uPgogICAgICA8ZGl2IGlkPSJvdXRwdXQtbW9kZWxzIiBjbGFz" + + "cz0ib3V0cHV0IiBzdHlsZT0iZGlzcGxheTpub25lIj48cHJlPjwvcHJlPjwvZGl2PgogICAgPC9kaXY+" + + "CiAgPC9kaXY+CgogIDxkaXYgY2xhc3M9ImNhcmQiPgogICAgPGRpdiBjbGFzcz0iY2FyZC1oZWFkZXIi" + + "IG9uY2xpY2s9InRvZ2dsZUNhcmQodGhpcykiPgogICAgICA8c3BhbiBjbGFzcz0ibWV0aG9kIHBvc3Qi" + + "PlBPU1Q8L3NwYW4+IC92MS9jaGF0L2NvbXBsZXRpb25zCiAgICAgIDxzcGFuIGNsYXNzPSJhcnJvdyI+" + + "4pa2PC9zcGFuPgogICAgPC9kaXY+CiAgICA8ZGl2IGNsYXNzPSJjYXJkLWJvZHkiPgogICAgICA8ZGl2" + + "IGNsYXNzPSJyb3ciPgogICAgICAgIDxkaXY+PGxhYmVsPk1vZGVsPC9sYWJlbD48aW5wdXQgdHlwZT0i" + + "dGV4dCIgaWQ9ImNoYXRNb2RlbCIgdmFsdWU9ImRlZXBzZWVrLXY0LWZsYXNoLWZyZWUiIC8+PC9kaXY+" + + "CiAgICAgICAgPGRpdj48bGFiZWw+TWF4IFRva2VuczwvbGFiZWw+PGlucHV0IHR5cGU9Im51bWJlciIg" + + "aWQ9ImNoYXRNYXhUb2tlbnMiIHZhbHVlPSIxMjgiIC8+PC9kaXY+CiAgICAgIDwvZGl2PgogICAgICA8" + + "bGFiZWw+TWVzc2FnZXMgKEpTT04gYXJyYXkpPC9sYWJlbD4KICAgICAgPHRleHRhcmVhIGlkPSJjaGF0" + + "TWVzc2FnZXMiIGNsYXNzPSJjb2RlIj5beyJyb2xlIjoidXNlciIsImNvbnRlbnQiOiJTYXkgaGVsbG8g" + + "aW4gb25lIHdvcmQifV08L3RleHRhcmVhPgogICAgICA8bGFiZWw+PGlucHV0IHR5cGU9ImNoZWNrYm94" + + "IiBpZD0iY2hhdFN0cmVhbSIgLz4gU3RyZWFtIChTU0UpPC9sYWJlbD4KICAgICAgPGRpdiBzdHlsZT0i" + + "bWFyZ2luLXRvcDowLjVyZW0iPjxidXR0b24gY2xhc3M9ImJ0biIgb25jbGljaz0iY2FsbENoYXQoKSI+" + + "U2VuZDwvYnV0dG9uPjwvZGl2PgogICAgICA8ZGl2IGlkPSJvdXRwdXQtY2hhdCIgY2xhc3M9Im91dHB1" + + "dCIgc3R5bGU9ImRpc3BsYXk6bm9uZSI+PHByZT48L3ByZT48L2Rpdj4KICAgIDwvZGl2PgogIDwvZGl2" + + "PgoKICA8ZGl2IGNsYXNzPSJjYXJkIj4KICAgIDxkaXYgY2xhc3M9ImNhcmQtaGVhZGVyIiBvbmNsaWNr" + + "PSJ0b2dnbGVDYXJkKHRoaXMpIj4KICAgICAgPHNwYW4gY2xhc3M9Im1ldGhvZCBwb3N0Ij5QT1NUPC9z" + + "cGFuPiAvdjEvbWVzc2FnZXMgKEFudGhyb3BpYykKICAgICAgPHNwYW4gY2xhc3M9ImFycm93Ij7ilrY8" + + "L3NwYW4+CiAgICA8L2Rpdj4KICAgIDxkaXYgY2xhc3M9ImNhcmQtYm9keSI+CiAgICAgIDxkaXYgY2xh" + + "c3M9InJvdyI+CiAgICAgICAgPGRpdj48bGFiZWw+TW9kZWw8L2xhYmVsPjxpbnB1dCB0eXBlPSJ0ZXh0" + + "IiBpZD0iYW50aE1vZGVsIiB2YWx1ZT0iZGVlcHNlZWstdjQtZmxhc2gtZnJlZSIgLz48L2Rpdj4KICAg" + + "ICAgICA8ZGl2PjxsYWJlbD5NYXggVG9rZW5zPC9sYWJlbD48aW5wdXQgdHlwZT0ibnVtYmVyIiBpZD0i" + + "YW50aE1heFRva2VucyIgdmFsdWU9IjI1NiIgLz48L2Rpdj4KICAgICAgPC9kaXY+CiAgICAgIDxsYWJl" + + "bD5TeXN0ZW0gUHJvbXB0IChvcHRpb25hbCwgd2l0aCBjYWNoZV9jb250cm9sKTwvbGFiZWw+CiAgICAg" + + "IDx0ZXh0YXJlYSBpZD0iYW50aFN5c3RlbSIgY2xhc3M9ImNvZGUiIHBsYWNlaG9sZGVyPSdbeyJ0eXBl" + + "IjoidGV4dCIsInRleHQiOiJZb3UgYXJlIGhlbHBmdWwuIiwiY2FjaGVfY29udHJvbCI6eyJ0eXBlIjoi" + + "ZXBoZW1lcmFsIn19XSc+PC90ZXh0YXJlYT4KICAgICAgPGxhYmVsPk1lc3NhZ2VzIChKU09OKTwvbGFi" + + "ZWw+CiAgICAgIDx0ZXh0YXJlYSBpZD0iYW50aE1lc3NhZ2VzIiBjbGFzcz0iY29kZSI+W3sicm9sZSI6" + + "InVzZXIiLCJjb250ZW50IjpbeyJ0eXBlIjoidGV4dCIsInRleHQiOiJTYXkgaGVsbG8gaW4gb25lIHdv" + + "cmQiLCJjYWNoZV9jb250cm9sIjp7InR5cGUiOiJlcGhlbWVyYWwifX1dfV08L3RleHRhcmVhPgogICAg" + + "ICA8bGFiZWw+PGlucHV0IHR5cGU9ImNoZWNrYm94IiBpZD0iYW50aFN0cmVhbSIgLz4gU3RyZWFtIChT" + + "U0UpPC9sYWJlbD4KICAgICAgPGRpdiBzdHlsZT0ibWFyZ2luLXRvcDowLjVyZW0iPjxidXR0b24gY2xh" + + "c3M9ImJ0biIgb25jbGljaz0iY2FsbEFudGhyb3BpYygpIj5TZW5kPC9idXR0b24+PC9kaXY+CiAgICAg" + + "IDxkaXYgaWQ9Im91dHB1dC1hbnRoIiBjbGFzcz0ib3V0cHV0IiBzdHlsZT0iZGlzcGxheTpub25lIj48" + + "cHJlPjwvcHJlPjwvZGl2PgogICAgPC9kaXY+CiAgPC9kaXY+CgogIDxkaXYgY2xhc3M9ImNhcmQiPgog" + + "ICAgPGRpdiBjbGFzcz0iY2FyZC1oZWFkZXIiIG9uY2xpY2s9InRvZ2dsZUNhcmQodGhpcykiPgogICAg" + + "ICA8c3BhbiBjbGFzcz0ibWV0aG9kIHBvc3QiPlJFTEFZPC9zcGFuPiBHZW5lcmljIEhUVFAgUmVsYXkK" + + "ICAgICAgPHNwYW4gY2xhc3M9ImFycm93Ij7ilrY8L3NwYW4+CiAgICA8L2Rpdj4KICAgIDxkaXYgY2xh" + + "c3M9ImNhcmQtYm9keSI+CiAgICAgIDxsYWJlbD5SZWxheSBUYXJnZXQgVVJMPC9sYWJlbD4KICAgICAg" + + "PGlucHV0IHR5cGU9InRleHQiIGlkPSJyZWxheVRhcmdldCIgdmFsdWU9Imh0dHBzOi8vaHR0cGJpbi5v" + + "cmciIC8+CiAgICAgIDxkaXYgY2xhc3M9InJvdyI+CiAgICAgICAgPGRpdj48bGFiZWw+UmVsYXkgUGF0" + + "aDwvbGFiZWw+PGlucHV0IHR5cGU9InRleHQiIGlkPSJyZWxheVBhdGgiIHZhbHVlPSIvZ2V0IiAvPjwv" + + "ZGl2PgogICAgICAgIDxkaXY+PGxhYmVsPk1ldGhvZDwvbGFiZWw+PHNlbGVjdCBpZD0icmVsYXlNZXRo" + + "b2QiPjxvcHRpb24+R0VUPC9vcHRpb24+PG9wdGlvbj5QT1NUPC9vcHRpb24+PC9zZWxlY3Q+PC9kaXY+" + + "CiAgICAgIDwvZGl2PgogICAgICA8bGFiZWw+Qm9keSAoSlNPTiwgb3B0aW9uYWwpPC9sYWJlbD4KICAg" + + "ICAgPHRleHRhcmVhIGlkPSJyZWxheUJvZHkiIGNsYXNzPSJjb2RlIiBwbGFjZWhvbGRlcj0neyJ0ZXN0" + + "Ijp0cnVlfSc+PC90ZXh0YXJlYT4KICAgICAgPGRpdiBzdHlsZT0ibWFyZ2luLXRvcDowLjVyZW0iPjxi" + + "dXR0b24gY2xhc3M9ImJ0biIgb25jbGljaz0iY2FsbFJlbGF5KCkiPlNlbmQ8L2J1dHRvbj48L2Rpdj4K" + + "ICAgICAgPGRpdiBpZD0ib3V0cHV0LXJlbGF5IiBjbGFzcz0ib3V0cHV0IiBzdHlsZT0iZGlzcGxheTpu" + + "b25lIj48cHJlPjwvcHJlPjwvZGl2PgogICAgPC9kaXY+CiAgPC9kaXY+CgogIDxkaXYgaWQ9InRvYXN0" + + "IiBjbGFzcz0idG9hc3QiPjwvZGl2Pgo8L21haW4+Cgo8c2NyaXB0PgovLyAtLS0gQ29uZmlnIC0tLQpm" + + "dW5jdGlvbiBhcGlCYXNlKCkgeyByZXR1cm4gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2Jhc2VVcmwn" + + "KS52YWx1ZSB8fCB3aW5kb3cubG9jYXRpb24ub3JpZ2luOyB9CmZ1bmN0aW9uIGF1dGhIZWFkZXJzKCkg" + + "ewogIGNvbnN0IGsgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnYXBpS2V5JykudmFsdWUgfHwgJ3Nr" + + "LWR1bW15LWtleSc7CiAgcmV0dXJuIHsgJ0F1dGhvcml6YXRpb24nOiAnQmVhcmVyICcgKyBrLCAnQ29u" + + "dGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nIH07Cn0KCi8vIC0tLSBUb2dnbGUgLS0tCmZ1bmN0" + + "aW9uIHRvZ2dsZUNhcmQoaGVhZGVyKSB7CiAgaGVhZGVyLnBhcmVudEVsZW1lbnQuY2xhc3NMaXN0LnRv" + + "Z2dsZSgnb3BlbicpOwp9CgovLyAtLS0gVG9hc3QgLS0tCmxldCB0b2FzdFRpbWVyOwpmdW5jdGlvbiBz" + + "aG93VG9hc3QobXNnLCBvayA9IHRydWUpIHsKICBjb25zdCBlbCA9IGRvY3VtZW50LmdldEVsZW1lbnRC" + + "eUlkKCd0b2FzdCcpOwogIGVsLnRleHRDb250ZW50ID0gKG9rID8gJ+KckyAnIDogJ+KclyAnKSArIG1z" + + "ZzsKICBlbC5zdHlsZS5kaXNwbGF5ID0gJ2Jsb2NrJzsKICBlbC5zdHlsZS5ib3JkZXJDb2xvciA9IG9r" + + "ID8gJyMzZmI5NTAnIDogJyNmODUxNDknOwogIGNsZWFyVGltZW91dCh0b2FzdFRpbWVyKTsKICB0b2Fz" + + "dFRpbWVyID0gc2V0VGltZW91dCgoKSA9PiBlbC5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnLCAzMDAwKTsK" + + "fQoKLy8gLS0tIFNoYXJlZCBmZXRjaCAtLS0KYXN5bmMgZnVuY3Rpb24gYXBpRmV0Y2gobWV0aG9kLCBw" + + "YXRoLCBib2R5LCB7IHJhd0hlYWRlcnMsIHN0cmVhbSB9ID0ge30pIHsKICBjb25zdCBoZWFkZXJzID0g" + + "cmF3SGVhZGVycyB8fCBhdXRoSGVhZGVycygpOwogIGxldCByZXNwOwogIGlmIChzdHJlYW0pIHsKICAg" + + "IHJlc3AgPSBhd2FpdCBmZXRjaChhcGlCYXNlKCkgKyBwYXRoLCB7IG1ldGhvZCwgaGVhZGVycywgYm9k" + + "eTogYm9keSA/IEpTT04uc3RyaW5naWZ5KGJvZHkpIDogdW5kZWZpbmVkIH0pOwogIH0gZWxzZSB7CiAg" + + "ICByZXNwID0gYXdhaXQgZmV0Y2goYXBpQmFzZSgpICsgcGF0aCwgeyBtZXRob2QsIGhlYWRlcnMsIGJv" + + "ZHk6IGJvZHkgPyBKU09OLnN0cmluZ2lmeShib2R5KSA6IHVuZGVmaW5lZCB9KTsKICB9CiAgaWYgKHN0" + + "cmVhbSAmJiByZXNwLm9rICYmIHJlc3AuaGVhZGVycy5nZXQoJ2NvbnRlbnQtdHlwZScpPy5pbmNsdWRl" + + "cygndGV4dC9ldmVudC1zdHJlYW0nKSkgewogICAgcmV0dXJuIHsgcmVzcCwgc3RyZWFtUmVhZGVyOiBy" + + "ZXNwLmJvZHkuZ2V0UmVhZGVyKCkgfTsKICB9CiAgbGV0IGRhdGEgPSBudWxsOwogIGNvbnN0IHRleHQg" + + "PSBhd2FpdCByZXNwLnRleHQoKTsKICB0cnkgeyBkYXRhID0gSlNPTi5wYXJzZSh0ZXh0KTsgfSBjYXRj" + + "aCB7IGRhdGEgPSB0ZXh0OyB9CiAgcmV0dXJuIHsgcmVzcCwgZGF0YSB9Owp9CgpmdW5jdGlvbiBzaG93" + + "T3V0cHV0KGlkLCByZXNwLCBkYXRhLCByYXcpIHsKICBjb25zdCBlbCA9IGRvY3VtZW50LmdldEVsZW1l" + + "bnRCeUlkKCdvdXRwdXQtJyArIGlkKTsKICBlbC5zdHlsZS5kaXNwbGF5ID0gJ2Jsb2NrJzsKICBjb25z" + + "dCBvayA9IHJlc3Auc3RhdHVzID49IDIwMCAmJiByZXNwLnN0YXR1cyA8IDMwMDsKICBlbC5pbm5lckhU" + + "TUwgPSBgPGRpdiBjbGFzcz0ibWV0YSI+CiAgICA8c3BhbiBjbGFzcz0ic3RhdHVzICR7b2sgPyAnb2sn" + + "IDogJ2Vycid9Ij4ke3Jlc3Auc3RhdHVzfSAke3Jlc3Auc3RhdHVzVGV4dH08L3NwYW4+CiAgICAke2Vs" + + "YXBzZWQoKX1tcwogIDwvZGl2PgogIDxwcmU+JHtlc2NhcGVIdG1sKHR5cGVvZiBkYXRhID09PSAnc3Ry" + + "aW5nJyA/IGRhdGEgOiBKU09OLnN0cmluZ2lmeShkYXRhLCBudWxsLCAyKSkuc2xpY2UoMCwgMTAwMDAp" + + "fTwvcHJlPmA7CiAgc2hvd1RvYXN0KGAke3Jlc3Auc3RhdHVzfSAke3Jlc3Auc3RhdHVzVGV4dH1gLCBv" + + "ayk7Cn0KCmZ1bmN0aW9uIHN0cmVhbU91dHB1dChpZCwgY2h1bmspIHsKICBjb25zdCBlbCA9IGRvY3Vt" + + "ZW50LmdldEVsZW1lbnRCeUlkKCdvdXRwdXQtJyArIGlkKTsKICBlbC5zdHlsZS5kaXNwbGF5ID0gJ2Js" + + "b2NrJzsKICBjb25zdCBwcmUgPSBlbC5xdWVyeVNlbGVjdG9yKCdwcmUnKTsKICBpZiAoIXByZSkgewog" + + "ICAgZWwuaW5uZXJIVE1MID0gYDxkaXYgY2xhc3M9Im1ldGEiPnN0cmVhbWluZ+KApjwvZGl2PjxwcmU+" + + "PC9wcmU+YDsKICB9CiAgY29uc3QgcCA9IGVsLnF1ZXJ5U2VsZWN0b3IoJ3ByZScpOwogIHAudGV4dENv" + + "bnRlbnQgKz0gY2h1bms7CiAgcC5zY3JvbGxUb3AgPSBwLnNjcm9sbEhlaWdodDsKfQoKbGV0IF9lbGFw" + + "c2VkQmFzZSA9IDA7CmZ1bmN0aW9uIGVsYXBzZWQoKSB7IHJldHVybiBEYXRlLm5vdygpIC0gX2VsYXBz" + + "ZWRCYXNlOyB9CgovLyAtLS0gSGVhbHRoIC0tLQphc3luYyBmdW5jdGlvbiBjYWxsSGVhbHRoKCkgewog" + + "IF9lbGFwc2VkQmFzZSA9IERhdGUubm93KCk7CiAgdHJ5IHsKICAgIGNvbnN0IHsgcmVzcCwgZGF0YSB9" + + "ID0gYXdhaXQgYXBpRmV0Y2goJ0dFVCcsICcvaGVhbHRoJyk7CiAgICBzaG93T3V0cHV0KCdoZWFsdGgn" + + "LCByZXNwLCBkYXRhKTsKICB9IGNhdGNoIChlKSB7IHNob3dPdXRwdXQoJ2hlYWx0aCcsIHtzdGF0dXM6" + + "MCxzdGF0dXNUZXh0OidOZXR3b3JrIEVycm9yJ30sIGUubWVzc2FnZSk7IHNob3dUb2FzdChlLm1lc3Nh" + + "Z2UsIGZhbHNlKTsgfQp9CgovLyAtLS0gTW9kZWxzIC0tLQphc3luYyBmdW5jdGlvbiBjYWxsTW9kZWxz" + + "KCkgewogIF9lbGFwc2VkQmFzZSA9IERhdGUubm93KCk7CiAgdHJ5IHsKICAgIGNvbnN0IHsgcmVzcCwg" + + "ZGF0YSB9ID0gYXdhaXQgYXBpRmV0Y2goJ0dFVCcsICcvdjEvbW9kZWxzJyk7CiAgICBzaG93T3V0cHV0" + + "KCdtb2RlbHMnLCByZXNwLCBkYXRhKTsKICB9IGNhdGNoIChlKSB7IHNob3dPdXRwdXQoJ21vZGVscycs" + + "IHtzdGF0dXM6MCxzdGF0dXNUZXh0OidOZXR3b3JrIEVycm9yJ30sIGUubWVzc2FnZSk7IHNob3dUb2Fz" + + "dChlLm1lc3NhZ2UsIGZhbHNlKTsgfQp9CgovLyAtLS0gQ2hhdCBDb21wbGV0aW9ucyAtLS0KYXN5bmMg" + + "ZnVuY3Rpb24gY2FsbENoYXQoKSB7CiAgX2VsYXBzZWRCYXNlID0gRGF0ZS5ub3coKTsKICBjb25zdCBz" + + "dHJlYW0gPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnY2hhdFN0cmVhbScpLmNoZWNrZWQ7CiAgbGV0" + + "IG1lc3NhZ2VzOwogIHRyeSB7IG1lc3NhZ2VzID0gSlNPTi5wYXJzZShkb2N1bWVudC5nZXRFbGVtZW50" + + "QnlJZCgnY2hhdE1lc3NhZ2VzJykudmFsdWUpOyB9CiAgY2F0Y2ggeyBzaG93VG9hc3QoJ0ludmFsaWQg" + + "bWVzc2FnZXMgSlNPTicsIGZhbHNlKTsgcmV0dXJuOyB9CgogIGNvbnN0IGJvZHkgPSB7CiAgICBtb2Rl" + + "bDogZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2NoYXRNb2RlbCcpLnZhbHVlIHx8ICdkZWVwc2Vlay12" + + "NC1mbGFzaC1mcmVlJywKICAgIG1lc3NhZ2VzLAogICAgc3RyZWFtLAogICAgbWF4X3Rva2VuczogcGFy" + + "c2VJbnQoZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2NoYXRNYXhUb2tlbnMnKS52YWx1ZSkgfHwgMTI4" + + "LAogIH07CgogIHRyeSB7CiAgICBpZiAoc3RyZWFtKSB7CiAgICAgIGNvbnN0IGVsID0gZG9jdW1lbnQu" + + "Z2V0RWxlbWVudEJ5SWQoJ291dHB1dC1jaGF0Jyk7CiAgICAgIGVsLnN0eWxlLmRpc3BsYXkgPSAnYmxv" + + "Y2snOwogICAgICBlbC5pbm5lckhUTUwgPSBgPGRpdiBjbGFzcz0ibWV0YSI+c3RyZWFtaW5nIOKApjwv" + + "ZGl2PjxwcmU+PC9wcmU+YDsKICAgICAgY29uc3QgcmVzcCA9IGF3YWl0IGZldGNoKGFwaUJhc2UoKSAr" + + "ICcvdjEvY2hhdC9jb21wbGV0aW9ucycsIHsKICAgICAgICBtZXRob2Q6ICdQT1NUJywKICAgICAgICBo" + + "ZWFkZXJzOiBhdXRoSGVhZGVycygpLAogICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KGJvZHkpLAog" + + "ICAgICB9KTsKICAgICAgaWYgKCFyZXNwLm9rKSB7CiAgICAgICAgc2hvd091dHB1dCgnY2hhdCcsIHJl" + + "c3AsIGF3YWl0IHJlc3AudGV4dCgpKTsKICAgICAgICByZXR1cm47CiAgICAgIH0KICAgICAgY29uc3Qg" + + "cmVhZGVyID0gcmVzcC5ib2R5LmdldFJlYWRlcigpOwogICAgICBjb25zdCBkZWNvZGVyID0gbmV3IFRl" + + "eHREZWNvZGVyKCk7CiAgICAgIGxldCBkb25lOwogICAgICB3aGlsZSAoIWRvbmUpIHsKICAgICAgICBj" + + "b25zdCB7IHZhbHVlLCBkb25lOiBkIH0gPSBhd2FpdCByZWFkZXIucmVhZCgpOwogICAgICAgIGRvbmUg" + + "PSBkOwogICAgICAgIGlmICh2YWx1ZSkgc3RyZWFtT3V0cHV0KCdjaGF0JywgZGVjb2Rlci5kZWNvZGUo" + + "dmFsdWUpKTsKICAgICAgfQogICAgICBzaG93VG9hc3QoJ3N0cmVhbSBjb21wbGV0ZScpOwogICAgfSBl" + + "bHNlIHsKICAgICAgY29uc3QgeyByZXNwLCBkYXRhIH0gPSBhd2FpdCBhcGlGZXRjaCgnUE9TVCcsICcv" + + "djEvY2hhdC9jb21wbGV0aW9ucycsIGJvZHkpOwogICAgICBzaG93T3V0cHV0KCdjaGF0JywgcmVzcCwg" + + "ZGF0YSk7CiAgICB9CiAgfSBjYXRjaCAoZSkgeyBzaG93T3V0cHV0KCdjaGF0Jywge3N0YXR1czowLHN0" + + "YXR1c1RleHQ6J05ldHdvcmsgRXJyb3InfSwgZS5tZXNzYWdlKTsgc2hvd1RvYXN0KGUubWVzc2FnZSwg" + + "ZmFsc2UpOyB9Cn0KCi8vIC0tLSBBbnRocm9waWMgLS0tCmFzeW5jIGZ1bmN0aW9uIGNhbGxBbnRocm9w" + + "aWMoKSB7CiAgX2VsYXBzZWRCYXNlID0gRGF0ZS5ub3coKTsKICBjb25zdCBzdHJlYW0gPSBkb2N1bWVu" + + "dC5nZXRFbGVtZW50QnlJZCgnYW50aFN0cmVhbScpLmNoZWNrZWQ7CiAgbGV0IG1lc3NhZ2VzOwogIHRy" + + "eSB7IG1lc3NhZ2VzID0gSlNPTi5wYXJzZShkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnYW50aE1lc3Nh" + + "Z2VzJykudmFsdWUpOyB9CiAgY2F0Y2ggeyBzaG93VG9hc3QoJ0ludmFsaWQgbWVzc2FnZXMgSlNPTics" + + "IGZhbHNlKTsgcmV0dXJuOyB9CgogIGNvbnN0IGJvZHkgPSB7CiAgICBtb2RlbDogZG9jdW1lbnQuZ2V0" + + "RWxlbWVudEJ5SWQoJ2FudGhNb2RlbCcpLnZhbHVlIHx8ICdkZWVwc2Vlay12NC1mbGFzaC1mcmVlJywK" + + "ICAgIG1heF90b2tlbnM6IHBhcnNlSW50KGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdhbnRoTWF4VG9r" + + "ZW5zJykudmFsdWUpIHx8IDI1NiwKICAgIG1lc3NhZ2VzLAogICAgc3RyZWFtLAogIH07CiAgLy8gUGFy" + + "c2Ugb3B0aW9uYWwgc3lzdGVtIHByb21wdCB3aXRoIGNhY2hlX2NvbnRyb2wgc3VwcG9ydAogIGNvbnN0" + + "IHN5cyA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdhbnRoU3lzdGVtJykudmFsdWUudHJpbSgpOwog" + + "IGlmIChzeXMpIHsKICAgIHRyeSB7IGJvZHkuc3lzdGVtID0gSlNPTi5wYXJzZShzeXMpOyB9IGNhdGNo" + + "IHsgYm9keS5zeXN0ZW0gPSBzeXM7IH0KICB9CgogIHRyeSB7CiAgICBpZiAoc3RyZWFtKSB7CiAgICAg" + + "IGNvbnN0IGVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ291dHB1dC1hbnRoJyk7CiAgICAgIGVs" + + "LnN0eWxlLmRpc3BsYXkgPSAnYmxvY2snOwogICAgICBlbC5pbm5lckhUTUwgPSBgPGRpdiBjbGFzcz0i" + + "bWV0YSI+c3RyZWFtaW5nIOKApjwvZGl2PjxwcmU+PC9wcmU+YDsKICAgICAgY29uc3QgcmVzcCA9IGF3" + + "YWl0IGZldGNoKGFwaUJhc2UoKSArICcvdjEvbWVzc2FnZXMnLCB7CiAgICAgICAgbWV0aG9kOiAnUE9T" + + "VCcsCiAgICAgICAgaGVhZGVyczogYXV0aEhlYWRlcnMoKSwKICAgICAgICBib2R5OiBKU09OLnN0cmlu" + + "Z2lmeShib2R5KSwKICAgICAgfSk7CiAgICAgIGlmICghcmVzcC5vaykgewogICAgICAgIHNob3dPdXRw" + + "dXQoJ2FudGgnLCByZXNwLCBhd2FpdCByZXNwLnRleHQoKSk7CiAgICAgICAgcmV0dXJuOwogICAgICB9" + + "CiAgICAgIGNvbnN0IHJlYWRlciA9IHJlc3AuYm9keS5nZXRSZWFkZXIoKTsKICAgICAgY29uc3QgZGVj" + + "b2RlciA9IG5ldyBUZXh0RGVjb2RlcigpOwogICAgICBsZXQgZG9uZTsKICAgICAgd2hpbGUgKCFkb25l" + + "KSB7CiAgICAgICAgY29uc3QgeyB2YWx1ZSwgZG9uZTogZCB9ID0gYXdhaXQgcmVhZGVyLnJlYWQoKTsK" + + "ICAgICAgICBkb25lID0gZDsKICAgICAgICBpZiAodmFsdWUpIHN0cmVhbU91dHB1dCgnYW50aCcsIGRl" + + "Y29kZXIuZGVjb2RlKHZhbHVlKSk7CiAgICAgIH0KICAgICAgc2hvd1RvYXN0KCdzdHJlYW0gY29tcGxl" + + "dGUnKTsKICAgIH0gZWxzZSB7CiAgICAgIGNvbnN0IHsgcmVzcCwgZGF0YSB9ID0gYXdhaXQgYXBpRmV0" + + "Y2goJ1BPU1QnLCAnL3YxL21lc3NhZ2VzJywgYm9keSk7CiAgICAgIHNob3dPdXRwdXQoJ2FudGgnLCBy" + + "ZXNwLCBkYXRhKTsKICAgIH0KICB9IGNhdGNoIChlKSB7IHNob3dPdXRwdXQoJ2FudGgnLCB7c3RhdHVz" + + "OjAsc3RhdHVzVGV4dDonTmV0d29yayBFcnJvcid9LCBlLm1lc3NhZ2UpOyBzaG93VG9hc3QoZS5tZXNz" + + "YWdlLCBmYWxzZSk7IH0KfQoKLy8gLS0tIFJlbGF5IC0tLQphc3luYyBmdW5jdGlvbiBjYWxsUmVsYXko" + + "KSB7CiAgX2VsYXBzZWRCYXNlID0gRGF0ZS5ub3coKTsKICBjb25zdCB0YXJnZXQgPSBkb2N1bWVudC5n" + + "ZXRFbGVtZW50QnlJZCgncmVsYXlUYXJnZXQnKS52YWx1ZTsKICBjb25zdCBwYXRoID0gZG9jdW1lbnQu" + + "Z2V0RWxlbWVudEJ5SWQoJ3JlbGF5UGF0aCcpLnZhbHVlIHx8ICcvJzsKICBjb25zdCBtZXRob2QgPSBk" + + "b2N1bWVudC5nZXRFbGVtZW50QnlJZCgncmVsYXlNZXRob2QnKS52YWx1ZTsKICBjb25zdCByYXdCb2R5" + + "ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3JlbGF5Qm9keScpLnZhbHVlOwoKICB0cnkgewogICAg" + + "Y29uc3QgcmVzcCA9IGF3YWl0IGZldGNoKGFwaUJhc2UoKSArICcvJywgewogICAgICBtZXRob2QsCiAg" + + "ICAgIGhlYWRlcnM6IHsKICAgICAgICAneC1yZWxheS10YXJnZXQnOiB0YXJnZXQsCiAgICAgICAgJ3gt" + + "cmVsYXktcGF0aCc6IHBhdGgsCiAgICAgICAgLi4uKHJhd0JvZHkgPyB7ICdDb250ZW50LVR5cGUnOiAn" + + "YXBwbGljYXRpb24vanNvbicgfSA6IHt9KSwKICAgICAgfSwKICAgICAgYm9keTogcmF3Qm9keSB8fCB1" + + "bmRlZmluZWQsCiAgICB9KTsKICAgIGNvbnN0IHRleHQgPSBhd2FpdCByZXNwLnRleHQoKTsKICAgIGxl" + + "dCBkYXRhOwogICAgdHJ5IHsgZGF0YSA9IEpTT04ucGFyc2UodGV4dCk7IH0gY2F0Y2ggeyBkYXRhID0g" + + "dGV4dDsgfQogICAgc2hvd091dHB1dCgncmVsYXknLCByZXNwLCBkYXRhKTsKICB9IGNhdGNoIChlKSB7" + + "IHNob3dPdXRwdXQoJ3JlbGF5Jywge3N0YXR1czowLHN0YXR1c1RleHQ6J05ldHdvcmsgRXJyb3InfSwg" + + "ZS5tZXNzYWdlKTsgc2hvd1RvYXN0KGUubWVzc2FnZSwgZmFsc2UpOyB9Cn0KCmZ1bmN0aW9uIGVzY2Fw" + + "ZUh0bWwocykgewogIGNvbnN0IGQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTsKICBkLnRl" + + "eHRDb250ZW50ID0gczsKICByZXR1cm4gZC5pbm5lckhUTUw7Cn0KZG9jdW1lbnQuYWRkRXZlbnRMaXN0" + + "ZW5lcignRE9NQ29udGVudExvYWRlZCcsICgpID0+IHsKICBjb25zdCBlbCA9IGRvY3VtZW50LmdldEVs" + + "ZW1lbnRCeUlkKCdiYXNlVXJsJyk7CiAgaWYgKGVsICYmICFlbC52YWx1ZSkgZWwudmFsdWUgPSB3aW5k" + + "b3cubG9jYXRpb24ub3JpZ2luOwp9KTsKPC9zY3JpcHQ+CjwvYm9keT4KPC9odG1sPgo=" +; + +// ── Decode cache (once) ──────────────────────────────────────────────────── + +let _decoded: string | null = null; + +function decodeBase64(b64: string): string { + // Bun / Node.js + if (typeof Buffer !== "undefined") { + return Buffer.from(b64, "base64").toString("utf-8"); + } + // Web/Workers (TextDecoder) + if (typeof TextDecoder !== "undefined") { + const binStr = atob(b64); + const bytes = new Uint8Array(binStr.length); + for (let i = 0; i < binStr.length; i++) { + bytes[i] = binStr.charCodeAt(i); + } + return new TextDecoder("utf-8").decode(bytes); + } + // Fallback + return atob(b64); +} + +/** Get the interactive test page HTML. Decoded once and cached. */ +export function getTestPageHtml(): string { + if (!_decoded) { + _decoded = decodeBase64(B64_HTML); + } + return _decoded; +} + +export default getTestPageHtml; diff --git a/src/worker.ts b/src/worker.ts index 99bdd32..87ea7a1 100644 --- a/src/worker.ts +++ b/src/worker.ts @@ -23,6 +23,7 @@ import { getCorsHeaders, } from "./lib/relay-utils"; +import { getTestPageHtml } from "./lib/test-page"; import { checkBodySize } from "./middleware/body-limiter"; import { createRateLimiter } from "./middleware/rate-limiter"; import { logRelayEvent } from "./middleware/logger"; @@ -307,20 +308,10 @@ export default { if (url.pathname === "/health") return handleHealth(); if (url.pathname === "/docs" || url.pathname === "/test") { - try { - const file = Bun.file("public/test-api.html"); - const exists = await file.exists(); - return new Response(exists ? file : "Not found", { - status: exists ? 200 : 404, - headers: { "Content-Type": "text/html; charset=utf-8" }, - }); - } catch { - // Bun.file not available in non-Bun runtimes (e.g. Workers) - return new Response("Not found", { - status: 404, - headers: { "Content-Type": "text/html; charset=utf-8" }, - }); - } + return new Response(getTestPageHtml(), { + status: 200, + headers: { "Content-Type": "text/html; charset=utf-8" }, + }); } if ( url.pathname === "/" &&