From bc81fc3282800fe40bc8ca859c9db0af1ee3cc7c Mon Sep 17 00:00:00 2001 From: Lucas Winther Date: Thu, 15 Oct 2026 12:09:53 +0200 Subject: [PATCH] docs: plan 003 ticked; possible early-click race noted Co-Authored-By: Claude Opus 5.5 --- docs/TODO.md | 3 +++ docs/plans/003-tapas.md | 10 +++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/TODO.md b/docs/TODO.md index 63e3a0d..f730064 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -44,6 +44,9 @@ Design: [specs/001-webtoons-covers.md](specs/001-webtoons-covers.md). "rehosted" mark says "rehosted on direct" for no rehosting and outlives expired links; `openHistory` reads `globalThis.indexedDB` outside its `try`. +- [ ] Possible race (unconfirmed): pressing **Find covers** before the page has mounted (it awaits `/api/config` + and IndexedDB first) may submit the form natively and reload. Seen once in a scripted run; not reproduced. + ## Someday - [ ] S3-compatible bucket as a `Storage` option, if a single server's disk stops being enough. - [ ] Password gate (spec §4.11) — only if the open site gets abused or traffic grows too large. diff --git a/docs/plans/003-tapas.md b/docs/plans/003-tapas.md index a23aab8..e61cb3f 100644 --- a/docs/plans/003-tapas.md +++ b/docs/plans/003-tapas.md @@ -21,27 +21,27 @@ lists; source-neutral copy. **Spec:** [`docs/specs/003-tapas.md`](../specs/003-t **Produces:** `TAPAS_HOSTS`, `IMAGE_HOST = "us-a.tapas.io"`, `IMAGE_HOSTS`, `parseTapasUrl(url): TapasRef` (`{ kind: "series", key: string /* slug or id */ } | { kind: "episode", id: string }`), `isTapasUrl(url)`, `infoUrl(key)`, `normalizeImageUrl(raw)`, `isSameTapasSeries(linkUrl, slug, id)`, `slugOf(canonicalUrl)`. -- [ ] Tests: every link form; non-series paths rejected (`/comics`, `/series/`); normalisation (cloudfront → us-a, +- [x] Tests: every link form; non-series paths rejected (`/comics`, `/series/`); normalisation (cloudfront → us-a, `_z`/`_m` dropped, query dropped, other hosts untouched); same-series by slug (case-insensitive, `/info`, trailing slash), by id, `-novel` rejected. RED → implement → GREEN → commit. ### Task 2: Parsing (`tapas/parse.ts`) **Produces:** `parseInfoPage(html, pageUrl): { id, title, canonicalUrl, novel, covers }`, `extractCovers(html, pageUrl)`, `episodeSeriesId(html)`, `ageGateTarget(html): string | null`. -- [ ] Tests on fixtures: comic (id 186414, title, not novel, poster 960×1440 URL, banner), novel (266599, novel), +- [x] Tests on fixtures: comic (id 186414, title, not novel, poster 960×1440 URL, banner), novel (266599, novel), 2020 archive (cloudfront poster + banner normalised), reader page (`seriesId` 186414), age check (`from` URL). RED → implement → GREEN → commit. ### Task 3: Source (`tapas/index.ts`) and registry -- [ ] Tests through `FakeTransport`: info link; `/series/` (fake redirect = info page served for id URL); +- [x] Tests through `FakeTransport`: info link; `/series/` (fake redirect = info page served for id URL); episode link (two fetches); age check (mature, no covers, warning via a `SourceSeries` flag read by the pipeline → add `ageGated` flag and pipeline warning); Wayback history over the CDX fixture keeps only the comic rows. Register in `SOURCES`; hosts. RED → implement → GREEN → commit. ### Task 4: Copy, userscript @connect, docs -- [ ] Link hint, "No rehosting" warning, userscript description/@connect (+ gm test), README sources section, +- [x] Link hint, "No rehosting" warning, userscript description/@connect (+ gm test), README sources section, ARCHITECTURE map, DECISIONS entry. Commit. ### Task 5: Verify -- [ ] Real run in headless Chrome: comic and novel (no Wayback), and one with Wayback every 12 months; final +- [x] Real run in headless Chrome: comic and novel (no Wayback), and one with Wayback every 12 months; final review; remove this plan; merge; push.