From 702b27df688ee5ac3f56defbdb9eb8c946a40e99 Mon Sep 17 00:00:00 2001 From: Marcos Caceres Date: Tue, 14 Apr 2026 00:41:48 +1000 Subject: [PATCH 1/7] chore: update types from deps --- routes/github/commits.ts | 5 ++++- routes/github/contributors.ts | 5 ++++- routes/w3c/group.ts | 5 ++++- routes/w3c/index.ts | 2 +- routes/xref/index.ts | 2 +- scripts/update-w3c-groups-list.ts | 3 ++- 6 files changed, 16 insertions(+), 6 deletions(-) diff --git a/routes/github/commits.ts b/routes/github/commits.ts index 125ca04f..b7dee952 100644 --- a/routes/github/commits.ts +++ b/routes/github/commits.ts @@ -2,7 +2,10 @@ import { Request, Response } from "express"; import { seconds } from "../../utils/misc.js"; import { getCommits } from "./lib/commits.js"; -export default async function route(req: Request, res: Response) { +export default async function route( + req: Request<{ org: string; repo: string }>, + res: Response, +) { const { org, repo } = req.params; const { from, to , path } = req.query; if (!from || typeof from !== "string") { diff --git a/routes/github/contributors.ts b/routes/github/contributors.ts index eadcc423..e12e3947 100644 --- a/routes/github/contributors.ts +++ b/routes/github/contributors.ts @@ -12,7 +12,10 @@ const cache = new DiskCache({ path: "github/contributors", }); -export default async function route(req: Request, res: Response) { +export default async function route( + req: Request<{ org: string; repo: string }>, + res: Response, +) { const { org, repo } = req.params; const cacheKey = `${org}/${repo}`; diff --git a/routes/w3c/group.ts b/routes/w3c/group.ts index 677ae957..e07ac168 100644 --- a/routes/w3c/group.ts +++ b/routes/w3c/group.ts @@ -39,7 +39,10 @@ const LEGACY_SHORTNAMES = new Map([ ["i18n", "i18n-core"], // more than 10 instances ]); -export default async function route(req: Request, res: Response) { +export default async function route( + req: Request<{ shortname?: string; type?: string }>, + res: Response, +) { const { shortname, type } = req.params; if (!shortname) { if (req.headers.accept?.includes("text/html")) { diff --git a/routes/w3c/index.ts b/routes/w3c/index.ts index 4830f686..4a809574 100644 --- a/routes/w3c/index.ts +++ b/routes/w3c/index.ts @@ -4,6 +4,6 @@ import cors from "cors"; import groupsRoute from "./group.js"; const w3c = Router(); -w3c.get("/groups/:shortname?/:type?", cors(), groupsRoute); +w3c.get("/groups{/:shortname}{/:type}", cors(), groupsRoute); export default w3c; diff --git a/routes/xref/index.ts b/routes/xref/index.ts index 50c31e23..7faf4ed9 100644 --- a/routes/xref/index.ts +++ b/routes/xref/index.ts @@ -25,7 +25,7 @@ xref .options("/search", cors({ methods: ["POST", "GET"], maxAge: ms("1day") })) .get("/search", cors(), searchRouteGet) .post("/search", express.json({ limit: "2mb" }), cors(), searchRoutePost); -xref.get("/meta/:field?", cors(), metaRoute); +xref.get("/meta{/:field}", cors(), metaRoute); xref.post("/update", authGithubWebhook(env("W3C_WEBREF_SECRET")), updateRoute); xref.use("/data", express.static(path.join(DATA_DIR, "xref"))); diff --git a/scripts/update-w3c-groups-list.ts b/scripts/update-w3c-groups-list.ts index 7ace808e..0da20800 100644 --- a/scripts/update-w3c-groups-list.ts +++ b/scripts/update-w3c-groups-list.ts @@ -75,13 +75,14 @@ export default async function update() { case "group": return g; case "tf": - return g.members; + return g.members || []; default: return []; } }); console.log(`Processing ${groups.length} items...`); for (const group of groups) { + if (!group) continue; const type = mapGroupType.get(group.type); if (!type) continue; From ad955d1c310f9e234d794e18ece452a61c2864be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20C=C3=A1ceres?= Date: Tue, 14 Apr 2026 12:23:43 +1000 Subject: [PATCH 2/7] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- scripts/update-w3c-groups-list.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/update-w3c-groups-list.ts b/scripts/update-w3c-groups-list.ts index 0da20800..6a238568 100644 --- a/scripts/update-w3c-groups-list.ts +++ b/scripts/update-w3c-groups-list.ts @@ -82,7 +82,6 @@ export default async function update() { }); console.log(`Processing ${groups.length} items...`); for (const group of groups) { - if (!group) continue; const type = mapGroupType.get(group.type); if (!type) continue; From 3ad3edc500b58912c206de4e9ce9b3e35362c5a8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 02:26:04 +0000 Subject: [PATCH 3/7] fix: use GroupType | undefined instead of type assertion in group route Agent-Logs-Url: https://github.com/speced/respec-web-services/sessions/d972ccea-f5eb-4212-b475-b3858cf8895e Co-authored-by: marcoscaceres <870154+marcoscaceres@users.noreply.github.com> --- routes/w3c/group.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/routes/w3c/group.ts b/routes/w3c/group.ts index e07ac168..2817aaa4 100644 --- a/routes/w3c/group.ts +++ b/routes/w3c/group.ts @@ -60,7 +60,7 @@ export default async function route( } try { - const requestedType = type as GroupType; + const requestedType: GroupType | undefined = type as GroupType | undefined; const groupInfo = await getGroupInfo(shortname, requestedType); res.set("Cache-Control", `max-age=${seconds("24h")}`); res.json(groupInfo); @@ -73,7 +73,7 @@ export default async function route( async function getGroupInfo( shortname: GroupMeta["name"], - requestedType: GroupType, + requestedType: GroupType | undefined, ) { const cacheKey = `${shortname}/${requestedType || ""}`; if (cache.expires(cacheKey) > 1000) { @@ -163,7 +163,7 @@ async function getPatentPolicy( } } -function getGroupMeta(shortname: string, requestedType: GroupType) { +function getGroupMeta(shortname: string, requestedType: GroupType | undefined) { const types = requestedType ? [requestedType] : (Object.keys(groups) as GroupType[]); From c43e2812bdc66aceedca328350ff694aed40f49a Mon Sep 17 00:00:00 2001 From: Marcos Caceres Date: Tue, 14 Apr 2026 12:34:35 +1000 Subject: [PATCH 4/7] refactor: remove redundant type annotation on requestedType cast --- routes/w3c/group.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes/w3c/group.ts b/routes/w3c/group.ts index 2817aaa4..0bf62661 100644 --- a/routes/w3c/group.ts +++ b/routes/w3c/group.ts @@ -60,7 +60,7 @@ export default async function route( } try { - const requestedType: GroupType | undefined = type as GroupType | undefined; + const requestedType = type as GroupType | undefined; const groupInfo = await getGroupInfo(shortname, requestedType); res.set("Cache-Control", `max-age=${seconds("24h")}`); res.json(groupInfo); From 61ce2640aceddf9ca1ea4e05237c6779889ceaee Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 09:28:52 +0000 Subject: [PATCH 5/7] refactor: apply @sidvishnoi's suggestions on typing style Agent-Logs-Url: https://github.com/speced/respec-web-services/sessions/889d3828-0bd4-454b-9055-65b66fea770d --- routes/github/commits.ts | 11 ++++++----- routes/w3c/group.ts | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/routes/github/commits.ts b/routes/github/commits.ts index b7dee952..65931bcf 100644 --- a/routes/github/commits.ts +++ b/routes/github/commits.ts @@ -2,12 +2,13 @@ import { Request, Response } from "express"; import { seconds } from "../../utils/misc.js"; import { getCommits } from "./lib/commits.js"; -export default async function route( - req: Request<{ org: string; repo: string }>, - res: Response, -) { +type Params = { org: string; repo: string }; +type Query = { from?: string; to?: string; path?: string }; +type IRequest = Request; + +export default async function route(req: IRequest, res: Response) { const { org, repo } = req.params; - const { from, to , path } = req.query; + const { from, to, path } = req.query; if (!from || typeof from !== "string") { res.set("Content-Type", "text/plain"); return res.status(400).send("query parameter 'from' is required"); diff --git a/routes/w3c/group.ts b/routes/w3c/group.ts index 0bf62661..1807a70c 100644 --- a/routes/w3c/group.ts +++ b/routes/w3c/group.ts @@ -73,7 +73,7 @@ export default async function route( async function getGroupInfo( shortname: GroupMeta["name"], - requestedType: GroupType | undefined, + requestedType?: GroupType, ) { const cacheKey = `${shortname}/${requestedType || ""}`; if (cache.expires(cacheKey) > 1000) { @@ -163,7 +163,7 @@ async function getPatentPolicy( } } -function getGroupMeta(shortname: string, requestedType: GroupType | undefined) { +function getGroupMeta(shortname: string, requestedType?: GroupType) { const types = requestedType ? [requestedType] : (Object.keys(groups) as GroupType[]); From 752956f113a644feaf3962712ed9c74a73e7325a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 16:58:43 +0000 Subject: [PATCH 6/7] refactor: apply @sidvishnoi's follow-up suggestions Agent-Logs-Url: https://github.com/speced/respec-web-services/sessions/2f839eef-b2b9-457a-8cef-016a2a78fa4a --- routes/github/commits.ts | 2 +- routes/github/contributors.ts | 8 ++++---- routes/w3c/group.ts | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/routes/github/commits.ts b/routes/github/commits.ts index 65931bcf..f2c69dc6 100644 --- a/routes/github/commits.ts +++ b/routes/github/commits.ts @@ -3,7 +3,7 @@ import { seconds } from "../../utils/misc.js"; import { getCommits } from "./lib/commits.js"; type Params = { org: string; repo: string }; -type Query = { from?: string; to?: string; path?: string }; +type Query = { from: string; to?: string; path?: string }; type IRequest = Request; export default async function route(req: IRequest, res: Response) { diff --git a/routes/github/contributors.ts b/routes/github/contributors.ts index e12e3947..aa53e8c7 100644 --- a/routes/github/contributors.ts +++ b/routes/github/contributors.ts @@ -12,10 +12,10 @@ const cache = new DiskCache({ path: "github/contributors", }); -export default async function route( - req: Request<{ org: string; repo: string }>, - res: Response, -) { +type Params = { org: string; repo: string }; +type IRequest = Request; + +export default async function route(req: IRequest, res: Response) { const { org, repo } = req.params; const cacheKey = `${org}/${repo}`; diff --git a/routes/w3c/group.ts b/routes/w3c/group.ts index 1807a70c..1665c840 100644 --- a/routes/w3c/group.ts +++ b/routes/w3c/group.ts @@ -39,10 +39,10 @@ const LEGACY_SHORTNAMES = new Map([ ["i18n", "i18n-core"], // more than 10 instances ]); -export default async function route( - req: Request<{ shortname?: string; type?: string }>, - res: Response, -) { +type Params = { shortname?: string; type?: string }; +type IRequest = Request; + +export default async function route(req: IRequest, res: Response) { const { shortname, type } = req.params; if (!shortname) { if (req.headers.accept?.includes("text/html")) { From 2730ed1664e742400e7a24400e9a11a023d384fb Mon Sep 17 00:00:00 2001 From: Marcos Caceres Date: Wed, 15 Apr 2026 12:56:16 +1000 Subject: [PATCH 7/7] fix: set Content-Type text/plain on error response to prevent XSS --- routes/github/commits.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/routes/github/commits.ts b/routes/github/commits.ts index f2c69dc6..8099421e 100644 --- a/routes/github/commits.ts +++ b/routes/github/commits.ts @@ -36,6 +36,7 @@ export default async function route(req: IRequest, res: Response) { } res.json(commits); } catch (error) { + res.set("Content-Type", "text/plain"); res.status(404).send(error.message); } }