From be262767b5c9f884a2a1df35b053e2cfedb679cd Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 28 Jul 2026 01:45:09 +0000 Subject: [PATCH 1/2] fix(star-tracker): add canonical tags and enforce HTTPS on stars.wavekat.com Google Search Console flagged http://stars.wavekat.com/ as a duplicate without a user-selected canonical. The Worker never emitted a on any page and didn't redirect plain-HTTP requests, so Google indexed the http:// and https:// variants as separate identical pages. Add a canonical tag (and noindex on account-gated / thin-duplicate pages: dashboard, owner tenant view, admin, and the untracked-slug invite) to every page, and redirect http -> https at the Worker. --- tools/star-tracker/src/index.ts | 17 +++++++++++++++-- tools/star-tracker/src/pages.ts | 27 +++++++++++++++++++++------ 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/tools/star-tracker/src/index.ts b/tools/star-tracker/src/index.ts index e5b79f3..8b4e74b 100644 --- a/tools/star-tracker/src/index.ts +++ b/tools/star-tracker/src/index.ts @@ -91,6 +91,19 @@ function parseRangeMs(raw: string | undefined): number | null { const app = new Hono(); +// GSC flagged http://stars.wavekat.com/ as a duplicate of the https:// URL +// with no canonical declared. Cloudflare's edge "Always Use HTTPS" redirect +// doesn't cover every path to this Worker, so enforce it here too. Skip +// localhost/127.0.0.1 so `wrangler dev` (plain HTTP) keeps working. +app.use('*', async (c, next) => { + const url = new URL(c.req.url); + if (url.protocol === 'http:' && url.hostname !== 'localhost' && url.hostname !== '127.0.0.1') { + url.protocol = 'https:'; + return c.redirect(url.toString(), 301); + } + await next(); +}); + // Resolve the current user (if any) from the session cookie on every request. app.use('*', async (c, next) => { const userId = await readSession(c, c.env.JWT_SECRET); @@ -218,7 +231,7 @@ app.get('/favicon.svg', () => { // -- Landing ---------------------------------------------------------------- -app.get('/', (c) => c.html(pages.landing(c.get('user')))); +app.get('/', (c) => c.html(pages.landing(c.get('user'), c.env.PUBLIC_URL))); // -- OAuth ------------------------------------------------------------------ @@ -289,7 +302,7 @@ app.get('/_admin', async (c) => { const user = c.get('user'); if (!isAdmin(user, c.env.ADMIN_USERNAMES)) return c.notFound(); const tenants = await db.listAllTenantsWithStats(c.env.DB); - return c.html(pages.adminTenants(user!, tenants)); + return c.html(pages.adminTenants(user!, tenants, c.env.PUBLIC_URL)); }); // -- Tenant creation -------------------------------------------------------- diff --git a/tools/star-tracker/src/pages.ts b/tools/star-tracker/src/pages.ts index e74dd6c..609c717 100644 --- a/tools/star-tracker/src/pages.ts +++ b/tools/star-tracker/src/pages.ts @@ -25,7 +25,7 @@ function esc(s: string): string { return s.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); } -function shell(title: string, user: User | null, body: string): string { +function shell(title: string, user: User | null, body: string, canonicalUrl?: string, noindex = false): string { const nav = user ? `${esc(user.username)} ·
` : `Sign in with GitHub`; @@ -34,6 +34,8 @@ function shell(title: string, user: User | null, body: string): string { ${esc(title)} +${canonicalUrl ? `` : ''} +${noindex ? '' : ''}