Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/honest-published-paths.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cloudflare/nimbus-docs": patch
---

Harden registry resolution and diagnostics, follow local imported Nimbus configs during checks, reject stale route manifests, report partial Cloudflare server setup, and preserve authored API union titles.
5 changes: 5 additions & 0 deletions .changeset/safe-empty-scaffolds.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cloudflare/create-nimbus-docs": patch
---

Support transactional scaffolding into an empty current directory and refresh generated project guidance and Nimbus build-output ignores.
11 changes: 0 additions & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
name: CI

# Red/green signal on every PR: typecheck (whole workspace) + test + audit.
on:
pull_request:
branches: [main]
push:
branches: [main]

# Default-deny; each job opts back into the minimum it needs.
permissions: {}

concurrency:
Expand All @@ -32,7 +30,6 @@ jobs:

- run: pnpm install --frozen-lockfile

# Root script builds nimbus-docs, then runs `pnpm -r typecheck`.
- run: pnpm typecheck

test:
Expand Down Expand Up @@ -94,9 +91,6 @@ jobs:

- run: pnpm --filter @nimbus/www generate-registry

# Registry payloads must import the scoped package. A bare
# `grep 'from "nimbus-docs'` false-passes because the JSON escapes the
# quote — match the escaped form / parse `.files[].content`.
- name: Assert no unscoped nimbus-docs imports
run: |
hits=$(grep -rl 'from \\"nimbus-docs' apps/www/public/registry/components || true)
Expand All @@ -121,13 +115,8 @@ jobs:
node-version: 24
cache: pnpm

# `pnpm audit` needs the resolved tree to populate advisory paths; without
# an install it returns advisories with empty `paths` and the fail-closed
# shape guard rejects the run.
- run: pnpm install --frozen-lockfile

# Fail closed: a non-JSON or unsupported audit response means this gate
# cannot classify published-package risk reliably.
- name: Audit published package prod deps
run: pnpm audit:published-prod

Expand Down
33 changes: 2 additions & 31 deletions .github/workflows/templates.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ on:
- "packages/create-nimbus-docs/**"
- "packages/nimbus-docs/**"
- "scripts/templates-check.mjs"
- "package.json"
- ".github/workflows/templates.yml"
pull_request:
branches: [main]
Expand All @@ -19,6 +20,7 @@ on:
- "packages/create-nimbus-docs/**"
- "packages/nimbus-docs/**"
- "scripts/templates-check.mjs"
- "package.json"
- ".github/workflows/templates.yml"

permissions:
Expand Down Expand Up @@ -47,34 +49,3 @@ jobs:
env:
TEMPLATES_CHECK_LANE: ${{ matrix.lane }}
run: node scripts/templates-check.mjs

# Scaffold + install a variant under pnpm@latest, so a build-scripts gate
# regression fails a PR instead of a user. The monorepo's pin to pnpm 9
# predates the gate, so the pnpm-9 checks above can't catch it.
templates-modern-pnpm:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
lane: [static, cloudflare]
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

- uses: pnpm/action-setup@f40ffcd9367d9f12939873eb1018b921a783ffaa # v4

- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: 24
cache: pnpm

- run: pnpm install --frozen-lockfile

- name: Enable corepack (for pnpm@latest)
run: corepack enable

- name: Scaffold + install + build a template under pnpm@latest
env:
SCAFFOLD_PNPM: pnpm@latest
TEMPLATES_CHECK_LANE: ${{ matrix.lane }}
COREPACK_ENABLE_DOWNLOAD_PROMPT: "0"
run: node scripts/templates-check.mjs
12 changes: 0 additions & 12 deletions .npmrc

This file was deleted.

2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Before you open a PR:

### Local development

Requires **Node ≥ 22.12.0** and **pnpm 9** (pinned via `packageManager`, so Corepack fetches it for you).
Requires **Node ≥ 22.12.0** and **pnpm 11**, pinned via `packageManager`. On Node 22–24, enable Corepack; on Node 25+, install Corepack or pnpm separately.

