From 41b563677b28f4a474b92f9e71cbc56e300dff69 Mon Sep 17 00:00:00 2001 From: Jeffrey Aven Date: Mon, 5 Oct 2026 18:40:26 +1100 Subject: [PATCH 1/5] menu update and new query --- CLAUDE.md | 13 ++- docusaurus.config.js | 93 ++++++++++++------- .../github/activity/repo-stargazers.md | 74 +++++++++++++++ query-library/scripts/build-artifacts.py | 58 +++++++----- query-library/scripts/precommit-artifacts.py | 26 ++++-- sidebars-query-library.js | 2 +- src/pages/{tutorials.js => blog/product.js} | 6 +- .../{stackqldocs.js => blog/providers.js} | 6 +- src/pages/blog/tutorials.js | 9 ++ .../embedded.js => command-line-usage/mcp.js} | 6 +- src/pages/docs/command-line-usage/mcp.js | 9 -- src/pages/docs/index.js | 12 ++- src/pages/installing-stackql.js | 9 ++ src/pages/{install.js => mcp/embedded.js} | 6 +- src/pages/{blog.js => mcp/index.js} | 6 +- .../{databricks.js => databricks-account.js} | 6 +- .../{docs/mcp/index.js => quick-starts.js} | 6 +- static/docs/query-library/index.json | 39 +++++++- static/docs/query-library/index.md | 3 +- static/docs/query-library/manifest.json | 8 +- static/docs/query-library/providers.json | 2 +- .../github/activity/repo-stargazers.json | 66 +++++++++++++ .../github/activity/repo-stargazers.md | 74 +++++++++++++++ 23 files changed, 430 insertions(+), 109 deletions(-) create mode 100644 query-library/queries/github/activity/repo-stargazers.md rename src/pages/{tutorials.js => blog/product.js} (68%) rename src/pages/{stackqldocs.js => blog/providers.js} (67%) create mode 100644 src/pages/blog/tutorials.js rename src/pages/{docs/mcp/embedded.js => command-line-usage/mcp.js} (62%) delete mode 100644 src/pages/docs/command-line-usage/mcp.js create mode 100644 src/pages/installing-stackql.js rename src/pages/{install.js => mcp/embedded.js} (65%) rename src/pages/{blog.js => mcp/index.js} (67%) rename src/pages/providers/{databricks.js => databricks-account.js} (74%) rename src/pages/{docs/mcp/index.js => quick-starts.js} (65%) create mode 100644 static/docs/query-library/queries/github/activity/repo-stargazers.json create mode 100644 static/docs/query-library/queries/github/activity/repo-stargazers.md diff --git a/CLAUDE.md b/CLAUDE.md index a2c624a3..f359e1c5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -144,10 +144,15 @@ external `href` links - each has a redirect stub page under `src/pages/` mounting [src/components/ExternalRedirect](src/components/ExternalRedirect/index.jsx), which gives the link a real internal route (no external-link icon, passes the broken-link checker, works on localhost and on the raw subdomain) and -instantly forwards to the real page on stackql.io. The stub route list, the -navbar/footer `to` values (`mainSitePaths` in docusaurus.config.js) and the -stub files must stay in lockstep with each other and with the main repo's -navbar/footer. Stub routes are noindexed, excluded from the sitemap and +instantly forwards to the real page on stackql.io. Stub paths equal the main +site's canonical paths (its docs are served at the site root, so `/mcp`, not +`/docs/mcp`); the one exception is the main docs root, `stackql.io/`, which +is the `/docs` stub here because `/` is the library landing. The stub route +list, the navbar/footer `to` values (`mainSitePaths` in docusaurus.config.js) +and the stub files must stay in lockstep with each other and with the main +repo's navbar/footer (its `navbar.items`, `footerStackQLItems`, +`footerMoreItems`, `blogSections` and the `featured` entries of its +`src/configs/providers.json`, which drive the Providers dropdown). Stub routes are noindexed, excluded from the sitemap and from structured-data JSON-LD. The footer is the swizzled main-site footer (`src/theme/Footer`, needs `@iconify/react`, `@mui/material`, `clsx`); `src/css/global.css` is the full main-site stylesheet for visual parity. diff --git a/docusaurus.config.js b/docusaurus.config.js index 88eb796f..31bbd16f 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -14,61 +14,93 @@ const nightOwlCodeTheme = themes.nightOwl; // library pages read as one site. Every main-site destination has a stub // page under src/pages/ (rendering src/components/ExternalRedirect) so the // links are internal routes here - no external-link icon, and the -// broken-link checker validates them. The `to` values below are -// baseUrl-relative; keep them in lockstep with the stub files and with the -// main repo's navbar/footer config. +// broken-link checker validates them. Stub paths equal the main site's own +// canonical paths (the docs tree there is served at the site root, so +// e.g. /mcp not /docs/mcp). The one exception is the docs root itself, +// stackql.io/: '/' here is the library landing, so that destination is the +// /docs stub, which forwards straight to the root. The `to` values below +// are baseUrl-relative; keep them in lockstep with the stub files and with +// the main repo's chrome config (docusaurus.config.js there: navbar.items, +// footerStackQLItems, footerMoreItems, blogSections, and the `featured` +// entries of src/configs/providers.json for the Providers dropdown). const mainSitePaths = [ - '/install', - '/stackql-deploy', - '/contact-us', - '/stackqldocs', - '/blog', - '/tutorials', '/docs', - '/docs/command-line-usage/mcp', - '/docs/mcp', - '/docs/mcp/embedded', + '/installing-stackql', + '/contact-us', + '/stackql-deploy', + '/command-line-usage/mcp', + '/mcp', + '/mcp/embedded', + '/quick-starts', + '/blog/product', + '/blog/providers', + '/blog/tutorials', '/providers', '/providers/aws', '/providers/azure', '/providers/google', - '/providers/databricks', + '/providers/cloudflare', + '/providers/databricks-account', '/providers/snowflake', '/providers/confluent', '/providers/okta', - '/providers/github', '/providers/openai', - '/providers/cloudflare', + '/providers/github', ]; // Full public route paths of the stubs (baseUrl + path): kept out of the // sitemap and of structured-data JSON-LD emission below. const redirectStubRoutes = mainSitePaths.map((p) => `/docs/query-library${p}`); +// The main site's Providers dropdown lists the `featured` entries of its +// provider catalog in catalog order, labelled by shortName. Databricks' +// canonical slug there is databricks-account (the family-level +// /providers/databricks route was retired and now 301s to /registry). const providerDropDownListItems = [ {label: 'AWS', to: '/providers/aws'}, {label: 'Azure', to: '/providers/azure'}, {label: 'Google', to: '/providers/google'}, - {label: 'Databricks', to: '/providers/databricks'}, + {label: 'Cloudflare', to: '/providers/cloudflare'}, + {label: 'Databricks', to: '/providers/databricks-account'}, {label: 'Snowflake', to: '/providers/snowflake'}, {label: 'Confluent', to: '/providers/confluent'}, {label: 'Okta', to: '/providers/okta'}, - {label: 'GitHub', to: '/providers/github'}, {label: 'OpenAI', to: '/providers/openai'}, - {label: 'Cloudflare', to: '/providers/cloudflare'}, + {label: 'GitHub', to: '/providers/github'}, {label: '... More', to: '/providers'}, ]; +// Blog sections: one @docusaurus/plugin-content-blog instance each on the +// main site, at /blog/. As there, the header entries carry a bullhorn +// on the two announcement sections, the footer entries are plain, and the +// /blog landing page is deliberately not linked from the chrome. +const blogSections = [ + {id: 'product', label: 'Product Announcements', navLabel: '📣 Product Announcements'}, + {id: 'providers', label: 'Provider Announcements', navLabel: '📣 Provider Announcements'}, + {id: 'tutorials', label: 'Tutorials'}, +]; + +const blogSectionNavItems = blogSections.map(({id, label, navLabel}) => ({ + label: navLabel || label, + to: `/blog/${id}`, +})); + +const blogSectionFooterItems = blogSections.map(({id, label}) => ({ + label, + to: `/blog/${id}`, +})); + const footerStackQLItems = [ - {label: 'Documentation', to: '/stackqldocs'}, - {label: 'Install', to: '/install'}, + // The main site links its docs root, stackql.io/ - see the /docs stub note above. + {label: 'Documentation', to: '/docs'}, + {label: 'Install', to: '/installing-stackql'}, {label: 'Contact us', to: '/contact-us'}, ]; const footerMoreItems = [ {label: 'Providers', to: '/providers'}, {label: 'stackql-deploy', to: '/stackql-deploy'}, - {label: 'Blog', to: '/blog'}, - {label: 'Tutorials', to: '/tutorials'}, + ...blogSectionFooterItems, + {label: 'Quick Starts', to: '/quick-starts'}, ]; /** @type {import('@docusaurus/types').Config} */ @@ -301,7 +333,7 @@ const config = { }, items: [ { - to: '/install', + to: '/installing-stackql', label: 'Install', position: 'left', }, @@ -311,15 +343,15 @@ const config = { position: 'left', items: [ { - to: '/docs/command-line-usage/mcp', + to: '/command-line-usage/mcp', label: 'MCP Server', }, { - to: '/docs/mcp', + to: '/mcp', label: 'MCP Tools', }, { - to: '/docs/mcp/embedded', + to: '/mcp/embedded', label: 'Embedded MCP', }, { @@ -346,13 +378,10 @@ const config = { label: 'More', position: 'left', items: [ + ...blogSectionNavItems, { - to: '/blog', - label: 'Blog', - }, - { - to: '/tutorials', - label: 'Tutorials', + to: '/quick-starts', + label: 'Quick Starts', }, ], }, diff --git a/query-library/queries/github/activity/repo-stargazers.md b/query-library/queries/github/activity/repo-stargazers.md new file mode 100644 index 00000000..a64e0a7d --- /dev/null +++ b/query-library/queries/github/activity/repo-stargazers.md @@ -0,0 +1,74 @@ +--- +title: GitHub repository stargazers +description: Lists the accounts that have starred a GitHub repository with login, profile URL and account type; the audience snapshot to take before a repository changes visibility or ownership. +verb: select +status: stable +providers: [github] +services: [activity] +tags: [github, activity, community, stars] +keywords: [stargazers, stars, who starred, star list, starred by, repository audience] +intent_keywords: + - who starred this github repo + - list stargazers for a repository + - which users have starred my repo +auth: [STACKQL_GITHUB_USERNAME, STACKQL_GITHUB_PASSWORD] +params: + - name: owner + type: identifier + required: true + description: Repository owner (organization or user) + example: stackql + - name: repo + type: identifier + required: true + description: Repository name + example: stackql +outputs: + - name: login + type: string + description: Stargazer login + - name: html_url + type: string + description: Profile URL of the stargazer + - name: type + type: string + description: Account type, User or Organization +cost: + fan_out: none + expensive: false + notes: Paginated transparently +related: + - github/repos/org-repos-list + - github/repos/contributor-analytics +author: Jeffrey Aven +author_company: StackQL Studios +last_verified: "2026-10-05" +--- + +Lists every account that has starred a repository, one row per stargazer. +Use it to capture a repository's audience before it changes visibility, moves +to another owner or is archived: GitHub clears stars when a public repository +is made private, and the `stargazers_count` on the repository record only +says how many, not who. + +## Query + +```sql +SELECT +login, +html_url, +type +FROM github.activity.repo_stargazers +WHERE owner = '{{owner}}' +AND repo = '{{repo}}'; +``` + +## Notes + +The resource also exposes a starred_at column, but the provider requests the +plain JSON media type rather than GitHub's star media type, so starred_at is +always null. For the star count alone read stargazers_count from +github.repos.repos instead of counting rows here. A 403 with the message +"Resource not accessible by personal access token" comes from a fine-grained +personal access token that does not cover the repository; use a classic token +or extend the fine-grained token's repository access and Metadata permission. diff --git a/query-library/scripts/build-artifacts.py b/query-library/scripts/build-artifacts.py index 00949a02..63c0a580 100644 --- a/query-library/scripts/build-artifacts.py +++ b/query-library/scripts/build-artifacts.py @@ -31,7 +31,6 @@ import hashlib import json import re -import shutil import subprocess import sys from datetime import datetime, timezone @@ -224,6 +223,24 @@ def build_index_md(entries, build_id: str) -> str: return "\n".join(lines).rstrip() + "\n" +def prune_stale_outputs(out_dir: Path, keep: set[Path]) -> None: + """Delete files under out_dir that this build did not write, then drop the + directories that are left empty, deepest first. A directory that cannot + be removed (a transient lock, seen on Windows) is left in place: git does + not track empty directories, so the committed tree is unaffected. A stale + file that cannot be deleted is an error - it would ship a removed entry. + """ + for path in sorted(out_dir.rglob("*"), key=lambda p: len(p.parts), reverse=True): + if path.is_file(): + if path not in keep: + path.unlink() + elif path.is_dir(): + try: + path.rmdir() # succeeds only once empty + except OSError: + pass + + def main() -> int: if validate.main() != 0: print("build-artifacts: validation failed, not emitting artifacts", file=sys.stderr) @@ -235,34 +252,33 @@ def main() -> int: build_id = compute_build_id(entries, docs, index_entries) manifest = build_manifest(build_id, len(entries)) - if STATIC_OUT_DIR.exists(): - shutil.rmtree(STATIC_OUT_DIR) - (STATIC_OUT_DIR / "queries").mkdir(parents=True) + # Write every output first, then remove whatever the previous build left + # that this one did not produce. The former rmtree-then-write was fragile + # on Windows: a transient handle on any subdirectory (editor file watcher, + # antivirus scanning the files just written) aborted the delete half-way + # and left the tree partially emptied under the pre-commit hook. + written: set[Path] = set() + + def emit(path: Path, text: str) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(text, encoding="utf-8", newline="\n") + written.add(path) - (STATIC_OUT_DIR / "index.json").write_text( + emit( + STATIC_OUT_DIR / "index.json", canonical_json({"build_id": build_id, "entries": index_entries}), - encoding="utf-8", - newline="\n", - ) - (STATIC_OUT_DIR / "manifest.json").write_text( - canonical_json(manifest), encoding="utf-8", newline="\n" - ) - (STATIC_OUT_DIR / "index.md").write_text( - build_index_md(entries, build_id), encoding="utf-8", newline="\n" ) + emit(STATIC_OUT_DIR / "manifest.json", canonical_json(manifest)) + emit(STATIC_OUT_DIR / "index.md", build_index_md(entries, build_id)) # Site-facing extras: not part of the frozen machine contract and not # hashed into build_id (presentation data only). providers_summary = build_providers_summary(entries) - (STATIC_OUT_DIR / "providers.json").write_text( - canonical_json(providers_summary), encoding="utf-8", newline="\n" - ) + emit(STATIC_OUT_DIR / "providers.json", canonical_json(providers_summary)) write_provider_stubs(providers_summary) for entry, doc in zip(entries, docs): - out_json = STATIC_OUT_DIR / "queries" / f"{entry.id}.json" - out_md = STATIC_OUT_DIR / "queries" / f"{entry.id}.md" - out_json.parent.mkdir(parents=True, exist_ok=True) - out_json.write_text(canonical_json(doc), encoding="utf-8", newline="\n") - out_md.write_text(entry.raw, encoding="utf-8", newline="\n") + emit(STATIC_OUT_DIR / "queries" / f"{entry.id}.json", canonical_json(doc)) + emit(STATIC_OUT_DIR / "queries" / f"{entry.id}.md", entry.raw) + prune_stale_outputs(STATIC_OUT_DIR, written) print( f"built {len(entries)} entries -> {STATIC_OUT_DIR.relative_to(REPO_ROOT)} " diff --git a/query-library/scripts/precommit-artifacts.py b/query-library/scripts/precommit-artifacts.py index 2f45a604..f84ec19a 100644 --- a/query-library/scripts/precommit-artifacts.py +++ b/query-library/scripts/precommit-artifacts.py @@ -4,15 +4,18 @@ Runs build-artifacts.py (which validates entries first), then checks git status for the generated outputs: static/docs/query-library/ and the -per-family .mdx stubs under query-library/. Any diff means the staged -sources and the staged artifacts are out of sync - the same condition the -CI freshness gate fails on. The rebuild is idempotent (build_id is a -content hash; manifest timestamps only change when it does), so a clean -tree passes with no side effects. +per-family .mdx stubs under query-library/. Only the working-tree column of +the porcelain status counts: a regenerated file that differs from the index +(" M"), or an untracked one ("??"), means the staged sources and the staged +artifacts are out of sync - the same condition the CI freshness gate fails +on. Staged-only changes ("M ", "A ", "R ") are the artifact updates this +commit legitimately carries and must pass. The rebuild is idempotent +(build_id is a content hash; manifest timestamps only change when it does), +so a clean tree passes with no side effects. -pre-commit stashes unstaged changes before running hooks, so a diff here -always means "regenerated artifacts were not staged", never "you have -unrelated local edits". +pre-commit stashes unstaged changes before running hooks, so a working-tree +diff here always means "regenerated artifacts were not staged", never "you +have unrelated local edits". """ from __future__ import annotations @@ -41,10 +44,15 @@ def main() -> int: print(status.stderr, file=sys.stderr) return 1 + # Porcelain v1 lines are "XY path": X is index-vs-HEAD, Y is + # worktree-vs-index. Stale means Y is set (modified/deleted in the + # worktree, or "??" untracked); a blank Y is a staged change and is fine. stale = [ line for line in status.stdout.splitlines() - if line.strip() and line[3:].strip('"') not in HANDWRITTEN + if len(line) > 3 + and line[1] != " " + and line[3:].strip('"') not in HANDWRITTEN ] if stale: print("Regenerated artifacts differ from what is staged:", file=sys.stderr) diff --git a/sidebars-query-library.js b/sidebars-query-library.js index 51ecd807..8c5ae0ad 100644 --- a/sidebars-query-library.js +++ b/sidebars-query-library.js @@ -30,7 +30,7 @@ const sidebars = { // Escape hatch back to the main stackql.io docs. '/docs' resolves under // baseUrl to the redirect stub at src/pages/docs/index.js, so the link // renders as internal (no external-link icon) and forwards to - // stackql.io/docs. + // stackql.io/ (the main site serves its docs at the site root). { type: 'link', href: '/docs', diff --git a/src/pages/tutorials.js b/src/pages/blog/product.js similarity index 68% rename from src/pages/tutorials.js rename to src/pages/blog/product.js index 81b46de8..0894f1eb 100644 --- a/src/pages/tutorials.js +++ b/src/pages/blog/product.js @@ -1,9 +1,9 @@ -// GENERATED-STYLE stub: makes the main-site path /tutorials an internal +// GENERATED-STYLE stub: makes the main-site path /blog/product an internal // route on this site (no external-link icon in nav/footer) and forwards to // stackql.io. See src/components/ExternalRedirect. import React from 'react'; import ExternalRedirect from '@site/src/components/ExternalRedirect'; export default function RedirectPage() { - return ; -} + return ; +} diff --git a/src/pages/stackqldocs.js b/src/pages/blog/providers.js similarity index 67% rename from src/pages/stackqldocs.js rename to src/pages/blog/providers.js index 9377148f..af7085fc 100644 --- a/src/pages/stackqldocs.js +++ b/src/pages/blog/providers.js @@ -1,9 +1,9 @@ -// GENERATED-STYLE stub: makes the main-site path /stackqldocs an internal +// GENERATED-STYLE stub: makes the main-site path /blog/providers an internal // route on this site (no external-link icon in nav/footer) and forwards to // stackql.io. See src/components/ExternalRedirect. import React from 'react'; import ExternalRedirect from '@site/src/components/ExternalRedirect'; export default function RedirectPage() { - return ; -} + return ; +} diff --git a/src/pages/blog/tutorials.js b/src/pages/blog/tutorials.js new file mode 100644 index 00000000..6e959c79 --- /dev/null +++ b/src/pages/blog/tutorials.js @@ -0,0 +1,9 @@ +// GENERATED-STYLE stub: makes the main-site path /blog/tutorials an internal +// route on this site (no external-link icon in nav/footer) and forwards to +// stackql.io. See src/components/ExternalRedirect. +import React from 'react'; +import ExternalRedirect from '@site/src/components/ExternalRedirect'; + +export default function RedirectPage() { + return ; +} diff --git a/src/pages/docs/mcp/embedded.js b/src/pages/command-line-usage/mcp.js similarity index 62% rename from src/pages/docs/mcp/embedded.js rename to src/pages/command-line-usage/mcp.js index a025b231..343ca7c6 100644 --- a/src/pages/docs/mcp/embedded.js +++ b/src/pages/command-line-usage/mcp.js @@ -1,9 +1,9 @@ -// GENERATED-STYLE stub: makes the main-site path /docs/mcp/embedded an internal +// GENERATED-STYLE stub: makes the main-site path /command-line-usage/mcp an internal // route on this site (no external-link icon in nav/footer) and forwards to // stackql.io. See src/components/ExternalRedirect. import React from 'react'; import ExternalRedirect from '@site/src/components/ExternalRedirect'; export default function RedirectPage() { - return ; -} + return ; +} diff --git a/src/pages/docs/command-line-usage/mcp.js b/src/pages/docs/command-line-usage/mcp.js deleted file mode 100644 index 5de09c33..00000000 --- a/src/pages/docs/command-line-usage/mcp.js +++ /dev/null @@ -1,9 +0,0 @@ -// GENERATED-STYLE stub: makes the main-site path /docs/command-line-usage/mcp an internal -// route on this site (no external-link icon in nav/footer) and forwards to -// stackql.io. See src/components/ExternalRedirect. -import React from 'react'; -import ExternalRedirect from '@site/src/components/ExternalRedirect'; - -export default function RedirectPage() { - return ; -} diff --git a/src/pages/docs/index.js b/src/pages/docs/index.js index f7edaa34..f5eb4dcc 100644 --- a/src/pages/docs/index.js +++ b/src/pages/docs/index.js @@ -1,9 +1,11 @@ -// GENERATED-STYLE stub: makes the main-site path /docs an internal -// route on this site (no external-link icon in nav/footer) and forwards to -// stackql.io. See src/components/ExternalRedirect. +// GENERATED-STYLE stub: the main-site docs root is https://stackql.io/ +// itself, and '/' on this site is the library landing page, so the footer +// "Documentation" link and the sidebar "Back to docs" link use this /docs +// route and forward straight to the root (skipping stackql.io's own +// /docs -> / 301). See src/components/ExternalRedirect. import React from 'react'; import ExternalRedirect from '@site/src/components/ExternalRedirect'; export default function RedirectPage() { - return ; -} + return ; +} diff --git a/src/pages/installing-stackql.js b/src/pages/installing-stackql.js new file mode 100644 index 00000000..eea2e14c --- /dev/null +++ b/src/pages/installing-stackql.js @@ -0,0 +1,9 @@ +// GENERATED-STYLE stub: makes the main-site path /installing-stackql an internal +// route on this site (no external-link icon in nav/footer) and forwards to +// stackql.io. See src/components/ExternalRedirect. +import React from 'react'; +import ExternalRedirect from '@site/src/components/ExternalRedirect'; + +export default function RedirectPage() { + return ; +} diff --git a/src/pages/install.js b/src/pages/mcp/embedded.js similarity index 65% rename from src/pages/install.js rename to src/pages/mcp/embedded.js index 7c4e0cbc..ee21144f 100644 --- a/src/pages/install.js +++ b/src/pages/mcp/embedded.js @@ -1,9 +1,9 @@ -// GENERATED-STYLE stub: makes the main-site path /install an internal +// GENERATED-STYLE stub: makes the main-site path /mcp/embedded an internal // route on this site (no external-link icon in nav/footer) and forwards to // stackql.io. See src/components/ExternalRedirect. import React from 'react'; import ExternalRedirect from '@site/src/components/ExternalRedirect'; export default function RedirectPage() { - return ; -} + return ; +} diff --git a/src/pages/blog.js b/src/pages/mcp/index.js similarity index 67% rename from src/pages/blog.js rename to src/pages/mcp/index.js index 9f47c27f..8567f402 100644 --- a/src/pages/blog.js +++ b/src/pages/mcp/index.js @@ -1,9 +1,9 @@ -// GENERATED-STYLE stub: makes the main-site path /blog an internal +// GENERATED-STYLE stub: makes the main-site path /mcp/index an internal // route on this site (no external-link icon in nav/footer) and forwards to // stackql.io. See src/components/ExternalRedirect. import React from 'react'; import ExternalRedirect from '@site/src/components/ExternalRedirect'; export default function RedirectPage() { - return ; -} + return ; +} diff --git a/src/pages/providers/databricks.js b/src/pages/providers/databricks-account.js similarity index 74% rename from src/pages/providers/databricks.js rename to src/pages/providers/databricks-account.js index 90d31317..99c31590 100644 --- a/src/pages/providers/databricks.js +++ b/src/pages/providers/databricks-account.js @@ -1,9 +1,9 @@ -// GENERATED-STYLE stub: makes the main-site path /providers/databricks an internal +// GENERATED-STYLE stub: makes the main-site path /providers/databricks-account an internal // route on this site (no external-link icon in nav/footer) and forwards to // stackql.io. See src/components/ExternalRedirect. import React from 'react'; import ExternalRedirect from '@site/src/components/ExternalRedirect'; export default function RedirectPage() { - return ; -} + return ; +} diff --git a/src/pages/docs/mcp/index.js b/src/pages/quick-starts.js similarity index 65% rename from src/pages/docs/mcp/index.js rename to src/pages/quick-starts.js index d71f7962..795e379c 100644 --- a/src/pages/docs/mcp/index.js +++ b/src/pages/quick-starts.js @@ -1,9 +1,9 @@ -// GENERATED-STYLE stub: makes the main-site path /docs/mcp an internal +// GENERATED-STYLE stub: makes the main-site path /quick-starts an internal // route on this site (no external-link icon in nav/footer) and forwards to // stackql.io. See src/components/ExternalRedirect. import React from 'react'; import ExternalRedirect from '@site/src/components/ExternalRedirect'; export default function RedirectPage() { - return ; -} + return ; +} diff --git a/static/docs/query-library/index.json b/static/docs/query-library/index.json index ece09ee4..82550b12 100644 --- a/static/docs/query-library/index.json +++ b/static/docs/query-library/index.json @@ -1,5 +1,5 @@ { - "build_id": "ql-ea4d2cbf5ec44568", + "build_id": "ql-2e0083ba3d9afd03", "entries": [ { "id": "aws/cloud_control/resource-request-by-token", @@ -1353,6 +1353,43 @@ "account_id" ] }, + { + "id": "github/activity/repo-stargazers", + "title": "GitHub repository stargazers", + "description": "Lists the accounts that have starred a GitHub repository with login, profile URL and account type; the audience snapshot to take before a repository changes visibility or ownership.", + "providers": [ + "github" + ], + "services": [ + "activity" + ], + "tags": [ + "github", + "activity", + "community", + "stars" + ], + "keywords": [ + "stargazers", + "stars", + "who starred", + "star list", + "starred by", + "repository audience" + ], + "intent_keywords": [ + "who starred this github repo", + "list stargazers for a repository", + "which users have starred my repo" + ], + "mutation": false, + "verb": "select", + "status": "stable", + "required_params": [ + "owner", + "repo" + ] + }, { "id": "github/issues/issue-velocity", "title": "GitHub issue creation velocity", diff --git a/static/docs/query-library/index.md b/static/docs/query-library/index.md index 65ede0d2..0aef5661 100644 --- a/static/docs/query-library/index.md +++ b/static/docs/query-library/index.md @@ -6,7 +6,7 @@ > (`.json`) consumed by the stackql MCP server's `query_library_search` > and `query_library_get` tools. -Build `ql-ea4d2cbf5ec44568` | 47 entries | machine catalogue: +Build `ql-2e0083ba3d9afd03` | 48 entries | machine catalogue: [index.json](https://stackql.io/docs/query-library/index.json) | [manifest.json](https://stackql.io/docs/query-library/manifest.json) @@ -62,6 +62,7 @@ Build `ql-ea4d2cbf5ec44568` | 47 entries | machine catalogue: ## github +- [GitHub repository stargazers](https://stackql.io/docs/query-library/queries/github/activity/repo-stargazers) (select; params: owner, repo): Lists the accounts that have starred a GitHub repository with login, profile URL and account type; the audience snapshot to take before a repository changes visibility or ownership. - [GitHub issue creation velocity](https://stackql.io/docs/query-library/queries/github/issues/issue-velocity) (select; draft; params: owner, repo): Sequences a repository's issues by creation date with a cumulative count and the gap since the previous issue; the intake rate and quiet-period view. - [GitHub weekly commit activity trend](https://stackql.io/docs/query-library/queries/github/repos/commit-activity-trend) (select; params: owner, repo): Reports the last year of weekly commit counts with a four-week moving average and cumulative total; the project momentum view. - [GitHub contributor ranking and concentration](https://stackql.io/docs/query-library/queries/github/repos/contributor-analytics) (select; params: owner, repo): Ranks a repository's contributors by commit count with running totals and share of the whole; the bus-factor and contribution concentration view. diff --git a/static/docs/query-library/manifest.json b/static/docs/query-library/manifest.json index 233532d6..07f7bace 100644 --- a/static/docs/query-library/manifest.json +++ b/static/docs/query-library/manifest.json @@ -1,6 +1,6 @@ { - "build_id": "ql-ea4d2cbf5ec44568", - "generated_at": "2026-07-31T21:03:45Z", - "library_commit": "30430712", - "entry_count": 47 + "build_id": "ql-2e0083ba3d9afd03", + "generated_at": "2026-10-05T04:38:58Z", + "library_commit": "8d895876", + "entry_count": 48 } diff --git a/static/docs/query-library/providers.json b/static/docs/query-library/providers.json index 8aa3430a..ab348117 100644 --- a/static/docs/query-library/providers.json +++ b/static/docs/query-library/providers.json @@ -31,7 +31,7 @@ "id": "github", "title": "GitHub", "description": "Web-based version-control and collaboration.", - "count": 5, + "count": 6, "logo": "/img/providers/github/favicon.ico" }, { diff --git a/static/docs/query-library/queries/github/activity/repo-stargazers.json b/static/docs/query-library/queries/github/activity/repo-stargazers.json new file mode 100644 index 00000000..42b5f817 --- /dev/null +++ b/static/docs/query-library/queries/github/activity/repo-stargazers.json @@ -0,0 +1,66 @@ +{ + "id": "github/activity/repo-stargazers", + "title": "GitHub repository stargazers", + "description": "Lists the accounts that have starred a GitHub repository with login, profile URL and account type; the audience snapshot to take before a repository changes visibility or ownership.", + "mutation": false, + "verb": "select", + "status": "stable", + "providers": [ + "github" + ], + "services": [ + "activity" + ], + "auth": [ + "STACKQL_GITHUB_USERNAME", + "STACKQL_GITHUB_PASSWORD" + ], + "params": [ + { + "name": "owner", + "type": "identifier", + "required": true, + "description": "Repository owner (organization or user)", + "example": "stackql" + }, + { + "name": "repo", + "type": "identifier", + "required": true, + "description": "Repository name", + "example": "stackql" + } + ], + "outputs": [ + { + "name": "login", + "type": "string", + "description": "Stargazer login" + }, + { + "name": "html_url", + "type": "string", + "description": "Profile URL of the stargazer" + }, + { + "name": "type", + "type": "string", + "description": "Account type, User or Organization" + } + ], + "cost": { + "fan_out": "none", + "expensive": false, + "notes": "Paginated transparently" + }, + "related": [ + "github/repos/org-repos-list", + "github/repos/contributor-analytics" + ], + "template": "SELECT\nlogin,\nhtml_url,\ntype\nFROM github.activity.repo_stargazers\nWHERE owner = '{{owner}}'\nAND repo = '{{repo}}';", + "notes": "The resource also exposes a starred_at column, but the provider requests the plain JSON media type rather than GitHub's star media type, so starred_at is always null. For the star count alone read stargazers_count from github.repos.repos instead of counting rows here. A 403 with the message \"Resource not accessible by personal access token\" comes from a fine-grained personal access token that does not cover the repository; use a classic token or extend the fine-grained token's repository access and Metadata permission.", + "doc_url": "https://stackql.io/docs/query-library/queries/github/activity/repo-stargazers", + "last_verified": "2026-10-05", + "author": "Jeffrey Aven", + "author_company": "StackQL Studios" +} diff --git a/static/docs/query-library/queries/github/activity/repo-stargazers.md b/static/docs/query-library/queries/github/activity/repo-stargazers.md new file mode 100644 index 00000000..a64e0a7d --- /dev/null +++ b/static/docs/query-library/queries/github/activity/repo-stargazers.md @@ -0,0 +1,74 @@ +--- +title: GitHub repository stargazers +description: Lists the accounts that have starred a GitHub repository with login, profile URL and account type; the audience snapshot to take before a repository changes visibility or ownership. +verb: select +status: stable +providers: [github] +services: [activity] +tags: [github, activity, community, stars] +keywords: [stargazers, stars, who starred, star list, starred by, repository audience] +intent_keywords: + - who starred this github repo + - list stargazers for a repository + - which users have starred my repo +auth: [STACKQL_GITHUB_USERNAME, STACKQL_GITHUB_PASSWORD] +params: + - name: owner + type: identifier + required: true + description: Repository owner (organization or user) + example: stackql + - name: repo + type: identifier + required: true + description: Repository name + example: stackql +outputs: + - name: login + type: string + description: Stargazer login + - name: html_url + type: string + description: Profile URL of the stargazer + - name: type + type: string + description: Account type, User or Organization +cost: + fan_out: none + expensive: false + notes: Paginated transparently +related: + - github/repos/org-repos-list + - github/repos/contributor-analytics +author: Jeffrey Aven +author_company: StackQL Studios +last_verified: "2026-10-05" +--- + +Lists every account that has starred a repository, one row per stargazer. +Use it to capture a repository's audience before it changes visibility, moves +to another owner or is archived: GitHub clears stars when a public repository +is made private, and the `stargazers_count` on the repository record only +says how many, not who. + +## Query + +```sql +SELECT +login, +html_url, +type +FROM github.activity.repo_stargazers +WHERE owner = '{{owner}}' +AND repo = '{{repo}}'; +``` + +## Notes + +The resource also exposes a starred_at column, but the provider requests the +plain JSON media type rather than GitHub's star media type, so starred_at is +always null. For the star count alone read stargazers_count from +github.repos.repos instead of counting rows here. A 403 with the message +"Resource not accessible by personal access token" comes from a fine-grained +personal access token that does not cover the repository; use a classic token +or extend the fine-grained token's repository access and Metadata permission. From ec6ced4fdc2a5dab939b60f6018156e7fccd82cd Mon Sep 17 00:00:00 2001 From: Jeffrey Aven Date: Mon, 5 Oct 2026 18:57:47 +1100 Subject: [PATCH 2/5] menu update and new query --- .gitignore | 3 + CLAUDE.md | 50 +++-- docusaurus.config.js | 240 +++++----------------- netlify.toml | 15 ++ package.json | 8 +- sidebars-query-library.js | 10 +- src/components/ExternalRedirect/index.jsx | 28 --- src/pages/blog/product.js | 9 - src/pages/blog/providers.js | 9 - src/pages/blog/tutorials.js | 9 - src/pages/command-line-usage/mcp.js | 9 - src/pages/contact-us.js | 9 - src/pages/docs/index.js | 11 - src/pages/installing-stackql.js | 9 - src/pages/mcp/embedded.js | 9 - src/pages/mcp/index.js | 9 - src/pages/providers/aws.js | 9 - src/pages/providers/azure.js | 9 - src/pages/providers/cloudflare.js | 9 - src/pages/providers/confluent.js | 9 - src/pages/providers/databricks-account.js | 9 - src/pages/providers/github.js | 9 - src/pages/providers/google.js | 9 - src/pages/providers/index.js | 9 - src/pages/providers/okta.js | 9 - src/pages/providers/openai.js | 9 - src/pages/providers/snowflake.js | 9 - src/pages/quick-starts.js | 9 - src/pages/stackql-deploy.js | 9 - static/img/logo-original.svg | 3 - static/img/logo-white.svg | 3 - yarn.lock | 67 +++++- 32 files changed, 179 insertions(+), 448 deletions(-) delete mode 100644 src/components/ExternalRedirect/index.jsx delete mode 100644 src/pages/blog/product.js delete mode 100644 src/pages/blog/providers.js delete mode 100644 src/pages/blog/tutorials.js delete mode 100644 src/pages/command-line-usage/mcp.js delete mode 100644 src/pages/contact-us.js delete mode 100644 src/pages/docs/index.js delete mode 100644 src/pages/installing-stackql.js delete mode 100644 src/pages/mcp/embedded.js delete mode 100644 src/pages/mcp/index.js delete mode 100644 src/pages/providers/aws.js delete mode 100644 src/pages/providers/azure.js delete mode 100644 src/pages/providers/cloudflare.js delete mode 100644 src/pages/providers/confluent.js delete mode 100644 src/pages/providers/databricks-account.js delete mode 100644 src/pages/providers/github.js delete mode 100644 src/pages/providers/google.js delete mode 100644 src/pages/providers/index.js delete mode 100644 src/pages/providers/okta.js delete mode 100644 src/pages/providers/openai.js delete mode 100644 src/pages/providers/snowflake.js delete mode 100644 src/pages/quick-starts.js delete mode 100644 src/pages/stackql-deploy.js delete mode 100644 static/img/logo-original.svg delete mode 100644 static/img/logo-white.svg diff --git a/.gitignore b/.gitignore index 2ca4c9bf..edd771b9 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,6 @@ vars.ps1 # Claude Code local settings .claude/settings.local.json __pycache__/ + +# vendored shared docusaurus config (cloned at build time by the vendor-config script) +.shared-config diff --git a/CLAUDE.md b/CLAUDE.md index f359e1c5..49907db6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -38,10 +38,13 @@ Consequences: - Every emitted link, asset path and canonical URL carries the `/docs/query-library/` prefix, so pages work when proxied. -- Browsing the raw subdomain directly shows broken asset paths - expected and - accepted; canonicalisation is via the `` tags - Docusaurus emits, not redirects. The origin must answer 200 to the proxy - - never add a blanket 301 to stackql.io here. +- Browsing the raw subdomain or a Netlify deploy preview directly works + too: a non-forced 200 rewrite in [netlify.toml](netlify.toml) maps the + prefixed asset and page paths the HTML emits back to the origin root (the + proxy never sends prefixed paths, so production is unaffected). + Canonicalisation is via the `` tags Docusaurus + emits, not redirects. The origin must answer 200 to the proxy - never add + a blanket 301 to stackql.io here. - The committed machine artifacts land in the build at `build/docs/query-library/` (static copy) while HTML lands at the build root; [netlify.toml](netlify.toml) has non-forced 200 rewrites that surface @@ -137,23 +140,28 @@ easy to get wrong: ## Site chrome (must look identical to stackql.io) -The navbar and footer mirror the main site's config so the proxied pages -read as one site. Main-site destinations (Install, Providers, Blog, the -docs dropdown items, footer links, the sidebar "Back to docs" link) are NOT -external `href` links - each has a redirect stub page under `src/pages/` -mounting [src/components/ExternalRedirect](src/components/ExternalRedirect/index.jsx), -which gives the link a real internal route (no external-link icon, passes -the broken-link checker, works on localhost and on the raw subdomain) and -instantly forwards to the real page on stackql.io. Stub paths equal the main -site's canonical paths (its docs are served at the site root, so `/mcp`, not -`/docs/mcp`); the one exception is the main docs root, `stackql.io/`, which -is the `/docs` stub here because `/` is the library landing. The stub route -list, the navbar/footer `to` values (`mainSitePaths` in docusaurus.config.js) -and the stub files must stay in lockstep with each other and with the main -repo's navbar/footer (its `navbar.items`, `footerStackQLItems`, -`footerMoreItems`, `blogSections` and the `featured` entries of its -`src/configs/providers.json`, which drive the Providers dropdown). Stub routes are noindexed, excluded from the sitemap and -from structured-data JSON-LD. The footer is the swizzled main-site footer +The navbar, footer and every cross-site link come from the shared StackQL +chrome repo, `stackql/docusaurus-config` (local checkout +`../docusaurus-config`), which also drives the provider microsites. The +`vendor-config` script in package.json shallow-clones its `main` into the +gitignored `.shared-config/` before every `yarn start`/`yarn build` (Yarn 1 +runs the pre-scripts, so the Netlify build is covered). A failed clone fails +the build by design, and `main` is unpinned, so a shared change goes live on +this site's next build. This site cannot use the shared `createConfig` +factory (it assumes a microsite at baseUrl `/` with its own preset), so +[docusaurus.config.js](docusaurus.config.js) composes the pieces instead: +`buildNavbar()`/`buildFooter()` for the chrome (logo href overridden to the +brand home, and AI Agents > Query Library pointed at `/` because that +destination is this site), `redirectsPlugin` for the main-site destinations +(one local route under baseUrl per link that client-side-forwards to the +real page, so links are internal here: no external-link icon, they pass the +broken-link checker, and they work on localhost and on the raw subdomain) +and `redirectRoutes(baseUrl)` to keep those stub routes out of the sitemap +and of structured-data JSON-LD (the shared Redirect component noindexes +them). There are no `src/pages/` stubs; menu changes belong in the shared +repo, whose README documents the composition contract ("Composing instead +of createConfig") and whose menus must be kept in step with the main site's +navbar/footer. The footer is the swizzled main-site footer (`src/theme/Footer`, needs `@iconify/react`, `@mui/material`, `clsx`); `src/css/global.css` is the full main-site stylesheet for visual parity. DocSearch is enabled only when the `ALGOLIA_*` env vars are set (shared diff --git a/docusaurus.config.js b/docusaurus.config.js index 31bbd16f..b9dd926c 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -10,98 +10,59 @@ const {themes} = require('prism-react-renderer'); const darkCodeTheme = themes.dracula; const nightOwlCodeTheme = themes.nightOwl; -// The navbar and footer mirror the main stackql.io site so the proxied -// library pages read as one site. Every main-site destination has a stub -// page under src/pages/ (rendering src/components/ExternalRedirect) so the -// links are internal routes here - no external-link icon, and the -// broken-link checker validates them. Stub paths equal the main site's own -// canonical paths (the docs tree there is served at the site root, so -// e.g. /mcp not /docs/mcp). The one exception is the docs root itself, -// stackql.io/: '/' here is the library landing, so that destination is the -// /docs stub, which forwards straight to the root. The `to` values below -// are baseUrl-relative; keep them in lockstep with the stub files and with -// the main repo's chrome config (docusaurus.config.js there: navbar.items, -// footerStackQLItems, footerMoreItems, blogSections, and the `featured` -// entries of src/configs/providers.json for the Providers dropdown). -const mainSitePaths = [ - '/docs', - '/installing-stackql', - '/contact-us', - '/stackql-deploy', - '/command-line-usage/mcp', - '/mcp', - '/mcp/embedded', - '/quick-starts', - '/blog/product', - '/blog/providers', - '/blog/tutorials', - '/providers', - '/providers/aws', - '/providers/azure', - '/providers/google', - '/providers/cloudflare', - '/providers/databricks-account', - '/providers/snowflake', - '/providers/confluent', - '/providers/okta', - '/providers/openai', - '/providers/github', -]; -// Full public route paths of the stubs (baseUrl + path): kept out of the -// sitemap and of structured-data JSON-LD emission below. -const redirectStubRoutes = mainSitePaths.map((p) => `/docs/query-library${p}`); +// The navbar, footer and every cross-site link come from the shared StackQL +// chrome (github.com/stackql/docusaurus-config), vendored into the +// gitignored .shared-config/ folder by the `vendor-config` script before +// every start and build - the same wiring the provider microsites use. One +// repo defines the header, footer and menus for every StackQL property, so +// the proxied library pages read as one site with stackql.io. This site +// cannot use the shared createConfig factory (it assumes a microsite at +// baseUrl '/' with its own preset), so the pieces are composed here: see +// "Composing instead of createConfig" in the shared README. The shared +// redirects plugin registers a local route under baseUrl for each main-site +// destination (so the links are internal here - no external-link icon, and +// the broken-link checker validates them) that client-side-forwards to the +// real page. +const shared = require('./.shared-config/index.js'); -// The main site's Providers dropdown lists the `featured` entries of its -// provider catalog in catalog order, labelled by shortName. Databricks' -// canonical slug there is databricks-account (the family-level -// /providers/databricks route was retired and now 301s to /registry). -const providerDropDownListItems = [ - {label: 'AWS', to: '/providers/aws'}, - {label: 'Azure', to: '/providers/azure'}, - {label: 'Google', to: '/providers/google'}, - {label: 'Cloudflare', to: '/providers/cloudflare'}, - {label: 'Databricks', to: '/providers/databricks-account'}, - {label: 'Snowflake', to: '/providers/snowflake'}, - {label: 'Confluent', to: '/providers/confluent'}, - {label: 'Okta', to: '/providers/okta'}, - {label: 'OpenAI', to: '/providers/openai'}, - {label: 'GitHub', to: '/providers/github'}, - {label: '... More', to: '/providers'}, -]; +const baseUrl = '/docs/query-library/'; -// Blog sections: one @docusaurus/plugin-content-blog instance each on the -// main site, at /blog/. As there, the header entries carry a bullhorn -// on the two announcement sections, the footer entries are plain, and the -// /blog landing page is deliberately not linked from the chrome. -const blogSections = [ - {id: 'product', label: 'Product Announcements', navLabel: '📣 Product Announcements'}, - {id: 'providers', label: 'Provider Announcements', navLabel: '📣 Provider Announcements'}, - {id: 'tutorials', label: 'Tutorials'}, -]; +// Full public route paths of the shared redirect stubs: kept out of the +// sitemap and of structured-data JSON-LD emission below (the shared +// Redirect component noindexes them). +const redirectStubRoutes = shared.redirectRoutes(baseUrl); -const blogSectionNavItems = blogSections.map(({id, label, navLabel}) => ({ - label: navLabel || label, - to: `/blog/${id}`, -})); - -const blogSectionFooterItems = blogSections.map(({id, label}) => ({ - label, - to: `/blog/${id}`, -})); +// The site logo goes to the brand home, not this site's root (the shared +// default suits a microsite whose root is its own landing page). An +// external href renders without an icon; target keeps it in the same tab. +const logo = { + ...shared.buildNavbar().logo, + href: 'https://stackql.io/', + target: '_self', +}; -const footerStackQLItems = [ - // The main site links its docs root, stackql.io/ - see the /docs stub note above. - {label: 'Documentation', to: '/docs'}, - {label: 'Install', to: '/installing-stackql'}, - {label: 'Contact us', to: '/contact-us'}, -]; +// Shared navbar, with the one destination that IS this site - AI Agents > +// Query Library - pointing at the library landing instead of its shared +// redirect route. +const navbar = (() => { + const nav = shared.buildNavbar(); + return { + ...nav, + logo, + items: nav.items.map((item) => + item.type === 'dropdown' && item.label === 'AI Agents' + ? { + ...item, + items: item.items.map((child) => + child.label === 'Query Library' ? {...child, to: '/'} : child, + ), + } + : item, + ), + }; +})(); -const footerMoreItems = [ - {label: 'Providers', to: '/providers'}, - {label: 'stackql-deploy', to: '/stackql-deploy'}, - ...blogSectionFooterItems, - {label: 'Quick Starts', to: '/quick-starts'}, -]; +const footer = {...shared.buildFooter(), logo}; /** @type {import('@docusaurus/types').Config} */ const config = { @@ -118,7 +79,7 @@ const config = { // paths - expected; canonical tags point at stackql.io. These two values // and the main repo's redirect must agree forever. url: 'https://stackql.io', - baseUrl: '/docs/query-library/', + baseUrl, onBrokenLinks: 'throw', favicon: 'favicon.ico', @@ -144,6 +105,9 @@ const config = { }, ], plugins: [ + // Local redirect routes for every shared main-site destination (see the + // chrome note at the top of this file). + shared.redirectsPlugin, '@stackql/docusaurus-plugin-structured-data', [ '@stackql/docusaurus-plugin-aeo', @@ -202,8 +166,9 @@ const config = { ({ docs: false, blog: false, - // src/pages holds only the redirect stubs for main-site nav targets. - pages: {}, + // No src/pages: the main-site redirect stubs are routes registered + // by the shared redirects plugin. + pages: false, sitemap: { changefreq: 'weekly', priority: 0.5, @@ -321,99 +286,8 @@ const config = { hideable: true, }, }, - navbar: { - logo: { - alt: 'StackQL', - // Same behavior as the main site's logo (-> home). External href - // renders without an icon; target keeps it in the same tab. - href: 'https://stackql.io/', - target: '_self', - src: 'img/logo-original.svg', - srcDark: 'img/logo-white.svg', - }, - items: [ - { - to: '/installing-stackql', - label: 'Install', - position: 'left', - }, - { - type: 'dropdown', - label: 'AI Agents', - position: 'left', - items: [ - { - to: '/command-line-usage/mcp', - label: 'MCP Server', - }, - { - to: '/mcp', - label: 'MCP Tools', - }, - { - to: '/mcp/embedded', - label: 'Embedded MCP', - }, - { - // The one destination that IS this site: the library landing. - to: '/', - label: 'Query Library', - }, - ], - }, - { - to: '/stackql-deploy', - label: 'stackql-deploy', - position: 'left', - }, - { - to: '/providers', - type: 'dropdown', - label: 'Providers', - position: 'left', - items: providerDropDownListItems, - }, - { - type: 'dropdown', - label: 'More', - position: 'left', - items: [ - ...blogSectionNavItems, - { - to: '/quick-starts', - label: 'Quick Starts', - }, - ], - }, - { - href: 'https://github.com/stackql/stackql', - position: 'right', - className: 'header-github-link', - 'aria-label': 'GitHub repository', - }, - ], - }, - footer: { - style: 'dark', - logo: { - alt: 'StackQL', - href: 'https://stackql.io/', - target: '_self', - src: 'img/logo-original.svg', - srcDark: 'img/logo-white.svg', - }, - links: [ - { - title: 'StackQL', - items: footerStackQLItems, - }, - { - title: 'More', - items: footerMoreItems, - }, - ], - copyright: `© ${new Date().getFullYear()} StackQL Studios ABN 65 656 147 054`, - }, + navbar, + footer, colorMode: { respectPrefersColorScheme: true, }, diff --git a/netlify.toml b/netlify.toml index a72718f5..08f9cf57 100644 --- a/netlify.toml +++ b/netlify.toml @@ -36,6 +36,21 @@ [build.environment] PYTHON_VERSION = "3.12" +# --- Direct hits on this origin (deploy previews, the raw subdomain) --- +# Proxied requests arrive with the /docs/query-library prefix already +# stripped, but a browser on a deploy preview or on query-library.stackql.io +# itself follows the emitted links and asset paths, which all carry the +# prefix (baseUrl). Map them back to the root so previews render styled and +# navigable. Not forced: the committed artifact tree really exists at +# build/docs/query-library/ (index.json, manifest.json, queries/*.json|md) +# and those real files win, exactly as they do for the proxied path. The +# proxy never sends a prefixed path to this origin, so this rule has no +# effect on production traffic. +[[redirects]] + from = "/docs/query-library/*" + to = "/:splat" + status = 200 + # --- Contract artifact rewrites (machine catalogue at the origin root) --- # Public URLs (via the proxy): stackql.io/docs/query-library/{manifest.json, # index.json, index.md, providers.json, queries/.{json,md}}. diff --git a/package.json b/package.json index a6a54e61..9b003848 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,9 @@ "private": true, "scripts": { "docusaurus": "docusaurus", + "vendor-config": "rimraf .shared-config && git clone --depth 1 --branch main https://github.com/stackql/docusaurus-config.git .shared-config", + "prestart": "yarn vendor-config", + "prebuild": "yarn vendor-config", "start": "docusaurus start", "build": "docusaurus build", "swizzle": "docusaurus swizzle", @@ -22,7 +25,7 @@ "@mui/icons-material": "^5.2.0", "@mui/material": "^5.2.5", "@stackql/docusaurus-plugin-aeo": "^0.4.2", - "@stackql/docusaurus-plugin-structured-data": "^1.5.1", + "@stackql/docusaurus-plugin-structured-data": "^1.6.0", "clsx": "^1.1.1", "prism-react-renderer": "^2.1.0", "react": "^18.2.0", @@ -39,5 +42,8 @@ "last 1 firefox version", "last 1 safari version" ] + }, + "devDependencies": { + "rimraf": "^6.0.1" } } diff --git a/sidebars-query-library.js b/sidebars-query-library.js index 8c5ae0ad..a7c23826 100644 --- a/sidebars-query-library.js +++ b/sidebars-query-library.js @@ -27,13 +27,13 @@ function labelFor(id) { /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ const sidebars = { queryLibrarySidebar: [ - // Escape hatch back to the main stackql.io docs. '/docs' resolves under - // baseUrl to the redirect stub at src/pages/docs/index.js, so the link - // renders as internal (no external-link icon) and forwards to - // stackql.io/ (the main site serves its docs at the site root). + // Escape hatch back to the main stackql.io docs. '/stackqldocs' is the + // shared chrome's redirect route for the main docs root (registered + // under baseUrl by the vendored redirects plugin), so the link renders + // as internal (no external-link icon) and forwards to stackql.io/. { type: 'link', - href: '/docs', + href: '/stackqldocs', label: 'Back to docs', className: 'ql-sidebar-back-link', }, diff --git a/src/components/ExternalRedirect/index.jsx b/src/components/ExternalRedirect/index.jsx deleted file mode 100644 index 9a63f038..00000000 --- a/src/components/ExternalRedirect/index.jsx +++ /dev/null @@ -1,28 +0,0 @@ -import React, {useEffect} from 'react'; -import Head from '@docusaurus/Head'; - -// Body for the redirect stub pages under src/pages/. This site is proxied -// under stackql.io/docs/query-library/, and its navbar/footer mirror the -// main site's; the stubs give those main-site destinations real internal -// routes (so links render without the external-link icon and satisfy the -// broken-link checker) and immediately forward to the real page on -// stackql.io. Stub routes are noindexed here and excluded from the sitemap -// and structured-data emission in docusaurus.config.js. -export default function ExternalRedirect({to}) { - useEffect(() => { - window.location.replace(to); - }, [to]); - return ( - <> - - - - - Redirecting... - -

