@shoalrun/cli 0.1.0-alpha.11 → 0.1.0-alpha.13
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/CHANGELOG.md +52 -0
- package/README.md +59 -17
- package/agent-docs/.well-known/shoalrun/navigation/examples-tab-50f26fe22670.txt +22 -0
- package/agent-docs/.well-known/shoalrun/navigation/project-updates-50f26fe22670.txt +33 -3
- package/agent-docs/.well-known/shoalrun/navigation/reference-tab-50f26fe22670.txt +22 -0
- package/agent-docs/SNAPSHOT.json +5 -5
- package/agent-docs/api-docs/focused-contracts.md +2 -2
- package/agent-docs/api-docs/generate.md +6 -6
- package/agent-docs/api-docs/generate.sections/add-useful-examples.md +2 -2
- package/agent-docs/api-docs/generate.sections/choose-generated-references-or-mdx.md +5 -5
- package/agent-docs/api-docs/generate.sections/describe-filters-that-do-not-use-their-openapi-parameter-name.md +2 -2
- package/agent-docs/api-docs/generate.sections/generate-many-pages-selectively.md +2 -2
- package/agent-docs/api-docs/generate.sections/link-guides-to-api-references.md +2 -2
- package/agent-docs/api-docs/generate.sections/map-extension-values-to-shoalrun-status.md +2 -2
- package/agent-docs/api-docs/generate.sections/override-generated-reference-order-in-navigation.md +3 -3
- package/agent-docs/api-docs/generate.sections/related-reading.md +2 -2
- package/agent-docs/api-docs/generate.sections/use-a-template-for-editorial-context.md +2 -2
- package/agent-docs/api-docs/support.md +14 -13
- package/agent-docs/author/add-page.md +8 -6
- package/agent-docs/author/agent-overview.md +1 -1
- package/agent-docs/author/agent-workflow.md +1 -1
- package/agent-docs/author/analytics.md +1 -1
- package/agent-docs/author/analytics.sections/adapter-exports-and-consent.md +1 -1
- package/agent-docs/author/analytics.sections/built-in-events.md +1 -1
- package/agent-docs/author/analytics.sections/configure-an-adapter.md +1 -1
- package/agent-docs/author/analytics.sections/custom-interactions.md +1 -1
- package/agent-docs/author/analytics.sections/event-format.md +1 -1
- package/agent-docs/author/analytics.sections/html-markdown-and-agents.md +1 -1
- package/agent-docs/author/analytics.sections/inspect-events-locally.md +1 -1
- package/agent-docs/author/analytics.sections/map-events-to-your-service.md +1 -1
- package/agent-docs/author/analytics.sections/posthog-example.md +1 -1
- package/agent-docs/author/analytics.sections/related-reading.md +1 -1
- package/agent-docs/author/authoring-agent.md +1 -1
- package/agent-docs/author/coding-agent.md +1 -1
- package/agent-docs/author/components/action-link.md +9 -3
- package/agent-docs/author/components/api-embeds.md +11 -3
- package/agent-docs/author/components/api-embeds.sections/apiexample.md +7 -3
- package/agent-docs/author/components/api-embeds.sections/html-markdown-and-agents.md +3 -3
- package/agent-docs/author/components/api-embeds.sections/related-reading.md +3 -3
- package/agent-docs/author/components/badge.md +8 -4
- package/agent-docs/author/components/breadcrumbs.md +1 -1
- package/agent-docs/author/components/callout.md +8 -4
- package/agent-docs/author/components/cards.md +2 -2
- package/agent-docs/author/components/cards.sections/add-a-lucide-icon.md +2 -2
- package/agent-docs/author/components/cards.sections/build-a-collection.md +2 -2
- package/agent-docs/author/components/cards.sections/curate-a-reading-list.md +2 -2
- package/agent-docs/author/components/cards.sections/html-markdown-and-agents.md +2 -2
- package/agent-docs/author/components/cards.sections/link-to-one-document.md +2 -2
- package/agent-docs/author/components/cards.sections/override-card-text.md +2 -2
- package/agent-docs/author/components/cards.sections/related-reading.md +2 -2
- package/agent-docs/author/components/code-blocks.md +8 -4
- package/agent-docs/author/components/collapsible.md +7 -3
- package/agent-docs/author/components/cookbook-chooser.md +7 -3
- package/agent-docs/author/components/custom/react.md +1 -1
- package/agent-docs/author/components/custom/react.sections/html-markdown-and-agents.md +1 -1
- package/agent-docs/author/components/custom/react.sections/interactive-react-example.md +1 -1
- package/agent-docs/author/components/custom/react.sections/registration.md +1 -1
- package/agent-docs/author/components/custom/react.sections/related-reading.md +1 -1
- package/agent-docs/author/components/custom/react.sections/share-the-model-with-the-browser.md +1 -1
- package/agent-docs/author/components/custom/react.sections/where-the-content-lives.md +1 -1
- package/agent-docs/author/components/custom.md +1 -1
- package/agent-docs/author/components/definition-list.md +5 -3
- package/agent-docs/author/components/diagrams/d2-gallery.md +2 -2
- package/agent-docs/author/components/diagrams/d2-gallery.sections/basic-shapes.md +2 -2
- package/agent-docs/author/components/diagrams/d2-gallery.sections/flows-and-structures.md +2 -2
- package/agent-docs/author/components/diagrams/d2-gallery.sections/html-markdown-and-agents.md +2 -2
- package/agent-docs/author/components/diagrams/d2-gallery.sections/layout-engines.md +2 -2
- package/agent-docs/author/components/diagrams/d2-gallery.sections/related-reading.md +2 -2
- package/agent-docs/author/components/diagrams/d2-gallery.sections/sequences-and-grids.md +2 -2
- package/agent-docs/author/components/diagrams/d2-gallery.sections/styles-and-code.md +2 -2
- package/agent-docs/author/components/diagrams/pele-gallery.md +2 -2
- package/agent-docs/author/components/diagrams/pele-gallery.sections/charts-and-planning.md +2 -2
- package/agent-docs/author/components/diagrams/pele-gallery.sections/flowchart-shapes.md +2 -2
- package/agent-docs/author/components/diagrams/pele-gallery.sections/flows-and-behavior.md +2 -2
- package/agent-docs/author/components/diagrams/pele-gallery.sections/html-markdown-and-agents.md +2 -2
- package/agent-docs/author/components/diagrams/pele-gallery.sections/related-reading.md +2 -2
- package/agent-docs/author/components/diagrams/pele-gallery.sections/specialized-diagrams.md +2 -2
- package/agent-docs/author/components/diagrams/pele-gallery.sections/systems-and-structures.md +2 -2
- package/agent-docs/author/components/diagrams.md +13 -5
- package/agent-docs/author/components/doc-link.md +7 -3
- package/agent-docs/author/components/fields.md +6 -4
- package/agent-docs/author/components/file-tree.md +7 -3
- package/agent-docs/author/components/images.md +5 -3
- package/agent-docs/author/components/info-hint.md +7 -3
- package/agent-docs/author/components/kbd.md +5 -3
- package/agent-docs/author/components/math.md +7 -3
- package/agent-docs/author/components/only.md +9 -5
- package/agent-docs/author/components/progress.md +7 -3
- package/agent-docs/author/components/related-reading.md +7 -3
- package/agent-docs/author/components/steps.md +9 -3
- package/agent-docs/author/components/tables.md +7 -3
- package/agent-docs/author/components/tabs.md +7 -3
- package/agent-docs/author/components/timeline.md +10 -4
- package/agent-docs/author/components/tooltips.md +7 -3
- package/agent-docs/author/components/walkthroughs.md +5 -3
- package/agent-docs/author/components/walkthroughs.sections/attributes.md +3 -3
- package/agent-docs/author/components/walkthroughs.sections/build-up-code.md +3 -3
- package/agent-docs/author/components/walkthroughs.sections/choose-a-layout.md +3 -3
- package/agent-docs/author/components/walkthroughs.sections/explain-one-file.md +3 -3
- package/agent-docs/author/components/walkthroughs.sections/html-markdown-and-agents.md +3 -3
- package/agent-docs/author/components/walkthroughs.sections/related-reading.md +3 -3
- package/agent-docs/author/components/walkthroughs.sections/syntax.md +51 -0
- package/agent-docs/author/components/walkthroughs.sections/take-code-from-a-file.md +3 -22
- package/agent-docs/author/components.md +19 -4
- package/agent-docs/author/css.md +13 -10
- package/agent-docs/author/css.sections/borders-fields-and-navigation-tokens.md +3 -3
- package/agent-docs/author/css.sections/core-color-tokens.md +3 -3
- package/agent-docs/author/css.sections/html-markdown-and-agents.md +54 -0
- package/agent-docs/author/css.sections/page-attributes.md +9 -9
- package/agent-docs/author/css.sections/page-transitions.md +3 -3
- package/agent-docs/author/css.sections/responsive-behavior.md +3 -3
- package/agent-docs/author/css.sections/status-code-and-callout-tokens.md +3 -3
- package/agent-docs/author/css.sections/typography-shape-and-width-tokens.md +3 -3
- package/agent-docs/author/custom-metadata.md +2 -2
- package/agent-docs/author/custom-metadata.sections/add-a-custom-page-field.md +2 -2
- package/agent-docs/author/custom-metadata.sections/choose-text-for-each-surface.md +2 -2
- package/agent-docs/author/custom-metadata.sections/preview-changes-to-metadata-providers.md +2 -2
- package/agent-docs/author/custom-metadata.sections/read-metadata-from-a-project-module.md +2 -2
- package/agent-docs/author/custom-metadata.sections/related-reading.md +2 -2
- package/agent-docs/author/design-templates.md +1 -1
- package/agent-docs/author/design-writing-guides.md +1 -1
- package/agent-docs/author/frontmatter-reference.md +34 -27
- package/agent-docs/author/frontmatter-reference.sections/choose-a-publication-and-visibility.md +5 -3
- package/agent-docs/author/frontmatter-reference.sections/control-output-details.md +5 -3
- package/agent-docs/author/frontmatter-reference.sections/global-defaults-and-enforced-values.md +5 -3
- package/agent-docs/author/frontmatter-reference.sections/html-markdown-and-agents.md +33 -0
- package/agent-docs/author/frontmatter-reference.sections/identify-and-route-a-page.md +5 -3
- package/agent-docs/author/frontmatter-reference.sections/point-agents-to-it.md +5 -3
- package/agent-docs/author/frontmatter-reference.sections/project-defined-fields.md +5 -3
- package/agent-docs/author/frontmatter-reference.sections/related-reading.md +5 -3
- package/agent-docs/author/frontmatter-reference.sections/use-the-local-files-while-authoring.md +5 -3
- package/agent-docs/author/frontmatter-reference.sections/when-the-files-update.md +5 -3
- package/agent-docs/author/frontmatter.md +7 -4
- package/agent-docs/author/frontmatter.sections/audience-badges.md +3 -3
- package/agent-docs/author/frontmatter.sections/give-deprecation-guidance.md +3 -3
- package/agent-docs/author/frontmatter.sections/global-defaults-and-enforced-values.md +3 -3
- package/agent-docs/author/frontmatter.sections/optional-native-fields.md +7 -4
- package/agent-docs/author/frontmatter.sections/publication-fields.md +3 -3
- package/agent-docs/author/frontmatter.sections/publishing-policy.md +3 -3
- package/agent-docs/author/frontmatter.sections/related-metadata-tasks.md +3 -3
- package/agent-docs/author/frontmatter.sections/related-reading.md +3 -3
- package/agent-docs/author/frontmatter.sections/required-after-inheritance.md +3 -3
- package/agent-docs/author/frontmatter.sections/seo-fields.md +3 -3
- package/agent-docs/author/frontmatter.sections/validation-rules.md +3 -3
- package/agent-docs/author/markdown-metadata.md +17 -9
- package/agent-docs/author/navigation.md +13 -2
- package/agent-docs/author/navigation.sections/arrange-authored-pages.md +2 -2
- package/agent-docs/author/navigation.sections/fill-an-api-tag-group.md +2 -2
- package/agent-docs/author/navigation.sections/hide-group-page-counts.md +13 -2
- package/agent-docs/author/navigation.sections/html-markdown-and-agents.md +2 -2
- package/agent-docs/author/navigation.sections/local-api-preview.md +2 -2
- package/agent-docs/author/navigation.sections/mix-guides-and-api-references.md +2 -2
- package/agent-docs/author/navigation.sections/optionally-split-a-large-menu-into-files.md +2 -2
- package/agent-docs/author/navigation.sections/reach-navigation-while-reading.md +2 -2
- package/agent-docs/author/navigation.sections/related-reading.md +2 -2
- package/agent-docs/author/navigation.sections/split-navigation-into-tabs.md +2 -2
- package/agent-docs/author/navigation.sections/subject-lifecycle-labels.md +2 -2
- package/agent-docs/author/recipe-drafts.md +16 -16
- package/agent-docs/author/recipe-drafts.sections/1-write-one-reusable-step.md +5 -5
- package/agent-docs/author/recipe-drafts.sections/2-list-the-steps-for-one-complete-goal.md +3 -3
- package/agent-docs/author/recipe-drafts.sections/3-generate-a-draft-and-review-it.md +4 -4
- package/agent-docs/author/recipe-drafts.sections/4-maintain-shoalrun-s-published-recipe-snapshots.md +3 -3
- package/agent-docs/author/recipe-drafts.sections/related-reading.md +1 -1
- package/agent-docs/author/recipe-drafts.sections/start-an-ingredient-from-an-api-example.md +5 -5
- package/agent-docs/author/recipes.md +4 -4
- package/agent-docs/author/recipes.sections/how-agents-use-this.md +1 -1
- package/agent-docs/author/recipes.sections/one-example-from-shoalrun.md +4 -4
- package/agent-docs/author/recipes.sections/related-reading.md +1 -1
- package/agent-docs/author/recipes.sections/try-a-complete-workflow.md +1 -1
- package/agent-docs/author/recipes.sections/use-recipes-for-task-oriented-how-tos.md +1 -1
- package/agent-docs/author/recipes.sections/what-changing-an-ingredient-updates.md +1 -1
- package/agent-docs/author/recipes.sections/what-each-file-does.md +1 -1
- package/agent-docs/author/recipes.sections/what-happens-and-when.md +1 -1
- package/agent-docs/author/related-reading.md +5 -1
- package/agent-docs/author/related-reading.sections/automatic-footers.md +1 -1
- package/agent-docs/author/related-reading.sections/declare-relationships.md +1 -1
- package/agent-docs/author/related-reading.sections/display-related-documents.md +1 -1
- package/agent-docs/author/related-reading.sections/html-markdown-and-agents.md +28 -0
- package/agent-docs/author/related-reading.sections/inspect-output-and-changes.md +1 -1
- package/agent-docs/author/related-reading.sections/reading-paths-in-section-markdown.md +1 -1
- package/agent-docs/author/related-reading.sections/related-reading.md +1 -1
- package/agent-docs/author/related-reading.sections/where-relationship-explanations-come-from.md +1 -1
- package/agent-docs/author/search.md +1 -1
- package/agent-docs/author/search.sections/choose-a-provider.md +1 -1
- package/agent-docs/author/search.sections/cli-and-mcp-ranking-details.md +1 -1
- package/agent-docs/author/search.sections/hosted-semantic-search-limits.md +1 -1
- package/agent-docs/author/search.sections/html-markdown-and-agents.md +1 -1
- package/agent-docs/author/search.sections/lexical-search.md +1 -1
- package/agent-docs/author/search.sections/local-semantic-preview.md +1 -1
- package/agent-docs/author/search.sections/read-a-search-result-with-an-agent.md +1 -1
- package/agent-docs/author/search.sections/related-reading.md +1 -1
- package/agent-docs/author/search.sections/reuse-the-lexical-index.md +1 -1
- package/agent-docs/author/search.sections/turn-search-off.md +1 -1
- package/agent-docs/author/search.sections/use-the-search-box.md +1 -1
- package/agent-docs/author/search.sections/write-a-custom-provider.md +1 -1
- package/agent-docs/author/snippets.md +5 -1
- package/agent-docs/author/taxonomy.md +1 -1
- package/agent-docs/author/templates.md +16 -8
- package/agent-docs/author/templates.sections/built-in-feature-templates.md +3 -3
- package/agent-docs/author/templates.sections/built-in-templates.md +3 -3
- package/agent-docs/author/templates.sections/choose-formatting-enforcement-for-your-project.md +3 -3
- package/agent-docs/author/templates.sections/create-or-edit-a-project-template.md +12 -4
- package/agent-docs/author/templates.sections/keep-the-four-shapes-distinct.md +3 -3
- package/agent-docs/author/templates.sections/project-added-templates.md +3 -3
- package/agent-docs/author/templates.sections/related-reading.md +3 -3
- package/agent-docs/author/templates.sections/scaffold-a-page.md +7 -7
- package/agent-docs/author/templates.sections/short-cli-and-derived-values.md +3 -3
- package/agent-docs/author/templates.sections/what-every-template-gives-you.md +3 -3
- package/agent-docs/author/workspace/commands.md +2 -2
- package/agent-docs/author/workspace.md +8 -2
- package/agent-docs/author/writing-style.md +27 -5
- package/agent-docs/author/writing-style.sections/adapt-this-example.md +3 -3
- package/agent-docs/author/writing-style.sections/choose-components-by-reader-need.md +6 -4
- package/agent-docs/author/writing-style.sections/evidence-and-uncertainty.md +3 -3
- package/agent-docs/author/writing-style.sections/example-audience-and-scope.md +3 -3
- package/agent-docs/author/writing-style.sections/feature-availability.md +36 -0
- package/agent-docs/author/writing-style.sections/ingredients-recipes-and-cookbooks.md +3 -3
- package/agent-docs/author/writing-style.sections/page-purpose-and-structure.md +12 -4
- package/agent-docs/author/writing-style.sections/procedures-and-examples.md +3 -3
- package/agent-docs/author/writing-style.sections/related-reading.md +3 -3
- package/agent-docs/author/writing-style.sections/review-a-draft.md +3 -3
- package/agent-docs/author/writing-style.sections/reviewed-writing-examples.md +3 -3
- package/agent-docs/author/writing-style.sections/voice-and-explanations.md +3 -3
- package/agent-docs/changelog/2026-10-14-agent-readiness.md +2 -2
- package/agent-docs/changelog/2026-10-15-evaluation-builds.md +2 -2
- package/agent-docs/changelog/2026-10-16-navigation-layouts.md +2 -2
- package/agent-docs/changelog/2026-10-17-mcp-hosting.md +2 -2
- package/agent-docs/changelog/2026-10-18-search-and-tooltips.md +2 -2
- package/agent-docs/changelog/2026-10-19-visual-navigation.md +2 -2
- package/agent-docs/changelog/2026-10-25.md +2 -2
- package/agent-docs/changelog/2026-10-26.md +2 -2
- package/agent-docs/changelog/2026-10-27.md +2 -2
- package/agent-docs/changelog/2026-10-28.md +89 -0
- package/agent-docs/changelog/authoring-preview.md +2 -2
- package/agent-docs/changelog/authoring-search.md +3 -3
- package/agent-docs/changelog/authoring-tools.md +2 -2
- package/agent-docs/changelog/working-tree-skill.md +2 -2
- package/agent-docs/changelog.md +11 -3
- package/agent-docs/chat/checks.md +1 -1
- package/agent-docs/chat/checks.sections/answer-ahead-of-time.md +1 -1
- package/agent-docs/chat/checks.sections/answer-for-one-audience.md +1 -1
- package/agent-docs/chat/checks.sections/answer-without-a-model.md +1 -1
- package/agent-docs/chat/checks.sections/follow-up-questions.md +1 -1
- package/agent-docs/chat/checks.sections/how-an-answer-is-checked.md +1 -1
- package/agent-docs/chat/checks.sections/questions-with-several-parts.md +1 -1
- package/agent-docs/chat/checks.sections/related-reading.md +1 -1
- package/agent-docs/chat/checks.sections/reuse-answers.md +1 -1
- package/agent-docs/chat/host.md +1 -1
- package/agent-docs/chat/host.sections/cap-the-daily-spend.md +1 -1
- package/agent-docs/chat/host.sections/keep-a-record-of-questions.md +1 -1
- package/agent-docs/chat/host.sections/related-reading.md +1 -1
- package/agent-docs/chat/passage-index.md +2 -2
- package/agent-docs/chat/passage-index.sections/build-the-index.md +2 -2
- package/agent-docs/chat/passage-index.sections/embed-passages.md +2 -2
- package/agent-docs/chat/passage-index.sections/how-the-default-chunker-splits-a-page.md +2 -2
- package/agent-docs/chat/passage-index.sections/limits.md +2 -2
- package/agent-docs/chat/passage-index.sections/passage-ids-and-links.md +2 -2
- package/agent-docs/chat/passage-index.sections/related-reading.md +2 -2
- package/agent-docs/chat/passage-index.sections/what-a-passage-contains.md +2 -2
- package/agent-docs/chat/prepared-answers.md +1 -1
- package/agent-docs/chat/settings.md +2 -2
- package/agent-docs/chat/settings.sections/choose-the-scorer.md +2 -2
- package/agent-docs/chat/settings.sections/configure-chat.md +2 -2
- package/agent-docs/chat/settings.sections/configure-retrieval.md +2 -2
- package/agent-docs/chat/settings.sections/related-reading.md +2 -2
- package/agent-docs/chat/settings.sections/send-extra-request-fields.md +2 -2
- package/agent-docs/chat/settings.sections/use-more-than-one-model.md +2 -2
- package/agent-docs/chat/settings.sections/when-the-scorer-is-down.md +2 -2
- package/agent-docs/chat/setup.md +1 -1
- package/agent-docs/chat.md +1 -1
- package/agent-docs/cli.md +2 -2
- package/agent-docs/cli.sections/audit-a-project-and-api-sources.md +2 -2
- package/agent-docs/cli.sections/author-pages.md +2 -2
- package/agent-docs/cli.sections/build-and-serve.md +2 -2
- package/agent-docs/cli.sections/inspect-config-and-operations.md +2 -2
- package/agent-docs/cli.sections/npm-scripts-in-this-repository.md +2 -2
- package/agent-docs/cli.sections/related-reading.md +2 -2
- package/agent-docs/cli.sections/search-and-chat.md +2 -2
- package/agent-docs/cli.sections/start-a-project.md +2 -2
- package/agent-docs/cli.sections/working-tree-authoring-tools.md +2 -2
- package/agent-docs/config/apis.md +2 -2
- package/agent-docs/config/content.md +2 -2
- package/agent-docs/config/content.sections/authoring.md +2 -2
- package/agent-docs/config/content.sections/badges.md +2 -2
- package/agent-docs/config/content.sections/callouts.md +2 -2
- package/agent-docs/config/content.sections/cookbooks.md +2 -2
- package/agent-docs/config/content.sections/frontmatter.md +2 -2
- package/agent-docs/config/content.sections/readerfilters.md +2 -2
- package/agent-docs/config/content.sections/related-reading.md +2 -2
- package/agent-docs/config/content.sections/relationships.md +2 -2
- package/agent-docs/config/content.sections/snippets.md +2 -2
- package/agent-docs/config/content.sections/templates.md +2 -2
- package/agent-docs/config/content.sections/variables.md +2 -2
- package/agent-docs/config/examples.md +22 -14
- package/agent-docs/config/examples.sections/feature-showcase.md +21 -13
- package/agent-docs/config/examples.sections/minimal-site.md +15 -10
- package/agent-docs/config/examples.sections/multilingual-help-center.md +15 -10
- package/agent-docs/config/examples.sections/parcel-api-documentation.md +15 -10
- package/agent-docs/config/examples.sections/related-reading.md +15 -10
- package/agent-docs/config/examples.sections/shared-company-preset.md +16 -11
- package/agent-docs/config/integrations.md +2 -2
- package/agent-docs/config/outputs.md +17 -13
- package/agent-docs/config/outputs.sections/exports.md +16 -13
- package/agent-docs/config/outputs.sections/metadata.md +3 -3
- package/agent-docs/config/outputs.sections/related-reading.md +3 -3
- package/agent-docs/config/publishing.md +2 -2
- package/agent-docs/config/publishing.sections/navigation.md +2 -2
- package/agent-docs/config/publishing.sections/redirects.md +2 -2
- package/agent-docs/config/publishing.sections/related-reading.md +2 -2
- package/agent-docs/config/site.md +2 -2
- package/agent-docs/config/site.sections/related-reading.md +2 -2
- package/agent-docs/config/site.sections/theme.md +2 -2
- package/agent-docs/config.md +2 -2
- package/agent-docs/configuration.md +22 -20
- package/agent-docs/configuration.sections/build-several-sites-from-shared-content.md +2 -2
- package/agent-docs/configuration.sections/change-inherited-lists-deliberately.md +5 -5
- package/agent-docs/configuration.sections/extract-a-section-with-include.md +4 -4
- package/agent-docs/configuration.sections/inspect-and-validate-changes.md +6 -6
- package/agent-docs/configuration.sections/related-reading.md +2 -2
- package/agent-docs/configuration.sections/separate-config-inheritance-from-page-metadata.md +2 -2
- package/agent-docs/configuration.sections/share-defaults-through-extends.md +7 -7
- package/agent-docs/configuration.sections/start-with-one-working-file.md +8 -6
- package/agent-docs/configuration.sections/understand-the-three-stages.md +2 -2
- package/agent-docs/configuration.sections/understand-where-paths-point.md +2 -2
- package/agent-docs/connect/mcp.md +1 -1
- package/agent-docs/content-delivery/agents.md +86 -0
- package/agent-docs/content-delivery/api.md +130 -0
- package/agent-docs/content-delivery/client.md +79 -0
- package/agent-docs/content-delivery/http-api/operations/get-content-representation-fa1d2e3f.md +394 -0
- package/agent-docs/content-delivery/http-api/operations/get-content-representation-head-4052375c.md +256 -0
- package/agent-docs/content-delivery/http-api/operations/get-content-resource-849f1c49.md +911 -0
- package/agent-docs/content-delivery/http-api/operations/get-content-resource-head-0a352acd.md +246 -0
- package/agent-docs/content-delivery/http-api/operations/list-content-resources-8e977ec7.md +913 -0
- package/agent-docs/content-delivery/http-api/operations/list-content-resources-head-b67cbad9.md +236 -0
- package/agent-docs/content-delivery/http-api.md +78 -0
- package/agent-docs/content-delivery/manifest.md +79 -0
- package/agent-docs/content-delivery/publish.md +72 -0
- package/agent-docs/content-delivery/render.md +73 -0
- package/agent-docs/content-delivery/rest.md +108 -0
- package/agent-docs/content-delivery/sections.md +110 -0
- package/agent-docs/content-delivery/select.md +100 -0
- package/agent-docs/content-delivery.md +79 -0
- package/agent-docs/contribute/agent-skills.md +1 -1
- package/agent-docs/cookbooks/authoring.md +7 -3
- package/agent-docs/cookbooks/site-workflows.md +8 -4
- package/agent-docs/cookbooks/welcome-email.md +7 -3
- package/agent-docs/documents.json +7707 -6283
- package/agent-docs/example-api/cedar/create-enrollment-7af3e5d2.md +2 -2
- package/agent-docs/example-api/cedar/get-legacy-parcel-6758d051.md +2 -2
- package/agent-docs/example-api/cedar/get-parcel-edee10e6.md +2 -2
- package/agent-docs/example-api/cedar/list-parcels-0345fb5f.md +2 -2
- package/agent-docs/example-api/cedar/parcel-delivered-7d1ba6db.md +2 -2
- package/agent-docs/example-api/cedar/upload-manifest-1af17891.md +2 -2
- package/agent-docs/example-api/cedar.md +2 -2
- package/agent-docs/example-api/create-note.md +2 -2
- package/agent-docs/example-api/generated/get-note-cbedb319.md +2 -2
- package/agent-docs/example-api/write-note.md +2 -2
- package/agent-docs/explore.md +2 -2
- package/agent-docs/glossary.md +3 -7
- package/agent-docs/ingredients/audit-site.md +2 -2
- package/agent-docs/ingredients/build-site.md +2 -2
- package/agent-docs/ingredients/compile-framework.md +2 -2
- package/agent-docs/ingredients/complete-page.md +2 -2
- package/agent-docs/ingredients/inspect-agent-bundle.md +2 -2
- package/agent-docs/ingredients/inspect-build.md +2 -2
- package/agent-docs/ingredients/preview-site.md +2 -2
- package/agent-docs/ingredients/refresh-agent-bundle.md +2 -2
- package/agent-docs/ingredients/scaffold-page.md +2 -2
- package/agent-docs/non-goals.md +2 -2
- package/agent-docs/provenance.json +4 -4
- package/agent-docs/publish/agent-discovery.md +1 -1
- package/agent-docs/publish/agent-friendliness.md +1 -1
- package/agent-docs/publish/agent-friendliness.sections/discover-a-page-with-a-small-context-budget.md +1 -1
- package/agent-docs/publish/agent-friendliness.sections/distinguish-examples-from-a-real-service.md +1 -1
- package/agent-docs/publish/agent-friendliness.sections/evidence-has-a-scope.md +1 -1
- package/agent-docs/publish/agent-friendliness.sections/keep-shared-instructions-complete.md +1 -1
- package/agent-docs/publish/agent-friendliness.sections/related-reading.md +1 -1
- package/agent-docs/publish/agent-friendliness.sections/secret-handshake.md +1 -1
- package/agent-docs/publish/agent-friendliness.sections/try-the-page-controls.md +1 -1
- package/agent-docs/publish/agent-friendliness.sections/use-the-transport-your-client-supports.md +1 -1
- package/agent-docs/publish/agent-friendliness.sections/verify-the-page-and-detect-changes.md +1 -1
- package/agent-docs/publish/agent-friendliness.sections/what-an-agent-reads.md +1 -1
- package/agent-docs/publish/agent-friendliness.sections/what-happens-to-an-unsupported-component.md +1 -1
- package/agent-docs/publish/api-references.md +10 -8
- package/agent-docs/publish/api-references.sections/author-the-reference-page.md +1 -1
- package/agent-docs/publish/api-references.sections/build-and-verify-the-output.md +1 -1
- package/agent-docs/publish/api-references.sections/inspect-the-machine-readable-contract.md +1 -1
- package/agent-docs/publish/api-references.sections/{generate-many-pages-selectively.md → next-steps.md} +28 -2
- package/agent-docs/publish/api-references.sections/preview-a-small-api-reference.md +1 -1
- package/agent-docs/publish/api-references.sections/put-the-spec-in-your-project.md +1 -1
- package/agent-docs/publish/api-references.sections/register-the-operation.md +1 -1
- package/agent-docs/publish/api-references.sections/related-reading.md +1 -1
- package/agent-docs/publish/api-references.sections/review-imported-content-before-publishing.md +1 -1
- package/agent-docs/publish/api-references.sections/what-readers-get.md +1 -1
- package/agent-docs/publish/audit.md +1 -1
- package/agent-docs/publish/audit.sections/add-project-tests.md +1 -1
- package/agent-docs/publish/audit.sections/check-agent-evaluation-reports.md +1 -1
- package/agent-docs/publish/audit.sections/check-before-pushing.md +1 -1
- package/agent-docs/publish/audit.sections/connect-a-documentation-test-suite.md +1 -1
- package/agent-docs/publish/audit.sections/read-the-report.md +1 -1
- package/agent-docs/publish/audit.sections/related-reading.md +1 -1
- package/agent-docs/publish/content-export.md +33 -17
- package/agent-docs/publish/content-export.sections/assets-downloads-and-notices.md +4 -4
- package/agent-docs/publish/content-export.sections/check-the-result.md +3 -3
- package/agent-docs/publish/content-export.sections/export-selected-pages.md +13 -10
- package/agent-docs/publish/content-export.sections/inspect-the-manifest.md +6 -4
- package/agent-docs/publish/content-export.sections/prerequisites.md +4 -4
- package/agent-docs/publish/content-export.sections/related-reading.md +3 -3
- package/agent-docs/publish/content-export.sections/review-exported-api-material.md +4 -4
- package/agent-docs/publish/content-export.sections/try-the-help-drawer-example.md +4 -4
- package/agent-docs/publish/content-export.sections/upgrade-an-existing-integration.md +34 -0
- package/agent-docs/publish/content-export.sections/what-the-representations-retain.md +5 -5
- package/agent-docs/publish/content-negotiation.md +2 -2
- package/agent-docs/publish/content-negotiation.sections/hosting-contract.md +2 -2
- package/agent-docs/publish/content-negotiation.sections/missing-pages.md +2 -2
- package/agent-docs/publish/content-negotiation.sections/related-reading.md +2 -2
- package/agent-docs/publish/content-negotiation.sections/validators-and-manifest-links.md +2 -2
- package/agent-docs/publish/content-negotiation.sections/verify-the-deployed-url.md +2 -2
- package/agent-docs/publish/content-negotiation.sections/what-if-the-host-cannot-negotiate.md +2 -2
- package/agent-docs/publish/content-negotiation.sections/what-shoalrun-builds-and-what-the-host-does.md +2 -2
- package/agent-docs/publish/content-negotiation.sections/why-this-matters.md +2 -2
- package/agent-docs/publish/deployment-check.md +2 -2
- package/agent-docs/publish/evals.md +1 -1
- package/agent-docs/publish/evals.sections/add-the-audit-hook.md +1 -1
- package/agent-docs/publish/evals.sections/check-the-report.md +1 -1
- package/agent-docs/publish/evals.sections/define-a-task-file.md +1 -1
- package/agent-docs/publish/evals.sections/diagnose-a-different-build.md +1 -1
- package/agent-docs/publish/evals.sections/prepare-a-report-for-the-built-site.md +1 -1
- package/agent-docs/publish/evals.sections/related-reading.md +1 -1
- package/agent-docs/publish/evals.sections/run-and-review-the-tasks.md +1 -1
- package/agent-docs/publish/evals.sections/shoalrun-s-own-example.md +1 -1
- package/agent-docs/publish/host-adapters.md +1 -1
- package/agent-docs/publish/manni.md +1 -1
- package/agent-docs/publish/manni.sections/check-the-result.md +1 -1
- package/agent-docs/publish/manni.sections/how-this-site-uses-manni.md +1 -1
- package/agent-docs/publish/manni.sections/optional-custom-policies.md +1 -1
- package/agent-docs/publish/manni.sections/prerequisites.md +1 -1
- package/agent-docs/publish/mcp-analytics.md +1 -1
- package/agent-docs/publish/mcp-analytics.sections/adapter-exports.md +1 -1
- package/agent-docs/publish/mcp-analytics.sections/enable-analytics.md +1 -1
- package/agent-docs/publish/mcp-analytics.sections/event-fields-and-service-mappings.md +1 -1
- package/agent-docs/publish/mcp-analytics.sections/optionally-collect-intent-and-group-calls.md +1 -1
- package/agent-docs/publish/mcp-analytics.sections/optionally-identify-the-client-and-model.md +1 -1
- package/agent-docs/publish/mcp-analytics.sections/related-reading.md +1 -1
- package/agent-docs/publish/mcp-analytics.sections/safeguards-and-limits.md +1 -1
- package/agent-docs/publish/mcp.md +12 -10
- package/agent-docs/publish/mcp.sections/check-budgets-and-errors.md +2 -2
- package/agent-docs/publish/mcp.sections/choose-the-documentation-source.md +7 -7
- package/agent-docs/publish/mcp.sections/configure-the-client.md +5 -5
- package/agent-docs/publish/mcp.sections/generate-a-vercel-endpoint.md +2 -2
- package/agent-docs/publish/mcp.sections/related-reading.md +4 -2
- package/agent-docs/publish/mcp.sections/search-then-read.md +2 -2
- package/agent-docs/publish/mcp.sections/serve-a-public-endpoint-on-node.md +2 -2
- package/agent-docs/publish/mcp.sections/verify-the-connection.md +2 -2
- package/agent-docs/publish/mcp.sections/why-offer-mcp-for-public-docs.md +2 -2
- package/agent-docs/publish/openapi-extension-mappings.md +2 -2
- package/agent-docs/publish/output.md +14 -14
- package/agent-docs/publish/output.sections/api-contracts.md +3 -3
- package/agent-docs/publish/output.sections/code-highlighting.md +3 -3
- package/agent-docs/publish/output.sections/current-limits.md +4 -4
- package/agent-docs/publish/output.sections/incremental-sync.md +3 -3
- package/agent-docs/publish/output.sections/manifest-records-and-sections.md +3 -3
- package/agent-docs/publish/output.sections/navigation-section-indexes.md +3 -3
- package/agent-docs/publish/output.sections/page-formats.md +3 -3
- package/agent-docs/publish/output.sections/published-output-contract.md +3 -3
- package/agent-docs/publish/output.sections/reader-appearance-and-controls.md +3 -3
- package/agent-docs/publish/output.sections/related-reading.md +3 -3
- package/agent-docs/publish/output.sections/response-identity.md +3 -3
- package/agent-docs/publish/output.sections/site-files.md +3 -3
- package/agent-docs/publish/output.sections/validate-an-existing-build-locally.md +5 -5
- package/agent-docs/publish/output.sections/where-files-go.md +11 -11
- package/agent-docs/publish/publications.md +1 -1
- package/agent-docs/publish/revisions.md +1 -1
- package/agent-docs/publish/seo.md +17 -3
- package/agent-docs/publish/seo.sections/related-reading.md +28 -0
- package/agent-docs/publish/seo.sections/set-the-public-address.md +36 -0
- package/agent-docs/publish/seo.sections/what-agents-receive.md +28 -0
- package/agent-docs/publish/seo.sections/what-the-build-adds.md +42 -0
- package/agent-docs/publish/seo.sections/write-the-page-title-and-summary.md +43 -0
- package/agent-docs/publish/single-source-sites.md +1 -1
- package/agent-docs/publish/troubleshooting.md +1 -1
- package/agent-docs/publish/vercel.md +1 -1
- package/agent-docs/publish/vercel.sections/check-the-deployment.md +1 -1
- package/agent-docs/publish/vercel.sections/include-an-mcp-endpoint.md +1 -1
- package/agent-docs/publish/vercel.sections/prepare-your-project.md +1 -1
- package/agent-docs/publish/vercel.sections/related-reading.md +1 -1
- package/agent-docs/publish.md +1 -1
- package/agent-docs/recipes/add-page.md +3 -3
- package/agent-docs/recipes/add-page.sections/audit-the-shoalrun-docs-project.md +2 -2
- package/agent-docs/recipes/add-page.sections/before-you-start.md +2 -3
- package/agent-docs/recipes/add-page.sections/build-the-shoalrun-docs-site.md +2 -2
- package/agent-docs/recipes/add-page.sections/check-agent-search-and-page-lookup.md +2 -2
- package/agent-docs/recipes/add-page.sections/check-the-built-page-artifacts.md +2 -2
- package/agent-docs/recipes/add-page.sections/check-the-outcome.md +2 -2
- package/agent-docs/recipes/add-page.sections/complete-the-guide-and-add-navigation.md +2 -2
- package/agent-docs/recipes/add-page.sections/install-the-site-dependencies.md +2 -2
- package/agent-docs/recipes/add-page.sections/regenerate-the-agent-documentation-bundle.md +3 -2
- package/agent-docs/recipes/add-page.sections/related-reading.md +2 -2
- package/agent-docs/recipes/add-page.sections/scaffold-a-new-guide.md +2 -2
- package/agent-docs/recipes/audit-docs.md +2 -3
- package/agent-docs/recipes/build-docs.md +2 -3
- package/agent-docs/recipes/preview-hybrid-search.md +2 -2
- package/agent-docs/recipes/preview-page.md +2 -3
- package/agent-docs/recipes/queue-email.md +2 -2
- package/agent-docs/recipes/refresh-agent-docs.md +21 -3
- package/agent-docs/recipes/send-welcome-email.md +2 -2
- package/agent-docs/reference/agent-skills.md +2 -2
- package/agent-docs/search-and-chat.md +1 -1
- package/agent-docs/search-index.json +1 -1
- package/agent-docs/start.md +7 -3
- package/agent-docs/start.sections/build-this-site.md +1 -1
- package/agent-docs/start.sections/migrating-from-github-packages.md +35 -0
- package/agent-docs/start.sections/prerequisites.md +1 -1
- package/agent-docs/start.sections/start-your-own-project.md +1 -1
- package/agent-docs/status.md +2 -2
- package/agent-docs/styling/color-modes.md +6 -2
- package/agent-docs/styling/footer.md +10 -8
- package/agent-docs/styling/header.md +5 -3
- package/agent-docs/styling/layouts.md +27 -5
- package/agent-docs/styling/layouts.sections/build-a-landing-page.md +7 -4
- package/agent-docs/styling/layouts.sections/build-a-splash-page.md +7 -4
- package/agent-docs/styling/layouts.sections/control-navigation-tabs.md +7 -4
- package/agent-docs/styling/layouts.sections/customize-the-hero.md +7 -4
- package/agent-docs/styling/layouts.sections/hero.md +8 -5
- package/agent-docs/styling/layouts.sections/hide-the-table-of-contents-or-give-content-more-room.md +54 -0
- package/agent-docs/styling/layouts.sections/html-markdown-and-agents.md +43 -0
- package/agent-docs/styling/layouts.sections/related-reading.md +7 -4
- package/agent-docs/styling/palettes.md +6 -2
- package/agent-docs/styling/share-images.md +6 -2
- package/agent-docs/styling/themes.md +6 -3
- package/agent-docs/styling/try.md +3 -15
- package/dist/api.js +70 -3
- package/dist/authoring-hints.d.ts +3 -0
- package/dist/authoring-hints.js +35 -0
- package/dist/authoring-project.d.ts +1 -1
- package/dist/authoring-project.js +2 -0
- package/dist/authoring-validation.js +2 -0
- package/dist/code-samples.js +22 -11
- package/dist/compiler-config.d.ts +1 -0
- package/dist/compiler-config.js +13 -0
- package/dist/compiler.js +2 -1
- package/dist/component-names.js +1 -1
- package/dist/component-transform.js +7 -1
- package/dist/content-delivery-contract.d.ts +108 -0
- package/dist/content-delivery-contract.js +15 -0
- package/dist/content-delivery-transport.d.ts +3 -0
- package/dist/content-delivery-transport.js +47 -0
- package/dist/content-delivery-validation.d.ts +7 -0
- package/dist/content-delivery-validation.js +122 -0
- package/dist/content-delivery.d.ts +21 -0
- package/dist/content-delivery.js +119 -0
- package/dist/content-export-anchors.d.ts +11 -0
- package/dist/content-export-anchors.js +79 -0
- package/dist/content-export-command.d.ts +4 -2
- package/dist/content-export-command.js +15 -2
- package/dist/content-export-comparison.d.ts +16 -0
- package/dist/content-export-comparison.js +48 -0
- package/dist/content-export-config.d.ts +17 -0
- package/dist/content-export-config.js +47 -3
- package/dist/content-export-render.js +20 -1
- package/dist/content-export.d.ts +5 -1
- package/dist/content-export.js +193 -40
- package/dist/content-mount.d.ts +11 -0
- package/dist/content-mount.js +73 -0
- package/dist/content-rest-client.d.ts +12 -0
- package/dist/content-rest-client.js +162 -0
- package/dist/content-rest-contract.d.ts +27 -0
- package/dist/content-rest-contract.js +9 -0
- package/dist/content-rest-server.d.ts +7 -0
- package/dist/content-rest-server.js +99 -0
- package/dist/content-source.d.ts +3 -1
- package/dist/frontmatter.js +8 -7
- package/dist/html-renderer.js +25 -0
- package/dist/markdown-sections.d.ts +2 -1
- package/dist/markdown-sections.js +8 -18
- package/dist/page-renderer.js +5 -3
- package/dist/publication-plan.js +2 -1
- package/dist/scaffold-placeholders.d.ts +2 -0
- package/dist/scaffold-placeholders.js +19 -0
- package/dist/section-identity.d.ts +24 -0
- package/dist/section-identity.js +137 -0
- package/examples/content-delivery/README.md +87 -0
- package/examples/content-delivery/app.js +91 -0
- package/examples/content-delivery/content/billing.mdx +22 -0
- package/examples/content-delivery/docs.config.yaml +36 -0
- package/examples/content-delivery/index.html +25 -0
- package/examples/content-delivery/preview.mjs +86 -0
- package/examples/content-delivery/snippets/refund-window.mdx +3 -0
- package/examples/help-drawer/README.md +2 -2
- package/examples/help-drawer/app.js +3 -3
- package/package.json +6 -3
- package/schemas/content-export.schema.json +469 -33
- package/schemas/content-rest.openapi.json +1627 -0
- package/skills/shoalrun-author/SKILL.md +2 -0
- package/styles/site.css +4 -1
- package/agent-docs/.well-known/shoalrun/navigation/changelog-tab-50f26fe22670.txt +0 -33
- package/agent-docs/publish/api-references.sections/add-useful-examples.md +0 -36
- package/agent-docs/publish/api-references.sections/describe-filters-that-do-not-use-their-openapi-parameter-name.md +0 -36
- package/agent-docs/publish/api-references.sections/link-guides-to-api-references.md +0 -36
- package/agent-docs/publish/api-references.sections/map-extension-values-to-shoalrun-status.md +0 -36
- package/agent-docs/publish/api-references.sections/publish-several-versions.md +0 -36
- package/agent-docs/publish/api-references.sections/use-a-template-for-editorial-context.md +0 -36
package/dist/content-export.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ export type ContentExportOptions = {
|
|
|
7
7
|
publication?: Variant;
|
|
8
8
|
publicBase?: string;
|
|
9
9
|
review?: boolean;
|
|
10
|
+
previousManifest?: string;
|
|
11
|
+
failOnRemoved?: boolean;
|
|
10
12
|
};
|
|
11
13
|
/** Export selected source content; never invoke the website shell/compiler. */
|
|
12
14
|
export declare function exportContent(configFile: string, destination: string, options?: ContentExportOptions): Promise<{
|
|
@@ -14,8 +16,10 @@ export declare function exportContent(configFile: string, destination: string, o
|
|
|
14
16
|
output: string;
|
|
15
17
|
publication: Variant;
|
|
16
18
|
formats: ExportFormat[];
|
|
19
|
+
resources: number;
|
|
17
20
|
documents: number;
|
|
18
21
|
documentIds: string[];
|
|
22
|
+
comparison: import("./content-export-comparison.js").ContentExportComparison;
|
|
19
23
|
assets: number;
|
|
20
24
|
digest: string;
|
|
21
25
|
apiReview: {
|
|
@@ -24,7 +28,7 @@ export declare function exportContent(configFile: string, destination: string, o
|
|
|
24
28
|
}[];
|
|
25
29
|
diagnostics: {
|
|
26
30
|
code: string;
|
|
27
|
-
documentId
|
|
31
|
+
documentId?: string;
|
|
28
32
|
message: string;
|
|
29
33
|
}[];
|
|
30
34
|
}>;
|
package/dist/content-export.js
CHANGED
|
@@ -22,13 +22,21 @@ import { ExportAssets, exportDigest } from './content-export-assets.js';
|
|
|
22
22
|
import { portableTree, passiveHtml, portableMarkdown } from './content-export-render.js';
|
|
23
23
|
import { checkOutputDirectory } from './output-location.js';
|
|
24
24
|
import { commitArtifacts } from './output-commit.js';
|
|
25
|
-
import { heading, root } from './content.js';
|
|
26
|
-
import { outputUrl } from './representation-tree.js';
|
|
25
|
+
import { heading, root, parse, transformMdx } from './content.js';
|
|
26
|
+
import { outputUrl, publicTree } from './representation-tree.js';
|
|
27
27
|
import { resolveSubjectDeprecation, subjectDeprecationNotice } from './subject-deprecation.js';
|
|
28
28
|
import { resolveAuthoredChange, authoredChangeNotice } from './authored-change.js';
|
|
29
|
+
import { resolveSnippetValues } from './snippets.js';
|
|
30
|
+
import { isolateExportTree, markExportSource, exportHeadingInventory, preserveExportHeadingIds } from './content-export-anchors.js';
|
|
31
|
+
import { selectSection } from './section-identity.js';
|
|
32
|
+
import { compareContentManifests } from './content-export-comparison.js';
|
|
29
33
|
const compare = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
30
34
|
const keyFor = (doc) => `${doc.frontmatter.id}|${doc.variant.channel}|${doc.variant.version}|${doc.variant.language}`;
|
|
31
|
-
const
|
|
35
|
+
const resourceIdentity = (item) => JSON.stringify([item.ref.kind, item.ref.kind === 'snippet' ? item.ref.id : item.ref.documentId, item.ref.kind === 'section' ? item.ref.sectionId : null, item.doc.variant.channel, item.doc.variant.version, item.doc.variant.language]);
|
|
36
|
+
// Pages and their sections share a source; named snippet instances do not.
|
|
37
|
+
const sourceKeyFor = (doc, kind = 'document') => JSON.stringify([kind, doc.frontmatter.id, doc.variant.channel, doc.variant.version, doc.variant.language]);
|
|
38
|
+
const selectedSourceKey = (item) => sourceKeyFor(item.doc, item.ref.kind === 'snippet' ? 'snippet' : 'document');
|
|
39
|
+
const resourceKey = (item) => `resource-${exportDigest(resourceIdentity(item)).slice(0, 24)}`;
|
|
32
40
|
const sameVariant = (a, b) => ['channel', 'version', 'language'].every(key => a[key] === b[key]);
|
|
33
41
|
const visitTree = (node, visit) => {
|
|
34
42
|
if (!node || typeof node !== 'object')
|
|
@@ -85,7 +93,7 @@ export async function exportContent(configFile, destination, options = {}) {
|
|
|
85
93
|
const metadataDependencies = new Set();
|
|
86
94
|
const workspace = await prepareContentWorkspace({ base, basePath, config, loaded, variants: [publication], language, readerFilters, metadataProvider, metadataDependencies, allowRouteCollisions: true });
|
|
87
95
|
const { docs: eligible, apiPlan, snippets, sourceForOperation } = workspace;
|
|
88
|
-
const ids = new Set(target.documents);
|
|
96
|
+
const ids = new Set(target.resources ? target.resources.filter(item => item.kind !== 'snippet').map(item => item.documentId) : target.documents);
|
|
89
97
|
for (const id of ids) {
|
|
90
98
|
const doc = [...eligible.values()].find(doc => doc.frontmatter.id === id);
|
|
91
99
|
if (!doc)
|
|
@@ -93,8 +101,8 @@ export async function exportContent(configFile, destination, options = {}) {
|
|
|
93
101
|
if (!matchesContentFilter(doc.readerFilters, target.contentFilter))
|
|
94
102
|
throw new Error(`Requested export document ${id} is excluded by the export contentFilter`);
|
|
95
103
|
}
|
|
96
|
-
const docs = new Map([...eligible].filter(([, doc]) => (!target.documents || ids.has(doc.frontmatter.id)) && matchesContentFilter(doc.readerFilters, target.contentFilter)).sort(([, a], [, b]) => compare(keyFor(a), keyFor(b))));
|
|
97
|
-
if (!docs.size)
|
|
104
|
+
const docs = new Map([...eligible].filter(([, doc]) => (!(target.documents || target.resources) || ids.has(doc.frontmatter.id)) && matchesContentFilter(doc.readerFilters, target.contentFilter)).sort(([, a], [, b]) => compare(keyFor(a), keyFor(b))));
|
|
105
|
+
if (!docs.size && !target.resources?.some(item => item.kind === 'snippet'))
|
|
98
106
|
throw new Error('Export selection matched no eligible pages');
|
|
99
107
|
const plugins = await loadComponentPlugins(loaded, { browser: false });
|
|
100
108
|
const materialized = await materializePages({ variables: isConfigMapping(config.variables) ? config.variables : {}, frontmatterConfig: config.frontmatter, publications, docs, linkDocuments: eligible, apiPlan, sourceForOperation,
|
|
@@ -106,6 +114,7 @@ export async function exportContent(configFile, destination, options = {}) {
|
|
|
106
114
|
const cookbooks = validateCookbooks(config.cookbooks, configFile);
|
|
107
115
|
const local = new Map([...eligible.values()].map(doc => [doc.frontmatter.id, doc]));
|
|
108
116
|
const diagnostics = [];
|
|
117
|
+
const requiredNotices = new Map();
|
|
109
118
|
for (const page of materialized.rendered) {
|
|
110
119
|
const use = { targets: [], queries: [] };
|
|
111
120
|
page.doc.tree = resolveCardTree(page.doc.tree, page.doc, eligible, publicationRelationships(edges, local), new Set(apiPlan.knownOperations.keys()), use, config);
|
|
@@ -114,18 +123,78 @@ export async function exportContent(configFile, destination, options = {}) {
|
|
|
114
123
|
const change = resolveAuthoredChange(page.doc, eligible);
|
|
115
124
|
const existing = page.doc.tree;
|
|
116
125
|
// Preserve authored notices in both output representations.
|
|
117
|
-
|
|
126
|
+
const notices = [
|
|
118
127
|
{ type: 'docRepresentation', representation: 'html', children: [...subjectDeprecationNotice(deprecation, 'html').children, ...authoredChangeNotice(change, 'html').children] },
|
|
119
|
-
{ type: 'docRepresentation', representation: 'markdown', children: [...subjectDeprecationNotice(deprecation, 'markdown').children, ...authoredChangeNotice(change, 'markdown').children] }
|
|
120
|
-
|
|
121
|
-
|
|
128
|
+
{ type: 'docRepresentation', representation: 'markdown', children: [...subjectDeprecationNotice(deprecation, 'markdown').children, ...authoredChangeNotice(change, 'markdown').children] }
|
|
129
|
+
];
|
|
130
|
+
requiredNotices.set(keyFor(page.doc), notices);
|
|
131
|
+
page.doc.tree = root([...notices, ...existing.children]);
|
|
122
132
|
const found = new Set();
|
|
123
133
|
visitTree(page.doc.tree, node => { if (['docTabs', 'docWalkthrough', 'docReaderSection', 'docCollapsible', 'docTooltip', 'docInfoHint', 'docCookbookChooser'].includes(node.type))
|
|
124
134
|
found.add(node.type); });
|
|
125
135
|
if (found.size)
|
|
126
136
|
diagnostics.push({ code: 'static-content', documentId: page.doc.frontmatter.id, message: 'Interactions and reader sections are exported as complete labeled content.' });
|
|
127
137
|
}
|
|
128
|
-
|
|
138
|
+
// Materialized snippets can share nodes with their registry definition.
|
|
139
|
+
// Isolate each document before assigning source provenance.
|
|
140
|
+
for (const doc of docs.values()) {
|
|
141
|
+
doc.tree = isolateExportTree(doc.tree);
|
|
142
|
+
markExportSource(doc.tree);
|
|
143
|
+
}
|
|
144
|
+
const selected = [];
|
|
145
|
+
const selections = target.resources ?? [...docs.values()].map(doc => ({ kind: 'page', documentId: doc.frontmatter.id }));
|
|
146
|
+
for (const selection of selections) {
|
|
147
|
+
if (selection.kind === 'snippet') {
|
|
148
|
+
const definition = snippets.get(selection.snippetId);
|
|
149
|
+
if (!definition)
|
|
150
|
+
throw new Error(`Unknown export snippet ${selection.snippetId}`);
|
|
151
|
+
// This is an explicit isolated context. It has no containing page, operations,
|
|
152
|
+
// relationships, page variables, or inherited publication/access metadata.
|
|
153
|
+
const snippetDocument = { file: definition.file, body: '', tree: root([]), variant: publication,
|
|
154
|
+
route: `/__content_snippets/${encodeURIComponent(selection.id)}`, markdownRoute: '',
|
|
155
|
+
frontmatter: { id: selection.id, title: selection.title, summary: selection.summary, type: 'snippet', slug: '/', access: { policy: 'public' } } };
|
|
156
|
+
const checkSnippet = (id, seen = new Set()) => {
|
|
157
|
+
if (seen.has(id))
|
|
158
|
+
return;
|
|
159
|
+
seen.add(id);
|
|
160
|
+
const source = snippets.get(id);
|
|
161
|
+
if (!source)
|
|
162
|
+
throw new Error(`Unknown snippet ${id}`);
|
|
163
|
+
visitTree(source.tree, node => {
|
|
164
|
+
if (['RelatedReading', 'DocCard', 'DocCards', 'DocCollection', 'CookbookChooser', 'ApiExample', 'ApiSchema', 'FrontmatterReference', 'Anchor'].includes(node.name))
|
|
165
|
+
throw new Error(`Snippet instance ${selection.id}: <${node.name}> needs page context`);
|
|
166
|
+
if (node.name === 'Snippet') {
|
|
167
|
+
const child = node.attributes?.find((a) => a.name === 'id')?.value;
|
|
168
|
+
if (typeof child === 'string')
|
|
169
|
+
checkSnippet(child, seen);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
};
|
|
173
|
+
checkSnippet(selection.snippetId);
|
|
174
|
+
const invocation = parse.parse(`<Snippet id=${JSON.stringify(selection.snippetId)} values={${JSON.stringify(selection.values ?? {})}} />`);
|
|
175
|
+
snippetDocument.tree = transformMdx(invocation, snippetDocument, new Map([...eligible.values()].map(doc => [doc.frontmatter.id, doc])), snippets, isConfigMapping(config.variables) ? config.variables : {}, [], resolveCalloutTypes(config.callouts, configFile), base, readerFilters, {}, publications, resolveBadgeVariants(config.badges, configFile), plugins.registry);
|
|
176
|
+
visitTree(snippetDocument.tree, node => { if (/^doc(?:Card|Collection|Related|Cookbook|Api)/.test(node.type))
|
|
177
|
+
throw new Error(`Snippet instance ${selection.id} needs page context`); });
|
|
178
|
+
snippetDocument.tree = isolateExportTree(snippetDocument.tree);
|
|
179
|
+
markExportSource(snippetDocument.tree);
|
|
180
|
+
selected.push({ ref: { kind: 'snippet', id: selection.id }, doc: snippetDocument, tree: snippetDocument.tree,
|
|
181
|
+
title: selection.title, summary: selection.summary, type: 'snippet', source: { snippetId: selection.snippetId, valuesDigest: exportDigest(JSON.stringify(resolveSnippetValues(selection.snippetId, definition, config.variables, undefined, selection.values ?? {}))) } });
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
const doc = [...docs.values()].find(doc => doc.frontmatter.id === selection.documentId);
|
|
185
|
+
if (selection.kind === 'page')
|
|
186
|
+
selected.push({ ref: { kind: 'page', documentId: doc.frontmatter.id }, doc,
|
|
187
|
+
tree: root([heading(1, doc.frontmatter.title), ...doc.tree.children]), title: doc.frontmatter.title, summary: doc.frontmatter.summary, type: doc.frontmatter.type });
|
|
188
|
+
else {
|
|
189
|
+
const slice = selectSection(doc.tree, selection.sectionId, doc.frontmatter.standaloneSections ?? [], doc.frontmatter.id);
|
|
190
|
+
selected.push({ ref: { kind: 'section', documentId: doc.frontmatter.id, sectionId: selection.sectionId }, doc,
|
|
191
|
+
tree: root([...(requiredNotices.get(keyFor(doc)) ?? []), ...slice.tree.children]), meaningTree: slice.tree, title: slice.section.title,
|
|
192
|
+
summary: doc.frontmatter.summary, type: 'section', source: { documentId: doc.frontmatter.id } });
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
selected.sort((a, b) => compare(resourceIdentity(a), resourceIdentity(b)));
|
|
197
|
+
const diagrams = await resolveDiagramTrees(selected.map(item => item.tree));
|
|
129
198
|
const assets = new ExportAssets(target.publicBase);
|
|
130
199
|
const assetRootsOrigin = options.target && target.assetRoots.length ? explainSegments(loaded, ['exports', options.target, 'assetRoots']).source.file : configFile;
|
|
131
200
|
const roots = [workspace.contentDir, ...target.assetRoots.map(root => path.resolve(path.dirname(assetRootsOrigin), root))];
|
|
@@ -134,13 +203,15 @@ export async function exportContent(configFile, destination, options = {}) {
|
|
|
134
203
|
assets.register(asset.route, { content: asset.svg });
|
|
135
204
|
for (const [url, contract] of materialized.focusedContracts)
|
|
136
205
|
assets.register(url, { content: contract.content });
|
|
137
|
-
for (const
|
|
138
|
-
|
|
206
|
+
for (const item of selected) {
|
|
207
|
+
const doc = item.doc;
|
|
208
|
+
visitTree(item.tree, node => {
|
|
139
209
|
if (typeof node.file === 'string' && typeof node.url === 'string' && ['docImage', 'image', 'definition'].includes(node.type))
|
|
140
|
-
assets.register(node.url, { file: node.file },
|
|
210
|
+
assets.register(node.url, { file: node.file }, selectedSourceKey(item));
|
|
141
211
|
if (node.type === 'docHero' && node.image?.file)
|
|
142
|
-
assets.register(node.image.url, { file: node.image.file },
|
|
212
|
+
assets.register(node.image.url, { file: node.image.file }, selectedSourceKey(item));
|
|
143
213
|
});
|
|
214
|
+
}
|
|
144
215
|
const reviews = await reviewApiPublication(configFile, apiPlan, materialized.rendered, materialized.apiEmbedUses, materialized.focusedContracts, [...materialized.apiPublications.values()].map(source => ({ apiId: source.apiId, sourceUrl: source.sourceUrl })), sourceForOperation, 'report');
|
|
145
216
|
const unreviewed = reviews.filter(review => (target.apiReview[review.apiId] ?? configField(apiPlan.apiDefinitions[review.apiId].publicReview, 'digest')) !== review.digest);
|
|
146
217
|
if (unreviewed.length && !options.review)
|
|
@@ -158,24 +229,62 @@ export async function exportContent(configFile, destination, options = {}) {
|
|
|
158
229
|
const trees = new Map();
|
|
159
230
|
const anchors = new Map();
|
|
160
231
|
const routes = new Set([...eligible.values()].map(doc => doc.route));
|
|
161
|
-
|
|
232
|
+
const sourceInventories = new Map();
|
|
233
|
+
const sourceAliases = new Map();
|
|
234
|
+
for (const item of selected)
|
|
162
235
|
for (const format of target.formats) {
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
236
|
+
const sourceKey = `${selectedSourceKey(item)}:${format}`;
|
|
237
|
+
if (!sourceInventories.has(sourceKey))
|
|
238
|
+
sourceInventories.set(sourceKey, exportHeadingInventory(portableTree(structuredClone(item.doc.tree), format, routes, basePath)));
|
|
239
|
+
const tree = portableTree(structuredClone(item.tree), format, routes, basePath);
|
|
240
|
+
if (item.ref.kind !== 'page') {
|
|
241
|
+
const meaning = item.meaningTree ? portableTree(structuredClone(item.meaningTree), format, routes, basePath) : tree;
|
|
242
|
+
const body = (meaning.children ?? []).filter((node) => node.type !== 'heading' && node.type !== 'definition' && node.type !== 'footnoteDefinition');
|
|
243
|
+
if (!portableMarkdown(root(body)).trim())
|
|
244
|
+
throw new Error(`Resource ${resourceIdentity(item)} has no content in ${format}`);
|
|
245
|
+
}
|
|
246
|
+
const aliases = preserveExportHeadingIds(tree, sourceInventories.get(sourceKey), format);
|
|
247
|
+
sourceAliases.set(`${resourceIdentity(item)}:${format}`, aliases);
|
|
248
|
+
trees.set(`${resourceIdentity(item)}:${format}`, tree);
|
|
249
|
+
// Resolve anchors independently in each representation, before URL rewriting.
|
|
250
|
+
anchors.set(`${resourceIdentity(item)}:${format}`, passiveHtml(tree, `sr-${resourceKey(item)}`, false).anchors);
|
|
168
251
|
}
|
|
252
|
+
const canonicalAnchors = new Map();
|
|
253
|
+
const verifiedCanonicalAnchors = (destination, format) => {
|
|
254
|
+
const key = `${sourceKeyFor(destination)}:${format}`;
|
|
255
|
+
if (canonicalAnchors.has(key))
|
|
256
|
+
return canonicalAnchors.get(key);
|
|
257
|
+
const source = sourceInventories.get(key);
|
|
258
|
+
if (!source || destination.endpoint)
|
|
259
|
+
throw new Error(`Cannot validate canonical fragments in ${destination.frontmatter.id}; select the target resource explicitly`);
|
|
260
|
+
const reserved = ['main', 'docs-navigation', 'docs-sections', 'documentation-menu', 'page-outline', 'nav-filter', 'examples-title', 'api-view-select'];
|
|
261
|
+
const explicit = new Set();
|
|
262
|
+
visitTree(destination.tree, node => {
|
|
263
|
+
if (node.type === 'docSection' && node.sectionId)
|
|
264
|
+
reserved.push(node.sectionId);
|
|
265
|
+
const alias = node.data?.hProperties?.['data-shoalrun-section-id'];
|
|
266
|
+
if (typeof alias === 'string')
|
|
267
|
+
explicit.add(alias);
|
|
268
|
+
});
|
|
269
|
+
const native = exportHeadingInventory(publicTree(structuredClone(destination.tree), 'html', routes, 'light', basePath), reserved);
|
|
270
|
+
const verified = new Set([...explicit].filter(id => native.ids.has(id)));
|
|
271
|
+
for (const [headingKey, id] of source.headings)
|
|
272
|
+
if (native.headings.get(headingKey) === id)
|
|
273
|
+
verified.add(id);
|
|
274
|
+
canonicalAnchors.set(key, verified);
|
|
275
|
+
return verified;
|
|
276
|
+
};
|
|
169
277
|
const records = [];
|
|
170
278
|
const artifacts = new Map();
|
|
171
|
-
for (const
|
|
279
|
+
for (const item of selected) {
|
|
280
|
+
const doc = item.doc;
|
|
172
281
|
const externalDependencies = new Map();
|
|
173
282
|
const usedAssets = new Set();
|
|
174
283
|
const representations = {};
|
|
175
|
-
const canonicalUrl = origin && canonicalDestination(doc) ? `${origin}${doc.route}` : undefined;
|
|
284
|
+
const canonicalUrl = item.ref.kind !== 'snippet' && origin && canonicalDestination(doc) ? `${origin}${doc.route}` : undefined;
|
|
176
285
|
for (const format of target.formats) {
|
|
177
286
|
const links = [];
|
|
178
|
-
const tree = trees.get(`${
|
|
287
|
+
const tree = trees.get(`${resourceIdentity(item)}:${format}`);
|
|
179
288
|
const resolve = async (node) => {
|
|
180
289
|
// Native adapters can express ordinary links/images as semantic elements.
|
|
181
290
|
const properties = node.data?.hProperties;
|
|
@@ -207,24 +316,56 @@ export async function exportContent(configFile, destination, options = {}) {
|
|
|
207
316
|
if (destination) {
|
|
208
317
|
let href;
|
|
209
318
|
let kind;
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
319
|
+
const fragment = decodeURIComponent(parsed.hash.slice(1));
|
|
320
|
+
const candidates = selected.filter(candidate => candidate.ref.kind !== 'snippet' && keyFor(candidate.doc) === keyFor(destination));
|
|
321
|
+
const hasAnchor = (candidate) => sourceAliases.get(`${resourceIdentity(candidate)}:${format}`)?.has(fragment);
|
|
322
|
+
let chosen = destination === doc && fragment && hasAnchor(item) ? item : undefined;
|
|
323
|
+
if (!chosen && fragment) {
|
|
324
|
+
const matching = candidates.filter(candidate => candidate.ref.kind === 'section' && hasAnchor(candidate));
|
|
325
|
+
if (matching.length > 1)
|
|
326
|
+
throw new Error(`Ambiguous fragment ${fragment} in ${destination.frontmatter.id}`);
|
|
327
|
+
chosen = matching[0];
|
|
328
|
+
}
|
|
329
|
+
chosen ??= candidates.find(candidate => candidate.ref.kind === 'page');
|
|
330
|
+
// Clean Markdown has no explicit alias anchors. Prefer an actual
|
|
331
|
+
// section resource for those references, otherwise the canonical HTML.
|
|
332
|
+
if (chosen && format === 'markdown' && fragment && chosen.ref.kind === 'page') {
|
|
333
|
+
const targetId = sourceAliases.get(`${resourceIdentity(chosen)}:${format}`)?.get(fragment);
|
|
334
|
+
const target = anchors.get(`${resourceIdentity(chosen)}:${format}`)?.find(entry => entry.id === targetId);
|
|
335
|
+
if (target && !target.title)
|
|
336
|
+
chosen = candidates.find(candidate => candidate.ref.kind === 'section' && candidate.ref.sectionId === fragment);
|
|
337
|
+
}
|
|
338
|
+
if (chosen) {
|
|
339
|
+
const targetAnchors = anchors.get(`${resourceIdentity(chosen)}:${format}`);
|
|
340
|
+
const targetId = sourceAliases.get(`${resourceIdentity(chosen)}:${format}`)?.get(fragment);
|
|
341
|
+
const anchor = fragment ? targetAnchors.find(entry => entry.id === targetId) : undefined;
|
|
342
|
+
if (fragment && !anchor)
|
|
343
|
+
throw new Error(`Missing export anchor ${fragment} in ${destination.frontmatter.id} (${format})`);
|
|
344
|
+
// A section-resource URL is sufficient when addressing its leading
|
|
345
|
+
// section; clean Markdown does not publish explicit HTML anchors.
|
|
346
|
+
const leadingSection = chosen.ref.kind === 'section' && chosen.ref.sectionId === fragment;
|
|
347
|
+
const markdownAnchor = anchor?.id ?? fragment;
|
|
348
|
+
const suffix = parsed.search + (fragment && !(format === 'markdown' && leadingSection) ? `#${format === 'html' ? anchor.exportedId : markdownAnchor}` : '');
|
|
349
|
+
href = chosen === item && !parsed.search && fragment && format === 'html' ? suffix : `${target.publicBase}content/${resourceKey(chosen)}.${format === 'html' ? 'html' : 'md'}${suffix}`;
|
|
350
|
+
kind = 'resource';
|
|
219
351
|
}
|
|
220
352
|
else {
|
|
221
353
|
if (!origin || !canonicalDestination(destination))
|
|
222
354
|
throw new Error(`Document ${destination.frontmatter.id} is outside the export and has no eligible canonical website fallback`);
|
|
355
|
+
if (fragment) {
|
|
356
|
+
const inventory = sourceInventories.get(`${sourceKeyFor(destination)}:${format}`);
|
|
357
|
+
if (!inventory)
|
|
358
|
+
throw new Error(`Cannot validate canonical anchor ${fragment} in unselected document ${destination.frontmatter.id}; select that page or section explicitly`);
|
|
359
|
+
if (!inventory.ids.has(fragment))
|
|
360
|
+
throw new Error(`Missing source anchor ${fragment} in ${destination.frontmatter.id} (${format})`);
|
|
361
|
+
if (!verifiedCanonicalAnchors(destination, format).has(fragment))
|
|
362
|
+
throw new Error(`Cannot verify canonical anchor ${fragment} in ${destination.frontmatter.id}; select its target resource explicitly`);
|
|
363
|
+
}
|
|
223
364
|
href = `${origin}${destination.route}${parsed.search}${parsed.hash}`;
|
|
224
365
|
kind = 'canonical';
|
|
225
366
|
}
|
|
226
367
|
const key = `link-${links.length + 1}`;
|
|
227
|
-
links.push({ key, kind, href,
|
|
368
|
+
links.push({ key, kind, href, ...(chosen ? { ref: chosen.ref } : {}), ...(fragment ? { fragment } : {}), ...(parsed.search ? { query: parsed.search.slice(1) } : {}) });
|
|
228
369
|
node.url = href;
|
|
229
370
|
if (format === 'html' && node.type === 'link')
|
|
230
371
|
node.data = { ...node.data, hProperties: { ...node.data?.hProperties, 'data-export-link': key } };
|
|
@@ -237,7 +378,7 @@ export async function exportContent(configFile, destination, options = {}) {
|
|
|
237
378
|
links.push({ key: `link-${links.length + 1}`, kind: 'external', href: node.url });
|
|
238
379
|
}
|
|
239
380
|
else {
|
|
240
|
-
const asset = await assets.resolve(value, doc.file,
|
|
381
|
+
const asset = await assets.resolve(value, doc.file, selectedSourceKey(item));
|
|
241
382
|
if (!asset)
|
|
242
383
|
throw new Error(`Unresolved local export ${node.type === 'image' ? 'image' : 'link'} ${value} in ${doc.frontmatter.id}`);
|
|
243
384
|
usedAssets.add(asset.path);
|
|
@@ -250,15 +391,15 @@ export async function exportContent(configFile, destination, options = {}) {
|
|
|
250
391
|
await resolve(child);
|
|
251
392
|
};
|
|
252
393
|
await resolve(tree);
|
|
253
|
-
const filename = `content/${resourceKey(
|
|
254
|
-
const rendered = format === 'html' ? passiveHtml(tree, `sr-${resourceKey(
|
|
394
|
+
const filename = `content/${resourceKey(item)}.${format === 'html' ? 'html' : 'md'}`;
|
|
395
|
+
const rendered = format === 'html' ? passiveHtml(tree, `sr-${resourceKey(item)}`) : undefined;
|
|
255
396
|
const content = rendered?.html ?? portableMarkdown(tree);
|
|
256
397
|
artifacts.set(filename, content);
|
|
257
398
|
representations[format] = { path: filename, mediaType: format === 'html' ? 'text/html' : 'text/markdown', bytes: Buffer.byteLength(content), digest: exportDigest(content), anchors: rendered?.anchors ?? [], links };
|
|
258
399
|
}
|
|
259
400
|
if (externalDependencies.size)
|
|
260
401
|
diagnostics.push({ code: 'external-render-dependencies', documentId: doc.frontmatter.id, message: `${externalDependencies.size} remote image(s) remain external; this document is not offline-complete.` });
|
|
261
|
-
records.push({
|
|
402
|
+
records.push({ ref: item.ref, publication, title: item.title, summary: item.summary, type: item.type, ...(item.source ? { source: item.source } : {}), ...(canonicalUrl ? { canonicalUrl } : {}), representations, assets: [...usedAssets].sort(), externalDependencies: [...externalDependencies.values()].sort((a, b) => compare(a.url, b.url)) });
|
|
262
403
|
}
|
|
263
404
|
for (const [filename, bytes] of assets.artifacts)
|
|
264
405
|
artifacts.set(filename, bytes);
|
|
@@ -291,8 +432,15 @@ export async function exportContent(configFile, destination, options = {}) {
|
|
|
291
432
|
artifacts.set('NOTICES.txt', notices);
|
|
292
433
|
const manifest = { schemaVersion: 1, kind: 'shoalrun-content-export', publicBase: target.publicBase, publication,
|
|
293
434
|
review: { status: unreviewed.length ? 'required' : 'ok', apis: reviews.map(row => ({ apiId: row.apiId, digest: row.digest })) },
|
|
294
|
-
|
|
435
|
+
resources: records, assets: [...assets.records.values()].sort((a, b) => compare(a.path, b.path)),
|
|
295
436
|
files: [...artifacts].map(([filename, content]) => ({ path: filename, bytes: Buffer.byteLength(content), digest: exportDigest(content) })).sort((a, b) => compare(a.path, b.path)), diagnostics };
|
|
437
|
+
const previous = options.previousManifest ? JSON.parse(await readFile(options.previousManifest, 'utf8')) : undefined;
|
|
438
|
+
const comparison = compareContentManifests(previous, manifest);
|
|
439
|
+
if (options.failOnRemoved && !options.previousManifest)
|
|
440
|
+
throw new Error('failOnRemoved requires previousManifest');
|
|
441
|
+
if (options.failOnRemoved && comparison.removed.length)
|
|
442
|
+
throw new Error(`Export removes ${comparison.removed.length} previously exported resource(s)`);
|
|
443
|
+
diagnostics.push(...comparison.diagnostics);
|
|
296
444
|
const bundleDigest = exportDigest(JSON.stringify(manifest));
|
|
297
445
|
artifacts.set('manifest.json', JSON.stringify({ ...manifest, digest: bundleDigest }, null, 2) + '\n');
|
|
298
446
|
const inputs = [...noticeFiles, ...loaded.dependencies, ...metadataDependencies, ...plugins.dependencies, ...apiPlan.api.dependencies, ...[...eligible.values()].map(doc => doc.file), ...[...snippets.values()].map(snippet => snippet.file)];
|
|
@@ -300,8 +448,13 @@ export async function exportContent(configFile, destination, options = {}) {
|
|
|
300
448
|
// No export can replace a directory containing an allowed asset root.
|
|
301
449
|
for (const directory of roots)
|
|
302
450
|
checkOutputDirectory(destination, base, directory, inputs);
|
|
451
|
+
if (unreviewed.length) {
|
|
452
|
+
const prior = await readFile(path.join(destination, 'manifest.json'), 'utf8').then(JSON.parse).catch(() => undefined);
|
|
453
|
+
if (prior?.review?.status === 'ok')
|
|
454
|
+
throw new Error('Review candidate cannot overwrite an approved export; choose a separate review destination');
|
|
455
|
+
}
|
|
303
456
|
await commitArtifacts(path.resolve(destination), artifacts, undefined, 'export');
|
|
304
457
|
return { status: unreviewed.length ? 'needs-review' : 'ok', output: path.resolve(destination), publication, formats: target.formats,
|
|
305
|
-
documents: records.length, documentIds: records.
|
|
458
|
+
resources: records.length, documents: records.filter(item => item.ref.kind === 'page').length, documentIds: records.flatMap(item => item.ref.kind === 'page' ? [item.ref.documentId] : []), comparison, assets: assets.records.size, digest: bundleDigest,
|
|
306
459
|
apiReview: reviews.map(row => ({ apiId: row.apiId, digest: row.digest })), diagnostics };
|
|
307
460
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ContentAnchor, ContentLink, ContentResult } from './content-delivery-contract.js';
|
|
2
|
+
export type ContentMount = {
|
|
3
|
+
anchors: readonly ContentAnchor[];
|
|
4
|
+
links: readonly ContentLink[];
|
|
5
|
+
unmount(): void;
|
|
6
|
+
};
|
|
7
|
+
/** Mount trusted compiler output, not arbitrary HTML. This is not a sanitizer. */
|
|
8
|
+
export declare function mountContent(container: Element, result: ContentResult, options?: {
|
|
9
|
+
instanceId?: string;
|
|
10
|
+
signal?: AbortSignal;
|
|
11
|
+
}): ContentMount;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { ContentDeliveryError, contentRefKey } from './content-delivery-contract.js';
|
|
2
|
+
/** Mount trusted compiler output, not arbitrary HTML. This is not a sanitizer. */
|
|
3
|
+
export function mountContent(container, result, options = {}) {
|
|
4
|
+
options.signal?.throwIfAborted();
|
|
5
|
+
if (result.format !== 'html')
|
|
6
|
+
throw new ContentDeliveryError('unsupported_format', 'Mounting requires HTML content.');
|
|
7
|
+
const instance = options.instanceId ?? `content-${globalThis.crypto.randomUUID()}`;
|
|
8
|
+
if (!/^[A-Za-z][A-Za-z0-9_-]{0,127}$/.test(instance))
|
|
9
|
+
throw new ContentDeliveryError('invalid_content', 'Invalid mount instance ID.');
|
|
10
|
+
const document = container.ownerDocument;
|
|
11
|
+
const template = document.createElement('template');
|
|
12
|
+
template.innerHTML = result.content;
|
|
13
|
+
const ids = new Map();
|
|
14
|
+
for (const element of template.content.querySelectorAll('[id]')) {
|
|
15
|
+
const old = element.id;
|
|
16
|
+
const next = `${instance}-${old}`;
|
|
17
|
+
if (!old || ids.has(old))
|
|
18
|
+
throw new ContentDeliveryError('invalid_content', 'Duplicate or empty content ID.');
|
|
19
|
+
const existing = document.getElementById(next);
|
|
20
|
+
if (existing && (existing === container || !container.contains(existing)))
|
|
21
|
+
throw new ContentDeliveryError('invalid_content', 'Mount instance ID is already in use.');
|
|
22
|
+
ids.set(old, next);
|
|
23
|
+
element.id = next;
|
|
24
|
+
}
|
|
25
|
+
const tokenAttributes = ['aria-labelledby', 'aria-describedby', 'aria-controls', 'aria-owns', 'aria-flowto', 'headers'];
|
|
26
|
+
const singleAttributes = ['aria-activedescendant', 'aria-details', 'aria-errormessage', 'for', 'list', 'form'];
|
|
27
|
+
const rewrite = (id) => ids.get(id) ?? id;
|
|
28
|
+
const links = result.representation.links.map(link => ({ ...link }));
|
|
29
|
+
for (const element of template.content.querySelectorAll('*')) {
|
|
30
|
+
for (const attribute of tokenAttributes)
|
|
31
|
+
if (element.hasAttribute(attribute))
|
|
32
|
+
element.setAttribute(attribute, element.getAttribute(attribute).split(/\s+/).map(rewrite).join(' '));
|
|
33
|
+
for (const attribute of singleAttributes)
|
|
34
|
+
if (element.hasAttribute(attribute))
|
|
35
|
+
element.setAttribute(attribute, rewrite(element.getAttribute(attribute)));
|
|
36
|
+
const href = element.getAttribute('href');
|
|
37
|
+
if (href?.startsWith('#')) {
|
|
38
|
+
let id;
|
|
39
|
+
try {
|
|
40
|
+
id = decodeURIComponent(href.slice(1));
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
throw new ContentDeliveryError('invalid_content', 'Malformed content fragment.');
|
|
44
|
+
}
|
|
45
|
+
if (ids.has(id))
|
|
46
|
+
element.setAttribute('href', '#' + ids.get(id));
|
|
47
|
+
}
|
|
48
|
+
const key = element.getAttribute('data-export-link');
|
|
49
|
+
const link = key ? links.find(link => link.key === key) : undefined;
|
|
50
|
+
if (link?.kind === 'resource' && link.ref && contentRefKey(link.ref) === contentRefKey(result.resource.ref) && link.fragment && !link.query) {
|
|
51
|
+
const anchor = result.representation.anchors.find(anchor => anchor.id === link.fragment || anchor.exportedId === link.fragment);
|
|
52
|
+
const id = anchor && ids.get(anchor.exportedId);
|
|
53
|
+
if (id) {
|
|
54
|
+
element.setAttribute('href', '#' + id);
|
|
55
|
+
link.href = '#' + id;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const anchors = result.representation.anchors.map(anchor => {
|
|
60
|
+
const exportedId = ids.get(anchor.exportedId);
|
|
61
|
+
if (!exportedId)
|
|
62
|
+
throw new ContentDeliveryError('invalid_content', 'Declared anchor is absent from HTML.');
|
|
63
|
+
return Object.freeze({ ...anchor, exportedId });
|
|
64
|
+
});
|
|
65
|
+
options.signal?.throwIfAborted();
|
|
66
|
+
const mounted = [...template.content.childNodes];
|
|
67
|
+
container.replaceChildren(template.content);
|
|
68
|
+
return Object.freeze({ anchors: Object.freeze(anchors), links: Object.freeze(links.map(link => Object.freeze(link))),
|
|
69
|
+
unmount() { for (const node of mounted)
|
|
70
|
+
if (node.parentNode === container)
|
|
71
|
+
node.remove(); },
|
|
72
|
+
});
|
|
73
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ContentSnapshot, ContentPublication } from './content-delivery-contract.js';
|
|
2
|
+
import type { ContentDeliveryLimits } from './content-delivery.js';
|
|
3
|
+
export type RestContentSourceOptions = {
|
|
4
|
+
baseUrl: string | URL;
|
|
5
|
+
publication: ContentPublication;
|
|
6
|
+
revision?: string;
|
|
7
|
+
fetch?: typeof globalThis.fetch;
|
|
8
|
+
signal?: AbortSignal;
|
|
9
|
+
limits?: ContentDeliveryLimits;
|
|
10
|
+
};
|
|
11
|
+
/** Preloads a REST inventory and pins all subsequent reads to that revision. */
|
|
12
|
+
export declare function openRestContentSource(options: RestContentSourceOptions): Promise<ContentSnapshot>;
|