Merged
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
41 changes: 41 additions & 0 deletions .changeset/docs-meta-index-detaches-folder-index.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
---
"@objectstack/docs": patch
---

fix(docs): stop listing `"index"` in `meta.json` `pages` — it detaches the folder index and shortens 164 breadcrumb trails (#12352)

Fumadocs attaches a folder's `index.mdx` as that folder's tree `index` node
**only when the folder's `meta.json` does not list it** in `pages`. Listing it
makes the page an ordinary child instead, and the folder node reaches every tree
consumer with a `name` and no `url` — `loader-*.js`, `buildFolder()`:

```js
if (indexPath) {
if (excludedPaths.has(indexPath)) delete node.index; // "index" was listed
else excludedPaths.add(indexPath);
}
```

Two surfaces read that one node, and both were degraded:

- **Breadcrumb.** `getBreadcrumbItems()` links a folder crumb to `item.index?.url`,
so an un-linkable ancestor is dropped rather than emitted name-only (Google
requires `item` on every `BreadcrumbList` entry but the last). 172 of 404 doc
pages advertised a two-level site structure they do not have.
- **Sidebar.** `node.index ? SidebarFolderLink : SidebarFolderTrigger` — the
section header was inert text, and the section's own overview page sat below it
as a child, in six cases under a label identical to the header's.

`"index"` is removed from 16 of the 17 `meta.json` files that listed it. It was
the first `pages` entry in 15 of them and the first entry after the
`---Start Here---` separator in `getting-started`, so no other entry's position
depends on it: the measured tree delta is exactly 16 folder headers going
`TRIGGER` → `LINK` and 16 index children leaving the child list, with every
removed child's URL now the header's `href` and no other line moved.

Short trails: **172 → 8**. The remaining 8 are `content/docs/releases/`, which
this PR does not touch — that directory is fenced by AGENTS.md, and its
`meta.json` still lists `"index"`.

No consumer-side change: `app/[lang]/docs/[[...slug]]/page.tsx` reconstructs no
URLs, deliberately, so a producer defect of this shape stays visible.
30 changes: 14 additions & 16 deletions apps/docs/app/[lang]/docs/[[...slug]]/page.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,23 +39,21 @@ type DocPage = NonNullable<ReturnType<typeof source.getPage>>;
* `index` node. ⛔ Nothing here splits `page.url` on `/`, and nothing constructs a
* URL the loader has not already produced.
*
* ⚠️ **An ancestor arrives without a URL more often than not, and this drops it.**
* Measured against a local production build, not inferred: fumadocs attaches a
* folder's `index.mdx` as that folder's `index` node only when the folder's
* `meta.json` does **not** list `"index"` in `pages`. 17 of the 35 `meta.json`
* files under `content/docs` do list it, so their folder nodes carry a
* `name` and no `url`, and 172 of 403 doc pages therefore ship a trail that skips
* its section. Confirmed causally by deleting that one line from
* `content/docs/data-modeling/meta.json` and rebuilding: the section crumb
* appeared, linked, while an untouched control section stayed short.
* ⚠️ **An ancestor can arrive without a URL, and this drops it.** Fumadocs
* attaches a folder's `index.mdx` as that folder's `index` node only when the
* folder's `meta.json` does **not** list `"index"` in `pages`; a folder that
* lists it reaches this walk with a `name` and no `url`. That was once 17 of the
* 35 `meta.json` files under `content/docs`, shortening 172 of 404 trails. 16 of
* the 17 were fixed producer-side (#12352) and 8 short trails remain, all under
* `content/docs/releases/` — a directory AGENTS.md fences off, so its `meta.json`
* still lists `"index"`. The condition is therefore live, just rare.
*
* ⛔ The missing URL is deliberately **not** reconstructed here. The folder's index
* page exists, is in the sitemap and answers 200 — the defect is in the content
* config that hides it from the tree, not in this consumer, and a lookup that
* re-derived it would make a producer bug invisible and permanent. Google requires
* `item` on every crumb but the last, so a name-only crumb is not an option
* either. Filed separately; when it lands, these trails complete with no change to
* this file.
* ⛔ The missing URL is deliberately **not** reconstructed here — that fence is
* the reason #12352 was fixable at all. The folder's index page exists, is in the
* sitemap and answers 200 — the defect is in the content config that hides it
* from the tree, not in this consumer, and a lookup that re-derived it would make
* a producer bug invisible and permanent. Google requires `item` on every crumb
* but the last, so a name-only crumb is not an option either.
*
* Two things the tree cannot supply are added around it, both from data this
* page already holds:
Expand Down
1 change: 0 additions & 1 deletion content/docs/ai/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "AI",
"pages": [
"index",
"connect-mcp",
"agents",
"actions-as-tools",
Expand Down
1 change: 0 additions & 1 deletion content/docs/api/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "API & SDK",
"pages": [
"index",
"data-api",
"metadata-api",
"plugin-endpoints",
Expand Down
1 change: 0 additions & 1 deletion content/docs/automation/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Automation",
"pages": [
"index",
"hooks",
"hook-bodies",
"flows",
Expand Down
1 change: 0 additions & 1 deletion content/docs/capabilities/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "What Can It Do?",
"pages": [
"index",
"data",
"views",
"forms",
Expand Down
1 change: 0 additions & 1 deletion content/docs/concepts/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Core Concepts",
"pages": [
"index",
"architecture",
"metadata-driven",
"metadata-lifecycle",
Expand Down
1 change: 0 additions & 1 deletion content/docs/data-modeling/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Data Modeling",
"pages": [
"index",
"schema-design",
"objects",
"fields",
Expand Down
1 change: 0 additions & 1 deletion content/docs/deployment/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Deployment & Operations",
"pages": [
"index",
"self-hosting",
"production-readiness",
"backup-restore",
Expand Down
1 change: 0 additions & 1 deletion content/docs/getting-started/meta.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,7 +2,6 @@
"title": "Get Started",
"pages": [
"---Start Here---",
"index",
"how-ai-development-works",
"build-with-claude-code",
"your-first-project",
Expand Down
2 changes: 1 addition & 1 deletion content/docs/kernel/contracts/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
{
"title": "Service Contracts",
"pages": ["index", "metadata-service", "auth-service", "storage-service", "data-engine", "cache-service"]
"pages": ["metadata-service", "auth-service", "storage-service", "data-engine", "cache-service"]
}
1 change: 0 additions & 1 deletion content/docs/kernel/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Kernel & Services",
"pages": [
"index",
"architecture",
"events",
"services",
Expand Down
1 change: 0 additions & 1 deletion content/docs/kernel/runtime-services/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Runtime Services",
"pages": [
"index",
"data-service",
"sharing-service",
"audit-service",
Expand Down
1 change: 0 additions & 1 deletion content/docs/permissions/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Permissions & Identity",
"pages": [
"index",
"administrator-guide",
"authentication",
"sso",
Expand Down
1 change: 0 additions & 1 deletion content/docs/plugins/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Plugins & Packages",
"pages": [
"index",
"anatomy",
"development",
"packages",
Expand Down
1 change: 0 additions & 1 deletion content/docs/protocol/kernel/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "System Protocol",
"pages": [
"index",
"lifecycle",
"http-protocol",
"realtime-protocol",
Expand Down
1 change: 0 additions & 1 deletion content/docs/protocol/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Protocol Spec",
"pages": [
"index",
"diagram",
"objectql",
"objectui",
Expand Down
1 change: 0 additions & 1 deletion content/docs/ui/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Views & Apps",
"pages": [
"index",
"apps",
"pages",
"react-pages",
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
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
41 changes: 41 additions & 0 deletions .changeset/docs-meta-index-detaches-folder-index.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
---
"@objectstack/docs": patch
---

fix(docs): stop listing `"index"` in `meta.json` `pages` — it detaches the folder index and shortens 164 breadcrumb trails (#12352)

Fumadocs attaches a folder's `index.mdx` as that folder's tree `index` node
**only when the folder's `meta.json` does not list it** in `pages`. Listing it
makes the page an ordinary child instead, and the folder node reaches every tree
consumer with a `name` and no `url` — `loader-*.js`, `buildFolder()`:

```js
if (indexPath) {
if (excludedPaths.has(indexPath)) delete node.index; // "index" was listed
else excludedPaths.add(indexPath);
}
```

Two surfaces read that one node, and both were degraded:

- **Breadcrumb.** `getBreadcrumbItems()` links a folder crumb to `item.index?.url`,
so an un-linkable ancestor is dropped rather than emitted name-only (Google
requires `item` on every `BreadcrumbList` entry but the last). 172 of 404 doc
pages advertised a two-level site structure they do not have.
- **Sidebar.** `node.index ? SidebarFolderLink : SidebarFolderTrigger` — the
section header was inert text, and the section's own overview page sat below it
as a child, in six cases under a label identical to the header's.

`"index"` is removed from 16 of the 17 `meta.json` files that listed it. It was
the first `pages` entry in 15 of them and the first entry after the
`---Start Here---` separator in `getting-started`, so no other entry's position
depends on it: the measured tree delta is exactly 16 folder headers going
`TRIGGER` → `LINK` and 16 index children leaving the child list, with every
removed child's URL now the header's `href` and no other line moved.

Short trails: **172 → 8**. The remaining 8 are `content/docs/releases/`, which
this PR does not touch — that directory is fenced by AGENTS.md, and its
`meta.json` still lists `"index"`.

No consumer-side change: `app/[lang]/docs/[[...slug]]/page.tsx` reconstructs no
URLs, deliberately, so a producer defect of this shape stays visible.
30 changes: 14 additions & 16 deletions apps/docs/app/[lang]/docs/[[...slug]]/page.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,23 +39,21 @@ type DocPage = NonNullable<ReturnType<typeof source.getPage>>;
* `index` node. ⛔ Nothing here splits `page.url` on `/`, and nothing constructs a
* URL the loader has not already produced.
*
* ⚠️ **An ancestor arrives without a URL more often than not, and this drops it.**
* Measured against a local production build, not inferred: fumadocs attaches a
* folder's `index.mdx` as that folder's `index` node only when the folder's
* `meta.json` does **not** list `"index"` in `pages`. 17 of the 35 `meta.json`
* files under `content/docs` do list it, so their folder nodes carry a
* `name` and no `url`, and 172 of 403 doc pages therefore ship a trail that skips
* its section. Confirmed causally by deleting that one line from
* `content/docs/data-modeling/meta.json` and rebuilding: the section crumb
* appeared, linked, while an untouched control section stayed short.
* ⚠️ **An ancestor can arrive without a URL, and this drops it.** Fumadocs
* attaches a folder's `index.mdx` as that folder's `index` node only when the
* folder's `meta.json` does **not** list `"index"` in `pages`; a folder that
* lists it reaches this walk with a `name` and no `url`. That was once 17 of the
* 35 `meta.json` files under `content/docs`, shortening 172 of 404 trails. 16 of
* the 17 were fixed producer-side (#12352) and 8 short trails remain, all under
* `content/docs/releases/` — a directory AGENTS.md fences off, so its `meta.json`
* still lists `"index"`. The condition is therefore live, just rare.
*
* ⛔ The missing URL is deliberately **not** reconstructed here. The folder's index
* page exists, is in the sitemap and answers 200 — the defect is in the content
* config that hides it from the tree, not in this consumer, and a lookup that
* re-derived it would make a producer bug invisible and permanent. Google requires
* `item` on every crumb but the last, so a name-only crumb is not an option
* either. Filed separately; when it lands, these trails complete with no change to
* this file.
* ⛔ The missing URL is deliberately **not** reconstructed here — that fence is
* the reason #12352 was fixable at all. The folder's index page exists, is in the
* sitemap and answers 200 — the defect is in the content config that hides it
* from the tree, not in this consumer, and a lookup that re-derived it would make
* a producer bug invisible and permanent. Google requires `item` on every crumb
* but the last, so a name-only crumb is not an option either.
*
* Two things the tree cannot supply are added around it, both from data this
* page already holds:
Expand Down
1 change: 0 additions & 1 deletion content/docs/ai/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "AI",
"pages": [
"index",
"connect-mcp",
"agents",
"actions-as-tools",
Expand Down
1 change: 0 additions & 1 deletion content/docs/api/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "API & SDK",
"pages": [
"index",
"data-api",
"metadata-api",
"plugin-endpoints",
Expand Down
1 change: 0 additions & 1 deletion content/docs/automation/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Automation",
"pages": [
"index",
"hooks",
"hook-bodies",
"flows",
Expand Down
1 change: 0 additions & 1 deletion content/docs/capabilities/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "What Can It Do?",
"pages": [
"index",
"data",
"views",
"forms",
Expand Down
1 change: 0 additions & 1 deletion content/docs/concepts/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Core Concepts",
"pages": [
"index",
"architecture",
"metadata-driven",
"metadata-lifecycle",
Expand Down
1 change: 0 additions & 1 deletion content/docs/data-modeling/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Data Modeling",
"pages": [
"index",
"schema-design",
"objects",
"fields",
Expand Down
1 change: 0 additions & 1 deletion content/docs/deployment/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Deployment & Operations",
"pages": [
"index",
"self-hosting",
"production-readiness",
"backup-restore",
Expand Down
1 change: 0 additions & 1 deletion content/docs/getting-started/meta.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,7 +2,6 @@
"title": "Get Started",
"pages": [
"---Start Here---",
"index",
"how-ai-development-works",
"build-with-claude-code",
"your-first-project",
Expand Down
2 changes: 1 addition & 1 deletion content/docs/kernel/contracts/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
{
"title": "Service Contracts",
"pages": ["index", "metadata-service", "auth-service", "storage-service", "data-engine", "cache-service"]
"pages": ["metadata-service", "auth-service", "storage-service", "data-engine", "cache-service"]
}
1 change: 0 additions & 1 deletion content/docs/kernel/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Kernel & Services",
"pages": [
"index",
"architecture",
"events",
"services",
Expand Down
1 change: 0 additions & 1 deletion content/docs/kernel/runtime-services/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Runtime Services",
"pages": [
"index",
"data-service",
"sharing-service",
"audit-service",
Expand Down
1 change: 0 additions & 1 deletion content/docs/permissions/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Permissions & Identity",
"pages": [
"index",
"administrator-guide",
"authentication",
"sso",
Expand Down
1 change: 0 additions & 1 deletion content/docs/plugins/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Plugins & Packages",
"pages": [
"index",
"anatomy",
"development",
"packages",
Expand Down
1 change: 0 additions & 1 deletion content/docs/protocol/kernel/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "System Protocol",
"pages": [
"index",
"lifecycle",
"http-protocol",
"realtime-protocol",
Expand Down
1 change: 0 additions & 1 deletion content/docs/protocol/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Protocol Spec",
"pages": [
"index",
"diagram",
"objectql",
"objectui",
Expand Down
1 change: 0 additions & 1 deletion content/docs/ui/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Views & Apps",
"pages": [
"index",
"apps",
"pages",
"react-pages",
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
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
41 changes: 41 additions & 0 deletions .changeset/docs-meta-index-detaches-folder-index.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
---
"@objectstack/docs": patch
---

fix(docs): stop listing `"index"` in `meta.json` `pages` — it detaches the folder index and shortens 164 breadcrumb trails (#12352)

Fumadocs attaches a folder's `index.mdx` as that folder's tree `index` node
**only when the folder's `meta.json` does not list it** in `pages`. Listing it
makes the page an ordinary child instead, and the folder node reaches every tree
consumer with a `name` and no `url` — `loader-*.js`, `buildFolder()`:

```js
if (indexPath) {
if (excludedPaths.has(indexPath)) delete node.index; // "index" was listed
else excludedPaths.add(indexPath);
}
```

Two surfaces read that one node, and both were degraded:

- **Breadcrumb.** `getBreadcrumbItems()` links a folder crumb to `item.index?.url`,
so an un-linkable ancestor is dropped rather than emitted name-only (Google
requires `item` on every `BreadcrumbList` entry but the last). 172 of 404 doc
pages advertised a two-level site structure they do not have.
- **Sidebar.** `node.index ? SidebarFolderLink : SidebarFolderTrigger` — the
section header was inert text, and the section's own overview page sat below it
as a child, in six cases under a label identical to the header's.

`"index"` is removed from 16 of the 17 `meta.json` files that listed it. It was
the first `pages` entry in 15 of them and the first entry after the
`---Start Here---` separator in `getting-started`, so no other entry's position
depends on it: the measured tree delta is exactly 16 folder headers going
`TRIGGER` → `LINK` and 16 index children leaving the child list, with every
removed child's URL now the header's `href` and no other line moved.

Short trails: **172 → 8**. The remaining 8 are `content/docs/releases/`, which
this PR does not touch — that directory is fenced by AGENTS.md, and its
`meta.json` still lists `"index"`.

No consumer-side change: `app/[lang]/docs/[[...slug]]/page.tsx` reconstructs no
URLs, deliberately, so a producer defect of this shape stays visible.
30 changes: 14 additions & 16 deletions apps/docs/app/[lang]/docs/[[...slug]]/page.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,23 +39,21 @@ type DocPage = NonNullable<ReturnType<typeof source.getPage>>;
* `index` node. ⛔ Nothing here splits `page.url` on `/`, and nothing constructs a
* URL the loader has not already produced.
*
* ⚠️ **An ancestor arrives without a URL more often than not, and this drops it.**
* Measured against a local production build, not inferred: fumadocs attaches a
* folder's `index.mdx` as that folder's `index` node only when the folder's
* `meta.json` does **not** list `"index"` in `pages`. 17 of the 35 `meta.json`
* files under `content/docs` do list it, so their folder nodes carry a
* `name` and no `url`, and 172 of 403 doc pages therefore ship a trail that skips
* its section. Confirmed causally by deleting that one line from
* `content/docs/data-modeling/meta.json` and rebuilding: the section crumb
* appeared, linked, while an untouched control section stayed short.
* ⚠️ **An ancestor can arrive without a URL, and this drops it.** Fumadocs
* attaches a folder's `index.mdx` as that folder's `index` node only when the
* folder's `meta.json` does **not** list `"index"` in `pages`; a folder that
* lists it reaches this walk with a `name` and no `url`. That was once 17 of the
* 35 `meta.json` files under `content/docs`, shortening 172 of 404 trails. 16 of
* the 17 were fixed producer-side (#12352) and 8 short trails remain, all under
* `content/docs/releases/` — a directory AGENTS.md fences off, so its `meta.json`
* still lists `"index"`. The condition is therefore live, just rare.
*
* ⛔ The missing URL is deliberately **not** reconstructed here. The folder's index
* page exists, is in the sitemap and answers 200 — the defect is in the content
* config that hides it from the tree, not in this consumer, and a lookup that
* re-derived it would make a producer bug invisible and permanent. Google requires
* `item` on every crumb but the last, so a name-only crumb is not an option
* either. Filed separately; when it lands, these trails complete with no change to
* this file.
* ⛔ The missing URL is deliberately **not** reconstructed here — that fence is
* the reason #12352 was fixable at all. The folder's index page exists, is in the
* sitemap and answers 200 — the defect is in the content config that hides it
* from the tree, not in this consumer, and a lookup that re-derived it would make
* a producer bug invisible and permanent. Google requires `item` on every crumb
* but the last, so a name-only crumb is not an option either.
*
* Two things the tree cannot supply are added around it, both from data this
* page already holds:
Expand Down
1 change: 0 additions & 1 deletion content/docs/ai/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "AI",
"pages": [
"index",
"connect-mcp",
"agents",
"actions-as-tools",
Expand Down
1 change: 0 additions & 1 deletion content/docs/api/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "API & SDK",
"pages": [
"index",
"data-api",
"metadata-api",
"plugin-endpoints",
Expand Down
1 change: 0 additions & 1 deletion content/docs/automation/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Automation",
"pages": [
"index",
"hooks",
"hook-bodies",
"flows",
Expand Down
1 change: 0 additions & 1 deletion content/docs/capabilities/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "What Can It Do?",
"pages": [
"index",
"data",
"views",
"forms",
Expand Down
1 change: 0 additions & 1 deletion content/docs/concepts/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Core Concepts",
"pages": [
"index",
"architecture",
"metadata-driven",
"metadata-lifecycle",
Expand Down
1 change: 0 additions & 1 deletion content/docs/data-modeling/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Data Modeling",
"pages": [
"index",
"schema-design",
"objects",
"fields",
Expand Down
1 change: 0 additions & 1 deletion content/docs/deployment/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Deployment & Operations",
"pages": [
"index",
"self-hosting",
"production-readiness",
"backup-restore",
Expand Down
1 change: 0 additions & 1 deletion content/docs/getting-started/meta.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,7 +2,6 @@
"title": "Get Started",
"pages": [
"---Start Here---",
"index",
"how-ai-development-works",
"build-with-claude-code",
"your-first-project",
Expand Down
2 changes: 1 addition & 1 deletion content/docs/kernel/contracts/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
{
"title": "Service Contracts",
"pages": ["index", "metadata-service", "auth-service", "storage-service", "data-engine", "cache-service"]
"pages": ["metadata-service", "auth-service", "storage-service", "data-engine", "cache-service"]
}
1 change: 0 additions & 1 deletion content/docs/kernel/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Kernel & Services",
"pages": [
"index",
"architecture",
"events",
"services",
Expand Down
1 change: 0 additions & 1 deletion content/docs/kernel/runtime-services/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Runtime Services",
"pages": [
"index",
"data-service",
"sharing-service",
"audit-service",
Expand Down
1 change: 0 additions & 1 deletion content/docs/permissions/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Permissions & Identity",
"pages": [
"index",
"administrator-guide",
"authentication",
"sso",
Expand Down
1 change: 0 additions & 1 deletion content/docs/plugins/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Plugins & Packages",
"pages": [
"index",
"anatomy",
"development",
"packages",
Expand Down
1 change: 0 additions & 1 deletion content/docs/protocol/kernel/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "System Protocol",
"pages": [
"index",
"lifecycle",
"http-protocol",
"realtime-protocol",
Expand Down
1 change: 0 additions & 1 deletion content/docs/protocol/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Protocol Spec",
"pages": [
"index",
"diagram",
"objectql",
"objectui",
Expand Down
1 change: 0 additions & 1 deletion content/docs/ui/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Views & Apps",
"pages": [
"index",
"apps",
"pages",
"react-pages",
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
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
41 changes: 41 additions & 0 deletions .changeset/docs-meta-index-detaches-folder-index.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
---
"@objectstack/docs": patch
---

fix(docs): stop listing `"index"` in `meta.json` `pages` — it detaches the folder index and shortens 164 breadcrumb trails (#12352)

Fumadocs attaches a folder's `index.mdx` as that folder's tree `index` node
**only when the folder's `meta.json` does not list it** in `pages`. Listing it
makes the page an ordinary child instead, and the folder node reaches every tree
consumer with a `name` and no `url` — `loader-*.js`, `buildFolder()`:

```js
if (indexPath) {
if (excludedPaths.has(indexPath)) delete node.index; // "index" was listed
else excludedPaths.add(indexPath);
}
```

Two surfaces read that one node, and both were degraded:

- **Breadcrumb.** `getBreadcrumbItems()` links a folder crumb to `item.index?.url`,
so an un-linkable ancestor is dropped rather than emitted name-only (Google
requires `item` on every `BreadcrumbList` entry but the last). 172 of 404 doc
pages advertised a two-level site structure they do not have.
- **Sidebar.** `node.index ? SidebarFolderLink : SidebarFolderTrigger` — the
section header was inert text, and the section's own overview page sat below it
as a child, in six cases under a label identical to the header's.

`"index"` is removed from 16 of the 17 `meta.json` files that listed it. It was
the first `pages` entry in 15 of them and the first entry after the
`---Start Here---` separator in `getting-started`, so no other entry's position
depends on it: the measured tree delta is exactly 16 folder headers going
`TRIGGER` → `LINK` and 16 index children leaving the child list, with every
removed child's URL now the header's `href` and no other line moved.

Short trails: **172 → 8**. The remaining 8 are `content/docs/releases/`, which
this PR does not touch — that directory is fenced by AGENTS.md, and its
`meta.json` still lists `"index"`.

No consumer-side change: `app/[lang]/docs/[[...slug]]/page.tsx` reconstructs no
URLs, deliberately, so a producer defect of this shape stays visible.
30 changes: 14 additions & 16 deletions apps/docs/app/[lang]/docs/[[...slug]]/page.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,23 +39,21 @@ type DocPage = NonNullable<ReturnType<typeof source.getPage>>;
* `index` node. ⛔ Nothing here splits `page.url` on `/`, and nothing constructs a
* URL the loader has not already produced.
*
* ⚠️ **An ancestor arrives without a URL more often than not, and this drops it.**
* Measured against a local production build, not inferred: fumadocs attaches a
* folder's `index.mdx` as that folder's `index` node only when the folder's
* `meta.json` does **not** list `"index"` in `pages`. 17 of the 35 `meta.json`
* files under `content/docs` do list it, so their folder nodes carry a
* `name` and no `url`, and 172 of 403 doc pages therefore ship a trail that skips
* its section. Confirmed causally by deleting that one line from
* `content/docs/data-modeling/meta.json` and rebuilding: the section crumb
* appeared, linked, while an untouched control section stayed short.
* ⚠️ **An ancestor can arrive without a URL, and this drops it.** Fumadocs
* attaches a folder's `index.mdx` as that folder's `index` node only when the
* folder's `meta.json` does **not** list `"index"` in `pages`; a folder that
* lists it reaches this walk with a `name` and no `url`. That was once 17 of the
* 35 `meta.json` files under `content/docs`, shortening 172 of 404 trails. 16 of
* the 17 were fixed producer-side (#12352) and 8 short trails remain, all under
* `content/docs/releases/` — a directory AGENTS.md fences off, so its `meta.json`
* still lists `"index"`. The condition is therefore live, just rare.
*
* ⛔ The missing URL is deliberately **not** reconstructed here. The folder's index
* page exists, is in the sitemap and answers 200 — the defect is in the content
* config that hides it from the tree, not in this consumer, and a lookup that
* re-derived it would make a producer bug invisible and permanent. Google requires
* `item` on every crumb but the last, so a name-only crumb is not an option
* either. Filed separately; when it lands, these trails complete with no change to
* this file.
* ⛔ The missing URL is deliberately **not** reconstructed here — that fence is
* the reason #12352 was fixable at all. The folder's index page exists, is in the
* sitemap and answers 200 — the defect is in the content config that hides it
* from the tree, not in this consumer, and a lookup that re-derived it would make
* a producer bug invisible and permanent. Google requires `item` on every crumb
* but the last, so a name-only crumb is not an option either.
*
* Two things the tree cannot supply are added around it, both from data this
* page already holds:
Expand Down
1 change: 0 additions & 1 deletion content/docs/ai/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "AI",
"pages": [
"index",
"connect-mcp",
"agents",
"actions-as-tools",
Expand Down
1 change: 0 additions & 1 deletion content/docs/api/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "API & SDK",
"pages": [
"index",
"data-api",
"metadata-api",
"plugin-endpoints",
Expand Down
1 change: 0 additions & 1 deletion content/docs/automation/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Automation",
"pages": [
"index",
"hooks",
"hook-bodies",
"flows",
Expand Down
1 change: 0 additions & 1 deletion content/docs/capabilities/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "What Can It Do?",
"pages": [
"index",
"data",
"views",
"forms",
Expand Down
1 change: 0 additions & 1 deletion content/docs/concepts/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Core Concepts",
"pages": [
"index",
"architecture",
"metadata-driven",
"metadata-lifecycle",
Expand Down
1 change: 0 additions & 1 deletion content/docs/data-modeling/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Data Modeling",
"pages": [
"index",
"schema-design",
"objects",
"fields",
Expand Down
1 change: 0 additions & 1 deletion content/docs/deployment/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Deployment & Operations",
"pages": [
"index",
"self-hosting",
"production-readiness",
"backup-restore",
Expand Down
1 change: 0 additions & 1 deletion content/docs/getting-started/meta.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,7 +2,6 @@
"title": "Get Started",
"pages": [
"---Start Here---",
"index",
"how-ai-development-works",
"build-with-claude-code",
"your-first-project",
Expand Down
2 changes: 1 addition & 1 deletion content/docs/kernel/contracts/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
{
"title": "Service Contracts",
"pages": ["index", "metadata-service", "auth-service", "storage-service", "data-engine", "cache-service"]
"pages": ["metadata-service", "auth-service", "storage-service", "data-engine", "cache-service"]
}
1 change: 0 additions & 1 deletion content/docs/kernel/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Kernel & Services",
"pages": [
"index",
"architecture",
"events",
"services",
Expand Down
1 change: 0 additions & 1 deletion content/docs/kernel/runtime-services/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Runtime Services",
"pages": [
"index",
"data-service",
"sharing-service",
"audit-service",
Expand Down
1 change: 0 additions & 1 deletion content/docs/permissions/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Permissions & Identity",
"pages": [
"index",
"administrator-guide",
"authentication",
"sso",
Expand Down
1 change: 0 additions & 1 deletion content/docs/plugins/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Plugins & Packages",
"pages": [
"index",
"anatomy",
"development",
"packages",
Expand Down
1 change: 0 additions & 1 deletion content/docs/protocol/kernel/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "System Protocol",
"pages": [
"index",
"lifecycle",
"http-protocol",
"realtime-protocol",
Expand Down
1 change: 0 additions & 1 deletion content/docs/protocol/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Protocol Spec",
"pages": [
"index",
"diagram",
"objectql",
"objectui",
Expand Down
1 change: 0 additions & 1 deletion content/docs/ui/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Views & Apps",
"pages": [
"index",
"apps",
"pages",
"react-pages",
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
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
41 changes: 41 additions & 0 deletions .changeset/docs-meta-index-detaches-folder-index.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
---
"@objectstack/docs": patch
---

fix(docs): stop listing `"index"` in `meta.json` `pages` — it detaches the folder index and shortens 164 breadcrumb trails (#12352)

Fumadocs attaches a folder's `index.mdx` as that folder's tree `index` node
**only when the folder's `meta.json` does not list it** in `pages`. Listing it
makes the page an ordinary child instead, and the folder node reaches every tree
consumer with a `name` and no `url` — `loader-*.js`, `buildFolder()`:

```js
if (indexPath) {
if (excludedPaths.has(indexPath)) delete node.index; // "index" was listed
else excludedPaths.add(indexPath);
}
```

Two surfaces read that one node, and both were degraded:

- **Breadcrumb.** `getBreadcrumbItems()` links a folder crumb to `item.index?.url`,
so an un-linkable ancestor is dropped rather than emitted name-only (Google
requires `item` on every `BreadcrumbList` entry but the last). 172 of 404 doc
pages advertised a two-level site structure they do not have.
- **Sidebar.** `node.index ? SidebarFolderLink : SidebarFolderTrigger` — the
section header was inert text, and the section's own overview page sat below it
as a child, in six cases under a label identical to the header's.

`"index"` is removed from 16 of the 17 `meta.json` files that listed it. It was
the first `pages` entry in 15 of them and the first entry after the
`---Start Here---` separator in `getting-started`, so no other entry's position
depends on it: the measured tree delta is exactly 16 folder headers going
`TRIGGER` → `LINK` and 16 index children leaving the child list, with every
removed child's URL now the header's `href` and no other line moved.

Short trails: **172 → 8**. The remaining 8 are `content/docs/releases/`, which
this PR does not touch — that directory is fenced by AGENTS.md, and its
`meta.json` still lists `"index"`.

No consumer-side change: `app/[lang]/docs/[[...slug]]/page.tsx` reconstructs no
URLs, deliberately, so a producer defect of this shape stays visible.
30 changes: 14 additions & 16 deletions apps/docs/app/[lang]/docs/[[...slug]]/page.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,23 +39,21 @@ type DocPage = NonNullable<ReturnType<typeof source.getPage>>;
* `index` node. ⛔ Nothing here splits `page.url` on `/`, and nothing constructs a
* URL the loader has not already produced.
*
* ⚠️ **An ancestor arrives without a URL more often than not, and this drops it.**
* Measured against a local production build, not inferred: fumadocs attaches a
* folder's `index.mdx` as that folder's `index` node only when the folder's
* `meta.json` does **not** list `"index"` in `pages`. 17 of the 35 `meta.json`
* files under `content/docs` do list it, so their folder nodes carry a
* `name` and no `url`, and 172 of 403 doc pages therefore ship a trail that skips
* its section. Confirmed causally by deleting that one line from
* `content/docs/data-modeling/meta.json` and rebuilding: the section crumb
* appeared, linked, while an untouched control section stayed short.
* ⚠️ **An ancestor can arrive without a URL, and this drops it.** Fumadocs
* attaches a folder's `index.mdx` as that folder's `index` node only when the
* folder's `meta.json` does **not** list `"index"` in `pages`; a folder that
* lists it reaches this walk with a `name` and no `url`. That was once 17 of the
* 35 `meta.json` files under `content/docs`, shortening 172 of 404 trails. 16 of
* the 17 were fixed producer-side (#12352) and 8 short trails remain, all under
* `content/docs/releases/` — a directory AGENTS.md fences off, so its `meta.json`
* still lists `"index"`. The condition is therefore live, just rare.
*
* ⛔ The missing URL is deliberately **not** reconstructed here. The folder's index
* page exists, is in the sitemap and answers 200 — the defect is in the content
* config that hides it from the tree, not in this consumer, and a lookup that
* re-derived it would make a producer bug invisible and permanent. Google requires
* `item` on every crumb but the last, so a name-only crumb is not an option
* either. Filed separately; when it lands, these trails complete with no change to
* this file.
* ⛔ The missing URL is deliberately **not** reconstructed here — that fence is
* the reason #12352 was fixable at all. The folder's index page exists, is in the
* sitemap and answers 200 — the defect is in the content config that hides it
* from the tree, not in this consumer, and a lookup that re-derived it would make
* a producer bug invisible and permanent. Google requires `item` on every crumb
* but the last, so a name-only crumb is not an option either.
*
* Two things the tree cannot supply are added around it, both from data this
* page already holds:
Expand Down
1 change: 0 additions & 1 deletion content/docs/ai/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "AI",
"pages": [
"index",
"connect-mcp",
"agents",
"actions-as-tools",
Expand Down
1 change: 0 additions & 1 deletion content/docs/api/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "API & SDK",
"pages": [
"index",
"data-api",
"metadata-api",
"plugin-endpoints",
Expand Down
1 change: 0 additions & 1 deletion content/docs/automation/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Automation",
"pages": [
"index",
"hooks",
"hook-bodies",
"flows",
Expand Down
1 change: 0 additions & 1 deletion content/docs/capabilities/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "What Can It Do?",
"pages": [
"index",
"data",
"views",
"forms",
Expand Down
1 change: 0 additions & 1 deletion content/docs/concepts/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Core Concepts",
"pages": [
"index",
"architecture",
"metadata-driven",
"metadata-lifecycle",
Expand Down
1 change: 0 additions & 1 deletion content/docs/data-modeling/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Data Modeling",
"pages": [
"index",
"schema-design",
"objects",
"fields",
Expand Down
1 change: 0 additions & 1 deletion content/docs/deployment/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Deployment & Operations",
"pages": [
"index",
"self-hosting",
"production-readiness",
"backup-restore",
Expand Down
1 change: 0 additions & 1 deletion content/docs/getting-started/meta.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,7 +2,6 @@
"title": "Get Started",
"pages": [
"---Start Here---",
"index",
"how-ai-development-works",
"build-with-claude-code",
"your-first-project",
Expand Down
2 changes: 1 addition & 1 deletion content/docs/kernel/contracts/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
{
"title": "Service Contracts",
"pages": ["index", "metadata-service", "auth-service", "storage-service", "data-engine", "cache-service"]
"pages": ["metadata-service", "auth-service", "storage-service", "data-engine", "cache-service"]
}
1 change: 0 additions & 1 deletion content/docs/kernel/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Kernel & Services",
"pages": [
"index",
"architecture",
"events",
"services",
Expand Down
1 change: 0 additions & 1 deletion content/docs/kernel/runtime-services/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Runtime Services",
"pages": [
"index",
"data-service",
"sharing-service",
"audit-service",
Expand Down
1 change: 0 additions & 1 deletion content/docs/permissions/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Permissions & Identity",
"pages": [
"index",
"administrator-guide",
"authentication",
"sso",
Expand Down
1 change: 0 additions & 1 deletion content/docs/plugins/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Plugins & Packages",
"pages": [
"index",
"anatomy",
"development",
"packages",
Expand Down
1 change: 0 additions & 1 deletion content/docs/protocol/kernel/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "System Protocol",
"pages": [
"index",
"lifecycle",
"http-protocol",
"realtime-protocol",
Expand Down
1 change: 0 additions & 1 deletion content/docs/protocol/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Protocol Spec",
"pages": [
"index",
"diagram",
"objectql",
"objectui",
Expand Down
1 change: 0 additions & 1 deletion content/docs/ui/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Views & Apps",
"pages": [
"index",
"apps",
"pages",
"react-pages",
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
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
41 changes: 41 additions & 0 deletions .changeset/docs-meta-index-detaches-folder-index.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
---
"@objectstack/docs": patch
---

fix(docs): stop listing `"index"` in `meta.json` `pages` — it detaches the folder index and shortens 164 breadcrumb trails (#12352)

Fumadocs attaches a folder's `index.mdx` as that folder's tree `index` node
**only when the folder's `meta.json` does not list it** in `pages`. Listing it
makes the page an ordinary child instead, and the folder node reaches every tree
consumer with a `name` and no `url` — `loader-*.js`, `buildFolder()`:

```js
if (indexPath) {
if (excludedPaths.has(indexPath)) delete node.index; // "index" was listed
else excludedPaths.add(indexPath);
}
```

Two surfaces read that one node, and both were degraded:

- **Breadcrumb.** `getBreadcrumbItems()` links a folder crumb to `item.index?.url`,
so an un-linkable ancestor is dropped rather than emitted name-only (Google
requires `item` on every `BreadcrumbList` entry but the last). 172 of 404 doc
pages advertised a two-level site structure they do not have.
- **Sidebar.** `node.index ? SidebarFolderLink : SidebarFolderTrigger` — the
section header was inert text, and the section's own overview page sat below it
as a child, in six cases under a label identical to the header's.

`"index"` is removed from 16 of the 17 `meta.json` files that listed it. It was
the first `pages` entry in 15 of them and the first entry after the
`---Start Here---` separator in `getting-started`, so no other entry's position
depends on it: the measured tree delta is exactly 16 folder headers going
`TRIGGER` → `LINK` and 16 index children leaving the child list, with every
removed child's URL now the header's `href` and no other line moved.

Short trails: **172 → 8**. The remaining 8 are `content/docs/releases/`, which
this PR does not touch — that directory is fenced by AGENTS.md, and its
`meta.json` still lists `"index"`.

No consumer-side change: `app/[lang]/docs/[[...slug]]/page.tsx` reconstructs no
URLs, deliberately, so a producer defect of this shape stays visible.
30 changes: 14 additions & 16 deletions apps/docs/app/[lang]/docs/[[...slug]]/page.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,23 +39,21 @@ type DocPage = NonNullable<ReturnType<typeof source.getPage>>;
* `index` node. ⛔ Nothing here splits `page.url` on `/`, and nothing constructs a
* URL the loader has not already produced.
*
* ⚠️ **An ancestor arrives without a URL more often than not, and this drops it.**
* Measured against a local production build, not inferred: fumadocs attaches a
* folder's `index.mdx` as that folder's `index` node only when the folder's
* `meta.json` does **not** list `"index"` in `pages`. 17 of the 35 `meta.json`
* files under `content/docs` do list it, so their folder nodes carry a
* `name` and no `url`, and 172 of 403 doc pages therefore ship a trail that skips
* its section. Confirmed causally by deleting that one line from
* `content/docs/data-modeling/meta.json` and rebuilding: the section crumb
* appeared, linked, while an untouched control section stayed short.
* ⚠️ **An ancestor can arrive without a URL, and this drops it.** Fumadocs
* attaches a folder's `index.mdx` as that folder's `index` node only when the
* folder's `meta.json` does **not** list `"index"` in `pages`; a folder that
* lists it reaches this walk with a `name` and no `url`. That was once 17 of the
* 35 `meta.json` files under `content/docs`, shortening 172 of 404 trails. 16 of
* the 17 were fixed producer-side (#12352) and 8 short trails remain, all under
* `content/docs/releases/` — a directory AGENTS.md fences off, so its `meta.json`
* still lists `"index"`. The condition is therefore live, just rare.
*
* ⛔ The missing URL is deliberately **not** reconstructed here. The folder's index
* page exists, is in the sitemap and answers 200 — the defect is in the content
* config that hides it from the tree, not in this consumer, and a lookup that
* re-derived it would make a producer bug invisible and permanent. Google requires
* `item` on every crumb but the last, so a name-only crumb is not an option
* either. Filed separately; when it lands, these trails complete with no change to
* this file.
* ⛔ The missing URL is deliberately **not** reconstructed here — that fence is
* the reason #12352 was fixable at all. The folder's index page exists, is in the
* sitemap and answers 200 — the defect is in the content config that hides it
* from the tree, not in this consumer, and a lookup that re-derived it would make
* a producer bug invisible and permanent. Google requires `item` on every crumb
* but the last, so a name-only crumb is not an option either.
*
* Two things the tree cannot supply are added around it, both from data this
* page already holds:
Expand Down
1 change: 0 additions & 1 deletion content/docs/ai/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "AI",
"pages": [
"index",
"connect-mcp",
"agents",
"actions-as-tools",
Expand Down
1 change: 0 additions & 1 deletion content/docs/api/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "API & SDK",
"pages": [
"index",
"data-api",
"metadata-api",
"plugin-endpoints",
Expand Down
1 change: 0 additions & 1 deletion content/docs/automation/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Automation",
"pages": [
"index",
"hooks",
"hook-bodies",
"flows",
Expand Down
1 change: 0 additions & 1 deletion content/docs/capabilities/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "What Can It Do?",
"pages": [
"index",
"data",
"views",
"forms",
Expand Down
1 change: 0 additions & 1 deletion content/docs/concepts/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Core Concepts",
"pages": [
"index",
"architecture",
"metadata-driven",
"metadata-lifecycle",
Expand Down
1 change: 0 additions & 1 deletion content/docs/data-modeling/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Data Modeling",
"pages": [
"index",
"schema-design",
"objects",
"fields",
Expand Down
1 change: 0 additions & 1 deletion content/docs/deployment/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Deployment & Operations",
"pages": [
"index",
"self-hosting",
"production-readiness",
"backup-restore",
Expand Down
1 change: 0 additions & 1 deletion content/docs/getting-started/meta.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,7 +2,6 @@
"title": "Get Started",
"pages": [
"---Start Here---",
"index",
"how-ai-development-works",
"build-with-claude-code",
"your-first-project",
Expand Down
2 changes: 1 addition & 1 deletion content/docs/kernel/contracts/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
{
"title": "Service Contracts",
"pages": ["index", "metadata-service", "auth-service", "storage-service", "data-engine", "cache-service"]
"pages": ["metadata-service", "auth-service", "storage-service", "data-engine", "cache-service"]
}
1 change: 0 additions & 1 deletion content/docs/kernel/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Kernel & Services",
"pages": [
"index",
"architecture",
"events",
"services",
Expand Down
1 change: 0 additions & 1 deletion content/docs/kernel/runtime-services/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Runtime Services",
"pages": [
"index",
"data-service",
"sharing-service",
"audit-service",
Expand Down
1 change: 0 additions & 1 deletion content/docs/permissions/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Permissions & Identity",
"pages": [
"index",
"administrator-guide",
"authentication",
"sso",
Expand Down
1 change: 0 additions & 1 deletion content/docs/plugins/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Plugins & Packages",
"pages": [
"index",
"anatomy",
"development",
"packages",
Expand Down
1 change: 0 additions & 1 deletion content/docs/protocol/kernel/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "System Protocol",
"pages": [
"index",
"lifecycle",
"http-protocol",
"realtime-protocol",
Expand Down
1 change: 0 additions & 1 deletion content/docs/protocol/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Protocol Spec",
"pages": [
"index",
"diagram",
"objectql",
"objectui",
Expand Down
1 change: 0 additions & 1 deletion content/docs/ui/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Views & Apps",
"pages": [
"index",
"apps",
"pages",
"react-pages",
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
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
41 changes: 41 additions & 0 deletions .changeset/docs-meta-index-detaches-folder-index.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
---
"@objectstack/docs": patch
---

fix(docs): stop listing `"index"` in `meta.json` `pages` — it detaches the folder index and shortens 164 breadcrumb trails (#12352)

Fumadocs attaches a folder's `index.mdx` as that folder's tree `index` node
**only when the folder's `meta.json` does not list it** in `pages`. Listing it
makes the page an ordinary child instead, and the folder node reaches every tree
consumer with a `name` and no `url` — `loader-*.js`, `buildFolder()`:

```js
if (indexPath) {
if (excludedPaths.has(indexPath)) delete node.index; // "index" was listed
else excludedPaths.add(indexPath);
}
```

Two surfaces read that one node, and both were degraded:

- **Breadcrumb.** `getBreadcrumbItems()` links a folder crumb to `item.index?.url`,
so an un-linkable ancestor is dropped rather than emitted name-only (Google
requires `item` on every `BreadcrumbList` entry but the last). 172 of 404 doc
pages advertised a two-level site structure they do not have.
- **Sidebar.** `node.index ? SidebarFolderLink : SidebarFolderTrigger` — the
section header was inert text, and the section's own overview page sat below it
as a child, in six cases under a label identical to the header's.

`"index"` is removed from 16 of the 17 `meta.json` files that listed it. It was
the first `pages` entry in 15 of them and the first entry after the
`---Start Here---` separator in `getting-started`, so no other entry's position
depends on it: the measured tree delta is exactly 16 folder headers going
`TRIGGER` → `LINK` and 16 index children leaving the child list, with every
removed child's URL now the header's `href` and no other line moved.

Short trails: **172 → 8**. The remaining 8 are `content/docs/releases/`, which
this PR does not touch — that directory is fenced by AGENTS.md, and its
`meta.json` still lists `"index"`.

No consumer-side change: `app/[lang]/docs/[[...slug]]/page.tsx` reconstructs no
URLs, deliberately, so a producer defect of this shape stays visible.
30 changes: 14 additions & 16 deletions apps/docs/app/[lang]/docs/[[...slug]]/page.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,23 +39,21 @@ type DocPage = NonNullable<ReturnType<typeof source.getPage>>;
* `index` node. ⛔ Nothing here splits `page.url` on `/`, and nothing constructs a
* URL the loader has not already produced.
*
* ⚠️ **An ancestor arrives without a URL more often than not, and this drops it.**
* Measured against a local production build, not inferred: fumadocs attaches a
* folder's `index.mdx` as that folder's `index` node only when the folder's
* `meta.json` does **not** list `"index"` in `pages`. 17 of the 35 `meta.json`
* files under `content/docs` do list it, so their folder nodes carry a
* `name` and no `url`, and 172 of 403 doc pages therefore ship a trail that skips
* its section. Confirmed causally by deleting that one line from
* `content/docs/data-modeling/meta.json` and rebuilding: the section crumb
* appeared, linked, while an untouched control section stayed short.
* ⚠️ **An ancestor can arrive without a URL, and this drops it.** Fumadocs
* attaches a folder's `index.mdx` as that folder's `index` node only when the
* folder's `meta.json` does **not** list `"index"` in `pages`; a folder that
* lists it reaches this walk with a `name` and no `url`. That was once 17 of the
* 35 `meta.json` files under `content/docs`, shortening 172 of 404 trails. 16 of
* the 17 were fixed producer-side (#12352) and 8 short trails remain, all under
* `content/docs/releases/` — a directory AGENTS.md fences off, so its `meta.json`
* still lists `"index"`. The condition is therefore live, just rare.
*
* ⛔ The missing URL is deliberately **not** reconstructed here. The folder's index
* page exists, is in the sitemap and answers 200 — the defect is in the content
* config that hides it from the tree, not in this consumer, and a lookup that
* re-derived it would make a producer bug invisible and permanent. Google requires
* `item` on every crumb but the last, so a name-only crumb is not an option
* either. Filed separately; when it lands, these trails complete with no change to
* this file.
* ⛔ The missing URL is deliberately **not** reconstructed here — that fence is
* the reason #12352 was fixable at all. The folder's index page exists, is in the
* sitemap and answers 200 — the defect is in the content config that hides it
* from the tree, not in this consumer, and a lookup that re-derived it would make
* a producer bug invisible and permanent. Google requires `item` on every crumb
* but the last, so a name-only crumb is not an option either.
*
* Two things the tree cannot supply are added around it, both from data this
* page already holds:
Expand Down
1 change: 0 additions & 1 deletion content/docs/ai/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "AI",
"pages": [
"index",
"connect-mcp",
"agents",
"actions-as-tools",
Expand Down
1 change: 0 additions & 1 deletion content/docs/api/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "API & SDK",
"pages": [
"index",
"data-api",
"metadata-api",
"plugin-endpoints",
Expand Down
1 change: 0 additions & 1 deletion content/docs/automation/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Automation",
"pages": [
"index",
"hooks",
"hook-bodies",
"flows",
Expand Down
1 change: 0 additions & 1 deletion content/docs/capabilities/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "What Can It Do?",
"pages": [
"index",
"data",
"views",
"forms",
Expand Down
1 change: 0 additions & 1 deletion content/docs/concepts/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Core Concepts",
"pages": [
"index",
"architecture",
"metadata-driven",
"metadata-lifecycle",
Expand Down
1 change: 0 additions & 1 deletion content/docs/data-modeling/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Data Modeling",
"pages": [
"index",
"schema-design",
"objects",
"fields",
Expand Down
1 change: 0 additions & 1 deletion content/docs/deployment/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Deployment & Operations",
"pages": [
"index",
"self-hosting",
"production-readiness",
"backup-restore",
Expand Down
1 change: 0 additions & 1 deletion content/docs/getting-started/meta.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,7 +2,6 @@
"title": "Get Started",
"pages": [
"---Start Here---",
"index",
"how-ai-development-works",
"build-with-claude-code",
"your-first-project",
Expand Down
2 changes: 1 addition & 1 deletion content/docs/kernel/contracts/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
{
"title": "Service Contracts",
"pages": ["index", "metadata-service", "auth-service", "storage-service", "data-engine", "cache-service"]
"pages": ["metadata-service", "auth-service", "storage-service", "data-engine", "cache-service"]
}
1 change: 0 additions & 1 deletion content/docs/kernel/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Kernel & Services",
"pages": [
"index",
"architecture",
"events",
"services",
Expand Down
1 change: 0 additions & 1 deletion content/docs/kernel/runtime-services/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Runtime Services",
"pages": [
"index",
"data-service",
"sharing-service",
"audit-service",
Expand Down
1 change: 0 additions & 1 deletion content/docs/permissions/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Permissions & Identity",
"pages": [
"index",
"administrator-guide",
"authentication",
"sso",
Expand Down
1 change: 0 additions & 1 deletion content/docs/plugins/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Plugins & Packages",
"pages": [
"index",
"anatomy",
"development",
"packages",
Expand Down
1 change: 0 additions & 1 deletion content/docs/protocol/kernel/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "System Protocol",
"pages": [
"index",
"lifecycle",
"http-protocol",
"realtime-protocol",
Expand Down
1 change: 0 additions & 1 deletion content/docs/protocol/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Protocol Spec",
"pages": [
"index",
"diagram",
"objectql",
"objectui",
Expand Down
1 change: 0 additions & 1 deletion content/docs/ui/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Views & Apps",
"pages": [
"index",
"apps",
"pages",
"react-pages",
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
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
41 changes: 41 additions & 0 deletions .changeset/docs-meta-index-detaches-folder-index.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
---
"@objectstack/docs": patch
---

fix(docs): stop listing `"index"` in `meta.json` `pages` — it detaches the folder index and shortens 164 breadcrumb trails (#12352)

Fumadocs attaches a folder's `index.mdx` as that folder's tree `index` node
**only when the folder's `meta.json` does not list it** in `pages`. Listing it
makes the page an ordinary child instead, and the folder node reaches every tree
consumer with a `name` and no `url` — `loader-*.js`, `buildFolder()`:

```js
if (indexPath) {
if (excludedPaths.has(indexPath)) delete node.index; // "index" was listed
else excludedPaths.add(indexPath);
}
```

Two surfaces read that one node, and both were degraded:

- **Breadcrumb.** `getBreadcrumbItems()` links a folder crumb to `item.index?.url`,
so an un-linkable ancestor is dropped rather than emitted name-only (Google
requires `item` on every `BreadcrumbList` entry but the last). 172 of 404 doc
pages advertised a two-level site structure they do not have.
- **Sidebar.** `node.index ? SidebarFolderLink : SidebarFolderTrigger` — the
section header was inert text, and the section's own overview page sat below it
as a child, in six cases under a label identical to the header's.

`"index"` is removed from 16 of the 17 `meta.json` files that listed it. It was
the first `pages` entry in 15 of them and the first entry after the
`---Start Here---` separator in `getting-started`, so no other entry's position
depends on it: the measured tree delta is exactly 16 folder headers going
`TRIGGER` → `LINK` and 16 index children leaving the child list, with every
removed child's URL now the header's `href` and no other line moved.

Short trails: **172 → 8**. The remaining 8 are `content/docs/releases/`, which
this PR does not touch — that directory is fenced by AGENTS.md, and its
`meta.json` still lists `"index"`.

No consumer-side change: `app/[lang]/docs/[[...slug]]/page.tsx` reconstructs no
URLs, deliberately, so a producer defect of this shape stays visible.
30 changes: 14 additions & 16 deletions apps/docs/app/[lang]/docs/[[...slug]]/page.tsx
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,23 +39,21 @@ type DocPage = NonNullable<ReturnType<typeof source.getPage>>;
* `index` node. ⛔ Nothing here splits `page.url` on `/`, and nothing constructs a
* URL the loader has not already produced.
*
* ⚠️ **An ancestor arrives without a URL more often than not, and this drops it.**
* Measured against a local production build, not inferred: fumadocs attaches a
* folder's `index.mdx` as that folder's `index` node only when the folder's
* `meta.json` does **not** list `"index"` in `pages`. 17 of the 35 `meta.json`
* files under `content/docs` do list it, so their folder nodes carry a
* `name` and no `url`, and 172 of 403 doc pages therefore ship a trail that skips
* its section. Confirmed causally by deleting that one line from
* `content/docs/data-modeling/meta.json` and rebuilding: the section crumb
* appeared, linked, while an untouched control section stayed short.
* ⚠️ **An ancestor can arrive without a URL, and this drops it.** Fumadocs
* attaches a folder's `index.mdx` as that folder's `index` node only when the
* folder's `meta.json` does **not** list `"index"` in `pages`; a folder that
* lists it reaches this walk with a `name` and no `url`. That was once 17 of the
* 35 `meta.json` files under `content/docs`, shortening 172 of 404 trails. 16 of
* the 17 were fixed producer-side (#12352) and 8 short trails remain, all under
* `content/docs/releases/` — a directory AGENTS.md fences off, so its `meta.json`
* still lists `"index"`. The condition is therefore live, just rare.
*
* ⛔ The missing URL is deliberately **not** reconstructed here. The folder's index
* page exists, is in the sitemap and answers 200 — the defect is in the content
* config that hides it from the tree, not in this consumer, and a lookup that
* re-derived it would make a producer bug invisible and permanent. Google requires
* `item` on every crumb but the last, so a name-only crumb is not an option
* either. Filed separately; when it lands, these trails complete with no change to
* this file.
* ⛔ The missing URL is deliberately **not** reconstructed here — that fence is
* the reason #12352 was fixable at all. The folder's index page exists, is in the
* sitemap and answers 200 — the defect is in the content config that hides it
* from the tree, not in this consumer, and a lookup that re-derived it would make
* a producer bug invisible and permanent. Google requires `item` on every crumb
* but the last, so a name-only crumb is not an option either.
*
* Two things the tree cannot supply are added around it, both from data this
* page already holds:
Expand Down
1 change: 0 additions & 1 deletion content/docs/ai/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "AI",
"pages": [
"index",
"connect-mcp",
"agents",
"actions-as-tools",
Expand Down
1 change: 0 additions & 1 deletion content/docs/api/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "API & SDK",
"pages": [
"index",
"data-api",
"metadata-api",
"plugin-endpoints",
Expand Down
1 change: 0 additions & 1 deletion content/docs/automation/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Automation",
"pages": [
"index",
"hooks",
"hook-bodies",
"flows",
Expand Down
1 change: 0 additions & 1 deletion content/docs/capabilities/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "What Can It Do?",
"pages": [
"index",
"data",
"views",
"forms",
Expand Down
1 change: 0 additions & 1 deletion content/docs/concepts/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Core Concepts",
"pages": [
"index",
"architecture",
"metadata-driven",
"metadata-lifecycle",
Expand Down
1 change: 0 additions & 1 deletion content/docs/data-modeling/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Data Modeling",
"pages": [
"index",
"schema-design",
"objects",
"fields",
Expand Down
1 change: 0 additions & 1 deletion content/docs/deployment/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Deployment & Operations",
"pages": [
"index",
"self-hosting",
"production-readiness",
"backup-restore",
Expand Down
1 change: 0 additions & 1 deletion content/docs/getting-started/meta.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,7 +2,6 @@
"title": "Get Started",
"pages": [
"---Start Here---",
"index",
"how-ai-development-works",
"build-with-claude-code",
"your-first-project",
Expand Down
2 changes: 1 addition & 1 deletion content/docs/kernel/contracts/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
{
"title": "Service Contracts",
"pages": ["index", "metadata-service", "auth-service", "storage-service", "data-engine", "cache-service"]
"pages": ["metadata-service", "auth-service", "storage-service", "data-engine", "cache-service"]
}
1 change: 0 additions & 1 deletion content/docs/kernel/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Kernel & Services",
"pages": [
"index",
"architecture",
"events",
"services",
Expand Down
1 change: 0 additions & 1 deletion content/docs/kernel/runtime-services/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Runtime Services",
"pages": [
"index",
"data-service",
"sharing-service",
"audit-service",
Expand Down
1 change: 0 additions & 1 deletion content/docs/permissions/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Permissions & Identity",
"pages": [
"index",
"administrator-guide",
"authentication",
"sso",
Expand Down
1 change: 0 additions & 1 deletion content/docs/plugins/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Plugins & Packages",
"pages": [
"index",
"anatomy",
"development",
"packages",
Expand Down
1 change: 0 additions & 1 deletion content/docs/protocol/kernel/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "System Protocol",
"pages": [
"index",
"lifecycle",
"http-protocol",
"realtime-protocol",
Expand Down
1 change: 0 additions & 1 deletion content/docs/protocol/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Protocol Spec",
"pages": [
"index",
"diagram",
"objectql",
"objectui",
Expand Down
1 change: 0 additions & 1 deletion content/docs/ui/meta.json
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
{
"title": "Views & Apps",
"pages": [
"index",
"apps",
"pages",
"react-pages",
Expand Down
Loading