From 6a39c6d705e2e2b5cb3e00b5b78b94fed5848452 Mon Sep 17 00:00:00 2001 From: Madraka <8898640+Madraka@users.noreply.github.com> Date: Thu, 22 Oct 2026 16:28:22 +0300 Subject: [PATCH 1/2] fix(core-ts): entryPath accepts the old one-argument call again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 0.3.11 replaced the renderer's `entryPath(entry)` with core's `entryPath(site, entry)` under the same exported name. Themes copied from the starter before then (cloudhal.com, try, Deploy-button sites) call `entryPath(e)` in `EntryList.astro`; the call threw, Astro had already started streaming, and every page with an entry list answered 200 with an empty body. cloudhal.com was rolled back to its 0.3.10 build. `entryPath` now also takes the old form — one argument, or a `map` index second — and returns `//` (deprecated overload). Verified on a site with the old theme copy: the home page renders again. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Madraka <8898640+Madraka@users.noreply.github.com> --- .changeset/entry-path-one-argument.md | 7 +++++++ packages/core-ts/src/permalinks.ts | 19 +++++++++++++++++-- packages/core-ts/test/permalinks.test.ts | 5 +++++ 3 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 .changeset/entry-path-one-argument.md diff --git a/.changeset/entry-path-one-argument.md b/.changeset/entry-path-one-argument.md new file mode 100644 index 00000000..72706d6d --- /dev/null +++ b/.changeset/entry-path-one-argument.md @@ -0,0 +1,7 @@ +--- +"@cloudhal/core-ts": patch +"@cloudhal/astro-renderer": patch +"@cloudhal/cli": patch +--- + +Fix: sites whose theme was copied from the starter before 0.3.11 rendered empty pages (200 with no body). Their `EntryList` calls the renderer's old one-argument `entryPath(entry)` (and `.map(entryPath)`), which became `entryPath(site, entry)` in 0.3.11. `entryPath` accepts the old call again (deprecated; it ignores collection permalinks — pass the site to get them). diff --git a/packages/core-ts/src/permalinks.ts b/packages/core-ts/src/permalinks.ts index b45af646..618ed9c2 100644 --- a/packages/core-ts/src/permalinks.ts +++ b/packages/core-ts/src/permalinks.ts @@ -25,10 +25,25 @@ export function permalinkPrefix(template: string): string { } /** `/blog/hello-world`: the collection's template with the entry's slug filled in. */ +type EntryRef = Pick; + +export function entryPath(site: PermalinkSite | undefined, entry: EntryRef): string; +/** + * @deprecated The one-argument form of the renderer's old `entryPath(entry)`, kept because themes + * copied from the starter before 0.3.11 call it (also as `entries.map(entryPath)`, which passes + * the index second). It ignores collection permalinks; pass the site. + */ +export function entryPath(entry: EntryRef, index?: number): string; export function entryPath( - site: PermalinkSite | undefined, - entry: Pick, + siteOrEntry: PermalinkSite | EntryRef | undefined, + entry?: EntryRef | number, ): string { + // Old call: no second argument, or a `map` index; the first argument is the entry. + if (typeof entry !== "object" || entry === null) { + const old = siteOrEntry as EntryRef; + return `/${old.collection}/${old.slug}`; + } + const site = siteOrEntry as PermalinkSite | undefined; return `${permalinkPrefix(collectionPermalink(site, entry.collection))}/${entry.slug}`; } diff --git a/packages/core-ts/test/permalinks.test.ts b/packages/core-ts/test/permalinks.test.ts index 603f2cb0..e53ce515 100644 --- a/packages/core-ts/test/permalinks.test.ts +++ b/packages/core-ts/test/permalinks.test.ts @@ -49,4 +49,9 @@ describe("permalinks (RFC-0038)", () => { ]) expect(entryAt(site, entryPath(site, x))).toEqual(x); }); + + it("still answers the old one-argument call of themes copied before 0.3.11", () => { + expect(entryPath(e("posts", "hello"))).toBe("/posts/hello"); + expect([e("posts", "a"), e("news", "b")].map(entryPath)).toEqual(["/posts/a", "/news/b"]); + }); }); From b36f88ad09adfcb1febb0e551ef97b7d00a626ae Mon Sep 17 00:00:00 2001 From: Madraka <8898640+Madraka@users.noreply.github.com> Date: Thu, 22 Oct 2026 16:41:16 +0300 Subject: [PATCH 2/2] test(cloudflare): anchor the comments job's clock on the real time The 30-day deleted-entry rule measures from the deletion snapshot, which the store stamps with the real clock, while the test's `now` was a fixed T0 + 40 days. Once the calendar reached 2026-10-22 the gap was no longer 30 days and the test failed on main too. `now` is now 40 days after the later of T0 and the real time. Co-Authored-By: Claude Opus 5.5 Signed-off-by: Madraka <8898640+Madraka@users.noreply.github.com> --- packages/cloudflare/test/comments.test.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/cloudflare/test/comments.test.ts b/packages/cloudflare/test/comments.test.ts index c0859a1b..64f56557 100644 --- a/packages/cloudflare/test/comments.test.ts +++ b/packages/cloudflare/test/comments.test.ts @@ -241,8 +241,9 @@ describe("the hourly comments job (§8.5, §9.3)", () => { T0.toISOString(), ]); - // the snapshots carry the real time: 40 days after T0 the deletion is due - const now = new Date(T0.getTime() + 40 * 86_400_000); + // the snapshots carry the real time, so the deletion is due 40 days after the later of T0 and + // now (a fixed T0 alone stopped being 30 days past the snapshot once the calendar caught up) + const now = new Date(Math.max(T0.getTime(), Date.now()) + 40 * 86_400_000); const r = await runCommentsHourly({ graph, store, now }); expect(r.sites).toBe(1); expect(await store.get(siteId, old)).toBeNull();