```sh
pnpm install
Expand Down
79 changes: 75 additions & 4 deletions apps/www/registry/features/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ Print a short, exact plan to the user **before** writing anything:
so `src/content.config.ts` can derive the collection from the same list — no
second spec declaration.
- Create `src/pages/api/[...slug].astro` and `src/pages/api/[...slug]/index.md.ts`.
- Add desktop product navigation to `src/components/Header.astro`; keep it out of
mobile navigation for now so the existing sidebar button remains the only
mobile menu.
- Resulting URLs: `/api` (overview), `/api/<slug>` (each page), the matching
`/api/<slug>/index.md` twins, and `/api/llms.txt`.

Expand Down Expand Up @@ -150,8 +153,9 @@ import nimbusConfig from "./nimbus.config";
`spec` is the path from Q1, resolved from the project root (not the current
working directory — builds from a monorepo root or `--root` resolve correctly).
`spec` may also be an inline OpenAPI object. Add a `label` for a friendlier name
in build diagnostics; it defaults to the collection name. To mount more than one
spec, add more entries to the array and explicitly register each one in 4c.
in navigation and build diagnostics; it defaults to the collection name. To
mount more than one spec, add more entries to the array and explicitly register
each one in 4c.

> **Why the `/config` entry?** `@cloudflare/nimbus-docs/config` exports only the
> identity `defineConfig` with no side effects, so a `nimbus.config.ts` imported
Expand Down Expand Up @@ -238,7 +242,9 @@ export async function GET({ props }: { props: SlugProps }) {
const { item } = props;
const { title, description, markdownUrl, sourceUrl, version } = item;

const markdown = await renderIndexedEntryMarkdown(item);
const markdown = await renderIndexedEntryMarkdown(item, {
base: import.meta.env.BASE_URL,
});

const body = [
"---",
Expand Down Expand Up @@ -312,10 +318,11 @@ const result = await getApiRoute(Astro);
if (result instanceof Response) return result;
const { page, nav, collection, version, coordinate } = result;
const socialImage = `/og${page.href.replace(/\/$/, "")}.png`;
const title = page.kind === "api" ? page.title : `${page.title} · API`;
---

<BaseLayout
title={`${page.title} · API`}
{title}
description={page.description}
markdownUrl={page.markdownHref}
socialImage={socialImage}
Expand All @@ -332,6 +339,68 @@ The nav is handled by `ApiSidebar` inside `ApiLayout` — there's no separate
`ApiNavList` to write. To customise the tree's look (icons, grouping, a
collapse-all affordance), edit `src/components/ui/api-sidebar/`; the active/
expanded flags and verb come pre-resolved on each `ApiNavItem`.

### 4f. Add desktop product navigation

The default starter is prose-only and deliberately carries no product-navigation
logic. Since this site now has a second product surface, update its user-owned
`src/components/Header.astro` to render Docs and configured API families as a
separate `Product` nav. Do not merge these links into prose `Sections`.

Import the framework mechanism alongside `getSidebarSections`:

<!-- api-reference-fixture:src/components/Header.astro#import -->
```ts
import {
getProductSections,
getSidebarSections,
} from "@cloudflare/nimbus-docs/runtime";
```

After the existing `sections` derivation, derive the product links. Preserve the
Header's explicit `sections` override as a complete automatic-navigation bypass:

<!-- api-reference-fixture:src/components/Header.astro#setup -->
```ts
const productSections =
sectionsProp === undefined
? await getProductSections(currentSlug, {
collection,
base: import.meta.env.BASE_URL,
})
: [];
const showProductSections = productSections.length >= 2;
```

Inside the Header's left-hand group, after the brand and before the prose
`Sections` nav, render:

<!-- api-reference-fixture:src/components/Header.astro#markup -->
```astro
{showProductSections && (
<nav aria-label="Product" class="hidden md:flex items-center gap-0.5 border-l border-border pl-3">
{productSections.map((section) => (
<a
href={section.href}
aria-current={section.isActive ? "page" : undefined}
class:list={[
"px-2 py-1 rounded-md text-[0.8125rem] font-medium no-underline transition-colors shrink-0 whitespace-nowrap",
section.isActive
? "text-foreground bg-accent"
: "text-muted-foreground hover:text-foreground hover:bg-accent/60",
]}
>
{section.label}
</a>
))}
</nav>
)}
```

Keep this nav desktop-only. Do not add another mobile trigger; the existing
sidebar hamburger remains the sole mobile menu until product switching has a
single consolidated mobile design.

## 5. Optional — add to the sidebar

Sidebar layout is taste-laden; ask before editing. If the user wants an "API"
Expand All @@ -354,6 +423,8 @@ After writing all files, run the user's build command and confirm:
4. `dist/api/llms.txt` lists every API page, and the root `dist/llms.txt`
includes `api` as a top-level section.
5. `dist/llms-full.txt` (if the site emits a corpus) embeds the API markdown.
6. The desktop Header shows separate Docs and API product links; both are hidden
on mobile, where only the existing sidebar hamburger remains.

Then tell the user the URLs to visit: `/api`, `/api/<slug>`,
`/api/<slug>/index.md`, `/api/llms.txt`.
Expand Down
2 changes: 1 addition & 1 deletion apps/www/registry/features/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -977,7 +977,7 @@ export async function GET({ props }: { props: SlugProps }) {
const socialImage =
typeof rawImage === "string" && rawImage.length > 0 ? rawImage : config.socialImage;

const markdown = renderEntryAsMarkdown(entry);
const markdown = renderEntryAsMarkdown(entry, { base: import.meta.env.BASE_URL });

const body = [
"---",
Expand Down
2 changes: 1 addition & 1 deletion apps/www/registry/features/new-collection.md
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ export async function GET({ props }: { props: SlugProps }) {
? rawImage
: config.socialImage;

const markdown = renderEntryAsMarkdown(entry);
const markdown = renderEntryAsMarkdown(entry, { base: import.meta.env.BASE_URL });

const body = [
"---",
Expand Down
2 changes: 1 addition & 1 deletion apps/www/registry/features/new-version.md
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ export async function GET({ props }: { props: SlugProps }) {
? rawImage
: config.socialImage;

const markdown = renderEntryAsMarkdown(entry);
const markdown = renderEntryAsMarkdown(entry, { base: import.meta.env.BASE_URL });

const body = [
"---",
Expand Down
3 changes: 1 addition & 2 deletions apps/www/src/components/ui/search/providers/pagefind.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,7 @@ const defaultFilters: PagefindFilters | undefined =
export const provider: SearchProvider = {
async init() {
if (pagefind) return;
const baseUrl = new URL(import.meta.env.BASE_URL ?? "/", window.location.origin);
const pagefindUrl = new URL("pagefind/pagefind.js", baseUrl);
const pagefindUrl = new URL(withBase("/pagefind/pagefind.js"), window.location.origin);
pagefind = (await import(/* @vite-ignore */ pagefindUrl.href)) as PagefindApi;
await pagefind.init();
},
Expand Down
2 changes: 1 addition & 1 deletion apps/www/src/pages/[...slug]/index.md.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export async function GET({ props }: { props: SlugProps }) {
? rawImage
: config.socialImage;

const markdown = renderEntryAsMarkdown(entry);
const markdown = renderEntryAsMarkdown(entry, { base: import.meta.env.BASE_URL });

const body = [
"---",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "0.0.0",
"private": true,
"type": "module",
"packageManager": "pnpm@9.0.0",
"packageManager": "pnpm@11.25.0",
"scripts": {
"build": "pnpm -r build",
"test": "pnpm -r test",
Expand Down
Loading
Loading