Stateful integration emulators for real developer APIs. Pick a service, create an isolated instance, copy a
@@ -36,7 +40,10 @@ export default function Home() {
{error &&
Could not load the service catalog ({error}).
}
- {!services && !error &&
Loading services...
}
+
+ {services && services.length > 0 && (
+
All emulators ยท {services.length}
+ )}
{(services ?? []).map((s) => (
diff --git a/packages/@emulators/cloudflare/src/console-html.ts b/packages/@emulators/cloudflare/src/console-html.ts
index 39bbe9cf..be3a6464 100644
--- a/packages/@emulators/cloudflare/src/console-html.ts
+++ b/packages/@emulators/cloudflare/src/console-html.ts
@@ -1,4 +1,3 @@
// AUTO-GENERATED from apps/console (pnpm --filter @emulators/console build).
// Do not edit by hand; regenerate with `node scripts/gen-console.mjs`.
-export const consoleHtml =
- '\n\n \n \n \n Emulate\n \n \n \n \n \n \n\n';
+export const consoleHtml = "\n\n \n \n \n Emulate\n \n \n \n \n \n \n \n \n \n\n";
diff --git a/packages/@emulators/cloudflare/src/worker.ts b/packages/@emulators/cloudflare/src/worker.ts
index 839ea6fc..8e177e7c 100644
--- a/packages/@emulators/cloudflare/src/worker.ts
+++ b/packages/@emulators/cloudflare/src/worker.ts
@@ -14,6 +14,19 @@ function serviceCatalogEntries() {
}));
}
+// The catalog is a static registry, so inline it into the served SPA HTML: the
+// console renders the grid on first paint, with no client fetch and no loading
+// state. JSON `<` is escaped so a description can never break out of the script.
+async function serveCatalogConsole(ctx: { origin: string; protocol: string; hostSuffix: string }): Promise {
+ const json = (await servicesCatalog(serviceCatalogEntries(), ctx).text()).replace(/
',
+ ``,
+ ),
+ );
+}
+
interface EmulatorNamespace {
idFromName(name: string): unknown;
get(id: unknown): { fetch(request: Request): Promise };
@@ -183,7 +196,8 @@ export default {
// Apex root or bare `/` โ the catalog. Browser โ SPA; agent โ a
// server-rendered list of emulators (readable without running JS).
if (!service || !instance) {
- if (isBrowserNavigation(request)) return html(consoleHtml);
+ if (isBrowserNavigation(request))
+ return serveCatalogConsole({ origin: apexOrigin, protocol: url.protocol, hostSuffix: suffix });
if (wantsJson(request)) {
return servicesCatalog(serviceCatalogEntries(), {
origin: apexOrigin,