- Redirecting to {to}... -

- - ); -} diff --git a/src/pages/blog/product.js b/src/pages/blog/product.js deleted file mode 100644 index 0894f1eb..00000000 --- a/src/pages/blog/product.js +++ /dev/null @@ -1,9 +0,0 @@ -// GENERATED-STYLE stub: makes the main-site path /blog/product an internal -// route on this site (no external-link icon in nav/footer) and forwards to -// stackql.io. See src/components/ExternalRedirect. -import React from 'react'; -import ExternalRedirect from '@site/src/components/ExternalRedirect'; - -export default function RedirectPage() { - return ; -} diff --git a/src/pages/blog/providers.js b/src/pages/blog/providers.js deleted file mode 100644 index af7085fc..00000000 --- a/src/pages/blog/providers.js +++ /dev/null @@ -1,9 +0,0 @@ -// GENERATED-STYLE stub: makes the main-site path /blog/providers an internal -// route on this site (no external-link icon in nav/footer) and forwards to -// stackql.io. See src/components/ExternalRedirect. -import React from 'react'; -import ExternalRedirect from '@site/src/components/ExternalRedirect'; - -export default function RedirectPage() { - return ; -} diff --git a/src/pages/blog/tutorials.js b/src/pages/blog/tutorials.js deleted file mode 100644 index 6e959c79..00000000 --- a/src/pages/blog/tutorials.js +++ /dev/null @@ -1,9 +0,0 @@ -// GENERATED-STYLE stub: makes the main-site path /blog/tutorials an internal -// route on this site (no external-link icon in nav/footer) and forwards to -// stackql.io. See src/components/ExternalRedirect. -import React from 'react'; -import ExternalRedirect from '@site/src/components/ExternalRedirect'; - -export default function RedirectPage() { - return ; -} diff --git a/src/pages/command-line-usage/mcp.js b/src/pages/command-line-usage/mcp.js deleted file mode 100644 index 343ca7c6..00000000 --- a/src/pages/command-line-usage/mcp.js +++ /dev/null @@ -1,9 +0,0 @@ -// GENERATED-STYLE stub: makes the main-site path /command-line-usage/mcp an internal -// route on this site (no external-link icon in nav/footer) and forwards to -// stackql.io. See src/components/ExternalRedirect. -import React from 'react'; -import ExternalRedirect from '@site/src/components/ExternalRedirect'; - -export default function RedirectPage() { - return ; -} diff --git a/src/pages/contact-us.js b/src/pages/contact-us.js deleted file mode 100644 index eea5210e..00000000 --- a/src/pages/contact-us.js +++ /dev/null @@ -1,9 +0,0 @@ -// GENERATED-STYLE stub: makes the main-site path /contact-us an internal -// route on this site (no external-link icon in nav/footer) and forwards to -// stackql.io. See src/components/ExternalRedirect. -import React from 'react'; -import ExternalRedirect from '@site/src/components/ExternalRedirect'; - -export default function RedirectPage() { - return ; -} diff --git a/src/pages/docs/index.js b/src/pages/docs/index.js deleted file mode 100644 index f5eb4dcc..00000000 --- a/src/pages/docs/index.js +++ /dev/null @@ -1,11 +0,0 @@ -// GENERATED-STYLE stub: the main-site docs root is https://stackql.io/ -// itself, and '/' on this site is the library landing page, so the footer -// "Documentation" link and the sidebar "Back to docs" link use this /docs -// route and forward straight to the root (skipping stackql.io's own -// /docs -> / 301). See src/components/ExternalRedirect. -import React from 'react'; -import ExternalRedirect from '@site/src/components/ExternalRedirect'; - -export default function RedirectPage() { - return ; -} diff --git a/src/pages/installing-stackql.js b/src/pages/installing-stackql.js deleted file mode 100644 index eea2e14c..00000000 --- a/src/pages/installing-stackql.js +++ /dev/null @@ -1,9 +0,0 @@ -// GENERATED-STYLE stub: makes the main-site path /installing-stackql an internal -// route on this site (no external-link icon in nav/footer) and forwards to -// stackql.io. See src/components/ExternalRedirect. -import React from 'react'; -import ExternalRedirect from '@site/src/components/ExternalRedirect'; - -export default function RedirectPage() { - return ; -} diff --git a/src/pages/mcp/embedded.js b/src/pages/mcp/embedded.js deleted file mode 100644 index ee21144f..00000000 --- a/src/pages/mcp/embedded.js +++ /dev/null @@ -1,9 +0,0 @@ -// GENERATED-STYLE stub: makes the main-site path /mcp/embedded an internal -// route on this site (no external-link icon in nav/footer) and forwards to -// stackql.io. See src/components/ExternalRedirect. -import React from 'react'; -import ExternalRedirect from '@site/src/components/ExternalRedirect'; - -export default function RedirectPage() { - return ; -} diff --git a/src/pages/mcp/index.js b/src/pages/mcp/index.js deleted file mode 100644 index 8567f402..00000000 --- a/src/pages/mcp/index.js +++ /dev/null @@ -1,9 +0,0 @@ -// GENERATED-STYLE stub: makes the main-site path /mcp/index an internal -// route on this site (no external-link icon in nav/footer) and forwards to -// stackql.io. See src/components/ExternalRedirect. -import React from 'react'; -import ExternalRedirect from '@site/src/components/ExternalRedirect'; - -export default function RedirectPage() { - return ; -} diff --git a/src/pages/providers/aws.js b/src/pages/providers/aws.js deleted file mode 100644 index f77c71de..00000000 --- a/src/pages/providers/aws.js +++ /dev/null @@ -1,9 +0,0 @@ -// GENERATED-STYLE stub: makes the main-site path /providers/aws an internal -// route on this site (no external-link icon in nav/footer) and forwards to -// stackql.io. See src/components/ExternalRedirect. -import React from 'react'; -import ExternalRedirect from '@site/src/components/ExternalRedirect'; - -export default function RedirectPage() { - return ; -} diff --git a/src/pages/providers/azure.js b/src/pages/providers/azure.js deleted file mode 100644 index aa65f1f8..00000000 --- a/src/pages/providers/azure.js +++ /dev/null @@ -1,9 +0,0 @@ -// GENERATED-STYLE stub: makes the main-site path /providers/azure an internal -// route on this site (no external-link icon in nav/footer) and forwards to -// stackql.io. See src/components/ExternalRedirect. -import React from 'react'; -import ExternalRedirect from '@site/src/components/ExternalRedirect'; - -export default function RedirectPage() { - return ; -} diff --git a/src/pages/providers/cloudflare.js b/src/pages/providers/cloudflare.js deleted file mode 100644 index ca052aec..00000000 --- a/src/pages/providers/cloudflare.js +++ /dev/null @@ -1,9 +0,0 @@ -// GENERATED-STYLE stub: makes the main-site path /providers/cloudflare an internal -// route on this site (no external-link icon in nav/footer) and forwards to -// stackql.io. See src/components/ExternalRedirect. -import React from 'react'; -import ExternalRedirect from '@site/src/components/ExternalRedirect'; - -export default function RedirectPage() { - return ; -} diff --git a/src/pages/providers/confluent.js b/src/pages/providers/confluent.js deleted file mode 100644 index 85242fa2..00000000 --- a/src/pages/providers/confluent.js +++ /dev/null @@ -1,9 +0,0 @@ -// GENERATED-STYLE stub: makes the main-site path /providers/confluent an internal -// route on this site (no external-link icon in nav/footer) and forwards to -// stackql.io. See src/components/ExternalRedirect. -import React from 'react'; -import ExternalRedirect from '@site/src/components/ExternalRedirect'; - -export default function RedirectPage() { - return ; -} diff --git a/src/pages/providers/databricks-account.js b/src/pages/providers/databricks-account.js deleted file mode 100644 index 99c31590..00000000 --- a/src/pages/providers/databricks-account.js +++ /dev/null @@ -1,9 +0,0 @@ -// GENERATED-STYLE stub: makes the main-site path /providers/databricks-account an internal -// route on this site (no external-link icon in nav/footer) and forwards to -// stackql.io. See src/components/ExternalRedirect. -import React from 'react'; -import ExternalRedirect from '@site/src/components/ExternalRedirect'; - -export default function RedirectPage() { - return ; -} diff --git a/src/pages/providers/github.js b/src/pages/providers/github.js deleted file mode 100644 index 331e9311..00000000 --- a/src/pages/providers/github.js +++ /dev/null @@ -1,9 +0,0 @@ -// GENERATED-STYLE stub: makes the main-site path /providers/github an internal -// route on this site (no external-link icon in nav/footer) and forwards to -// stackql.io. See src/components/ExternalRedirect. -import React from 'react'; -import ExternalRedirect from '@site/src/components/ExternalRedirect'; - -export default function RedirectPage() { - return ; -} diff --git a/src/pages/providers/google.js b/src/pages/providers/google.js deleted file mode 100644 index f1c9b4ac..00000000 --- a/src/pages/providers/google.js +++ /dev/null @@ -1,9 +0,0 @@ -// GENERATED-STYLE stub: makes the main-site path /providers/google an internal -// route on this site (no external-link icon in nav/footer) and forwards to -// stackql.io. See src/components/ExternalRedirect. -import React from 'react'; -import ExternalRedirect from '@site/src/components/ExternalRedirect'; - -export default function RedirectPage() { - return ; -} diff --git a/src/pages/providers/index.js b/src/pages/providers/index.js deleted file mode 100644 index 614157ff..00000000 --- a/src/pages/providers/index.js +++ /dev/null @@ -1,9 +0,0 @@ -// GENERATED-STYLE stub: makes the main-site path /providers an internal -// route on this site (no external-link icon in nav/footer) and forwards to -// stackql.io. See src/components/ExternalRedirect. -import React from 'react'; -import ExternalRedirect from '@site/src/components/ExternalRedirect'; - -export default function RedirectPage() { - return ; -} diff --git a/src/pages/providers/okta.js b/src/pages/providers/okta.js deleted file mode 100644 index f971e837..00000000 --- a/src/pages/providers/okta.js +++ /dev/null @@ -1,9 +0,0 @@ -// GENERATED-STYLE stub: makes the main-site path /providers/okta an internal -// route on this site (no external-link icon in nav/footer) and forwards to -// stackql.io. See src/components/ExternalRedirect. -import React from 'react'; -import ExternalRedirect from '@site/src/components/ExternalRedirect'; - -export default function RedirectPage() { - return ; -} diff --git a/src/pages/providers/openai.js b/src/pages/providers/openai.js deleted file mode 100644 index c1856de6..00000000 --- a/src/pages/providers/openai.js +++ /dev/null @@ -1,9 +0,0 @@ -// GENERATED-STYLE stub: makes the main-site path /providers/openai an internal -// route on this site (no external-link icon in nav/footer) and forwards to -// stackql.io. See src/components/ExternalRedirect. -import React from 'react'; -import ExternalRedirect from '@site/src/components/ExternalRedirect'; - -export default function RedirectPage() { - return ; -} diff --git a/src/pages/providers/snowflake.js b/src/pages/providers/snowflake.js deleted file mode 100644 index 53dbde25..00000000 --- a/src/pages/providers/snowflake.js +++ /dev/null @@ -1,9 +0,0 @@ -// GENERATED-STYLE stub: makes the main-site path /providers/snowflake an internal -// route on this site (no external-link icon in nav/footer) and forwards to -// stackql.io. See src/components/ExternalRedirect. -import React from 'react'; -import ExternalRedirect from '@site/src/components/ExternalRedirect'; - -export default function RedirectPage() { - return ; -} diff --git a/src/pages/quick-starts.js b/src/pages/quick-starts.js deleted file mode 100644 index 795e379c..00000000 --- a/src/pages/quick-starts.js +++ /dev/null @@ -1,9 +0,0 @@ -// GENERATED-STYLE stub: makes the main-site path /quick-starts an internal -// route on this site (no external-link icon in nav/footer) and forwards to -// stackql.io. See src/components/ExternalRedirect. -import React from 'react'; -import ExternalRedirect from '@site/src/components/ExternalRedirect'; - -export default function RedirectPage() { - return ; -} diff --git a/src/pages/stackql-deploy.js b/src/pages/stackql-deploy.js deleted file mode 100644 index dfe68e04..00000000 --- a/src/pages/stackql-deploy.js +++ /dev/null @@ -1,9 +0,0 @@ -// GENERATED-STYLE stub: makes the main-site path /stackql-deploy an internal -// route on this site (no external-link icon in nav/footer) and forwards to -// stackql.io. See src/components/ExternalRedirect. -import React from 'react'; -import ExternalRedirect from '@site/src/components/ExternalRedirect'; - -export default function RedirectPage() { - return ; -} diff --git a/static/img/logo-original.svg b/static/img/logo-original.svg deleted file mode 100644 index 1de09ec4..00000000 --- a/static/img/logo-original.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/static/img/logo-white.svg b/static/img/logo-white.svg deleted file mode 100644 index 88c628e0..00000000 --- a/static/img/logo-white.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/yarn.lock b/yarn.lock index 25ad474f..33405de1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2607,10 +2607,10 @@ dependencies: gray-matter "^4.0.3" -"@stackql/docusaurus-plugin-structured-data@^1.5.1": - version "1.5.1" - resolved "https://registry.yarnpkg.com/@stackql/docusaurus-plugin-structured-data/-/docusaurus-plugin-structured-data-1.5.1.tgz#ab70476710cc01933994d6200c782865b697689b" - integrity sha512-Q1RV9RxOwwDJyDfmQ0/ydTr2qAIkVIrlBIZ4JI2+cWJjPkaR6gSNBRYhk9b5z+2QsVXpDTxfdC/xyjXAPQbC0w== +"@stackql/docusaurus-plugin-structured-data@^1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@stackql/docusaurus-plugin-structured-data/-/docusaurus-plugin-structured-data-1.6.0.tgz#caffcf6bfede64679b4ee05132494605d9449c73" + integrity sha512-vRGJHITOP54bPNLas5iIBpMXDQidB2ILDBVOhdj/Et4O175ux+taj7ZEcvS5pGmLpaHhZUKGCYG8jIxkb/uu0A== dependencies: jsdom "^21.0.0" @@ -3489,6 +3489,11 @@ balanced-match@^1.0.0: resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +balanced-match@^4.0.2: + version "4.0.4" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-4.0.4.tgz#bfb10662feed8196a2c62e7c68e17720c274179a" + integrity sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA== + batch@0.6.1: version "0.6.1" resolved "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz" @@ -3571,6 +3576,13 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +brace-expansion@^5.0.8: + version "5.0.12" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-5.0.12.tgz#995fbb4750a77c4d16a7dc942ff2ca6ef8e675ec" + integrity sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ== + dependencies: + balanced-match "^4.0.2" + braces@^3.0.3, braces@~3.0.2: version "3.0.3" resolved "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz" @@ -5118,6 +5130,15 @@ glob-to-regexp@^0.4.1: resolved "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== +glob@^13.0.3: + version "13.0.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-13.0.6.tgz#078666566a425147ccacfbd2e332deb66a2be71d" + integrity sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw== + dependencies: + minimatch "^10.2.2" + minipass "^7.1.3" + path-scurry "^2.0.2" + global-dirs@^3.0.0: version "3.0.1" resolved "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz" @@ -6112,6 +6133,11 @@ lowercase-keys@^3.0.0: resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz" integrity sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ== +lru-cache@^11.0.0: + version "11.5.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.5.3.tgz#a7767b4034e35269562d2b9da2b185b5df70c421" + integrity sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" @@ -6907,11 +6933,23 @@ minimatch@3.1.5: dependencies: brace-expansion "^1.1.7" +minimatch@^10.2.2: + version "10.2.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.2.6.tgz#fd956bbe0b77241e9f15ac5dccb1c638060968ef" + integrity sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A== + dependencies: + brace-expansion "^5.0.8" + minimist@^1.2.0: version "1.2.8" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== +minipass@^7.1.2, minipass@^7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.3.tgz#79389b4eb1bb2d003a9bba87d492f2bd37bdc65b" + integrity sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A== + mrmime@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz" @@ -7155,6 +7193,11 @@ p-timeout@^3.2.0: dependencies: p-finally "^1.0.0" +package-json-from-dist@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" + integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== + package-json@^8.1.0: version "8.1.1" resolved "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz" @@ -7256,6 +7299,14 @@ path-parse@^1.0.7: resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-scurry@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-2.0.2.tgz#6be0d0ee02a10d9e0de7a98bae65e182c9061f85" + integrity sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg== + dependencies: + lru-cache "^11.0.0" + minipass "^7.1.2" + path-to-regexp@3.3.0: version "3.3.0" resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.3.0.tgz" @@ -8425,6 +8476,14 @@ reusify@^1.0.4: resolved "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz" integrity sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw== +rimraf@^6.0.1: + version "6.1.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-6.1.3.tgz#afbee236b3bd2be331d4e7ce4493bac1718981af" + integrity sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA== + dependencies: + glob "^13.0.3" + package-json-from-dist "^1.0.1" + rrweb-cssom@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz#ed298055b97cbddcdeb278f904857629dec5e0e1" From 16030765a87063541592cda6ad2131852b288577 Mon Sep 17 00:00:00 2001 From: Jeffrey Aven Date: Tue, 6 Oct 2026 02:42:30 +1100 Subject: [PATCH 3/5] use selfUrl from the shared chrome --- CLAUDE.md | 11 +++++++---- docusaurus.config.js | 28 +++++++--------------------- 2 files changed, 14 insertions(+), 25 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 49907db6..de079009 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -151,14 +151,17 @@ this site's next build. This site cannot use the shared `createConfig` factory (it assumes a microsite at baseUrl `/` with its own preset), so [docusaurus.config.js](docusaurus.config.js) composes the pieces instead: `buildNavbar()`/`buildFooter()` for the chrome (logo href overridden to the -brand home, and AI Agents > Query Library pointed at `/` because that -destination is this site), `redirectsPlugin` for the main-site destinations +brand home; `selfUrl` tells the shared code that AI Agents > Query Library +is this site, so it becomes an internal link), `redirectsPlugin` for the +main-site destinations (one local route under baseUrl per link that client-side-forwards to the real page, so links are internal here: no external-link icon, they pass the broken-link checker, and they work on localhost and on the raw subdomain) and `redirectRoutes(baseUrl)` to keep those stub routes out of the sitemap -and of structured-data JSON-LD (the shared Redirect component noindexes -them). There are no `src/pages/` stubs; menu changes belong in the shared +and of structured-data JSON-LD. The shared Redirect pages carry a canonical +to their target and a zero-second meta refresh and are deliberately not +noindexed (noindex plus canonical is a contradictory signal, and a redirect +is never indexed). There are no `src/pages/` stubs; menu changes belong in the shared repo, whose README documents the composition contract ("Composing instead of createConfig") and whose menus must be kept in step with the main site's navbar/footer. The footer is the swizzled main-site footer diff --git a/docusaurus.config.js b/docusaurus.config.js index b9dd926c..af4f668d 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -41,28 +41,14 @@ const logo = { target: '_self', }; -// Shared navbar, with the one destination that IS this site - AI Agents > -// Query Library - pointing at the library landing instead of its shared -// redirect route. -const navbar = (() => { - const nav = shared.buildNavbar(); - return { - ...nav, - logo, - items: nav.items.map((item) => - item.type === 'dropdown' && item.label === 'AI Agents' - ? { - ...item, - items: item.items.map((child) => - child.label === 'Query Library' ? {...child, to: '/'} : child, - ), - } - : item, - ), - }; -})(); +// selfUrl tells the shared chrome which destination IS this site, so its +// menu entry (AI Agents > Query Library) becomes an internal link to the +// landing page instead of a redirect route that bounces back here. The +// shared code owns the comparison; nothing here names the label or path. +const selfUrl = `https://stackql.io${baseUrl}`; -const footer = {...shared.buildFooter(), logo}; +const navbar = {...shared.buildNavbar({selfUrl}), logo}; +const footer = {...shared.buildFooter({selfUrl}), logo}; /** @type {import('@docusaurus/types').Config} */ const config = { From 0b6ca1f2689a578adc7fb02f2dcecb95190bff8b Mon Sep 17 00:00:00 2001 From: Jeffrey Aven Date: Tue, 6 Oct 2026 02:52:03 +1100 Subject: [PATCH 4/5] redirect prefix-less direct hits to baseUrl before render --- CLAUDE.md | 17 +++++++++++------ docusaurus.config.js | 15 +++++++++++++++ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index de079009..ae051fd8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -39,12 +39,17 @@ Consequences: - Every emitted link, asset path and canonical URL carries the `/docs/query-library/` prefix, so pages work when proxied. - Browsing the raw subdomain or a Netlify deploy preview directly works - too: a non-forced 200 rewrite in [netlify.toml](netlify.toml) maps the - prefixed asset and page paths the HTML emits back to the origin root (the - proxy never sends prefixed paths, so production is unaffected). - Canonicalisation is via the `` tags Docusaurus - emits, not redirects. The origin must answer 200 to the proxy - never add - a blanket 301 to stackql.io here. + too, by two cooperating pieces: a non-forced 200 rewrite in + [netlify.toml](netlify.toml) maps the prefixed asset and page paths the + HTML emits back to the origin root, and an inline head script + (`headTags` in docusaurus.config.js) sends a prefix-less pathname to the + prefixed URL before render, because the client router only knows routes + under baseUrl and would otherwise swap the server-rendered page for Not + Found on hydration. The proxy never sends prefixed paths and the browser + URL there always carries the prefix, so neither piece fires in + production. Canonicalisation is via the `` tags + Docusaurus emits, not redirects. The origin must answer 200 to the proxy + - never add a server-side redirect from the root here. - The committed machine artifacts land in the build at `build/docs/query-library/` (static copy) while HTML lands at the build root; [netlify.toml](netlify.toml) has non-forced 200 rewrites that surface diff --git a/docusaurus.config.js b/docusaurus.config.js index af4f668d..7b071189 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -74,6 +74,21 @@ const config = { baseUrlIssueBanner: false, trailingSlash: false, headTags: [ + { + // Direct hits on this origin (Netlify deploy previews, the raw + // query-library.stackql.io host) arrive WITHOUT the baseUrl prefix: + // the HTML the server returns is right (netlify.toml maps the prefixed + // asset paths), but the client router only knows routes under + // baseUrl, so on hydration it matches nothing and swaps the page for + // Not Found - a flash of content, then a 404. Send such a hit to the + // prefixed URL before anything renders. Via the stackql.io proxy the + // pathname always carries the prefix, so this never fires there. A + // server-side redirect cannot do this: the proxy strips the prefix and + // needs the origin to keep answering 200 at the root. + tagName: 'script', + attributes: {}, + innerHTML: `(function(){var b='${baseUrl.replace(/\/$/, '')}';var p=location.pathname;if(p.indexOf(b+'/')===0)return;location.replace(b+(p===b?'/':p)+location.search+location.hash)})()`, + }, { tagName: 'link', attributes: { From 02becd1562c2af9a06b5e8a5617579756129fdd9 Mon Sep 17 00:00:00 2001 From: Jeffrey Aven Date: Tue, 6 Oct 2026 02:59:40 +1100 Subject: [PATCH 5/5] pass selfUrl to the shared redirects plugin --- CLAUDE.md | 6 ++++-- docusaurus.config.js | 25 +++++++++++++------------ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index ae051fd8..ef80d275 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -157,8 +157,10 @@ factory (it assumes a microsite at baseUrl `/` with its own preset), so [docusaurus.config.js](docusaurus.config.js) composes the pieces instead: `buildNavbar()`/`buildFooter()` for the chrome (logo href overridden to the brand home; `selfUrl` tells the shared code that AI Agents > Query Library -is this site, so it becomes an internal link), `redirectsPlugin` for the -main-site destinations +is this site, so it becomes an internal link and its redirect route is not +registered - that page would build to `docs/query-library.html`, which +Netlify's pretty URLs would serve in place of the baseUrl root on direct +hits), `redirectsPlugin` for the main-site destinations (one local route under baseUrl per link that client-side-forwards to the real page, so links are internal here: no external-link icon, they pass the broken-link checker, and they work on localhost and on the raw subdomain) diff --git a/docusaurus.config.js b/docusaurus.config.js index 7b071189..880b3ea1 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -27,10 +27,17 @@ const shared = require('./.shared-config/index.js'); const baseUrl = '/docs/query-library/'; +// selfUrl tells the shared chrome which destination IS this site: its menu +// entry (AI Agents > Query Library) becomes an internal link to the landing +// page, and its redirect route is not registered (a page redirecting to its +// own site, whose built file docs/query-library.html would otherwise shadow +// the baseUrl root on direct hits via Netlify's pretty URLs). The shared +// code owns the comparison; nothing here names the label or path. +const selfUrl = `https://stackql.io${baseUrl}`; + // Full public route paths of the shared redirect stubs: kept out of the -// sitemap and of structured-data JSON-LD emission below (the shared -// Redirect component noindexes them). -const redirectStubRoutes = shared.redirectRoutes(baseUrl); +// sitemap and of structured-data JSON-LD emission below. +const redirectStubRoutes = shared.redirectRoutes(baseUrl, {selfUrl}); // The site logo goes to the brand home, not this site's root (the shared // default suits a microsite whose root is its own landing page). An @@ -41,12 +48,6 @@ const logo = { target: '_self', }; -// selfUrl tells the shared chrome which destination IS this site, so its -// menu entry (AI Agents > Query Library) becomes an internal link to the -// landing page instead of a redirect route that bounces back here. The -// shared code owns the comparison; nothing here names the label or path. -const selfUrl = `https://stackql.io${baseUrl}`; - const navbar = {...shared.buildNavbar({selfUrl}), logo}; const footer = {...shared.buildFooter({selfUrl}), logo}; @@ -106,9 +107,9 @@ const config = { }, ], plugins: [ - // Local redirect routes for every shared main-site destination (see the - // chrome note at the top of this file). - shared.redirectsPlugin, + // Local redirect routes for every shared main-site destination except + // this site itself (see the selfUrl note at the top of this file). + [shared.redirectsPlugin, {selfUrl}], '@stackql/docusaurus-plugin-structured-data', [ '@stackql/docusaurus-plugin-aeo',