Ctrl K
ComunidadGuías…

documentation/docusaurus.config.js

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// @ts-check
// `@type` JSDoc annotations allow editor autocompletion and type checking
// (when paired with `@ts-check`).
// There are various equivalent ways to declare your Docusaurus config.
// See: https://docusaurus.io/docs/api/docusaurus-config

import { themes as prismThemes } from "prism-react-renderer";
import poimandresTheme from "./src/prism/poimandres.js";
import path from "path";
import fs from "fs/promises";
import { fileURLToPath } from "url";
import sidebars from "./sidebars.js";
import { buildLlmsTxt, buildLlmsFullTxt } from "./scripts/generate-llms-txt.js";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// Opening line of /llms.txt. An assistant reads it before it reads anything
// else, so it says what Hook0 does and under what licence, in one breath.
const LLMS_TXT_SUMMARY =
  "Hook0 sends webhooks on your behalf: one API call per event, HMAC signatures, " +
  "retries with a dead letter queue, delivery logs, and a subscriber portal your " +
  "customers manage themselves. Open-source (SSPL-1.0) — self-host it, or use the " +
  "cloud hosted in the EU (France). Every page published here is listed below.";

const url = process.env.DOCUMENTATION_URL || "http://localhost:3000/";
const baseUrl = process.env.DOCUMENTATION_BASE_URL || "/";

/** @type {import('@docusaurus/types').Config} */
const config = {
  title: "Hook0 Documentation",
  tagline:
    "Comprehensive documentation for Hook0 - The open-source webhook server",
  favicon: "favicon.ico",

  future: {
    v4: {
      removeLegacyPostBuildHeadAttribute: true,
      fasterByDefault: true,
    },
  },

  // Set the production url of your site here
  url,
  // Set the /<baseUrl>/ pathname under which your site is served
  baseUrl,

  // GitLab pages deployment config.
  organizationName: "hook0",
  projectName: "hook0",

  trailingSlash: false,
  onBrokenLinks: "throw",

  staticDirectories: ["static"],

  // Even if you don't use internationalization, you can use this field to set
  // useful metadata like html lang. For example, if your site is Chinese, you
  // may want to replace "en" with "zh-Hans".
  i18n: {
    defaultLocale: "en",
    locales: ["en"],
  },

  presets: [
    [
      "classic",
      /** @type {import('@docusaurus/preset-classic').Options} */
      ({
        docs: {
          path: ".",
          sidebarPath: "./sidebars.js",
          routeBasePath: "/",
          editUrl: "https://gitlab.com/hook0/hook0/-/tree/master/documentation/",
          exclude: [
            "**/node_modules/**",
            "**/build/**",
            "**/.docusaurus/**",
            "**/scripts/**",
            "**/CLAUDE.md",
            // The harnesses the SDK examples are assembled into, and the note explaining them.
            // They live beside the pages so that whoever edits a snippet can see what it stands
            // on, and they are addressed to that person rather than to a reader of the product.
            "**/reference/sdk/examples/**",
          ],
        },
        sitemap: {
          ignorePatterns: ['/search', '/search/**', '/self-hosting/_dev-only-warning', '/CLAUDE'],
        },
        blog: false,
        theme: {
          customCss: "./src/css/custom.css",
        },
      }),
    ],
  ],

  plugins: [
    // Inline build-time env vars pulled in via @shared/website-data (website/data.js)
    // so they don't leak `process.env.*` into the browser bundle. Without this, the
    // literal `process.env.LOCAL_PREVIEW_URL` reaches the client and throws
    // "ReferenceError: process is not defined" (most visibly on the client-rendered /api page).
    // `currentBundler.instance` resolves to the active bundler (Rspack under `future.faster`).
    () => ({
      name: "define-shared-env",
      configureWebpack: (_config, _isServer, utils) => ({
        plugins: [
          new utils.currentBundler.instance.DefinePlugin({
            "process.env.LOCAL_PREVIEW_URL": JSON.stringify(
              process.env.LOCAL_PREVIEW_URL || ""
            ),
          }),
        ],
      }),
    }),
    // Module alias plugin to import shared data from website/
    // Without this, importing via relative path (../../../../website/...) causes Webpack
    // to watch the entire parent directory, leading to EMFILE "too many open files" errors
    [
      "docusaurus-plugin-module-alias",
      {
        alias: {
          "@shared/website-data": path.resolve(__dirname, "../website/data.js"),
        },
      },
    ],
    // @scalar/docusaurus, minus the script it adds to every page: the API
    // reference bundle now loads only when /api renders (src/scalar/lazy-plugin.js).
    [
      require.resolve("./src/scalar/lazy-plugin.js"),
      {
        label: "API Reference",
        route: "/api",
        showNavLink: false,
        configuration: {
          spec: {
            url: `${baseUrl}hook0-api.json`,
          },
          theme: "none",
          authentication: {
            preferredSecurityScheme: "apiToken",
          },
          customCss: `@import url('https://unpkg.com/highlight.js@11.11.1/styles/night-owl.min.css');`,
        },
      },
    ],
    // Publishes /llms.txt and /llms-full.txt: the index an assistant reads before
    // answering a question about Hook0, and its full-text companion — every page
    // inlined whole, in the same order — so a model can read the documentation in
    // one file the way svix and webhookrelay already serve theirs. www.hook0.com
    // serves an index and points here; the documentation, where the answers live,
    // served neither. Built from the pages Docusaurus has just emitted and ordered
    // by the same sidebar as the navigation, so a page added tomorrow appears on
    // its own.
    () => ({
      name: "generate-llms-txt",
      async postBuild({ siteConfig, outDir, plugins }) {
        const docsPlugin = plugins.find(
          (plugin) => plugin.name === "docusaurus-plugin-content-docs"
        );
        if (!docsPlugin?.content?.loadedVersions?.length) {
          throw new Error(
            "generate-llms-txt: no loaded docs version to index. The docs " +
              "plugin moved or changed shape; llms.txt would be published empty."
          );
        }

        const loaded = docsPlugin.content.loadedVersions.flatMap(
          (version) => version.docs
        );

        const siteUrl = siteConfig.url + siteConfig.baseUrl;
        const sidebarItems = sidebars.tutorialSidebar;

        const docs = loaded.map(({ id, title, description, permalink }) => ({
          id,
          title,
          description,
          permalink,
        }));

        await fs.writeFile(
          path.join(outDir, "llms.txt"),
          buildLlmsTxt({
            siteUrl,
            title: siteConfig.title,
            summary: LLMS_TXT_SUMMARY,
            sidebarItems,
            docs,
          }),
          "utf8"
        );

        // Docusaurus points each doc at its Markdown source through the `@site`
        // alias; `__dirname` is that site directory, so the alias resolves to the
        // file it built the page from.
        const fullDocs = await Promise.all(
          loaded.map(async ({ id, title, permalink, source }) => ({
            id,
            title,
            permalink,
            content: await fs.readFile(
              path.join(__dirname, source.replace(/^@site\//, "")),
              "utf8"
            ),
          }))
        );

        await fs.writeFile(
          path.join(outDir, "llms-full.txt"),
          buildLlmsFullTxt({
            siteUrl,
            title: siteConfig.title,
            summary: LLMS_TXT_SUMMARY,
            sidebarItems,
            docs: fullDocs,
          }),
          "utf8"
        );
      },
    }),
  ],

  themes: [
    "@docusaurus/theme-mermaid",
    [
      require.resolve("@easyops-cn/docusaurus-search-local"),
      {
        hashed: true,
        language: ["en", "fr"],
        highlightSearchTermsOnTargetPage: true,
        explicitSearchResultPath: true,
        docsDir: ".",
        docsRouteBasePath: "/",
      },
    ],
  ],

  markdown: {
    mermaid: true,
    hooks: {
      onBrokenMarkdownLinks: "throw",
    },
  },

  // Client modules for Matomo advanced tracking
  clientModules: [
    require.resolve("./src/mermaid/theme-switcher.js"),
    // Re-navigates the Scalar API reference to a hash permalink on hard load, so
    // /api#tag/.../GET/... deep links open the endpoint instead of the overview
    // after a refresh or when opened in a new tab (HOO-123).
    require.resolve("./src/scalar/deep-link-restore.js"),
    ...(process.env.DOCUMENTATION_MATOMO_URL
      ? [require.resolve("./src/matomo/tracking.js")]
      : []),
  ],

  // Matomo analytics script (injected in <head>)
  // Uses same configuration as website (piwik.php/piwik.js)
  // Site ID 3 is for documentation
  headTags:
    process.env.DOCUMENTATION_MATOMO_URL && process.env.DOCUMENTATION_MATOMO_SITE_ID
      ? [
          {
            tagName: "script",
            attributes: {},
            innerHTML: `
              var _paq = window._paq = window._paq || [];
              /* Custom dimension 1 = Content Type (Diataxis) - set by tracking.js */
              _paq.push(['enableLinkTracking']);
              _paq.push(['setLinkTrackingTimer', 500]);
              (function() {
                var u="${process.env.DOCUMENTATION_MATOMO_URL}";
                _paq.push(['setTrackerUrl', u+'piwik.php']);
                _paq.push(['setSiteId', '${process.env.DOCUMENTATION_MATOMO_SITE_ID}']);
                var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
                g.async=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
              })();
            `,
          },
        ]
      : [],

  themeConfig:
    /** @type {import('@docusaurus/preset-classic').ThemeConfig} */
    ({
      // Social card for og:image / twitter:image. An absolute URL hosted on the
      // main site rather than a local file: img/hook0-social-card.jpg never
      // existed in the repo (every docs page emitted a broken preview), and a
      // raster committed under this static/ dir would ship as an LFS pointer,
      // since the docs build does no LFS smudge. website serves it reliably.
      // This is the doc-specific 1200x630 card, next to the site's own one.
      image: "https://www.hook0.com/img/hook0-doc-social-card.png",
      navbar: {
        title: "Hook0",
        logo: {
          alt: "Hook0 Logo",
          src: "img/logo.svg",
          href: "https://www.hook0.com",
        },
        items: [
          // Left side
          {
            to: "/",
            label: "Documentation",
            position: "left",
            activeBaseRegex: "^/hook0/(?!tutorials|api).*$|^/hook0/$",
          },
          {
            to: "/tutorials",
            label: "Tutorials",
            position: "left",
            activeBaseRegex: "^/hook0/tutorials(/.*)?$",
          },
          {
            to: "/api",
            label: "Reference",
            position: "left",
            activeBaseRegex: "^/hook0/api(/.*)?$",
          },
          // Right side
          {
            href: "https://play.hook0.com",
            label: "Play",
            position: "right",
            className: "navbar__item--no-external-icon",
          },
          {
            href: "mailto:support@hook0.com",
            label: "Contact",
            position: "right",
            className: "navbar__item--no-external-icon",
          },
          {
            href: "https://app.hook0.com/",
            label: "Login",
            position: "right",
            className: "navbar__item--no-external-icon",
          },
          {
            href: "https://app.hook0.com/register",
            label: "Get Started →",
            position: "right",
            className: "navbar__item--primary navbar__item--no-external-icon",
          },
        ],
      },
      // Footer is handled by custom component in src/theme/Footer
      prism: {
        theme: prismThemes.github,
        darkTheme: poimandresTheme,
        // One entry per language an SDK page shows code in; a language absent here
        // renders as plain text.
        additionalLanguages: [
          "rust",
          "bash",
          "json",
          "yaml",
          "toml",
          "python",
          "go",
          "ruby",
          "php",
          "csharp",
          "java",
          "kotlin",
          "lua",
          "zig",
        ],
      },
      // announcementBar: {
      //   id: "hook0_v2",
      //   content:
      //     '🚀 Hook0 v2.0 is now available! Check out the <a href="/tutorials/getting-started">updated getting started guide</a> and <a href="https://github.com/hook0/hook0/releases">release notes</a>.',
      //   backgroundColor: "#4ade80",
      //   textColor: "#ffffff",
      //   isCloseable: true,
      // },
      colorMode: {
        defaultMode: "dark",
        disableSwitch: false,
        respectPrefersColorScheme: true,
      },
      mermaid: {
        theme: {
          light: 'base',
          dark: 'dark',
        },
      },
      docs: {
        sidebar: {
          hideable: true,
          autoCollapseCategories: true,
        },
      },
    }),
};

export default config;