Public: anyone can read this; the crew can change it.

The make-it-yours page's Server-Timing names its phases: session, each read, render #3539

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

scout/forge:scout/3509-the-make-it-yours-page-s-server-timing-n → main 1 commit fork

  • Merged. scout/3509-the-make-it-yours-page-s-server-timing-n was merged into main as 2d4f0b0.

Review

Sign in to review this change.
2 files changed +74 −5
src/web/studio/make_it_yours.ts +16 −5
@@ -19,15 +19,23 @@ import { html, when } from "../html.ts";
1919 import { flashTo, page, redirect } from "../layout.ts";
2020 import { btn, card } from "../ui.ts";
2121 import { NOT_A_MEMBER } from "../../core/roles.ts";
22 import {
23 notePhase,
24 takeSessionTime,
25 timePhaseAsync,
26 timePhase,
27 } from "../../core/route_timing.ts";
2228
2329 // GET /:owner/:name/make-it-yours
2430 export async function makeItYoursPage(ctx: Ctx): Promise<Response> {
25 const repo = loadRepo(ctx);
31 notePhase(ctx.request, "session", takeSessionTime(ctx.request));
32 const repo = timePhase(ctx.request, "repo", () => loadRepo(ctx));
2633 if (!repo) return notFoundPage(ctx);
2734 if (!ctx.auth.user) return signInFirst(ctx);
28 const plan = await makeItYours(ctx.app, ctx.auth.user, repo, {
29 dryRun: true,
30 });
35 const user = ctx.auth.user;
36 const plan = await timePhaseAsync(ctx.request, "plan", () =>
37 makeItYours(ctx.app, user, repo, { dryRun: true }),
38 );
3139 if (!plan.ok) {
3240 if (plan.error.kind === "own")
3341 return flashTo(ctx, repoBase(repo), {
@@ -46,6 +54,7 @@ export async function makeItYoursPage(ctx: Ctx): Promise<Response> {
4654 });
4755 }
4856 const p = plan.value;
57 const rendering = performance.now();
4958 const body = html`<div class="narrow-wide">
5059 ${pageHead("Make it yours", {
5160 sub: p.existing
@@ -111,7 +120,9 @@ export async function makeItYoursPage(ctx: Ctx): Promise<Response> {
111120 </form>`,
112121 )}
113122 </div>`;
114 return page({ ctx, title: `Make ${p.from} yours`, body });
123 const response = page({ ctx, title: `Make ${p.from} yours`, body });
124 notePhase(ctx.request, "render", performance.now() - rendering);
125 return response;
115126 }
116127
117128 // POST /:owner/:name/make-it-yours
test/make-it-yours-timing.test.ts added +58
@@ -0,0 +1,58 @@
1 /** `/:owner/:name/make-it-yours` names session, repo, plan and render in Server-Timing (#3509). */
2 import { afterAll, beforeAll, expect, test } from "bun:test";
3 import { mkdtempSync, rmSync } from "node:fs";
4 import { tmpdir } from "node:os";
5 import { join } from "node:path";
6 import { newApp } from "../src/actions/apps.ts";
7 import { createApp, type App } from "../src/app.ts";
8 import { createSession } from "../src/core/sessions.ts";
9 import { createUser } from "../src/core/users.ts";
10 import { serve, type Servers } from "../src/http/server.ts";
11 import { quietLogs } from "./helpers/globals.ts";
12 import { promote } from "./helpers/members.ts";
13
14 quietLogs();
15
16 let root = "";
17 let app: App;
18 let servers: Servers;
19 let cookie = "";
20
21 beforeAll(async () => {
22 root = mkdtempSync(join(tmpdir(), "forge-make-it-yours-timing-"));
23 app = createApp({ dataDir: root, port: 0 });
24 const mk = async (username: string, first = false) => {
25 const r = await createUser(app.db, {
26 origin: "seed",
27 trusted: true,
28 username,
29 email: `${username}@forge.local`,
30 password: "a-good-passphrase",
31 adminIfFirst: first,
32 });
33 if (!r.ok) throw new Error(r.error);
34 promote(app.db, r.value);
35 return r.value;
36 };
37 const alice = await mk("alice", true);
38 const bob = await mk("bob");
39 const made = await newApp(app, alice, { name: "garden", visibility: "public" });
40 if (!made.ok) throw new Error(String(made.error));
41 cookie = `forge_session=${createSession(app.db, bob.id).token}`;
42 servers = await serve(app);
43 }, 60_000);
44 afterAll(() => {
45 servers.stop();
46 app.close();
47 rmSync(root, { recursive: true, force: true });
48 });
49
50 test("GET /:owner/:name/make-it-yours names its phases", async () => {
51 const res = await fetch(`${servers.url}/alice/garden/make-it-yours`, { headers: { cookie } });
52 const body = await res.text();
53 expect(res.status).toBe(200);
54 expect(body).toContain("Make it yours");
55 const parts = (res.headers.get("server-timing") ?? "").split(", ");
56 for (const name of ["app", "session", "repo", "plan", "render"])
57 expect(parts.find((p) => p.startsWith(`${name};`))).toMatch(/^[a-z]+;dur=\d+\.\d$/);
58 });

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs