jamdesk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +323 -0
- package/bin/jamdesk.js +76 -0
- package/dist/__tests__/integration/deprecated-components.integration.test.d.ts +8 -0
- package/dist/__tests__/integration/deprecated-components.integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration/deprecated-components.integration.test.js +165 -0
- package/dist/__tests__/integration/deprecated-components.integration.test.js.map +1 -0
- package/dist/__tests__/integration/migrate.integration.test.d.ts +2 -0
- package/dist/__tests__/integration/migrate.integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration/migrate.integration.test.js +64 -0
- package/dist/__tests__/integration/migrate.integration.test.js.map +1 -0
- package/dist/__tests__/integration/prepublish.integration.test.d.ts +2 -0
- package/dist/__tests__/integration/prepublish.integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration/prepublish.integration.test.js +27 -0
- package/dist/__tests__/integration/prepublish.integration.test.js.map +1 -0
- package/dist/__tests__/integration/validate.integration.test.d.ts +2 -0
- package/dist/__tests__/integration/validate.integration.test.d.ts.map +1 -0
- package/dist/__tests__/integration/validate.integration.test.js +56 -0
- package/dist/__tests__/integration/validate.integration.test.js.map +1 -0
- package/dist/__tests__/unit/deploy-templates.test.d.ts +2 -0
- package/dist/__tests__/unit/deploy-templates.test.d.ts.map +1 -0
- package/dist/__tests__/unit/deploy-templates.test.js +124 -0
- package/dist/__tests__/unit/deploy-templates.test.js.map +1 -0
- package/dist/__tests__/unit/deprecated-components-sync.test.d.ts +2 -0
- package/dist/__tests__/unit/deprecated-components-sync.test.d.ts.map +1 -0
- package/dist/__tests__/unit/deprecated-components-sync.test.js +69 -0
- package/dist/__tests__/unit/deprecated-components-sync.test.js.map +1 -0
- package/dist/__tests__/unit/deps-sync.test.d.ts +14 -0
- package/dist/__tests__/unit/deps-sync.test.d.ts.map +1 -0
- package/dist/__tests__/unit/deps-sync.test.js +166 -0
- package/dist/__tests__/unit/deps-sync.test.js.map +1 -0
- package/dist/__tests__/unit/docs-config.test.d.ts +2 -0
- package/dist/__tests__/unit/docs-config.test.d.ts.map +1 -0
- package/dist/__tests__/unit/docs-config.test.js +288 -0
- package/dist/__tests__/unit/docs-config.test.js.map +1 -0
- package/dist/__tests__/unit/errors.test.d.ts +2 -0
- package/dist/__tests__/unit/errors.test.d.ts.map +1 -0
- package/dist/__tests__/unit/errors.test.js +27 -0
- package/dist/__tests__/unit/errors.test.js.map +1 -0
- package/dist/__tests__/unit/extract-hooks.test.d.ts +5 -0
- package/dist/__tests__/unit/extract-hooks.test.d.ts.map +1 -0
- package/dist/__tests__/unit/extract-hooks.test.js +205 -0
- package/dist/__tests__/unit/extract-hooks.test.js.map +1 -0
- package/dist/__tests__/unit/frontmatter-sync.test.d.ts +8 -0
- package/dist/__tests__/unit/frontmatter-sync.test.d.ts.map +1 -0
- package/dist/__tests__/unit/frontmatter-sync.test.js +26 -0
- package/dist/__tests__/unit/frontmatter-sync.test.js.map +1 -0
- package/dist/__tests__/unit/mdx-validator.test.d.ts +2 -0
- package/dist/__tests__/unit/mdx-validator.test.d.ts.map +1 -0
- package/dist/__tests__/unit/mdx-validator.test.js +264 -0
- package/dist/__tests__/unit/mdx-validator.test.js.map +1 -0
- package/dist/__tests__/unit/migrate-convert.test.d.ts +2 -0
- package/dist/__tests__/unit/migrate-convert.test.d.ts.map +1 -0
- package/dist/__tests__/unit/migrate-convert.test.js +297 -0
- package/dist/__tests__/unit/migrate-convert.test.js.map +1 -0
- package/dist/__tests__/unit/migrate-detect.test.d.ts +2 -0
- package/dist/__tests__/unit/migrate-detect.test.d.ts.map +1 -0
- package/dist/__tests__/unit/migrate-detect.test.js +35 -0
- package/dist/__tests__/unit/migrate-detect.test.js.map +1 -0
- package/dist/__tests__/unit/migrate-mdx.test.d.ts +2 -0
- package/dist/__tests__/unit/migrate-mdx.test.d.ts.map +1 -0
- package/dist/__tests__/unit/migrate-mdx.test.js +158 -0
- package/dist/__tests__/unit/migrate-mdx.test.js.map +1 -0
- package/dist/__tests__/unit/openapi.test.d.ts +2 -0
- package/dist/__tests__/unit/openapi.test.d.ts.map +1 -0
- package/dist/__tests__/unit/openapi.test.js +52 -0
- package/dist/__tests__/unit/openapi.test.js.map +1 -0
- package/dist/__tests__/unit/package-config.test.d.ts +2 -0
- package/dist/__tests__/unit/package-config.test.d.ts.map +1 -0
- package/dist/__tests__/unit/package-config.test.js +63 -0
- package/dist/__tests__/unit/package-config.test.js.map +1 -0
- package/dist/__tests__/unit/port.test.d.ts +2 -0
- package/dist/__tests__/unit/port.test.d.ts.map +1 -0
- package/dist/__tests__/unit/port.test.js +20 -0
- package/dist/__tests__/unit/port.test.js.map +1 -0
- package/dist/__tests__/unit/vendored-sync.test.d.ts +14 -0
- package/dist/__tests__/unit/vendored-sync.test.d.ts.map +1 -0
- package/dist/__tests__/unit/vendored-sync.test.js +90 -0
- package/dist/__tests__/unit/vendored-sync.test.js.map +1 -0
- package/dist/commands/broken-links.d.ts +11 -0
- package/dist/commands/broken-links.d.ts.map +1 -0
- package/dist/commands/broken-links.js +95 -0
- package/dist/commands/broken-links.js.map +1 -0
- package/dist/commands/clean.d.ts +7 -0
- package/dist/commands/clean.d.ts.map +1 -0
- package/dist/commands/clean.js +59 -0
- package/dist/commands/clean.js.map +1 -0
- package/dist/commands/deploy/cloudflare.d.ts +12 -0
- package/dist/commands/deploy/cloudflare.d.ts.map +1 -0
- package/dist/commands/deploy/cloudflare.js +409 -0
- package/dist/commands/deploy/cloudflare.js.map +1 -0
- package/dist/commands/deploy/templates.d.ts +23 -0
- package/dist/commands/deploy/templates.d.ts.map +1 -0
- package/dist/commands/deploy/templates.js +179 -0
- package/dist/commands/deploy/templates.js.map +1 -0
- package/dist/commands/deploy/types.d.ts +19 -0
- package/dist/commands/deploy/types.d.ts.map +1 -0
- package/dist/commands/deploy/types.js +5 -0
- package/dist/commands/deploy/types.js.map +1 -0
- package/dist/commands/dev.d.ts +14 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +817 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/doctor.d.ts +7 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +159 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/init.d.ts +7 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +96 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/migrate/convert-mdx.d.ts +50 -0
- package/dist/commands/migrate/convert-mdx.d.ts.map +1 -0
- package/dist/commands/migrate/convert-mdx.js +108 -0
- package/dist/commands/migrate/convert-mdx.js.map +1 -0
- package/dist/commands/migrate/convert.d.ts +80 -0
- package/dist/commands/migrate/convert.d.ts.map +1 -0
- package/dist/commands/migrate/convert.js +158 -0
- package/dist/commands/migrate/convert.js.map +1 -0
- package/dist/commands/migrate/detect.d.ts +31 -0
- package/dist/commands/migrate/detect.d.ts.map +1 -0
- package/dist/commands/migrate/detect.js +62 -0
- package/dist/commands/migrate/detect.js.map +1 -0
- package/dist/commands/migrate/extract-hooks.d.ts +71 -0
- package/dist/commands/migrate/extract-hooks.d.ts.map +1 -0
- package/dist/commands/migrate/extract-hooks.js +473 -0
- package/dist/commands/migrate/extract-hooks.js.map +1 -0
- package/dist/commands/migrate/index.d.ts +17 -0
- package/dist/commands/migrate/index.d.ts.map +1 -0
- package/dist/commands/migrate/index.js +282 -0
- package/dist/commands/migrate/index.js.map +1 -0
- package/dist/commands/migrate/prompts.d.ts +22 -0
- package/dist/commands/migrate/prompts.d.ts.map +1 -0
- package/dist/commands/migrate/prompts.js +67 -0
- package/dist/commands/migrate/prompts.js.map +1 -0
- package/dist/commands/migrate/types.d.ts +22 -0
- package/dist/commands/migrate/types.d.ts.map +1 -0
- package/dist/commands/migrate/types.js +26 -0
- package/dist/commands/migrate/types.js.map +1 -0
- package/dist/commands/openapi-check.d.ts +11 -0
- package/dist/commands/openapi-check.d.ts.map +1 -0
- package/dist/commands/openapi-check.js +88 -0
- package/dist/commands/openapi-check.js.map +1 -0
- package/dist/commands/rename.d.ts +10 -0
- package/dist/commands/rename.d.ts.map +1 -0
- package/dist/commands/rename.js +125 -0
- package/dist/commands/rename.js.map +1 -0
- package/dist/commands/update.d.ts +10 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +57 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/validate.d.ts +12 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +163 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +334 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/config.d.ts +7 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +18 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/deprecated-components.d.ts +72 -0
- package/dist/lib/deprecated-components.d.ts.map +1 -0
- package/dist/lib/deprecated-components.js +138 -0
- package/dist/lib/deprecated-components.js.map +1 -0
- package/dist/lib/deps.d.ts +17 -0
- package/dist/lib/deps.d.ts.map +1 -0
- package/dist/lib/deps.js +186 -0
- package/dist/lib/deps.js.map +1 -0
- package/dist/lib/docs-config.d.ts +67 -0
- package/dist/lib/docs-config.d.ts.map +1 -0
- package/dist/lib/docs-config.js +294 -0
- package/dist/lib/docs-config.js.map +1 -0
- package/dist/lib/errors.d.ts +23 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +32 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/frontmatter-utils.d.ts +25 -0
- package/dist/lib/frontmatter-utils.d.ts.map +1 -0
- package/dist/lib/frontmatter-utils.js +64 -0
- package/dist/lib/frontmatter-utils.js.map +1 -0
- package/dist/lib/mdx-validator.d.ts +27 -0
- package/dist/lib/mdx-validator.d.ts.map +1 -0
- package/dist/lib/mdx-validator.js +148 -0
- package/dist/lib/mdx-validator.js.map +1 -0
- package/dist/lib/navigation-validator.d.ts +31 -0
- package/dist/lib/navigation-validator.d.ts.map +1 -0
- package/dist/lib/navigation-validator.js +75 -0
- package/dist/lib/navigation-validator.js.map +1 -0
- package/dist/lib/normalize-config.d.ts +57 -0
- package/dist/lib/normalize-config.d.ts.map +1 -0
- package/dist/lib/normalize-config.js +63 -0
- package/dist/lib/normalize-config.js.map +1 -0
- package/dist/lib/openapi/cache.d.ts +40 -0
- package/dist/lib/openapi/cache.d.ts.map +1 -0
- package/dist/lib/openapi/cache.js +76 -0
- package/dist/lib/openapi/cache.js.map +1 -0
- package/dist/lib/openapi/errors.d.ts +36 -0
- package/dist/lib/openapi/errors.d.ts.map +1 -0
- package/dist/lib/openapi/errors.js +162 -0
- package/dist/lib/openapi/errors.js.map +1 -0
- package/dist/lib/openapi/index.d.ts +10 -0
- package/dist/lib/openapi/index.d.ts.map +1 -0
- package/dist/lib/openapi/index.js +12 -0
- package/dist/lib/openapi/index.js.map +1 -0
- package/dist/lib/openapi/types.d.ts +198 -0
- package/dist/lib/openapi/types.d.ts.map +1 -0
- package/dist/lib/openapi/types.js +8 -0
- package/dist/lib/openapi/types.js.map +1 -0
- package/dist/lib/openapi/validator.d.ts +45 -0
- package/dist/lib/openapi/validator.d.ts.map +1 -0
- package/dist/lib/openapi/validator.js +128 -0
- package/dist/lib/openapi/validator.js.map +1 -0
- package/dist/lib/openapi.d.ts +7 -0
- package/dist/lib/openapi.d.ts.map +1 -0
- package/dist/lib/openapi.js +7 -0
- package/dist/lib/openapi.js.map +1 -0
- package/dist/lib/output.d.ts +14 -0
- package/dist/lib/output.d.ts.map +1 -0
- package/dist/lib/output.js +19 -0
- package/dist/lib/output.js.map +1 -0
- package/dist/lib/path-security.d.ts +23 -0
- package/dist/lib/path-security.d.ts.map +1 -0
- package/dist/lib/path-security.js +35 -0
- package/dist/lib/path-security.js.map +1 -0
- package/dist/lib/port.d.ts +18 -0
- package/dist/lib/port.d.ts.map +1 -0
- package/dist/lib/port.js +65 -0
- package/dist/lib/port.js.map +1 -0
- package/dist/lib/spinner.d.ts +4 -0
- package/dist/lib/spinner.d.ts.map +1 -0
- package/dist/lib/spinner.js +16 -0
- package/dist/lib/spinner.js.map +1 -0
- package/dist/lib/version.d.ts +2 -0
- package/dist/lib/version.d.ts.map +1 -0
- package/dist/lib/version.js +49 -0
- package/dist/lib/version.js.map +1 -0
- package/dist/utils/update-checker.d.ts +34 -0
- package/dist/utils/update-checker.d.ts.map +1 -0
- package/dist/utils/update-checker.js +142 -0
- package/dist/utils/update-checker.js.map +1 -0
- package/package.json +125 -0
- package/templates/docs.json +11 -0
- package/templates/introduction.mdx +19 -0
- package/templates/quickstart.mdx +20 -0
- package/vendored/app/[[...slug]]/error.tsx +103 -0
- package/vendored/app/[[...slug]]/page.tsx +690 -0
- package/vendored/app/api/assets/[...path]/route.ts +78 -0
- package/vendored/app/api/ev/route.ts +61 -0
- package/vendored/app/api/isr-health/route.ts +66 -0
- package/vendored/app/api/mcp/[project]/route.ts +435 -0
- package/vendored/app/api/og/route.tsx +167 -0
- package/vendored/app/api/r2/[project]/[...path]/route.ts +214 -0
- package/vendored/app/api/revalidate/route.ts +76 -0
- package/vendored/app/globals.css +37 -0
- package/vendored/app/layout.tsx +571 -0
- package/vendored/app/not-found.tsx +47 -0
- package/vendored/components/CodeBlockCopyButton.tsx +146 -0
- package/vendored/components/HeaderLinkCopy.tsx +135 -0
- package/vendored/components/errors/NotFoundContent.tsx +147 -0
- package/vendored/components/layout/LayoutWrapper.tsx +128 -0
- package/vendored/components/mdx/Accordion.tsx +91 -0
- package/vendored/components/mdx/ApiCodePanel.tsx +51 -0
- package/vendored/components/mdx/ApiEndpoint.tsx +104 -0
- package/vendored/components/mdx/ApiPage.tsx +379 -0
- package/vendored/components/mdx/Badge.tsx +169 -0
- package/vendored/components/mdx/Callouts.tsx +140 -0
- package/vendored/components/mdx/Card.tsx +214 -0
- package/vendored/components/mdx/CodeGroup.tsx +136 -0
- package/vendored/components/mdx/Color.tsx +244 -0
- package/vendored/components/mdx/Columns.tsx +37 -0
- package/vendored/components/mdx/Expandable.tsx +37 -0
- package/vendored/components/mdx/Frame.tsx +51 -0
- package/vendored/components/mdx/Icon.tsx +132 -0
- package/vendored/components/mdx/Latex.tsx +75 -0
- package/vendored/components/mdx/MDXComponents.tsx +414 -0
- package/vendored/components/mdx/Mermaid.tsx +35 -0
- package/vendored/components/mdx/MermaidInner.tsx +342 -0
- package/vendored/components/mdx/OpenApiEndpoint.tsx +971 -0
- package/vendored/components/mdx/Panel.tsx +26 -0
- package/vendored/components/mdx/PanelWrapper.tsx +100 -0
- package/vendored/components/mdx/ParamField.tsx +75 -0
- package/vendored/components/mdx/RequestExample.tsx +91 -0
- package/vendored/components/mdx/ResponseExample.tsx +145 -0
- package/vendored/components/mdx/ResponseField.tsx +109 -0
- package/vendored/components/mdx/Steps.tsx +173 -0
- package/vendored/components/mdx/Table.tsx +352 -0
- package/vendored/components/mdx/Tabs.tsx +147 -0
- package/vendored/components/mdx/Tile.tsx +127 -0
- package/vendored/components/mdx/Tooltip.tsx +111 -0
- package/vendored/components/mdx/Tree.tsx +484 -0
- package/vendored/components/mdx/Update.tsx +90 -0
- package/vendored/components/mdx/View.tsx +354 -0
- package/vendored/components/mdx/YouTube.tsx +35 -0
- package/vendored/components/mdx/ZoomableImage.tsx +83 -0
- package/vendored/components/navigation/Breadcrumb.tsx +241 -0
- package/vendored/components/navigation/DefaultLogo.tsx +81 -0
- package/vendored/components/navigation/Header.tsx +512 -0
- package/vendored/components/navigation/LanguageSelector.tsx +249 -0
- package/vendored/components/navigation/PageNavigation.tsx +174 -0
- package/vendored/components/navigation/Sidebar.tsx +713 -0
- package/vendored/components/navigation/SocialFooter.tsx +186 -0
- package/vendored/components/navigation/TableOfContents.tsx +435 -0
- package/vendored/components/navigation/TabsNav.tsx +182 -0
- package/vendored/components/search/LazySearchModal.tsx +19 -0
- package/vendored/components/search/SearchModal.tsx +573 -0
- package/vendored/components/snippets/ProjectSnippets.tsx +4 -0
- package/vendored/components/theme/ThemeProvider.tsx +31 -0
- package/vendored/components/theme/ThemeToggle.tsx +134 -0
- package/vendored/components/ui/CodePanel.tsx +517 -0
- package/vendored/components/ui/CodePanelModal.tsx +342 -0
- package/vendored/contexts/TabSyncContext.tsx +30 -0
- package/vendored/hooks/useFocusTrap.ts +42 -0
- package/vendored/hooks/useHashNavigation.ts +39 -0
- package/vendored/hooks/useShikiHighlight.ts +101 -0
- package/vendored/lib/analytics-client.ts +77 -0
- package/vendored/lib/build/cache.ts +138 -0
- package/vendored/lib/build/error-parser.ts +690 -0
- package/vendored/lib/build/estimation.ts +113 -0
- package/vendored/lib/build/index.ts +17 -0
- package/vendored/lib/build/page-file-map.ts +48 -0
- package/vendored/lib/build/r2-upload.ts +179 -0
- package/vendored/lib/cache-keys.ts +117 -0
- package/vendored/lib/code-utils.ts +42 -0
- package/vendored/lib/content-loader.ts +176 -0
- package/vendored/lib/deprecated-components.ts +185 -0
- package/vendored/lib/docs-isr.ts +180 -0
- package/vendored/lib/docs-types.ts +874 -0
- package/vendored/lib/docs.ts +203 -0
- package/vendored/lib/domain-helpers.ts +107 -0
- package/vendored/lib/email-notifier.ts +102 -0
- package/vendored/lib/email-templates/build-failure.tsx +193 -0
- package/vendored/lib/email-templates/components/base-layout.tsx +150 -0
- package/vendored/lib/email-templates/components/error-box.tsx +88 -0
- package/vendored/lib/email-templates/components/info-row.tsx +63 -0
- package/vendored/lib/email-templates/index.ts +13 -0
- package/vendored/lib/empty-polyfill.js +3 -0
- package/vendored/lib/extract-highlights.ts +124 -0
- package/vendored/lib/fonts.ts +227 -0
- package/vendored/lib/frontmatter-utils.ts +77 -0
- package/vendored/lib/fs-utils.ts +20 -0
- package/vendored/lib/git-utils.ts +87 -0
- package/vendored/lib/health-checks.ts +224 -0
- package/vendored/lib/icon-utils.ts +492 -0
- package/vendored/lib/infer-page-type.ts +14 -0
- package/vendored/lib/isr-build-executor.ts +185 -0
- package/vendored/lib/language-icons.ts +152 -0
- package/vendored/lib/language-utils.ts +338 -0
- package/vendored/lib/latex-config.ts +64 -0
- package/vendored/lib/link-prefix-context.tsx +32 -0
- package/vendored/lib/logger.ts +63 -0
- package/vendored/lib/mcp-search.ts +255 -0
- package/vendored/lib/mdx-inline-components.ts +155 -0
- package/vendored/lib/mdx.ts +100 -0
- package/vendored/lib/middleware-helpers.ts +519 -0
- package/vendored/lib/navigation-resolver.ts +621 -0
- package/vendored/lib/navigation-utils.ts +103 -0
- package/vendored/lib/normalize-config.ts +94 -0
- package/vendored/lib/openapi/cache.ts +92 -0
- package/vendored/lib/openapi/code-examples.ts +389 -0
- package/vendored/lib/openapi/errors.ts +253 -0
- package/vendored/lib/openapi/generator.ts +230 -0
- package/vendored/lib/openapi/index.ts +84 -0
- package/vendored/lib/openapi/parser.ts +474 -0
- package/vendored/lib/openapi/types.ts +232 -0
- package/vendored/lib/openapi/validator.ts +156 -0
- package/vendored/lib/openapi-isr.ts +121 -0
- package/vendored/lib/page-isr-helpers.ts +137 -0
- package/vendored/lib/path-safety.ts +130 -0
- package/vendored/lib/paths.ts +35 -0
- package/vendored/lib/preprocess-mdx.ts +951 -0
- package/vendored/lib/process-mdx-with-exports.ts +75 -0
- package/vendored/lib/project-resolver.ts +165 -0
- package/vendored/lib/r2-content.ts +60 -0
- package/vendored/lib/r2-manifest.ts +84 -0
- package/vendored/lib/recent-searches.ts +41 -0
- package/vendored/lib/recma-compound-components.ts +84 -0
- package/vendored/lib/redirect-compiler.ts +160 -0
- package/vendored/lib/redirect-matcher.ts +296 -0
- package/vendored/lib/redis.ts +23 -0
- package/vendored/lib/rehype-class-to-classname.ts +31 -0
- package/vendored/lib/rehype-code-meta.ts +275 -0
- package/vendored/lib/rehype-nozoom-to-data.ts +45 -0
- package/vendored/lib/remark-extract-exports.ts +104 -0
- package/vendored/lib/resilience.ts +260 -0
- package/vendored/lib/revalidation-helpers.ts +200 -0
- package/vendored/lib/revalidation-trigger.ts +150 -0
- package/vendored/lib/screenshot-capture.ts +229 -0
- package/vendored/lib/search-client.ts +91 -0
- package/vendored/lib/search-suggestions.ts +38 -0
- package/vendored/lib/search.ts +158 -0
- package/vendored/lib/seo.ts +264 -0
- package/vendored/lib/shiki-client.ts +131 -0
- package/vendored/lib/shiki-config.ts +289 -0
- package/vendored/lib/shiki-css-theme.ts +46 -0
- package/vendored/lib/shiki-highlighter.ts +62 -0
- package/vendored/lib/shiki-transformers.ts +337 -0
- package/vendored/lib/slack-notifier.ts +248 -0
- package/vendored/lib/snippet-compiler-isr.ts +114 -0
- package/vendored/lib/snippet-loader-isr.ts +276 -0
- package/vendored/lib/static-artifacts.ts +375 -0
- package/vendored/lib/static-file-route.ts +72 -0
- package/vendored/lib/tracking-script.ts +19 -0
- package/vendored/lib/typography-config.ts +42 -0
- package/vendored/lib/validate-config.ts +268 -0
- package/vendored/next.config.js +45 -0
- package/vendored/postcss.config.js +6 -0
- package/vendored/schema/README.md +28 -0
- package/vendored/schema/docs-schema.json +4631 -0
- package/vendored/scripts/build-project.cjs +174 -0
- package/vendored/scripts/build-search-index.cjs +347 -0
- package/vendored/scripts/compile-snippets.cjs +488 -0
- package/vendored/scripts/copy-files.cjs +295 -0
- package/vendored/scripts/dev-project.cjs +534 -0
- package/vendored/scripts/enhance-navigation.cjs +354 -0
- package/vendored/scripts/validate-links.cjs +423 -0
- package/vendored/shared/constants.ts +6 -0
- package/vendored/shared/index.ts +19 -0
- package/vendored/shared/logger.ts +62 -0
- package/vendored/shared/memory-monitor.ts +190 -0
- package/vendored/shared/navigation-validator.ts +101 -0
- package/vendored/shared/path-security.ts +39 -0
- package/vendored/shared/status-reporter.ts +199 -0
- package/vendored/shared/timer.ts +51 -0
- package/vendored/shared/types.ts +102 -0
- package/vendored/tailwind.config.ts +39 -0
- package/vendored/themes/base.css +1311 -0
- package/vendored/themes/index.ts +119 -0
- package/vendored/themes/jam/variables.css +835 -0
- package/vendored/themes/nebula/variables.css +282 -0
- package/vendored/themes/pulsar/variables.css +1009 -0
- package/vendored/themes/types.ts +89 -0
- package/vendored/tsconfig.json +48 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
export type BuildEstimationType = 'full' | 'incremental';
|
|
5
|
+
|
|
6
|
+
export interface BuildEstimate {
|
|
7
|
+
minutes: number;
|
|
8
|
+
type: BuildEstimationType;
|
|
9
|
+
fileCount: number;
|
|
10
|
+
changedFiles?: number; // For future incremental builds
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Fixed overhead for all builds (in seconds):
|
|
15
|
+
* - Clone: ~1s
|
|
16
|
+
* - Validate: ~1s
|
|
17
|
+
* - Copy: ~0.5s
|
|
18
|
+
* - R2 upload: ~3-10s (depends on file count)
|
|
19
|
+
* - Cache wait: 30s
|
|
20
|
+
* - Cleanup: ~1s
|
|
21
|
+
* Total: ~45s fixed + variable upload time
|
|
22
|
+
*/
|
|
23
|
+
const FIXED_OVERHEAD_SECONDS = 45;
|
|
24
|
+
|
|
25
|
+
export function countFilesRecursive(dirPath: string): number {
|
|
26
|
+
let count = 0;
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const items = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
30
|
+
|
|
31
|
+
for (const item of items) {
|
|
32
|
+
if (item.name === 'node_modules' || item.name === '.git') {
|
|
33
|
+
continue; // Skip node_modules and .git
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const fullPath = path.join(dirPath, item.name);
|
|
37
|
+
|
|
38
|
+
if (item.isFile()) {
|
|
39
|
+
count++;
|
|
40
|
+
} else if (item.isDirectory()) {
|
|
41
|
+
count += countFilesRecursive(fullPath);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
} catch {
|
|
45
|
+
// If we can't read directory, just return current count
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return count;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Calculate estimated build time based on build type and file counts
|
|
53
|
+
*
|
|
54
|
+
* This is the FALLBACK formula used when historical data is not available.
|
|
55
|
+
* For projects with build history, Firebase Functions uses actual historical
|
|
56
|
+
* averages instead (see functions/src/index.ts:getEstimatedMinutes).
|
|
57
|
+
*
|
|
58
|
+
* Full builds use a non-linear formula because:
|
|
59
|
+
* - Next.js build time scales worse than linear (dependency resolution, memory pressure)
|
|
60
|
+
* - Observed: acme (466 files) = ~100s, dodo (4277 files) = ~555s
|
|
61
|
+
* - That's 9x files but 5.5x time, showing sub-linear scaling at small sizes
|
|
62
|
+
* but super-linear at larger sizes due to memory/CPU constraints
|
|
63
|
+
*
|
|
64
|
+
* Formula: baseSeconds + linear component + quadratic component + fixed overhead
|
|
65
|
+
* - Base: 30s minimum for Next.js
|
|
66
|
+
* - Linear: 25s per 1000 files
|
|
67
|
+
* - Quadratic: 8s per (1000 files)^2 (captures non-linear scaling)
|
|
68
|
+
* - Fixed: 60s (cache wait, clone, cleanup)
|
|
69
|
+
* - Buffer: +20% conservative estimate
|
|
70
|
+
*
|
|
71
|
+
* @param fileCount Total files in project
|
|
72
|
+
* @param changedFiles Number of changed files (for incremental builds)
|
|
73
|
+
* @param buildType 'full' or 'incremental'
|
|
74
|
+
*/
|
|
75
|
+
export function calculateBuildEstimate(
|
|
76
|
+
fileCount: number,
|
|
77
|
+
changedFiles?: number,
|
|
78
|
+
buildType: BuildEstimationType = 'full'
|
|
79
|
+
): BuildEstimate {
|
|
80
|
+
let minutes: number;
|
|
81
|
+
|
|
82
|
+
if (buildType === 'incremental' && changedFiles !== undefined) {
|
|
83
|
+
// Incremental build: ~1 min per 500 changed files + 1 min overhead
|
|
84
|
+
minutes = Math.max(1, Math.ceil(changedFiles / 500) + 1);
|
|
85
|
+
} else {
|
|
86
|
+
// Non-linear formula for full builds (fallback when no history)
|
|
87
|
+
const filesIn1K = fileCount / 1000;
|
|
88
|
+
|
|
89
|
+
// Next.js build: base + linear + quadratic components
|
|
90
|
+
const nextjsSeconds = 30 + filesIn1K * 25 + filesIn1K * filesIn1K * 8;
|
|
91
|
+
|
|
92
|
+
// R2 upload scales roughly linearly (~0.002s per file)
|
|
93
|
+
const uploadSeconds = Math.max(3, fileCount * 0.002);
|
|
94
|
+
|
|
95
|
+
// Total with fixed overhead
|
|
96
|
+
const totalSeconds = nextjsSeconds + uploadSeconds + FIXED_OVERHEAD_SECONDS;
|
|
97
|
+
|
|
98
|
+
// Add 20% buffer for conservative estimate
|
|
99
|
+
const bufferedSeconds = totalSeconds * 1.2;
|
|
100
|
+
|
|
101
|
+
minutes = Math.ceil(bufferedSeconds / 60);
|
|
102
|
+
|
|
103
|
+
// Minimum 2 minutes for any build
|
|
104
|
+
minutes = Math.max(2, minutes);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
minutes,
|
|
109
|
+
type: buildType,
|
|
110
|
+
fileCount,
|
|
111
|
+
changedFiles,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export {
|
|
2
|
+
countFilesRecursive,
|
|
3
|
+
calculateBuildEstimate,
|
|
4
|
+
type BuildEstimate,
|
|
5
|
+
type BuildEstimationType,
|
|
6
|
+
} from './estimation.js';
|
|
7
|
+
|
|
8
|
+
export {
|
|
9
|
+
generateErrorRef,
|
|
10
|
+
extractErrorSource,
|
|
11
|
+
formatErrorLocation,
|
|
12
|
+
parseErrorDetails,
|
|
13
|
+
} from './error-parser.js';
|
|
14
|
+
|
|
15
|
+
export { purgeNextJsCache, purgeVercelCache } from './cache.js';
|
|
16
|
+
|
|
17
|
+
export { runR2Upload, type R2UploadOptions, type R2UploadResult } from './r2-upload.js';
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds a mapping of URL paths to source MDX files.
|
|
3
|
+
* Used by error parser to show actual file names instead of URL paths.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import fs from 'fs';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Build a mapping of URL paths to MDX file paths.
|
|
11
|
+
*
|
|
12
|
+
* @param contentDir - Path to the content directory
|
|
13
|
+
* @returns Map of URL path -> relative file path
|
|
14
|
+
*/
|
|
15
|
+
export function buildPageToFileMap(contentDir: string): Record<string, string> {
|
|
16
|
+
const map: Record<string, string> = {};
|
|
17
|
+
|
|
18
|
+
function traverseDir(dir: string, basePath: string = '') {
|
|
19
|
+
if (!fs.existsSync(dir)) return;
|
|
20
|
+
|
|
21
|
+
const files = fs.readdirSync(dir);
|
|
22
|
+
|
|
23
|
+
for (const file of files) {
|
|
24
|
+
if (file.startsWith('.')) continue;
|
|
25
|
+
|
|
26
|
+
const filePath = path.join(dir, file);
|
|
27
|
+
let stat;
|
|
28
|
+
try {
|
|
29
|
+
stat = fs.statSync(filePath);
|
|
30
|
+
} catch {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (stat.isDirectory()) {
|
|
35
|
+
traverseDir(filePath, path.join(basePath, file));
|
|
36
|
+
} else if (file.endsWith('.mdx') || file.endsWith('.md')) {
|
|
37
|
+
const slug = path.join(basePath, file.replace(/\.mdx?$/, ''));
|
|
38
|
+
// Handle index files -> root path
|
|
39
|
+
const urlPath = slug === 'index' ? '/' : `/${slug.replace(/\\/g, '/')}`;
|
|
40
|
+
const relativePath = path.join(basePath, file).replace(/\\/g, '/');
|
|
41
|
+
map[urlPath] = relativePath;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
traverseDir(contentDir);
|
|
47
|
+
return map;
|
|
48
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* R2 upload utilities
|
|
3
|
+
*
|
|
4
|
+
* Functions for uploading build output to Cloudflare R2.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { spawn } from 'child_process';
|
|
8
|
+
|
|
9
|
+
export interface R2UploadOptions {
|
|
10
|
+
slug: string;
|
|
11
|
+
buildId: string;
|
|
12
|
+
commitSha: string;
|
|
13
|
+
fullRebuild: boolean;
|
|
14
|
+
appDir: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface R2UploadResult {
|
|
18
|
+
filesWereUploaded: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Upload build output to R2 with progress streaming
|
|
23
|
+
*
|
|
24
|
+
* Runs the upload-r2 script with parallel uploads and manifest-based
|
|
25
|
+
* incremental uploads (unless fullRebuild is true).
|
|
26
|
+
*/
|
|
27
|
+
export async function runR2Upload(options: R2UploadOptions): Promise<R2UploadResult> {
|
|
28
|
+
const { slug, buildId, commitSha, fullRebuild, appDir } = options;
|
|
29
|
+
|
|
30
|
+
// Build upload args - add --full flag for full rebuild (ignores manifest)
|
|
31
|
+
const uploadArgs = [
|
|
32
|
+
'run',
|
|
33
|
+
'upload-r2',
|
|
34
|
+
slug,
|
|
35
|
+
'--',
|
|
36
|
+
'--parallel',
|
|
37
|
+
'150',
|
|
38
|
+
'--buildId',
|
|
39
|
+
buildId,
|
|
40
|
+
'--commitSha',
|
|
41
|
+
commitSha || 'unknown',
|
|
42
|
+
];
|
|
43
|
+
if (fullRebuild) {
|
|
44
|
+
uploadArgs.push('--full');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Track whether files were actually uploaded (used to skip cache wait if no changes)
|
|
48
|
+
let filesWereUploaded = true; // Default to true for safety
|
|
49
|
+
|
|
50
|
+
await new Promise<void>((resolve, reject) => {
|
|
51
|
+
const uploadProcess = spawn('npm', uploadArgs, {
|
|
52
|
+
cwd: appDir,
|
|
53
|
+
env: process.env,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
let lastProgress = '';
|
|
57
|
+
let stdoutBuffer = '';
|
|
58
|
+
let stderrBuffer = '';
|
|
59
|
+
|
|
60
|
+
uploadProcess.stdout.on('data', (data: Buffer) => {
|
|
61
|
+
const output = data.toString();
|
|
62
|
+
stdoutBuffer += output;
|
|
63
|
+
|
|
64
|
+
// Log progress updates (upload counts, manifest operations, diff summary)
|
|
65
|
+
const lines = output.split('\n');
|
|
66
|
+
for (const line of lines) {
|
|
67
|
+
// Capture progress lines AND individual file paths (indented with spaces)
|
|
68
|
+
const isProgressLine =
|
|
69
|
+
line.includes('Uploading...') ||
|
|
70
|
+
line.includes('files to upload') ||
|
|
71
|
+
line.includes('UPLOAD COMPLETE') ||
|
|
72
|
+
line.includes('Deleted') ||
|
|
73
|
+
line.includes('Cleaning') ||
|
|
74
|
+
line.includes('manifest') ||
|
|
75
|
+
line.includes('Fetching') ||
|
|
76
|
+
line.includes('Found') ||
|
|
77
|
+
line.includes('Diff') ||
|
|
78
|
+
line.includes('New files') ||
|
|
79
|
+
line.includes('Changed files') ||
|
|
80
|
+
line.includes('Unchanged') ||
|
|
81
|
+
line.includes('No changes') ||
|
|
82
|
+
line.includes('Full upload') ||
|
|
83
|
+
line.includes('INCREMENTAL') ||
|
|
84
|
+
line.includes('Hashed') ||
|
|
85
|
+
line.includes('Sample') ||
|
|
86
|
+
line.includes('_next/static') ||
|
|
87
|
+
line.includes('HTML files') ||
|
|
88
|
+
line.includes('Files to upload');
|
|
89
|
+
// Also capture indented file paths (lines starting with spaces followed by a path)
|
|
90
|
+
const isFilePath =
|
|
91
|
+
/^\s{4,}\S/.test(line) &&
|
|
92
|
+
(line.includes('.html') ||
|
|
93
|
+
line.includes('.xml') ||
|
|
94
|
+
line.includes('.json') ||
|
|
95
|
+
line.includes('.txt'));
|
|
96
|
+
if (isProgressLine || isFilePath) {
|
|
97
|
+
const trimmed = line.trim();
|
|
98
|
+
if (trimmed && trimmed !== lastProgress) {
|
|
99
|
+
lastProgress = trimmed;
|
|
100
|
+
console.log(
|
|
101
|
+
JSON.stringify({
|
|
102
|
+
severity: 'INFO',
|
|
103
|
+
message: 'R2 upload progress',
|
|
104
|
+
buildId,
|
|
105
|
+
output: trimmed,
|
|
106
|
+
})
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
uploadProcess.stderr.on('data', (data: Buffer) => {
|
|
114
|
+
stderrBuffer += data.toString();
|
|
115
|
+
console.log(
|
|
116
|
+
JSON.stringify({
|
|
117
|
+
severity: 'WARNING',
|
|
118
|
+
message: 'R2 upload stderr',
|
|
119
|
+
buildId,
|
|
120
|
+
output: data.toString().slice(0, 500),
|
|
121
|
+
})
|
|
122
|
+
);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Timeout after 10 minutes (large projects have 35K+ files)
|
|
126
|
+
const timeout = setTimeout(() => {
|
|
127
|
+
uploadProcess.kill('SIGTERM');
|
|
128
|
+
reject(new Error('R2 upload timed out after 10 minutes'));
|
|
129
|
+
}, 600000);
|
|
130
|
+
|
|
131
|
+
uploadProcess.on('close', (code) => {
|
|
132
|
+
clearTimeout(timeout);
|
|
133
|
+
if (code === 0) {
|
|
134
|
+
// Check if files were actually uploaded by parsing the output
|
|
135
|
+
// The upload script outputs "No changes detected, skipping upload" when nothing changed
|
|
136
|
+
if (stdoutBuffer.includes('No changes detected')) {
|
|
137
|
+
filesWereUploaded = false;
|
|
138
|
+
}
|
|
139
|
+
console.log(
|
|
140
|
+
JSON.stringify({
|
|
141
|
+
severity: 'INFO',
|
|
142
|
+
message: 'R2 upload process completed',
|
|
143
|
+
buildId,
|
|
144
|
+
exitCode: code,
|
|
145
|
+
filesWereUploaded,
|
|
146
|
+
})
|
|
147
|
+
);
|
|
148
|
+
resolve();
|
|
149
|
+
} else {
|
|
150
|
+
console.log(
|
|
151
|
+
JSON.stringify({
|
|
152
|
+
severity: 'ERROR',
|
|
153
|
+
message: 'R2 upload failed',
|
|
154
|
+
buildId,
|
|
155
|
+
exitCode: code,
|
|
156
|
+
stdout: stdoutBuffer.slice(-2000),
|
|
157
|
+
stderr: stderrBuffer.slice(-2000),
|
|
158
|
+
})
|
|
159
|
+
);
|
|
160
|
+
reject(new Error(`R2 upload failed with exit code ${code}`));
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
uploadProcess.on('error', (err) => {
|
|
165
|
+
clearTimeout(timeout);
|
|
166
|
+
console.log(
|
|
167
|
+
JSON.stringify({
|
|
168
|
+
severity: 'ERROR',
|
|
169
|
+
message: 'R2 upload process error',
|
|
170
|
+
buildId,
|
|
171
|
+
error: err.message,
|
|
172
|
+
})
|
|
173
|
+
);
|
|
174
|
+
reject(err);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
return { filesWereUploaded };
|
|
179
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cache Key Generation for Multi-Tenant ISR
|
|
3
|
+
*
|
|
4
|
+
* Ensures cache keys are properly namespaced by project to prevent
|
|
5
|
+
* cache bleed between tenants. All caches should use these functions
|
|
6
|
+
* for key generation.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Generate a cache key for project-scoped resources.
|
|
11
|
+
*
|
|
12
|
+
* @param projectSlug - Project identifier
|
|
13
|
+
* @param resourcePath - Resource path within project
|
|
14
|
+
* @returns Namespaced cache key
|
|
15
|
+
*/
|
|
16
|
+
export function getCacheKey(projectSlug: string, resourcePath: string): string {
|
|
17
|
+
// Normalize path (remove leading/trailing slashes)
|
|
18
|
+
const normalizedPath = resourcePath.replace(/^\/+|\/+$/g, '');
|
|
19
|
+
return `${projectSlug}:${normalizedPath}`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Generate a cache key for config resources.
|
|
24
|
+
*
|
|
25
|
+
* @param projectSlug - Project identifier
|
|
26
|
+
* @returns Namespaced cache key for docs.json
|
|
27
|
+
*/
|
|
28
|
+
export function getConfigCacheKey(projectSlug: string): string {
|
|
29
|
+
return `${projectSlug}:config`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Generate a cache key for snippet resources.
|
|
34
|
+
*
|
|
35
|
+
* @param projectSlug - Project identifier
|
|
36
|
+
* @param snippetPath - Path to snippet file
|
|
37
|
+
* @returns Namespaced cache key
|
|
38
|
+
*/
|
|
39
|
+
export function getSnippetCacheKey(projectSlug: string, snippetPath: string): string {
|
|
40
|
+
return `${projectSlug}:snippet:${snippetPath}`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Generate a cache key for OpenAPI specs.
|
|
45
|
+
*
|
|
46
|
+
* @param projectSlug - Project identifier
|
|
47
|
+
* @param specPath - Path or URL to OpenAPI spec
|
|
48
|
+
* @returns Namespaced cache key
|
|
49
|
+
*/
|
|
50
|
+
export function getOpenApiCacheKey(projectSlug: string, specPath: string): string {
|
|
51
|
+
// For URLs, include the full URL in the key
|
|
52
|
+
if (specPath.startsWith('http://') || specPath.startsWith('https://')) {
|
|
53
|
+
return `${projectSlug}:openapi:url:${specPath}`;
|
|
54
|
+
}
|
|
55
|
+
return `${projectSlug}:openapi:${specPath}`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Generate a cache key for page content.
|
|
60
|
+
*
|
|
61
|
+
* @param projectSlug - Project identifier
|
|
62
|
+
* @param pagePath - Page path
|
|
63
|
+
* @returns Namespaced cache key
|
|
64
|
+
*/
|
|
65
|
+
export function getPageCacheKey(projectSlug: string, pagePath: string): string {
|
|
66
|
+
return `${projectSlug}:page:${pagePath}`;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Generate a Next.js revalidation tag for a project.
|
|
71
|
+
*
|
|
72
|
+
* @param projectSlug - Project identifier
|
|
73
|
+
* @returns Tag for use with revalidateTag()
|
|
74
|
+
*/
|
|
75
|
+
export function getProjectTag(projectSlug: string): string {
|
|
76
|
+
return `project:${projectSlug}`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Generate a Next.js revalidation tag for a specific page.
|
|
81
|
+
*
|
|
82
|
+
* @param projectSlug - Project identifier
|
|
83
|
+
* @param pagePath - Page path
|
|
84
|
+
* @returns Tag for use with revalidateTag()
|
|
85
|
+
*/
|
|
86
|
+
export function getPageTag(projectSlug: string, pagePath: string): string {
|
|
87
|
+
return `page:${projectSlug}:${pagePath}`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Parse a cache key back to its components.
|
|
92
|
+
*
|
|
93
|
+
* @param cacheKey - Cache key to parse
|
|
94
|
+
* @returns Project slug and resource path
|
|
95
|
+
*/
|
|
96
|
+
export function parseCacheKey(cacheKey: string): { projectSlug: string; resourcePath: string } {
|
|
97
|
+
const colonIndex = cacheKey.indexOf(':');
|
|
98
|
+
if (colonIndex === -1) {
|
|
99
|
+
throw new Error(`Invalid cache key format: ${cacheKey}`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
projectSlug: cacheKey.slice(0, colonIndex),
|
|
104
|
+
resourcePath: cacheKey.slice(colonIndex + 1),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Check if a cache key belongs to a specific project.
|
|
110
|
+
*
|
|
111
|
+
* @param cacheKey - Cache key to check
|
|
112
|
+
* @param projectSlug - Project to check against
|
|
113
|
+
* @returns true if key belongs to project
|
|
114
|
+
*/
|
|
115
|
+
export function isProjectKey(cacheKey: string, projectSlug: string): boolean {
|
|
116
|
+
return cacheKey.startsWith(`${projectSlug}:`);
|
|
117
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared utilities for code block components
|
|
3
|
+
*/
|
|
4
|
+
import { ReactElement } from 'react';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Language display name mapping
|
|
8
|
+
*/
|
|
9
|
+
const LANGUAGE_LABELS: Record<string, string> = {
|
|
10
|
+
bash: 'cURL',
|
|
11
|
+
javascript: 'JavaScript',
|
|
12
|
+
typescript: 'TypeScript',
|
|
13
|
+
python: 'Python',
|
|
14
|
+
php: 'PHP',
|
|
15
|
+
go: 'Go',
|
|
16
|
+
java: 'Java',
|
|
17
|
+
csharp: 'C#',
|
|
18
|
+
rust: 'Rust',
|
|
19
|
+
ruby: 'Ruby',
|
|
20
|
+
json: 'JSON',
|
|
21
|
+
shell: 'Shell',
|
|
22
|
+
html: 'HTML',
|
|
23
|
+
css: 'CSS',
|
|
24
|
+
sql: 'SQL',
|
|
25
|
+
yaml: 'YAML',
|
|
26
|
+
xml: 'XML',
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Get display name for a programming language
|
|
31
|
+
*/
|
|
32
|
+
export function formatLanguage(lang: string): string {
|
|
33
|
+
return LANGUAGE_LABELS[lang.toLowerCase()] || lang.charAt(0).toUpperCase() + lang.slice(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Helper for accessing React element props
|
|
38
|
+
* Uses `any` to allow property access without type guards
|
|
39
|
+
*/
|
|
40
|
+
export function getElementProps(element: ReactElement): Record<string, any> {
|
|
41
|
+
return (element.props || {}) as Record<string, any>;
|
|
42
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content Loader
|
|
3
|
+
*
|
|
4
|
+
* Unified interface for loading docs content in both static and ISR modes.
|
|
5
|
+
* Abstracts the difference between filesystem (static) and R2 (ISR) content sources.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* const loader = getContentLoader(projectSlug); // projectSlug only used in ISR mode
|
|
9
|
+
* const config = await loader.getConfig();
|
|
10
|
+
* const content = await loader.getContent('api/auth');
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import fs from 'fs';
|
|
14
|
+
import path from 'path';
|
|
15
|
+
import { parseFrontmatterLenient } from './frontmatter-utils';
|
|
16
|
+
import { getDocsConfig as getStaticDocsConfig, getContentDir } from './docs';
|
|
17
|
+
import {
|
|
18
|
+
getDocsConfig as getIsrDocsConfig,
|
|
19
|
+
getMdxContent,
|
|
20
|
+
getAllDocPaths as getIsrDocPaths,
|
|
21
|
+
type DocsConfig,
|
|
22
|
+
} from './docs-isr';
|
|
23
|
+
import { isIsrMode, ISR_REVALIDATE_SECONDS } from './page-isr-helpers';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Content loader interface.
|
|
27
|
+
*/
|
|
28
|
+
export interface ContentLoader {
|
|
29
|
+
/** Get docs.json configuration */
|
|
30
|
+
getConfig(): Promise<DocsConfig> | DocsConfig;
|
|
31
|
+
/** Get raw MDX content for a page */
|
|
32
|
+
getContent(pagePath: string): Promise<string>;
|
|
33
|
+
/** Get all document paths */
|
|
34
|
+
getAllPaths(): Promise<string[]>;
|
|
35
|
+
/** Check if content exists for a path */
|
|
36
|
+
contentExists(pagePath: string): Promise<boolean>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Static mode content loader (filesystem).
|
|
41
|
+
*/
|
|
42
|
+
class StaticContentLoader implements ContentLoader {
|
|
43
|
+
private contentDir: string;
|
|
44
|
+
|
|
45
|
+
constructor() {
|
|
46
|
+
this.contentDir = getContentDir();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
getConfig(): DocsConfig {
|
|
50
|
+
return getStaticDocsConfig();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async getContent(pagePath: string): Promise<string> {
|
|
54
|
+
const filePath = path.join(this.contentDir, pagePath) + '.mdx';
|
|
55
|
+
return fs.readFileSync(filePath, 'utf8');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async getAllPaths(): Promise<string[]> {
|
|
59
|
+
const paths: string[] = [];
|
|
60
|
+
|
|
61
|
+
const traverseDir = (dir: string, basePath: string = '') => {
|
|
62
|
+
if (!fs.existsSync(dir)) return;
|
|
63
|
+
|
|
64
|
+
const files = fs.readdirSync(dir);
|
|
65
|
+
|
|
66
|
+
for (const file of files) {
|
|
67
|
+
if (file.startsWith('.')) continue;
|
|
68
|
+
|
|
69
|
+
const filePath = path.join(dir, file);
|
|
70
|
+
|
|
71
|
+
let stat;
|
|
72
|
+
try {
|
|
73
|
+
stat = fs.statSync(filePath);
|
|
74
|
+
} catch {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (stat.isDirectory()) {
|
|
79
|
+
traverseDir(filePath, path.join(basePath, file));
|
|
80
|
+
} else if (file.endsWith('.mdx')) {
|
|
81
|
+
const slug = path.join(basePath, file.replace(/\.mdx$/, ''));
|
|
82
|
+
paths.push(slug);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
traverseDir(this.contentDir);
|
|
88
|
+
return paths;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async contentExists(pagePath: string): Promise<boolean> {
|
|
92
|
+
const filePath = path.join(this.contentDir, pagePath) + '.mdx';
|
|
93
|
+
return fs.existsSync(filePath);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* ISR mode content loader (R2).
|
|
99
|
+
*/
|
|
100
|
+
class IsrContentLoader implements ContentLoader {
|
|
101
|
+
private projectSlug: string;
|
|
102
|
+
private configCache: DocsConfig | null = null;
|
|
103
|
+
|
|
104
|
+
constructor(projectSlug: string) {
|
|
105
|
+
this.projectSlug = projectSlug;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async getConfig(): Promise<DocsConfig> {
|
|
109
|
+
if (!this.configCache) {
|
|
110
|
+
this.configCache = await getIsrDocsConfig(this.projectSlug);
|
|
111
|
+
}
|
|
112
|
+
return this.configCache;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async getContent(pagePath: string): Promise<string> {
|
|
116
|
+
return getMdxContent(this.projectSlug, pagePath);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async getAllPaths(): Promise<string[]> {
|
|
120
|
+
return getIsrDocPaths(this.projectSlug);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async contentExists(pagePath: string): Promise<boolean> {
|
|
124
|
+
try {
|
|
125
|
+
await this.getContent(pagePath);
|
|
126
|
+
return true;
|
|
127
|
+
} catch {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Get appropriate content loader based on mode.
|
|
135
|
+
*
|
|
136
|
+
* @param projectSlug - Project identifier (only used in ISR mode)
|
|
137
|
+
* @returns Content loader instance
|
|
138
|
+
*/
|
|
139
|
+
export function getContentLoader(projectSlug?: string): ContentLoader {
|
|
140
|
+
if (isIsrMode()) {
|
|
141
|
+
if (!projectSlug) {
|
|
142
|
+
throw new Error('Project slug is required in ISR mode');
|
|
143
|
+
}
|
|
144
|
+
return new IsrContentLoader(projectSlug);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return new StaticContentLoader();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Get Next.js revalidate value based on mode.
|
|
152
|
+
*
|
|
153
|
+
* In static mode, returns false (no revalidation).
|
|
154
|
+
* In ISR mode, returns the revalidation interval in seconds.
|
|
155
|
+
*/
|
|
156
|
+
export function getRevalidateValue(): number | false {
|
|
157
|
+
return isIsrMode() ? ISR_REVALIDATE_SECONDS : false;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Parse frontmatter from raw MDX content.
|
|
162
|
+
* Uses lenient parsing to handle common YAML issues like colons in values.
|
|
163
|
+
*/
|
|
164
|
+
export function parseFrontmatter(content: string): {
|
|
165
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
166
|
+
data: { [key: string]: any };
|
|
167
|
+
content: string;
|
|
168
|
+
} {
|
|
169
|
+
return parseFrontmatterLenient(content);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Re-export for convenience
|
|
173
|
+
export { isIsrMode } from './page-isr-helpers';
|
|
174
|
+
export { getProjectFromRequest, getHostAtDocs, normalizeSlugForContent } from './page-isr-helpers';
|
|
175
|
+
export { projectExists } from './docs-isr';
|
|
176
|
+
export type { DocsConfig };
|