@shoalrun/cli 0.1.0-alpha.16 → 0.1.0-alpha.18
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/AUTHORING.md +29 -0
- package/CHANGELOG.md +40 -0
- package/DEPLOYMENT-PROFILES.md +96 -5
- package/README.md +59 -3
- package/agent-docs/.well-known/shoalrun/navigation/project-updates-50f26fe22670.txt +21 -17
- package/agent-docs/SNAPSHOT.json +5 -5
- package/agent-docs/api-docs/focused-contracts.md +4 -4
- package/agent-docs/api-docs/generate.md +11 -11
- package/agent-docs/api-docs/generate.sections/add-useful-examples.md +3 -3
- package/agent-docs/api-docs/generate.sections/choose-generated-references-or-mdx.md +4 -4
- package/agent-docs/api-docs/generate.sections/describe-filters-that-do-not-use-their-openapi-parameter-name.md +1 -1
- 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 +1 -1
- package/agent-docs/api-docs/generate.sections/map-extension-values-to-shoalrun-status.md +1 -1
- package/agent-docs/api-docs/generate.sections/override-generated-reference-order-in-navigation.md +4 -4
- package/agent-docs/api-docs/generate.sections/related-reading.md +1 -1
- package/agent-docs/api-docs/generate.sections/use-a-template-for-editorial-context.md +2 -2
- package/agent-docs/api-docs/support.md +7 -7
- package/agent-docs/author/add-page.md +3 -3
- package/agent-docs/author/agent-overview.md +3 -3
- package/agent-docs/author/agent-workflow.md +7 -7
- package/agent-docs/author/analytics.md +27 -27
- package/agent-docs/author/analytics.sections/adapter-exports-and-consent.md +3 -3
- package/agent-docs/author/analytics.sections/built-in-events.md +15 -15
- package/agent-docs/author/analytics.sections/configure-an-adapter.md +1 -1
- package/agent-docs/author/analytics.sections/custom-interactions.md +2 -2
- package/agent-docs/author/analytics.sections/event-format.md +2 -2
- package/agent-docs/author/analytics.sections/html-markdown-and-agents.md +4 -4
- package/agent-docs/author/analytics.sections/inspect-events-locally.md +2 -2
- package/agent-docs/author/analytics.sections/map-events-to-your-service.md +3 -3
- package/agent-docs/author/analytics.sections/posthog-example.md +3 -3
- package/agent-docs/author/analytics.sections/related-reading.md +1 -1
- package/agent-docs/author/authoring-agent.md +3 -3
- package/agent-docs/author/coding-agent.md +4 -4
- package/agent-docs/author/components/api-embeds.md +6 -6
- package/agent-docs/author/components/api-embeds.sections/apiexample.md +3 -3
- package/agent-docs/author/components/api-embeds.sections/html-markdown-and-agents.md +1 -1
- package/agent-docs/author/components/api-embeds.sections/related-reading.md +1 -1
- package/agent-docs/author/components/badge.md +2 -2
- package/agent-docs/author/components/callout.md +2 -2
- package/agent-docs/author/components/cards.md +16 -16
- package/agent-docs/author/components/cards.sections/add-a-lucide-icon.md +4 -4
- package/agent-docs/author/components/cards.sections/build-a-collection.md +7 -7
- package/agent-docs/author/components/cards.sections/curate-a-reading-list.md +9 -9
- package/agent-docs/author/components/cards.sections/html-markdown-and-agents.md +3 -3
- package/agent-docs/author/components/cards.sections/link-to-one-document.md +3 -3
- package/agent-docs/author/components/cards.sections/override-card-text.md +5 -5
- package/agent-docs/author/components/cards.sections/related-reading.md +3 -3
- package/agent-docs/author/components/code-blocks.md +2 -2
- package/agent-docs/author/components/collapsible.md +3 -3
- package/agent-docs/author/components/cookbook-chooser.md +5 -5
- package/agent-docs/author/components/custom/react.md +8 -8
- package/agent-docs/author/components/custom/react.sections/html-markdown-and-agents.md +3 -3
- package/agent-docs/author/components/custom/react.sections/interactive-react-example.md +2 -2
- 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 +3 -3
- package/agent-docs/author/components/custom/react.sections/where-the-content-lives.md +3 -3
- package/agent-docs/author/components/custom.md +7 -7
- package/agent-docs/author/components/definition-list.md +2 -2
- 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 +3 -3
- 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 +3 -3
- 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 +8 -8
- package/agent-docs/author/components/doc-link.md +3 -3
- package/agent-docs/author/components/fields.md +18 -18
- package/agent-docs/author/components/file-tree.md +2 -2
- package/agent-docs/author/components/images.md +5 -5
- package/agent-docs/author/components/info-hint.md +3 -3
- package/agent-docs/author/components/kbd.md +2 -2
- package/agent-docs/author/components/math.md +2 -2
- package/agent-docs/author/components/only.md +3 -3
- package/agent-docs/author/components/progress.md +3 -3
- package/agent-docs/author/components/steps.md +2 -2
- package/agent-docs/author/components/tables.md +2 -2
- package/agent-docs/author/components/tabs.md +5 -5
- package/agent-docs/author/components/timeline.md +2 -2
- package/agent-docs/author/components/tooltips.md +2 -2
- package/agent-docs/author/components/walkthroughs.md +2 -2
- package/agent-docs/author/components/walkthroughs.sections/attributes.md +1 -1
- package/agent-docs/author/components/walkthroughs.sections/build-up-code.md +1 -1
- package/agent-docs/author/components/walkthroughs.sections/choose-a-layout.md +2 -2
- package/agent-docs/author/components/walkthroughs.sections/explain-one-file.md +1 -1
- package/agent-docs/author/components/walkthroughs.sections/html-markdown-and-agents.md +1 -1
- package/agent-docs/author/components/walkthroughs.sections/related-reading.md +1 -1
- package/agent-docs/author/components/walkthroughs.sections/syntax.md +1 -1
- package/agent-docs/author/components/walkthroughs.sections/take-code-from-a-file.md +1 -1
- package/agent-docs/author/components.md +2 -2
- package/agent-docs/author/content.md +3 -3
- package/agent-docs/author/cookbooks.md +9 -9
- package/agent-docs/author/css.md +4 -4
- 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 +4 -4
- package/agent-docs/author/css.sections/page-attributes.md +3 -3
- 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 +13 -13
- package/agent-docs/author/custom-metadata.sections/add-a-custom-page-field.md +4 -4
- package/agent-docs/author/custom-metadata.sections/choose-text-for-each-surface.md +3 -3
- 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 +3 -3
- package/agent-docs/author/custom-metadata.sections/related-reading.md +1 -1
- package/agent-docs/author/design-templates.md +3 -3
- package/agent-docs/author/design-writing-guides.md +3 -3
- package/agent-docs/author/frontmatter-reference.md +59 -16
- package/agent-docs/author/frontmatter-reference.sections/categorize-connect-and-present-the-page.md +64 -0
- package/agent-docs/author/frontmatter-reference.sections/choose-a-publication-and-visibility.md +14 -12
- package/agent-docs/author/frontmatter-reference.sections/control-output-details.md +2 -2
- package/agent-docs/author/frontmatter-reference.sections/feature-availability.md +59 -0
- package/agent-docs/author/frontmatter-reference.sections/global-defaults-and-enforced-values.md +2 -2
- package/agent-docs/author/frontmatter-reference.sections/html-markdown-and-agents.md +3 -3
- package/agent-docs/author/frontmatter-reference.sections/identify-and-route-a-page.md +2 -2
- package/agent-docs/author/frontmatter-reference.sections/point-agents-to-it.md +2 -2
- package/agent-docs/author/frontmatter-reference.sections/product-publication-fields.md +37 -0
- package/agent-docs/author/frontmatter-reference.sections/project-defined-fields.md +2 -2
- package/agent-docs/author/frontmatter-reference.sections/related-reading.md +2 -2
- package/agent-docs/author/frontmatter-reference.sections/use-the-local-files-while-authoring.md +4 -4
- package/agent-docs/author/frontmatter-reference.sections/when-the-files-update.md +2 -2
- package/agent-docs/author/frontmatter.md +13 -13
- package/agent-docs/author/frontmatter.sections/audience-badges.md +3 -3
- package/agent-docs/author/frontmatter.sections/give-deprecation-guidance.md +4 -4
- package/agent-docs/author/frontmatter.sections/global-defaults-and-enforced-values.md +1 -1
- package/agent-docs/author/frontmatter.sections/optional-native-fields.md +4 -4
- package/agent-docs/author/frontmatter.sections/publication-fields.md +2 -2
- package/agent-docs/author/frontmatter.sections/publishing-policy.md +1 -1
- package/agent-docs/author/frontmatter.sections/related-metadata-tasks.md +1 -1
- package/agent-docs/author/frontmatter.sections/related-reading.md +1 -1
- package/agent-docs/author/frontmatter.sections/required-after-inheritance.md +1 -1
- package/agent-docs/author/frontmatter.sections/seo-fields.md +2 -2
- package/agent-docs/author/frontmatter.sections/validation-rules.md +3 -3
- package/agent-docs/author/markdown-metadata.md +20 -20
- package/agent-docs/author/navigation.md +12 -12
- package/agent-docs/author/navigation.sections/arrange-authored-pages.md +4 -4
- 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 +4 -4
- package/agent-docs/author/navigation.sections/html-markdown-and-agents.md +4 -4
- package/agent-docs/author/navigation.sections/local-api-preview.md +2 -2
- package/agent-docs/author/navigation.sections/mix-guides-and-api-references.md +3 -3
- 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 +4 -4
- package/agent-docs/author/navigation.sections/subject-lifecycle-labels.md +3 -3
- package/agent-docs/author/reader-views.md +9 -9
- package/agent-docs/author/reader-views.sections/configure-the-choices.md +2 -2
- package/agent-docs/author/reader-views.sections/connect-your-own-control.md +1 -1
- package/agent-docs/author/reader-views.sections/how-it-works-for-agents.md +3 -3
- package/agent-docs/author/reader-views.sections/mark-pages.md +3 -3
- package/agent-docs/author/reader-views.sections/mark-sections-and-add-an-entry-choice.md +2 -2
- package/agent-docs/author/reader-views.sections/place-filter-controls.md +2 -2
- package/agent-docs/author/reader-views.sections/try-the-controls-here.md +2 -2
- package/agent-docs/author/recipe-drafts.md +5 -5
- package/agent-docs/author/recipe-drafts.sections/1-write-one-reusable-step.md +2 -2
- package/agent-docs/author/recipe-drafts.sections/2-list-the-steps-for-one-complete-goal.md +2 -2
- package/agent-docs/author/recipe-drafts.sections/3-generate-a-draft-and-review-it.md +1 -1
- package/agent-docs/author/recipe-drafts.sections/4-maintain-shoalrun-s-published-recipe-snapshots.md +2 -2
- 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 +2 -2
- package/agent-docs/author/recipes.md +9 -9
- package/agent-docs/author/recipes.sections/how-agents-use-this.md +3 -3
- package/agent-docs/author/recipes.sections/one-example-from-shoalrun.md +3 -3
- package/agent-docs/author/recipes.sections/related-reading.md +2 -2
- package/agent-docs/author/recipes.sections/try-a-complete-workflow.md +3 -3
- package/agent-docs/author/recipes.sections/use-recipes-for-task-oriented-how-tos.md +4 -4
- package/agent-docs/author/recipes.sections/what-changing-an-ingredient-updates.md +3 -3
- package/agent-docs/author/recipes.sections/what-each-file-does.md +2 -2
- package/agent-docs/author/recipes.sections/what-happens-and-when.md +3 -3
- package/agent-docs/author/related-reading.md +11 -11
- package/agent-docs/author/related-reading.sections/automatic-footers.md +3 -3
- package/agent-docs/author/related-reading.sections/declare-relationships.md +3 -3
- package/agent-docs/author/related-reading.sections/display-related-documents.md +3 -3
- package/agent-docs/author/related-reading.sections/html-markdown-and-agents.md +1 -1
- package/agent-docs/author/related-reading.sections/inspect-output-and-changes.md +2 -2
- package/agent-docs/author/related-reading.sections/reading-paths-in-section-markdown.md +3 -3
- 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 +2 -2
- package/agent-docs/author/release-notes.md +8 -8
- package/agent-docs/author/search.md +82 -29
- package/agent-docs/author/search.sections/agent-and-mcp-search-scope.md +52 -0
- package/agent-docs/author/search.sections/choose-a-provider.md +8 -7
- package/agent-docs/author/search.sections/cli-and-mcp-ranking-details.md +4 -4
- package/agent-docs/author/search.sections/enable-included-semantic-search.md +66 -0
- package/agent-docs/author/search.sections/hosted-semantic-search-limits.md +3 -3
- package/agent-docs/author/search.sections/html-markdown-and-agents.md +3 -3
- package/agent-docs/author/search.sections/lexical-search.md +6 -6
- package/agent-docs/author/search.sections/local-semantic-preview.md +3 -3
- package/agent-docs/author/search.sections/read-a-search-result-with-an-agent.md +2 -2
- package/agent-docs/author/search.sections/related-reading.md +2 -2
- package/agent-docs/author/search.sections/reuse-the-lexical-index.md +5 -5
- package/agent-docs/author/search.sections/turn-search-off.md +3 -3
- package/agent-docs/author/search.sections/use-the-search-box.md +2 -2
- package/agent-docs/author/search.sections/write-a-custom-provider.md +11 -11
- package/agent-docs/author/snippets.md +3 -3
- package/agent-docs/author/taxonomy.md +3 -3
- package/agent-docs/author/templates.md +16 -14
- package/agent-docs/author/templates.sections/built-in-feature-templates.md +2 -2
- package/agent-docs/author/templates.sections/built-in-templates.md +2 -2
- package/agent-docs/author/templates.sections/choose-formatting-enforcement-for-your-project.md +7 -7
- package/agent-docs/author/templates.sections/create-or-edit-a-project-template.md +8 -6
- package/agent-docs/author/templates.sections/keep-the-four-shapes-distinct.md +2 -2
- package/agent-docs/author/templates.sections/project-added-templates.md +3 -3
- package/agent-docs/author/templates.sections/related-reading.md +2 -2
- package/agent-docs/author/templates.sections/scaffold-a-page.md +2 -2
- 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 +4 -4
- package/agent-docs/author/workspace.md +7 -7
- package/agent-docs/author/writing-style.md +33 -18
- package/agent-docs/author/writing-style.sections/adapt-this-example.md +2 -2
- package/agent-docs/author/writing-style.sections/choose-components-by-reader-need.md +3 -3
- package/agent-docs/author/writing-style.sections/evidence-and-uncertainty.md +4 -4
- package/agent-docs/author/writing-style.sections/example-audience-and-scope.md +2 -2
- package/agent-docs/author/writing-style.sections/feature-availability.md +20 -7
- package/agent-docs/author/writing-style.sections/ingredients-recipes-and-cookbooks.md +5 -5
- package/agent-docs/author/writing-style.sections/page-purpose-and-structure.md +4 -4
- package/agent-docs/author/writing-style.sections/procedures-and-examples.md +4 -4
- package/agent-docs/author/writing-style.sections/related-reading.md +2 -2
- package/agent-docs/author/writing-style.sections/review-a-draft.md +3 -3
- package/agent-docs/author/writing-style.sections/reviewed-writing-examples.md +2 -2
- package/agent-docs/author/writing-style.sections/voice-and-explanations.md +4 -2
- package/agent-docs/changelog/2026-10-14-agent-readiness.md +2 -2
- package/agent-docs/changelog/2026-10-15-evaluation-builds.md +9 -9
- package/agent-docs/changelog/2026-10-16-navigation-layouts.md +4 -4
- package/agent-docs/changelog/2026-10-17-mcp-hosting.md +2 -2
- package/agent-docs/changelog/2026-10-18-search-and-tooltips.md +3 -3
- package/agent-docs/changelog/2026-10-19-visual-navigation.md +3 -3
- package/agent-docs/changelog/2026-10-25.md +2 -2
- package/agent-docs/changelog/2026-10-26.md +4 -4
- package/agent-docs/changelog/2026-10-27.md +1 -1
- package/agent-docs/changelog/2026-10-28.md +3 -3
- package/agent-docs/changelog/2026-10-30.md +1 -1
- package/agent-docs/changelog/2026-11-03.md +5 -5
- package/agent-docs/changelog/2026-11-04-runtime-packaging.md +46 -0
- package/agent-docs/changelog/authoring-preview.md +3 -3
- package/agent-docs/changelog/authoring-search.md +1 -1
- package/agent-docs/changelog/authoring-tools.md +2 -2
- package/agent-docs/changelog/product-publications.md +60 -0
- package/agent-docs/changelog/working-tree-skill.md +1 -1
- package/agent-docs/changelog.md +17 -1
- package/agent-docs/chat/checks.md +11 -11
- package/agent-docs/chat/checks.sections/answer-ahead-of-time.md +1 -1
- package/agent-docs/chat/checks.sections/answer-for-one-audience.md +2 -2
- package/agent-docs/chat/checks.sections/answer-without-a-model.md +2 -2
- package/agent-docs/chat/checks.sections/follow-up-questions.md +2 -2
- package/agent-docs/chat/checks.sections/how-an-answer-is-checked.md +3 -3
- package/agent-docs/chat/checks.sections/questions-with-several-parts.md +3 -3
- package/agent-docs/chat/checks.sections/related-reading.md +1 -1
- package/agent-docs/chat/checks.sections/reuse-answers.md +4 -4
- package/agent-docs/chat/host.md +8 -8
- package/agent-docs/chat/host.sections/cap-the-daily-spend.md +2 -2
- package/agent-docs/chat/host.sections/keep-a-record-of-questions.md +3 -3
- package/agent-docs/chat/host.sections/related-reading.md +2 -2
- package/agent-docs/chat/passage-index.md +31 -27
- package/agent-docs/chat/passage-index.sections/build-the-index.md +3 -3
- package/agent-docs/chat/passage-index.sections/embed-passages.md +4 -4
- package/agent-docs/chat/passage-index.sections/how-the-default-chunker-splits-a-page.md +3 -3
- package/agent-docs/chat/passage-index.sections/limits.md +3 -3
- package/agent-docs/chat/passage-index.sections/passage-ids-and-links.md +14 -10
- package/agent-docs/chat/passage-index.sections/related-reading.md +3 -3
- package/agent-docs/chat/passage-index.sections/what-a-passage-contains.md +19 -19
- package/agent-docs/chat/prepared-answers.md +4 -4
- package/agent-docs/chat/settings.md +3 -3
- package/agent-docs/chat/settings.sections/choose-the-scorer.md +1 -1
- package/agent-docs/chat/settings.sections/configure-chat.md +1 -1
- package/agent-docs/chat/settings.sections/configure-retrieval.md +1 -1
- package/agent-docs/chat/settings.sections/related-reading.md +1 -1
- 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 +1 -1
- package/agent-docs/chat/setup.md +2 -2
- package/agent-docs/chat.md +3 -3
- package/agent-docs/cli.md +73 -59
- package/agent-docs/cli.sections/audit-a-project-and-api-sources.md +11 -7
- package/agent-docs/cli.sections/author-pages.md +16 -12
- package/agent-docs/cli.sections/build-and-serve.md +30 -18
- package/agent-docs/cli.sections/inspect-config-and-operations.md +13 -9
- package/agent-docs/cli.sections/npm-scripts-in-this-repository.md +7 -3
- package/agent-docs/cli.sections/related-reading.md +6 -2
- package/agent-docs/cli.sections/search-and-chat.md +24 -18
- package/agent-docs/cli.sections/start-a-project.md +7 -3
- package/agent-docs/cli.sections/working-tree-authoring-tools.md +7 -3
- package/agent-docs/concepts.md +2 -2
- package/agent-docs/config/apis.md +2 -2
- package/agent-docs/config/content.md +3 -3
- package/agent-docs/config/content.sections/authoring.md +3 -3
- package/agent-docs/config/content.sections/badges.md +1 -1
- package/agent-docs/config/content.sections/callouts.md +1 -1
- package/agent-docs/config/content.sections/cookbooks.md +1 -1
- package/agent-docs/config/content.sections/frontmatter.md +1 -1
- package/agent-docs/config/content.sections/readerfilters.md +1 -1
- package/agent-docs/config/content.sections/related-reading.md +1 -1
- package/agent-docs/config/content.sections/relationships.md +1 -1
- package/agent-docs/config/content.sections/snippets.md +1 -1
- package/agent-docs/config/content.sections/templates.md +1 -1
- package/agent-docs/config/content.sections/variables.md +1 -1
- package/agent-docs/config/examples.md +4 -4
- package/agent-docs/config/examples.sections/feature-showcase.md +4 -4
- package/agent-docs/config/examples.sections/minimal-site.md +2 -2
- package/agent-docs/config/examples.sections/multilingual-help-center.md +2 -2
- package/agent-docs/config/examples.sections/parcel-api-documentation.md +2 -2
- package/agent-docs/config/examples.sections/related-reading.md +2 -2
- package/agent-docs/config/examples.sections/shared-company-preset.md +2 -2
- package/agent-docs/config/integrations.md +4 -4
- package/agent-docs/config/outputs.md +22 -16
- package/agent-docs/config/outputs.sections/exports.md +19 -13
- package/agent-docs/config/outputs.sections/metadata.md +2 -2
- package/agent-docs/config/outputs.sections/related-reading.md +1 -1
- package/agent-docs/config/publishing.md +29 -19
- package/agent-docs/config/publishing.sections/navigation.md +2 -2
- package/agent-docs/config/publishing.sections/redirects.md +8 -8
- package/agent-docs/config/publishing.sections/related-reading.md +2 -2
- package/agent-docs/config/site.md +42 -18
- package/agent-docs/config/site.sections/related-reading.md +1 -1
- package/agent-docs/config/site.sections/theme.md +1 -1
- package/agent-docs/config.md +2 -2
- package/agent-docs/configuration.md +19 -19
- package/agent-docs/configuration.sections/build-several-sites-from-shared-content.md +1 -1
- package/agent-docs/configuration.sections/change-inherited-lists-deliberately.md +5 -5
- package/agent-docs/configuration.sections/extract-a-section-with-include.md +1 -1
- package/agent-docs/configuration.sections/inspect-and-validate-changes.md +5 -5
- package/agent-docs/configuration.sections/related-reading.md +1 -1
- package/agent-docs/configuration.sections/separate-config-inheritance-from-page-metadata.md +5 -5
- package/agent-docs/configuration.sections/share-defaults-through-extends.md +3 -3
- package/agent-docs/configuration.sections/start-with-one-working-file.md +2 -2
- package/agent-docs/configuration.sections/understand-the-three-stages.md +3 -3
- package/agent-docs/configuration.sections/understand-where-paths-point.md +2 -2
- package/agent-docs/connect/mcp.md +24 -15
- package/agent-docs/content-delivery/agents.md +6 -6
- package/agent-docs/content-delivery/api.md +29 -16
- package/agent-docs/content-delivery/client.md +14 -8
- package/agent-docs/content-delivery/http-api/operations/get-content-representation-fa1d2e3f.md +10 -2
- package/agent-docs/content-delivery/http-api/operations/get-content-representation-head-4052375c.md +10 -2
- package/agent-docs/content-delivery/http-api/operations/get-content-resource-849f1c49.md +537 -3
- package/agent-docs/content-delivery/http-api/operations/get-content-resource-head-0a352acd.md +10 -2
- package/agent-docs/content-delivery/http-api/operations/list-content-resources-8e977ec7.md +545 -3
- package/agent-docs/content-delivery/http-api/operations/list-content-resources-head-b67cbad9.md +10 -2
- package/agent-docs/content-delivery/http-api.md +21 -7
- package/agent-docs/content-delivery/manifest.md +30 -8
- package/agent-docs/content-delivery/publish.md +5 -5
- package/agent-docs/content-delivery/render.md +6 -6
- package/agent-docs/content-delivery/rest.md +16 -8
- package/agent-docs/content-delivery/sections.md +11 -11
- package/agent-docs/content-delivery/select.md +6 -6
- package/agent-docs/content-delivery.md +4 -4
- package/agent-docs/contribute/agent-skills.md +3 -3
- package/agent-docs/cookbooks/authoring.md +3 -3
- package/agent-docs/cookbooks/site-workflows.md +2 -2
- package/agent-docs/cookbooks/welcome-email.md +14 -11
- package/agent-docs/documents.json +2445 -1942
- package/agent-docs/example-api/cedar.md +4 -4
- package/agent-docs/features.md +49 -0
- package/agent-docs/glossary.md +22 -22
- package/agent-docs/index.md +5 -5
- package/agent-docs/ingredients/audit-site.md +2 -2
- package/agent-docs/ingredients/build-site.md +2 -2
- package/agent-docs/ingredients/complete-page.md +2 -2
- package/agent-docs/ingredients/refresh-agent-bundle.md +2 -2
- package/agent-docs/non-goals.md +4 -4
- package/agent-docs/provenance.json +10 -4
- package/agent-docs/publish/agent-discovery.md +8 -2
- package/agent-docs/publish/agent-friendliness.md +21 -21
- package/agent-docs/publish/agent-friendliness.sections/discover-a-page-with-a-small-context-budget.md +5 -5
- package/agent-docs/publish/agent-friendliness.sections/distinguish-examples-from-a-real-service.md +5 -5
- package/agent-docs/publish/agent-friendliness.sections/evidence-has-a-scope.md +5 -5
- package/agent-docs/publish/agent-friendliness.sections/keep-shared-instructions-complete.md +5 -5
- package/agent-docs/publish/agent-friendliness.sections/related-reading.md +3 -3
- package/agent-docs/publish/agent-friendliness.sections/secret-handshake.md +3 -3
- package/agent-docs/publish/agent-friendliness.sections/try-the-page-controls.md +3 -3
- package/agent-docs/publish/agent-friendliness.sections/use-the-transport-your-client-supports.md +4 -4
- package/agent-docs/publish/agent-friendliness.sections/verify-the-page-and-detect-changes.md +9 -9
- package/agent-docs/publish/agent-friendliness.sections/what-an-agent-reads.md +5 -5
- package/agent-docs/publish/agent-friendliness.sections/what-happens-to-an-unsupported-component.md +4 -4
- package/agent-docs/publish/api-references.md +5 -5
- package/agent-docs/publish/api-references.sections/author-the-reference-page.md +2 -2
- package/agent-docs/publish/api-references.sections/build-and-verify-the-output.md +3 -3
- package/agent-docs/publish/api-references.sections/inspect-the-machine-readable-contract.md +2 -2
- package/agent-docs/publish/api-references.sections/next-steps.md +2 -2
- package/agent-docs/publish/api-references.sections/preview-a-small-api-reference.md +2 -2
- package/agent-docs/publish/api-references.sections/put-the-spec-in-your-project.md +2 -2
- package/agent-docs/publish/api-references.sections/register-the-operation.md +2 -2
- package/agent-docs/publish/api-references.sections/related-reading.md +2 -2
- package/agent-docs/publish/api-references.sections/review-imported-content-before-publishing.md +3 -3
- package/agent-docs/publish/api-references.sections/what-readers-get.md +3 -3
- package/agent-docs/publish/audit.md +8 -8
- package/agent-docs/publish/audit.sections/add-project-tests.md +2 -2
- package/agent-docs/publish/audit.sections/check-agent-evaluation-reports.md +2 -2
- package/agent-docs/publish/audit.sections/check-before-pushing.md +3 -3
- package/agent-docs/publish/audit.sections/connect-a-documentation-test-suite.md +2 -2
- package/agent-docs/publish/audit.sections/read-the-report.md +3 -3
- package/agent-docs/publish/audit.sections/related-reading.md +1 -1
- package/agent-docs/publish/content-export.md +37 -15
- 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 +2 -2
- package/agent-docs/publish/content-export.sections/inspect-the-manifest.md +3 -3
- package/agent-docs/publish/content-export.sections/prerequisites.md +4 -4
- package/agent-docs/publish/content-export.sections/related-reading.md +2 -2
- package/agent-docs/publish/content-export.sections/review-exported-api-material.md +3 -3
- package/agent-docs/publish/content-export.sections/try-the-help-drawer-example.md +2 -2
- package/agent-docs/publish/content-export.sections/what-the-representations-retain.md +4 -4
- package/agent-docs/publish/content-negotiation.md +10 -10
- package/agent-docs/publish/content-negotiation.sections/hosting-contract.md +2 -2
- package/agent-docs/publish/content-negotiation.sections/missing-pages.md +3 -3
- package/agent-docs/publish/content-negotiation.sections/related-reading.md +1 -1
- 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 +3 -3
- 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 +6 -6
- package/agent-docs/publish/deployment-profiles.md +60 -26
- package/agent-docs/publish/deployment-profiles.sections/before-you-begin.md +5 -5
- package/agent-docs/publish/deployment-profiles.sections/build-and-inspect-the-edition.md +9 -9
- package/agent-docs/publish/deployment-profiles.sections/check-the-result.md +7 -7
- package/agent-docs/publish/deployment-profiles.sections/choose-navigation-labels.md +6 -6
- package/agent-docs/publish/deployment-profiles.sections/current-limits.md +7 -7
- package/agent-docs/publish/deployment-profiles.sections/define-the-shared-sku-manifest.md +6 -6
- package/agent-docs/publish/deployment-profiles.sections/html-markdown-and-agents.md +7 -7
- package/agent-docs/publish/deployment-profiles.sections/mark-pages-and-shared-sections.md +13 -13
- package/agent-docs/publish/deployment-profiles.sections/preview-and-edit-a-customer-edition.md +55 -0
- package/agent-docs/publish/deployment-profiles.sections/related-reading.md +6 -6
- package/agent-docs/publish/deployment-profiles.sections/select-each-product-release.md +55 -0
- package/agent-docs/publish/deployment-profiles.sections/supply-the-profile-from-the-deployment.md +6 -6
- package/agent-docs/publish/evals.md +16 -16
- package/agent-docs/publish/evals.sections/add-the-audit-hook.md +5 -5
- package/agent-docs/publish/evals.sections/check-the-report.md +4 -4
- package/agent-docs/publish/evals.sections/define-a-task-file.md +5 -5
- package/agent-docs/publish/evals.sections/diagnose-a-different-build.md +5 -5
- package/agent-docs/publish/evals.sections/prepare-a-report-for-the-built-site.md +5 -5
- package/agent-docs/publish/evals.sections/related-reading.md +3 -3
- package/agent-docs/publish/evals.sections/run-and-review-the-tasks.md +4 -4
- package/agent-docs/publish/evals.sections/shoalrun-s-own-example.md +6 -6
- package/agent-docs/publish/host-adapters.md +6 -6
- package/agent-docs/publish/manni.md +16 -16
- package/agent-docs/publish/manni.sections/check-the-result.md +3 -3
- package/agent-docs/publish/manni.sections/how-this-site-uses-manni.md +6 -6
- package/agent-docs/publish/manni.sections/optional-custom-policies.md +4 -4
- package/agent-docs/publish/manni.sections/prerequisites.md +2 -2
- package/agent-docs/publish/mcp-analytics.md +12 -12
- package/agent-docs/publish/mcp-analytics.sections/adapter-exports.md +4 -4
- package/agent-docs/publish/mcp-analytics.sections/enable-analytics.md +4 -4
- package/agent-docs/publish/mcp-analytics.sections/event-fields-and-service-mappings.md +4 -4
- package/agent-docs/publish/mcp-analytics.sections/optionally-collect-intent-and-group-calls.md +4 -4
- package/agent-docs/publish/mcp-analytics.sections/optionally-identify-the-client-and-model.md +5 -5
- package/agent-docs/publish/mcp-analytics.sections/related-reading.md +3 -3
- package/agent-docs/publish/mcp-analytics.sections/safeguards-and-limits.md +5 -5
- package/agent-docs/publish/mcp.md +56 -29
- package/agent-docs/publish/mcp.sections/check-budgets-and-errors.md +8 -8
- package/agent-docs/publish/mcp.sections/choose-the-documentation-source.md +4 -4
- package/agent-docs/publish/mcp.sections/configure-the-client.md +4 -4
- package/agent-docs/publish/mcp.sections/discover-product-releases-before-searching.md +52 -0
- package/agent-docs/publish/mcp.sections/generate-a-vercel-endpoint.md +6 -6
- package/agent-docs/publish/mcp.sections/html-markdown-and-agents.md +38 -0
- package/agent-docs/publish/mcp.sections/related-reading.md +3 -3
- package/agent-docs/publish/mcp.sections/search-then-read.md +13 -12
- package/agent-docs/publish/mcp.sections/serve-a-public-endpoint-on-node.md +12 -8
- package/agent-docs/publish/mcp.sections/verify-the-connection.md +4 -4
- package/agent-docs/publish/mcp.sections/why-offer-mcp-for-public-docs.md +4 -4
- package/agent-docs/publish/openapi-extension-mappings.md +12 -12
- package/agent-docs/publish/output.md +20 -20
- package/agent-docs/publish/output.sections/api-contracts.md +1 -1
- package/agent-docs/publish/output.sections/code-highlighting.md +1 -1
- package/agent-docs/publish/output.sections/current-limits.md +1 -1
- package/agent-docs/publish/output.sections/incremental-sync.md +4 -4
- package/agent-docs/publish/output.sections/manifest-records-and-sections.md +3 -3
- package/agent-docs/publish/output.sections/navigation-section-indexes.md +1 -1
- package/agent-docs/publish/output.sections/page-formats.md +2 -2
- package/agent-docs/publish/output.sections/published-output-contract.md +5 -5
- package/agent-docs/publish/output.sections/reader-appearance-and-controls.md +1 -1
- package/agent-docs/publish/output.sections/related-reading.md +1 -1
- package/agent-docs/publish/output.sections/response-identity.md +1 -1
- package/agent-docs/publish/output.sections/site-files.md +6 -6
- package/agent-docs/publish/output.sections/validate-an-existing-build-locally.md +3 -3
- package/agent-docs/publish/output.sections/where-files-go.md +3 -3
- package/agent-docs/publish/publications.md +108 -19
- package/agent-docs/publish/publications.sections/add-a-language.md +60 -0
- package/agent-docs/publish/publications.sections/change-just-one-part-of-a-shared-page.md +63 -0
- package/agent-docs/publish/publications.sections/give-each-api-version-its-own-contract.md +34 -0
- package/agent-docs/publish/publications.sections/keep-an-unchanged-page-in-one-file.md +53 -0
- package/agent-docs/publish/publications.sections/publish-versions-without-a-product-catalog.md +49 -0
- package/agent-docs/publish/publications.sections/related-reading.md +42 -0
- package/agent-docs/publish/publications.sections/version-products-independently.md +115 -0
- package/agent-docs/publish/publications.sections/what-agents-receive.md +38 -0
- package/agent-docs/publish/revisions.md +4 -4
- package/agent-docs/publish/seo.md +10 -10
- package/agent-docs/publish/seo.sections/related-reading.md +2 -2
- package/agent-docs/publish/seo.sections/set-the-public-address.md +3 -3
- package/agent-docs/publish/seo.sections/what-agents-receive.md +3 -3
- package/agent-docs/publish/seo.sections/what-the-build-adds.md +2 -2
- package/agent-docs/publish/seo.sections/write-the-page-title-and-summary.md +2 -2
- package/agent-docs/publish/single-source-sites.md +5 -5
- package/agent-docs/publish/troubleshooting.md +10 -10
- package/agent-docs/publish/vercel.md +5 -5
- package/agent-docs/publish/vercel.sections/check-the-deployment.md +1 -1
- package/agent-docs/publish/vercel.sections/include-an-mcp-endpoint.md +2 -2
- package/agent-docs/publish/vercel.sections/prepare-your-project.md +2 -2
- package/agent-docs/publish/vercel.sections/related-reading.md +1 -1
- package/agent-docs/publish.md +2 -2
- package/agent-docs/recipes/add-page.md +5 -5
- 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 +1 -1
- 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 +1 -1
- package/agent-docs/recipes/add-page.sections/check-the-built-page-artifacts.md +1 -1
- package/agent-docs/recipes/add-page.sections/check-the-outcome.md +1 -1
- 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 +1 -1
- package/agent-docs/recipes/add-page.sections/regenerate-the-agent-documentation-bundle.md +2 -2
- package/agent-docs/recipes/add-page.sections/related-reading.md +1 -1
- package/agent-docs/recipes/add-page.sections/scaffold-a-new-guide.md +1 -1
- package/agent-docs/recipes/audit-docs.md +4 -4
- package/agent-docs/recipes/build-docs.md +2 -2
- package/agent-docs/recipes/preview-hybrid-search.md +5 -5
- package/agent-docs/recipes/preview-page.md +2 -2
- package/agent-docs/recipes/queue-email.md +3 -3
- package/agent-docs/recipes/refresh-agent-docs.md +4 -4
- package/agent-docs/recipes/send-welcome-email.md +15 -15
- package/agent-docs/reference/agent-skills.md +7 -7
- package/agent-docs/search-and-chat.md +4 -4
- package/agent-docs/search-index.json +1 -1
- package/agent-docs/start.md +5 -5
- package/agent-docs/start.sections/add-the-page-to-navigation.md +3 -3
- package/agent-docs/start.sections/build-and-check-both-outputs.md +3 -3
- package/agent-docs/start.sections/build-this-site.md +2 -2
- package/agent-docs/start.sections/check-writing-style.md +2 -2
- package/agent-docs/start.sections/create-a-page.md +2 -2
- package/agent-docs/start.sections/make-it-yours.md +2 -2
- package/agent-docs/start.sections/migrating-from-github-packages.md +2 -2
- package/agent-docs/start.sections/prerequisites.md +2 -2
- package/agent-docs/start.sections/related-reading.md +2 -2
- package/agent-docs/start.sections/start-your-own-project.md +3 -3
- package/agent-docs/status.md +14 -4
- package/agent-docs/styling/color-modes.md +2 -2
- package/agent-docs/styling/footer.md +2 -2
- package/agent-docs/styling/header.md +2 -2
- package/agent-docs/styling/layouts.md +3 -3
- package/agent-docs/styling/layouts.sections/build-a-landing-page.md +1 -1
- package/agent-docs/styling/layouts.sections/build-a-splash-page.md +1 -1
- package/agent-docs/styling/layouts.sections/control-navigation-tabs.md +2 -2
- package/agent-docs/styling/layouts.sections/customize-the-hero.md +1 -1
- package/agent-docs/styling/layouts.sections/hero.md +1 -1
- package/agent-docs/styling/layouts.sections/hide-the-table-of-contents-or-give-content-more-room.md +1 -1
- package/agent-docs/styling/layouts.sections/html-markdown-and-agents.md +2 -2
- package/agent-docs/styling/layouts.sections/related-reading.md +1 -1
- package/agent-docs/styling/palettes.md +3 -3
- package/agent-docs/styling/share-images.md +3 -3
- package/agent-docs/styling/themes.md +2 -2
- package/agent-docs/styling/try.md +2 -2
- package/agent-docs/what-is-shoalrun.md +7 -3
- package/assets/ask-widget.js +20 -6
- package/assets/navigation.js +5 -0
- package/dist/ai-directory.d.ts +1 -0
- package/dist/ai-directory.js +12 -0
- package/dist/answer-cards.js +1 -1
- package/dist/api-materialize.d.ts +2 -1
- package/dist/api-materialize.js +21 -9
- package/dist/api-publication-plan.d.ts +2 -0
- package/dist/api-publication-plan.js +23 -7
- package/dist/api-publication-review.js +4 -3
- package/dist/api-selection.d.ts +5 -2
- package/dist/api-selection.js +18 -11
- package/dist/artifact-bundle.js +9 -6
- package/dist/ask-function.d.ts +4 -18
- package/dist/ask-function.js +12 -71
- package/dist/ask-runtime.d.ts +46 -0
- package/dist/ask-runtime.js +101 -0
- package/dist/ask-setup.d.ts +3 -42
- package/dist/ask-setup.js +5 -93
- package/dist/authored-change.js +2 -1
- package/dist/authoring-project.js +1 -1
- package/dist/cards.js +2 -1
- package/dist/cli-discovery.d.ts +2 -2
- package/dist/cli-discovery.js +9 -4
- package/dist/cli.js +48 -23
- package/dist/compiler-config.d.ts +17 -0
- package/dist/compiler-config.js +43 -2
- package/dist/compiler.d.ts +21 -0
- package/dist/compiler.js +16 -12
- package/dist/component-transform.d.ts +2 -4
- package/dist/component-transform.js +20 -7
- package/dist/config.d.ts +1 -0
- package/dist/config.js +2 -1
- package/dist/content-delivery-contract.d.ts +2 -1
- package/dist/content-delivery-validation.d.ts +2 -2
- package/dist/content-delivery-validation.js +6 -4
- package/dist/content-export-command.d.ts +1 -1
- package/dist/content-export-command.js +4 -4
- package/dist/content-export-comparison.js +6 -5
- package/dist/content-export-config.js +3 -1
- package/dist/content-export.js +9 -8
- package/dist/content-rest-client.js +4 -2
- package/dist/content-rest-contract.d.ts +2 -2
- package/dist/content-rest-server.js +11 -6
- package/dist/content-source.d.ts +13 -0
- package/dist/content-source.js +5 -2
- package/dist/content-workspace.d.ts +12 -0
- package/dist/content-workspace.js +2 -1
- package/dist/content.js +3 -2
- package/dist/cookbook-chooser.js +2 -1
- package/dist/deployment-profile.d.ts +2 -1
- package/dist/deployment-profile.js +38 -8
- package/dist/dev.d.ts +3 -1
- package/dist/dev.js +99 -12
- package/dist/docs-author.js +2 -1
- package/dist/docs-command.js +2 -2
- package/dist/docs-eval.d.ts +1 -0
- package/dist/docs-eval.js +2 -2
- package/dist/docs-mcp.d.ts +1 -0
- package/dist/docs-mcp.js +10 -5
- package/dist/docs-tool.d.ts +4 -10
- package/dist/document-sync.d.ts +1 -0
- package/dist/document-sync.js +2 -2
- package/dist/documentation-core.d.ts +29 -10
- package/dist/documentation-core.js +38 -4
- package/dist/embeddings.d.ts +1 -1
- package/dist/embeddings.js +1 -1
- package/dist/freshness.js +2 -2
- package/dist/frontmatter.js +13 -7
- package/dist/function-package.js +5 -0
- package/dist/function-runtime.d.ts +24 -0
- package/dist/function-runtime.js +45 -0
- package/dist/index-build.d.ts +2 -2
- package/dist/index-build.js +5 -13
- package/dist/ingredient-draft.js +20 -10
- package/dist/mcp-analytics.d.ts +1 -0
- package/dist/mcp-artifacts.js +13 -4
- package/dist/mcp-config.d.ts +1 -0
- package/dist/mcp-config.js +3 -1
- package/dist/mcp-http.js +1 -1
- package/dist/page-materialization.d.ts +3 -4
- package/dist/page-materialization.js +15 -8
- package/dist/page-renderer.d.ts +6 -0
- package/dist/page-renderer.js +16 -5
- package/dist/project-navigation.js +2 -1
- package/dist/publication-identity.d.ts +12 -0
- package/dist/publication-identity.js +17 -0
- package/dist/publication-manifest.d.ts +24 -1
- package/dist/publication-manifest.js +14 -6
- package/dist/publication-plan.js +21 -9
- package/dist/publication-render.js +24 -8
- package/dist/recipe-draft.js +9 -6
- package/dist/retrieval-runtime.d.ts +5 -0
- package/dist/retrieval-runtime.js +21 -0
- package/dist/scaffold.d.ts +7 -4
- package/dist/scaffold.js +16 -16
- package/dist/search-function.d.ts +2 -0
- package/dist/search-function.js +30 -0
- package/dist/search-handler.js +2 -2
- package/dist/search-identifier-core.d.ts +4 -0
- package/dist/search-identifier-core.js +30 -0
- package/dist/search-identifier.d.ts +3 -3
- package/dist/search-identifier.js +7 -30
- package/dist/search-literal.js +1 -1
- package/dist/search-query.d.ts +4 -10
- package/dist/search-query.js +10 -9
- package/dist/search-results.js +1 -1
- package/dist/search-snippet.d.ts +1 -1
- package/dist/search-snippet.js +2 -14
- package/dist/search-text.d.ts +1 -0
- package/dist/search-text.js +14 -0
- package/dist/server.d.ts +8 -0
- package/dist/server.js +14 -3
- package/dist/subject-deprecation.js +2 -1
- package/dist/vercel-function.js +11 -3
- package/example-configs/products/README.md +37 -0
- package/example-configs/products/content/operations.mdx +50 -0
- package/example-configs/products/content/payments-v2.mdx +30 -0
- package/example-configs/products/content/payments-v3.mdx +38 -0
- package/example-configs/products/content/priority-settlement.mdx +23 -0
- package/example-configs/products/content/reporting-v1.mdx +36 -0
- package/example-configs/products/content/scheduled-exports.mdx +23 -0
- package/example-configs/products/docs.config.yaml +56 -0
- package/example-configs/products/profiles/all-releases.yaml +9 -0
- package/example-configs/products/profiles/customer-a.yaml +13 -0
- package/example-configs/products/profiles/customer-b.yaml +13 -0
- package/example-configs/products/skus.yaml +11 -0
- package/examples/content-delivery/preview.mjs +1 -1
- package/package.json +1 -1
- package/schemas/content-export.schema.json +41 -3
- package/schemas/content-rest.openapi.json +184 -37
- package/skills/shoalrun-author/SKILL.md +6 -2
- package/skills/shoalrun-author/references/customer-editions.md +34 -4
- package/skills/shoalrun-author/references/publications.md +60 -0
- package/skills/shoalrun-recipes/SKILL.md +2 -0
- package/skills/shoalrun-setup/SKILL.md +3 -1
- package/styles/header.css +3 -0
- package/styles/site.css +3 -0
- package/agent-docs/publish/content-export.sections/export-selected-pages.md +0 -116
package/dist/compiler-config.js
CHANGED
|
@@ -58,12 +58,13 @@ export function requireSiteSection(config) {
|
|
|
58
58
|
}
|
|
59
59
|
export function requirePublicationsSection(config) {
|
|
60
60
|
const publications = config.publications;
|
|
61
|
-
if (!isConfigMapping(publications) || !isConfigMapping(publications.channels) || !isConfigMapping(publications.versions)) {
|
|
61
|
+
if (!isConfigMapping(publications) || !isConfigMapping(publications.channels) || (publications.versions !== undefined && !isConfigMapping(publications.versions)) || (publications.versions === undefined && !isConfigMapping(publications.products))) {
|
|
62
62
|
throw new Error('publications needs channels and versions mappings');
|
|
63
63
|
}
|
|
64
64
|
if (publications.defaults !== undefined && !isConfigMapping(publications.defaults)) {
|
|
65
65
|
throw new Error('publications.defaults must be a mapping of channel, version, and language');
|
|
66
66
|
}
|
|
67
|
+
publications.versions ??= {};
|
|
67
68
|
for (const group of ['channels', 'versions']) {
|
|
68
69
|
for (const [name, value] of Object.entries(publications[group])) {
|
|
69
70
|
if (!isConfigMapping(value) || (value.pathPrefix !== undefined && typeof value.pathPrefix !== 'string')) {
|
|
@@ -72,8 +73,48 @@ export function requirePublicationsSection(config) {
|
|
|
72
73
|
}
|
|
73
74
|
}
|
|
74
75
|
const defaults = publications.defaults;
|
|
75
|
-
if (isConfigMapping(defaults) && ['channel', 'version', 'language'].some(key => defaults[key] !== undefined && typeof defaults[key] !== 'string')) {
|
|
76
|
+
if (isConfigMapping(defaults) && ['product', 'channel', 'version', 'language'].some(key => defaults[key] !== undefined && typeof defaults[key] !== 'string')) {
|
|
76
77
|
throw new Error('publications.defaults must be a mapping of channel, version, and language');
|
|
77
78
|
}
|
|
79
|
+
if (publications.products !== undefined) {
|
|
80
|
+
if (!isConfigMapping(publications.products) || !Object.keys(publications.products).length)
|
|
81
|
+
throw new Error('publications.products must be a nonempty mapping');
|
|
82
|
+
const prefixes = new Set();
|
|
83
|
+
for (const [id, product] of Object.entries(publications.products)) {
|
|
84
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(id) || !isConfigMapping(product) || Object.keys(product).some(key => !['label', 'pathPrefix', 'defaultVersion', 'versions'].includes(key)))
|
|
85
|
+
throw new Error(`Invalid publication product ${id}`);
|
|
86
|
+
if (typeof product.pathPrefix !== 'string' || !/^\/[A-Za-z0-9/_-]+$/.test(product.pathPrefix) || product.pathPrefix.endsWith('/') || product.pathPrefix.includes('//') || product.pathPrefix.includes('..'))
|
|
87
|
+
throw new Error(`Product ${id} needs an absolute nonempty pathPrefix without a trailing slash`);
|
|
88
|
+
if (prefixes.has(product.pathPrefix.toLowerCase()))
|
|
89
|
+
throw new Error(`Duplicate product pathPrefix ${product.pathPrefix}`);
|
|
90
|
+
prefixes.add(product.pathPrefix.toLowerCase());
|
|
91
|
+
if (product.label !== undefined && (typeof product.label !== 'string' || !product.label.trim()))
|
|
92
|
+
throw new Error(`Product ${id}.label must be nonempty text`);
|
|
93
|
+
if (!isConfigMapping(product.versions) || !Object.keys(product.versions).length || typeof product.defaultVersion !== 'string' || !Object.hasOwn(product.versions, product.defaultVersion))
|
|
94
|
+
throw new Error(`Product ${id} needs versions and a valid defaultVersion`);
|
|
95
|
+
const versionPrefixes = new Set();
|
|
96
|
+
for (const [version, definition] of Object.entries(product.versions)) {
|
|
97
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(version) || !isConfigMapping(definition) || (definition.pathPrefix !== undefined && (typeof definition.pathPrefix !== 'string' || (definition.pathPrefix !== '' && (!/^\/[A-Za-z0-9/_-]+$/.test(definition.pathPrefix) || definition.pathPrefix.includes('//') || definition.pathPrefix.endsWith('/'))))))
|
|
98
|
+
throw new Error(`Product ${id} has invalid version ${version}`);
|
|
99
|
+
const prefix = String(definition.pathPrefix ?? '').toLowerCase();
|
|
100
|
+
if (versionPrefixes.has(prefix))
|
|
101
|
+
throw new Error(`Product ${id} has duplicate version pathPrefix ${prefix || '(empty)'}`);
|
|
102
|
+
versionPrefixes.add(prefix);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
78
106
|
return publications;
|
|
79
107
|
}
|
|
108
|
+
/** Resolve product-local defaults without borrowing another product's catalog. */
|
|
109
|
+
export function resolvePublication(publications, value, language = 'en') {
|
|
110
|
+
const product = value.product;
|
|
111
|
+
if (product !== undefined && (typeof product !== 'string' || !publications.products || !Object.hasOwn(publications.products, product)))
|
|
112
|
+
throw new Error(`Unknown publication product ${String(product)}`);
|
|
113
|
+
const catalog = product === undefined ? publications.versions ?? {} : publications.products[product].versions;
|
|
114
|
+
const scopedDefault = product !== undefined && publications.defaults?.product === product && publications.defaults.version && Object.hasOwn(catalog, publications.defaults.version) ? publications.defaults.version : undefined;
|
|
115
|
+
const version = value.version ?? (product === undefined ? publications.defaults?.version : scopedDefault ?? publications.products[product].defaultVersion);
|
|
116
|
+
const channel = value.channel ?? publications.defaults?.channel;
|
|
117
|
+
if (typeof channel !== 'string' || !Object.hasOwn(publications.channels, channel) || typeof version !== 'string' || !Object.hasOwn(catalog, version) || (value.language !== undefined && (typeof value.language !== 'string' || !value.language)))
|
|
118
|
+
throw new Error(`Unknown publication ${product === undefined ? '' : String(product) + '/'}${String(channel)}/${String(version)}`);
|
|
119
|
+
return { ...(product === undefined ? {} : { product: product }), channel, version, language: value.language ?? language };
|
|
120
|
+
}
|
package/dist/compiler.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export declare function compile(configFile: string, destination?: string, proven
|
|
|
11
11
|
sourceOverrides?: ReadonlyMap<string, string>;
|
|
12
12
|
authoringFiles?: ReadonlySet<string>;
|
|
13
13
|
profile?: string;
|
|
14
|
+
onDependency?: (file: string) => void;
|
|
14
15
|
}): Promise<{
|
|
15
16
|
authoringSources?: {
|
|
16
17
|
id: string;
|
|
@@ -93,6 +94,10 @@ export declare function compile(configFile: string, destination?: string, proven
|
|
|
93
94
|
url?: string;
|
|
94
95
|
}[];
|
|
95
96
|
verified?: string | undefined;
|
|
97
|
+
availability?: {
|
|
98
|
+
since?: string;
|
|
99
|
+
through?: string;
|
|
100
|
+
} | undefined;
|
|
96
101
|
updated?: string | undefined;
|
|
97
102
|
indexable: boolean;
|
|
98
103
|
navigationTab: {
|
|
@@ -158,6 +163,10 @@ export declare function compile(configFile: string, destination?: string, proven
|
|
|
158
163
|
url?: string;
|
|
159
164
|
}[];
|
|
160
165
|
verified?: string | undefined;
|
|
166
|
+
availability?: {
|
|
167
|
+
since?: string;
|
|
168
|
+
through?: string;
|
|
169
|
+
} | undefined;
|
|
161
170
|
updated?: string | undefined;
|
|
162
171
|
indexable: boolean;
|
|
163
172
|
navigationTab?: undefined;
|
|
@@ -176,6 +185,7 @@ export declare function compile(configFile: string, destination?: string, proven
|
|
|
176
185
|
operations: Record<string, {
|
|
177
186
|
id: string;
|
|
178
187
|
type: string;
|
|
188
|
+
product?: string;
|
|
179
189
|
channel: string;
|
|
180
190
|
version: string;
|
|
181
191
|
language: string;
|
|
@@ -195,6 +205,7 @@ export declare function compile(configFile: string, destination?: string, proven
|
|
|
195
205
|
}[];
|
|
196
206
|
apiSources: {
|
|
197
207
|
apiId: string;
|
|
208
|
+
product?: string;
|
|
198
209
|
channel: string;
|
|
199
210
|
version: string;
|
|
200
211
|
endpoint: string | null;
|
|
@@ -216,6 +227,16 @@ export declare function compile(configFile: string, destination?: string, proven
|
|
|
216
227
|
sitemap?: string | undefined;
|
|
217
228
|
basePath: string;
|
|
218
229
|
searchSynonyms?: unknown[] | undefined;
|
|
230
|
+
publications?: {
|
|
231
|
+
enabled: Variant[];
|
|
232
|
+
products: {
|
|
233
|
+
[k: string]: {
|
|
234
|
+
versions: string[];
|
|
235
|
+
defaultVersion?: string | undefined;
|
|
236
|
+
label?: string | undefined;
|
|
237
|
+
};
|
|
238
|
+
};
|
|
239
|
+
} | undefined;
|
|
219
240
|
schemaVersion: number;
|
|
220
241
|
configDigest: string;
|
|
221
242
|
}>;
|
package/dist/compiler.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { documentKey, publicationKey, samePublication } from './publication-identity.js';
|
|
1
2
|
import { validateHeader, validateFooter } from './site-identity.js';
|
|
2
3
|
import { profileSelection } from './deployment-profile.js';
|
|
3
4
|
import { profileNavigation } from './project-navigation.js';
|
|
@@ -43,14 +44,14 @@ import { assembleArtifacts } from './artifact-bundle.js';
|
|
|
43
44
|
import { materializePages } from './page-materialization.js';
|
|
44
45
|
import { renderPublicationPages } from './publication-render.js';
|
|
45
46
|
import { buildPublicationManifest } from './publication-manifest.js';
|
|
46
|
-
import { configField, isConfigMapping, requirePublicationsSection, requireSiteSection, resolvedCompilerConfig } from './compiler-config.js';
|
|
47
|
+
import { configField, isConfigMapping, requirePublicationsSection, resolvePublication, requireSiteSection, resolvedCompilerConfig } from './compiler-config.js';
|
|
47
48
|
import { validateRetrieval } from './retrieval-config.js';
|
|
48
49
|
import { validateChat } from './chat-config.js';
|
|
49
50
|
import { normalizeBasePath, sitePath } from './site-path.js';
|
|
50
51
|
const generatedReferenceBody = 'This reference is generated from the OpenAPI description. It shows the operation contract; follow any related guides below for task steps and context.\n';
|
|
51
52
|
const generatedWebhookBody = 'This webhook reference is generated from the OpenAPI description. The provider sends this event to the receiver.\n';
|
|
52
53
|
const digest = (value) => createHash('sha256').update(value).digest('hex');
|
|
53
|
-
const keyFor =
|
|
54
|
+
const keyFor = documentKey;
|
|
54
55
|
function validateSearch(value, declaringFile) {
|
|
55
56
|
if (value === undefined)
|
|
56
57
|
return { provider: 'lexical', module: builtInSearchProvider, index: true };
|
|
@@ -101,7 +102,7 @@ export async function checkThemeContrast(configFile) {
|
|
|
101
102
|
return { modes, palette: palette.name };
|
|
102
103
|
}
|
|
103
104
|
export async function compile(configFile, destination, provenance = {}, options = {}) {
|
|
104
|
-
const loaded = await loadConfig(configFile, { profile: options.profile });
|
|
105
|
+
const loaded = await loadConfig(configFile, { profile: options.profile, onDependency: options.onDependency });
|
|
105
106
|
const componentPlugins = await loadComponentPlugins(loaded);
|
|
106
107
|
const provenanceRecord = buildInfo(loaded.digest, provenance);
|
|
107
108
|
const resolvedConfig = resolvedCompilerConfig(loaded.value);
|
|
@@ -215,10 +216,12 @@ export async function compile(configFile, destination, provenance = {}, options
|
|
|
215
216
|
if (!Array.isArray(enabledVariants))
|
|
216
217
|
throw new Error('publications.enabled must declare at least one variant');
|
|
217
218
|
const variants = enabledVariants.map((variant) => {
|
|
218
|
-
if (!isConfigMapping(variant)
|
|
219
|
-
throw new Error('publications.enabled needs
|
|
220
|
-
return
|
|
219
|
+
if (!isConfigMapping(variant))
|
|
220
|
+
throw new Error('publications.enabled needs publication coordinates');
|
|
221
|
+
return resolvePublication(config.publications, variant, language);
|
|
221
222
|
});
|
|
223
|
+
if (new Set(variants.map(publicationKey)).size !== variants.length)
|
|
224
|
+
throw new Error('publications.enabled has duplicate publication coordinates');
|
|
222
225
|
if (!variants.length)
|
|
223
226
|
throw new Error('publications.enabled must declare at least one variant');
|
|
224
227
|
const externalSites = config.publications.externalSites ?? [];
|
|
@@ -263,7 +266,7 @@ export async function compile(configFile, destination, provenance = {}, options
|
|
|
263
266
|
const document = isConfigMapping(rawDocument) ? rawDocument : {};
|
|
264
267
|
const rawVariant = document.variant;
|
|
265
268
|
const route = document.url;
|
|
266
|
-
if (typeof document.id !== 'string' || !document.id || !isConfigMapping(rawVariant) || ['channel', 'version', 'language'].some(field => typeof rawVariant[field] !== 'string' || !rawVariant[field]) || typeof route !== 'string' || !route.startsWith('/') || route.startsWith('//') || route.includes('..') || /[?#\\]|%2f|%5c/i.test(route)) {
|
|
269
|
+
if (typeof document.id !== 'string' || !document.id || !isConfigMapping(rawVariant) || (rawVariant.product !== undefined && (typeof rawVariant.product !== 'string' || !rawVariant.product)) || ['channel', 'version', 'language'].some(field => typeof rawVariant[field] !== 'string' || !rawVariant[field]) || typeof route !== 'string' || !route.startsWith('/') || route.startsWith('//') || route.includes('..') || /[?#\\]|%2f|%5c/i.test(route)) {
|
|
267
270
|
throw new Error(`${setting}.manifest has an invalid document identity, publication, or URL`);
|
|
268
271
|
}
|
|
269
272
|
const variant = rawVariant;
|
|
@@ -283,8 +286,8 @@ export async function compile(configFile, destination, provenance = {}, options
|
|
|
283
286
|
if (editionBadge !== 'auto' && editionBadge !== 'always' && editionBadge !== 'never')
|
|
284
287
|
throw new Error('site.editionBadge must be auto, always, or never');
|
|
285
288
|
const varying = (field) => new Set(variants.map(variant => variant[field])).size > 1;
|
|
286
|
-
const editionLabel = (variant) => editionBadge === 'never' ? '' : ['channel', 'version', 'language']
|
|
287
|
-
.filter(field => editionBadge === 'always' || varying(field)).map(field => variant[field]).join(' · ');
|
|
289
|
+
const editionLabel = (variant) => editionBadge === 'never' ? '' : ['product', 'channel', 'version', 'language']
|
|
290
|
+
.filter(field => variant[field] !== undefined && (editionBadge === 'always' || varying(field))).map(field => variant[field]).join(' · ');
|
|
288
291
|
const { docs, knownDocumentIds, knownDocumentTypes, routeOwners, contentDir, snippets, apiPlan, api, sourceForVariant, knownOperations, relatedApiTargets, guidesByApi, sourceForOperation } = await prepareContentWorkspace({
|
|
289
292
|
base, basePath, config, loaded, variants, language, readerFilters, contentFilter, metadataProvider, metadataDependencies,
|
|
290
293
|
sourceOverrides: options.sourceOverrides, authoringFiles: options.authoringFiles
|
|
@@ -390,7 +393,7 @@ export async function compile(configFile, destination, provenance = {}, options
|
|
|
390
393
|
] : [];
|
|
391
394
|
for (const [operationId, bindings] of Object.entries(operations)) {
|
|
392
395
|
for (const variant of variants) {
|
|
393
|
-
const inVariant = bindings.filter(b => b
|
|
396
|
+
const inVariant = bindings.filter(b => samePublication(b, variant));
|
|
394
397
|
if (inVariant.filter(b => b.type === 'api-reference').length > 1)
|
|
395
398
|
throw new Error(`Multiple canonical references for ${operationId}`);
|
|
396
399
|
}
|
|
@@ -414,7 +417,7 @@ export async function compile(configFile, destination, provenance = {}, options
|
|
|
414
417
|
const to = rule.to;
|
|
415
418
|
if (!isConfigMapping(to) || typeof to.doc !== 'string' || !to.doc || typeof to.channel !== 'string' || !to.channel || typeof to.version !== 'string' || !to.version || typeof to.language !== 'string' || !to.language)
|
|
416
419
|
throw new Error(`Redirect ${rule.from} needs an explicit target variant`);
|
|
417
|
-
const target = docs.get(keyFor(to.doc, { channel: to.channel, version: to.version, language: to.language }));
|
|
420
|
+
const target = docs.get(keyFor(to.doc, { channel: to.channel, version: to.version, language: to.language, ...(to.product === undefined ? {} : { product: String(to.product) }) }));
|
|
418
421
|
if (!target)
|
|
419
422
|
throw new Error(`Redirect ${rule.from} targets missing document variant`);
|
|
420
423
|
const status = rule.status ?? 308;
|
|
@@ -423,7 +426,7 @@ export async function compile(configFile, destination, provenance = {}, options
|
|
|
423
426
|
// The old page's Markdown twin moves too, so its .md URL redirects to the target's twin.
|
|
424
427
|
redirects.push({ from: sourceRoute, to: target.route, markdownFrom: markdownRoute(sourceRoute.replace(/(.)\/+$/, '$1'), basePath), markdownTo: target.markdownRoute, status });
|
|
425
428
|
}
|
|
426
|
-
const apiSources = [...apiPublications.values()].map(({ apiId, variant, endpoint, referenceUrl, sourceUrl, mediaType }) => ({ apiId, channel: variant.channel, version: variant.version, endpoint: endpoint ?? null, referenceUrl, sourceUrl, mediaType }));
|
|
429
|
+
const apiSources = [...apiPublications.values()].map(({ apiId, variant, endpoint, referenceUrl, sourceUrl, mediaType }) => ({ apiId, ...(variant.product === undefined ? {} : { product: variant.product }), channel: variant.channel, version: variant.version, endpoint: endpoint ?? null, referenceUrl, sourceUrl, mediaType }));
|
|
427
430
|
let catalog = null;
|
|
428
431
|
const discoverable = apiSources.filter(item => item.endpoint);
|
|
429
432
|
if (discoverable.length) {
|
|
@@ -442,6 +445,7 @@ export async function compile(configFile, destination, provenance = {}, options
|
|
|
442
445
|
const manifestDependencies = [...new Set([...loaded.dependencies, ...componentPlugins.dependencies, ...externalManifestFiles, ...api.dependencies, ...(metadataProvider ? [metadataProvider.module] : []), ...metadataDependencies, ...(highlighter.dependency ? [highlighter.dependency] : []), ...styleFiles, ...(themeStyleFile ? [themeStyleFile] : []), ...palette.files, ...(search.module ? [search.module] : []), ...previewFiles, ...(customStyleFile ? [customStyleFile] : []), ...(customReaderModule ? [customReaderModule] : []), ...(analyticsModule ? [analyticsModule] : []), ...(mcpAnalyticsModule ? [mcpAnalyticsModule] : []), ...(shareImages.template ? [shareImages.template] : []), ...shareImages.fonts, ...(faviconFile ? [faviconFile] : []), ...heroImages.values(), ...walkthroughSources, ...fontFiles, ...fonts.faces.map(face => face.file), ...scriptFiles, iconLicenseFile, ...[...snippets.values()].map(s => s.file), ...[...docs.values()].map(d => d.file)])].sort();
|
|
443
446
|
const llmsDiscovery = resolveLlmsDiscovery(configField(config.outputs, 'llms'));
|
|
444
447
|
const { manifest, headers, sitemaps } = buildPublicationManifest({
|
|
448
|
+
configPublications: config.publications,
|
|
445
449
|
fictionalDocuments: new Set(rendered.filter(({ doc }) => fictionalDocument(doc, llmsDiscovery)).map(({ doc }) => doc)),
|
|
446
450
|
configDigest: loaded.digest, synonyms, basePath, publicPath, readerFilters, taxonomy: resolveTaxonomy(configField(config.frontmatter, 'taxonomy')), dependencies: manifestDependencies,
|
|
447
451
|
rendered, resolvedNavigation, cardUses, snippetUses, apiEmbedUses, focusedContracts, operations,
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
+
import type { CompilerPublicationsConfig } from './compiler-config.js';
|
|
1
2
|
import { type ComponentRegistry } from './component-plugins.js';
|
|
2
3
|
import { type CalloutTypes } from './callouts.js';
|
|
3
4
|
import { type BadgeVariants } from './badges.js';
|
|
4
5
|
import { SnippetDefinition, SnippetUse } from './snippets.js';
|
|
5
6
|
import { type ReaderFiltersConfig } from './reader-filters.js';
|
|
6
7
|
import type { Document } from './content-source.js';
|
|
7
|
-
export declare function transformMdx(tree: unknown, current: Document, registry: Map<string, Document>, snippets?: Map<string, SnippetDefinition>, projectValues?: Record<string, unknown>, uses?: SnippetUse[], calloutTypes?: CalloutTypes, projectRoot?: string, readerConfig?: ReaderFiltersConfig, frontmatterConfig?: unknown, publicationConfig?:
|
|
8
|
-
channels: Record<string, unknown>;
|
|
9
|
-
versions: Record<string, unknown>;
|
|
10
|
-
}, badgeVariants?: BadgeVariants, componentPlugins?: ComponentRegistry): unknown;
|
|
8
|
+
export declare function transformMdx(tree: unknown, current: Document, registry: Map<string, Document>, snippets?: Map<string, SnippetDefinition>, projectValues?: Record<string, unknown>, uses?: SnippetUse[], calloutTypes?: CalloutTypes, projectRoot?: string, readerConfig?: ReaderFiltersConfig, frontmatterConfig?: unknown, publicationConfig?: CompilerPublicationsConfig, badgeVariants?: BadgeVariants, componentPlugins?: ComponentRegistry, publicationRegistry?: Map<string, Document>): unknown;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { documentKey } from './publication-identity.js';
|
|
1
2
|
import { pruneFeatureTree } from './deployment-profile.js';
|
|
2
3
|
import { lowerComponent } from './component-plugins.js';
|
|
3
4
|
import { cardComponent } from './cards.js';
|
|
@@ -57,7 +58,7 @@ function isMdxAttribute(value) {
|
|
|
57
58
|
function literalAttributes(attributes) {
|
|
58
59
|
return attributes.every(item => item.type === 'mdxJsxAttribute' && typeof item.value === 'string');
|
|
59
60
|
}
|
|
60
|
-
export function transformMdx(tree, current, registry, snippets = new Map(), projectValues = {}, uses = [], calloutTypes = resolveCalloutTypes(undefined, current.file), projectRoot, readerConfig, frontmatterConfig = {}, publicationConfig, badgeVariants = resolveBadgeVariants(undefined, current.file), componentPlugins = new Map()) {
|
|
61
|
+
export function transformMdx(tree, current, registry, snippets = new Map(), projectValues = {}, uses = [], calloutTypes = resolveCalloutTypes(undefined, current.file), projectRoot, readerConfig, frontmatterConfig = {}, publicationConfig, badgeVariants = resolveBadgeVariants(undefined, current.file), componentPlugins = new Map(), publicationRegistry) {
|
|
61
62
|
if (!isMdxRoot(tree))
|
|
62
63
|
throw new Error(`${current.file}: parsed content must be a root with children`);
|
|
63
64
|
tree = lowerSectionMarkers(pruneFeatureTree(tree, current.featureContext, current.file), current.file);
|
|
@@ -138,14 +139,18 @@ export function transformMdx(tree, current, registry, snippets = new Map(), proj
|
|
|
138
139
|
}
|
|
139
140
|
if (node.name === 'ForPublication') {
|
|
140
141
|
const attributes = node.attributes ?? [];
|
|
141
|
-
const allowed = ['channel', 'version', 'language'];
|
|
142
|
+
const allowed = ['product', 'channel', 'version', 'language'];
|
|
142
143
|
if (node.type !== 'mdxJsxFlowElement' || !node.children?.length || !attributes.length || !literalAttributes(attributes) || attributes.some((item) => !allowed.includes(item.name) || !item.value.trim()) || new Set(attributes.map((item) => item.name)).size !== attributes.length) {
|
|
143
144
|
throw new Error(`${sourceFile}: <ForPublication> needs block content and distinct literal channel, version, or language attributes`);
|
|
144
145
|
}
|
|
145
|
-
|
|
146
|
-
|
|
146
|
+
const product = attributes.find(item => item.name === 'product')?.value ?? current.variant.product;
|
|
147
|
+
for (const item of attributes) {
|
|
148
|
+
const catalog = item.name === 'product' ? publicationConfig?.products
|
|
149
|
+
: item.name === 'channel' ? publicationConfig?.channels
|
|
150
|
+
: item.name === 'version' ? (product ? publicationConfig?.products?.[product]?.versions : publicationConfig?.versions) : undefined;
|
|
151
|
+
if (publicationConfig && item.name !== 'language' && (!catalog || !Object.hasOwn(catalog, item.value)))
|
|
147
152
|
throw new Error(`${sourceFile}: <ForPublication> names unknown ${item.name} ${item.value}`);
|
|
148
|
-
|
|
153
|
+
}
|
|
149
154
|
if (attributes.some((item) => current.variant[item.name] !== item.value))
|
|
150
155
|
return [];
|
|
151
156
|
return childrenOf(node.children, scope, stack, sourceFile);
|
|
@@ -635,9 +640,17 @@ export function transformMdx(tree, current, registry, snippets = new Map(), proj
|
|
|
635
640
|
return text(String(scope[name]));
|
|
636
641
|
}
|
|
637
642
|
if (node.name === 'DocLink') {
|
|
638
|
-
const
|
|
643
|
+
const attributes = node.attributes ?? [];
|
|
644
|
+
if (!literalAttributes(attributes) || attributes.some(item => !['doc', 'product', 'channel', 'version', 'language'].includes(item.name)) || new Set(attributes.map(item => item.name)).size !== attributes.length)
|
|
645
|
+
throw new Error(`${sourceFile}: DocLink needs distinct literal publication attributes`);
|
|
646
|
+
const id = attr(node, 'doc');
|
|
647
|
+
const qualified = attributes.some(item => item.name !== 'doc');
|
|
648
|
+
if (qualified && attributes.some(item => item.name === 'product' && item.value !== current.variant.product) && !attributes.some(item => item.name === 'version'))
|
|
649
|
+
throw new Error(`${sourceFile}: cross-product DocLink needs an explicit version`);
|
|
650
|
+
const variant = { ...current.variant, ...Object.fromEntries(attributes.filter(item => item.name !== 'doc').map(item => [item.name, item.value])) };
|
|
651
|
+
const target = qualified ? publicationRegistry?.get(documentKey(id, variant)) : registry.get(id);
|
|
639
652
|
if (!target)
|
|
640
|
-
throw new Error(`${sourceFile}: unknown DocLink target`);
|
|
653
|
+
throw new Error(`${sourceFile}: unknown DocLink target ${id} in selected publication`);
|
|
641
654
|
return link(target.route, (node.children ?? []).map((x) => x.value ?? '').join('') || target.frontmatter.title);
|
|
642
655
|
}
|
|
643
656
|
if (node.name === 'Callout') {
|
package/dist/config.d.ts
CHANGED
package/dist/config.js
CHANGED
|
@@ -68,6 +68,7 @@ export async function loadConfig(file, options = {}) {
|
|
|
68
68
|
if (stack.includes(current))
|
|
69
69
|
throw new ConfigError(`Configuration cycle: ${[...stack, current].join(' -> ')}`);
|
|
70
70
|
dependencies.add(current);
|
|
71
|
+
options.onDependency?.(current);
|
|
71
72
|
const raw = await readFile(current, 'utf8');
|
|
72
73
|
let parsed;
|
|
73
74
|
try {
|
|
@@ -121,7 +122,7 @@ export async function loadConfig(file, options = {}) {
|
|
|
121
122
|
const raw = value;
|
|
122
123
|
const profileSettings = treeObject(tree.value) ? tree.value.profiles : undefined;
|
|
123
124
|
const manifestNode = profileSettings && treeObject(profileSettings.value) ? profileSettings.value.manifest : undefined;
|
|
124
|
-
const deployment = await resolveDeploymentProfile(raw.profiles, raw, manifestNode?.source.file ?? root, options.profile);
|
|
125
|
+
const deployment = await resolveDeploymentProfile(raw.profiles, raw, manifestNode?.source.file ?? root, options.profile, options.onDependency);
|
|
125
126
|
if (deployment) {
|
|
126
127
|
for (const file of deployment.dependencies)
|
|
127
128
|
dependencies.add(file);
|
|
@@ -3,6 +3,7 @@ export type ContentPublication = {
|
|
|
3
3
|
channel: string;
|
|
4
4
|
version: string;
|
|
5
5
|
language: string;
|
|
6
|
+
product?: string;
|
|
6
7
|
};
|
|
7
8
|
export type ContentFormat = 'html' | 'markdown';
|
|
8
9
|
export type ContentRef = {
|
|
@@ -62,7 +63,7 @@ export type ContentResource = {
|
|
|
62
63
|
}>;
|
|
63
64
|
};
|
|
64
65
|
export type ContentManifest = {
|
|
65
|
-
schemaVersion: 1;
|
|
66
|
+
schemaVersion: 1 | 2;
|
|
66
67
|
kind: 'shoalrun-content-export';
|
|
67
68
|
digest: string;
|
|
68
69
|
publicBase: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { ContentManifest, ContentRef } from './content-delivery-contract.js';
|
|
1
|
+
import type { ContentManifest, ContentRef, ContentPublication } from './content-delivery-contract.js';
|
|
2
2
|
export declare const safeContentPath: (value: any) => value is string;
|
|
3
|
-
export declare const validContentPublication: (value: any) =>
|
|
3
|
+
export declare const validContentPublication: (value: any) => value is ContentPublication;
|
|
4
4
|
export declare function validContentRef(value: any): value is ContentRef;
|
|
5
5
|
export declare function validateContentManifest(value: any, maxResources?: number, maxResourceBytes?: number): asserts value is ContentManifest;
|
|
6
6
|
/** Shared metadata validation; transport supplies its file/asset inventory policy. */
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { samePublication } from './publication-identity.js';
|
|
1
2
|
import { ContentDeliveryError, contentRefKey } from './content-delivery-contract.js';
|
|
2
3
|
const object = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
|
|
3
4
|
const keys = (value, allowed) => object(value) && Object.keys(value).every(key => allowed.includes(key));
|
|
@@ -6,8 +7,7 @@ const digestPattern = /^[a-f0-9]{64}$/;
|
|
|
6
7
|
const pathPattern = /^(?:NOTICES\.txt|(?:content|assets)\/[A-Za-z0-9_.-]+(?:\/[A-Za-z0-9_.-]+)*)$/;
|
|
7
8
|
export const safeContentPath = (value) => typeof value === 'string' && pathPattern.test(value) && value.split('/').every(part => part !== '.' && part !== '..');
|
|
8
9
|
const invalid = (message) => { throw new ContentDeliveryError('invalid_manifest', message); };
|
|
9
|
-
export const validContentPublication = (value) =>
|
|
10
|
-
const samePublication = (left, right) => ['channel', 'version', 'language'].every(key => left[key] === right[key]);
|
|
10
|
+
export const validContentPublication = (value) => keys(value, ['channel', 'version', 'language', 'product']) && ['channel', 'version', 'language'].every(key => nonempty(value[key])) && (value.product === undefined ? !Object.hasOwn(value, 'product') : nonempty(value.product));
|
|
11
11
|
export function validContentRef(value) {
|
|
12
12
|
if (!object(value))
|
|
13
13
|
return false;
|
|
@@ -27,11 +27,11 @@ function safeExternal(value, image = false) {
|
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
export function validateContentManifest(value, maxResources = 10_000, maxResourceBytes = 8_000_000) {
|
|
30
|
-
if (!keys(value, ['schemaVersion', 'kind', 'digest', 'publicBase', 'publication', 'review', 'resources', 'assets', 'files', 'diagnostics']) || value.schemaVersion
|
|
30
|
+
if (!keys(value, ['schemaVersion', 'kind', 'digest', 'publicBase', 'publication', 'review', 'resources', 'assets', 'files', 'diagnostics']) || ![1, 2].includes(value.schemaVersion) || value.kind !== 'shoalrun-content-export' || !digestPattern.test(value.digest ?? ''))
|
|
31
31
|
invalid('Unsupported content manifest.');
|
|
32
32
|
if (typeof value.publicBase !== 'string' || !/^\/(?:[A-Za-z0-9_~.-]+\/)*$/.test(value.publicBase) || value.publicBase.split('/').some((part) => part === '.' || part === '..'))
|
|
33
33
|
invalid('Invalid content mount.');
|
|
34
|
-
if (!validContentPublication(value.publication))
|
|
34
|
+
if (!validContentPublication(value.publication) || value.schemaVersion !== (value.publication.product === undefined ? 1 : 2))
|
|
35
35
|
invalid('Invalid publication.');
|
|
36
36
|
if (!keys(value.review, ['status', 'apis']) || value.review.status !== 'ok' || !Array.isArray(value.review.apis) || value.review.apis.some((api) => !keys(api, ['apiId', 'digest']) || !nonempty(api.apiId) || !digestPattern.test(api.digest ?? '')))
|
|
37
37
|
invalid('Content must have approved API review metadata.');
|
|
@@ -57,6 +57,8 @@ export function validateContentManifest(value, maxResources = 10_000, maxResourc
|
|
|
57
57
|
}
|
|
58
58
|
/** Shared metadata validation; transport supplies its file/asset inventory policy. */
|
|
59
59
|
export function validateContentResources(resources, expectedPublication, assets, checkRepresentation, publicBase = '/') {
|
|
60
|
+
if (!validContentPublication(expectedPublication))
|
|
61
|
+
invalid('Invalid expected publication.');
|
|
60
62
|
const refs = new Set();
|
|
61
63
|
const links = [];
|
|
62
64
|
for (const resource of resources) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const exportHelp = "Usage: shoalrun export [config] --out DIRECTORY [--target NAME]\n [--format markdown|html|both] [--document ID]...\n [--channel C --version V --language L] [--public-base /help/] [--review]\n [--profile FILE] [--previous-manifest FILE] [--fail-on-removed]\n\nExport selected pages, sections, and named snippets as Markdown and passive HTML.\nConfigure typed resources in an export target; --document selects whole pages.\nNavigation, facets, and a prior website build are not required.\n--review writes an API-review candidate; status needs-review exits 2 until pinned.\n--previous-manifest compares public references with an earlier reviewed export.\n--fail-on-removed requires that baseline and refuses to replace output if references disappear.\n";
|
|
1
|
+
export declare const exportHelp = "Usage: shoalrun export [config] --out DIRECTORY [--target NAME]\n [--format markdown|html|both] [--document ID]...\n [--channel C --version V --language L [--product P]] [--public-base /help/] [--review]\n [--profile FILE] [--previous-manifest FILE] [--fail-on-removed]\n\nExport selected pages, sections, and named snippets as Markdown and passive HTML.\nConfigure typed resources in an export target; --document selects whole pages.\nNavigation, facets, and a prior website build are not required.\n--review writes an API-review candidate; status needs-review exits 2 until pinned.\n--previous-manifest compares public references with an earlier reviewed export.\n--fail-on-removed requires that baseline and refuses to replace output if references disappear.\n";
|
|
2
2
|
export declare function runExportCommand(args: string[]): Promise<{
|
|
3
3
|
status: string;
|
|
4
4
|
output: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { exportContent } from './content-export.js';
|
|
2
2
|
export const exportHelp = `Usage: shoalrun export [config] --out DIRECTORY [--target NAME]
|
|
3
3
|
[--format markdown|html|both] [--document ID]...
|
|
4
|
-
[--channel C --version V --language L] [--public-base /help/] [--review]
|
|
4
|
+
[--channel C --version V --language L [--product P]] [--public-base /help/] [--review]
|
|
5
5
|
[--profile FILE] [--previous-manifest FILE] [--fail-on-removed]
|
|
6
6
|
|
|
7
7
|
Export selected pages, sections, and named snippets as Markdown and passive HTML.
|
|
@@ -30,7 +30,7 @@ export async function runExportCommand(args) {
|
|
|
30
30
|
continue;
|
|
31
31
|
}
|
|
32
32
|
if (arg.startsWith('--')) {
|
|
33
|
-
if (!['--out', '--target', '--format', '--document', '--channel', '--version', '--language', '--public-base', '--previous-manifest', '--profile'].includes(arg) || !args[index + 1] || args[index + 1].startsWith('--'))
|
|
33
|
+
if (!['--out', '--target', '--format', '--document', '--channel', '--version', '--language', '--product', '--public-base', '--previous-manifest', '--profile'].includes(arg) || !args[index + 1] || args[index + 1].startsWith('--'))
|
|
34
34
|
throw new Error(exportHelp);
|
|
35
35
|
const value = args[++index];
|
|
36
36
|
if (arg === '--document') {
|
|
@@ -56,10 +56,10 @@ export async function runExportCommand(args) {
|
|
|
56
56
|
if (format)
|
|
57
57
|
options.formats = format === 'both' ? ['markdown', 'html'] : [format];
|
|
58
58
|
const coordinates = ['--channel', '--version', '--language'].map(key => values.get(key));
|
|
59
|
-
if (coordinates.some(Boolean)) {
|
|
59
|
+
if (coordinates.some(Boolean) || values.has('--product')) {
|
|
60
60
|
if (!coordinates.every(Boolean))
|
|
61
61
|
throw new Error('Select all three export publication coordinates: --channel, --version, and --language');
|
|
62
|
-
options.publication = { channel: coordinates[0], version: coordinates[1], language: coordinates[2] };
|
|
62
|
+
options.publication = { channel: coordinates[0], version: coordinates[1], language: coordinates[2], ...(values.has('--product') ? { product: values.get('--product') } : {}) };
|
|
63
63
|
}
|
|
64
64
|
options.profile = values.get('--profile');
|
|
65
65
|
options.target = values.get('--target');
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
+
import { validContentPublication } from './content-delivery-validation.js';
|
|
1
2
|
import { contentRefKey } from './content-delivery-contract.js';
|
|
2
3
|
const object = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
|
|
3
4
|
const nonempty = (value) => typeof value === 'string' && value.length > 0 && value.trim() === value;
|
|
4
|
-
const keyFor = ({ publication, ref }) => JSON.stringify([publication.channel, publication.version, publication.language, contentRefKey(ref)]);
|
|
5
|
+
const keyFor = ({ publication, ref }) => JSON.stringify([publication.channel, publication.version, publication.language, ...(publication.product === undefined ? [] : [publication.product]), contentRefKey(ref)]);
|
|
5
6
|
/** Validate the public identity surface, without reading files or executing source. */
|
|
6
7
|
function references(manifest, label, requireReviewed) {
|
|
7
8
|
const fail = () => { throw new Error(`${label} must be a content export manifest with valid, unique public resource references`); };
|
|
8
|
-
if (!object(manifest) || manifest.schemaVersion !== 1 || manifest.kind !== 'shoalrun-content-export' || !Array.isArray(manifest.resources) || !manifest.resources.length)
|
|
9
|
+
if (!object(manifest) || manifest.schemaVersion !== 1 && manifest.schemaVersion !== 2 || manifest.kind !== 'shoalrun-content-export' || !Array.isArray(manifest.resources) || !manifest.resources.length)
|
|
9
10
|
return fail();
|
|
10
11
|
const publication = manifest.publication;
|
|
11
|
-
if (!
|
|
12
|
+
if (!validContentPublication(publication) || !object(publication) || manifest.schemaVersion !== (publication.product === undefined ? 1 : 2))
|
|
12
13
|
return fail();
|
|
13
14
|
if (!object(manifest.review) || !['ok', 'required'].includes(String(manifest.review.status)))
|
|
14
15
|
return fail();
|
|
@@ -18,13 +19,13 @@ function references(manifest, label, requireReviewed) {
|
|
|
18
19
|
for (const resource of manifest.resources) {
|
|
19
20
|
if (!object(resource) || !object(resource.ref) || !object(resource.publication))
|
|
20
21
|
return fail();
|
|
21
|
-
if (
|
|
22
|
+
if (!validContentPublication(resource.publication) || !['channel', 'version', 'language', 'product'].every(key => resource.publication && resource.publication[key] === publication[key]))
|
|
22
23
|
return fail();
|
|
23
24
|
const ref = resource.ref;
|
|
24
25
|
const keys = ref.kind === 'page' ? ['kind', 'documentId'] : ref.kind === 'section' ? ['kind', 'documentId', 'sectionId'] : ref.kind === 'snippet' ? ['kind', 'id'] : [];
|
|
25
26
|
if (!keys.length || Object.keys(ref).length !== keys.length || !keys.every(key => nonempty(ref[key])))
|
|
26
27
|
return fail();
|
|
27
|
-
const entry = { publication: { channel: publication.channel, version: publication.version, language: publication.language }, ref: { ...ref } };
|
|
28
|
+
const entry = { publication: { channel: publication.channel, version: publication.version, language: publication.language, ...(publication.product !== undefined ? { product: publication.product } : {}) }, ref: { ...ref } };
|
|
28
29
|
const key = keyFor(entry);
|
|
29
30
|
if (result.has(key))
|
|
30
31
|
return fail();
|
|
@@ -66,8 +66,10 @@ export function validateExportTarget(value, readerFilters) {
|
|
|
66
66
|
};
|
|
67
67
|
let publication;
|
|
68
68
|
if (value.publication !== undefined) {
|
|
69
|
-
if (!isConfigMapping(value.publication) || Object.keys(value.publication).some(key => !['channel', 'version', 'language'].includes(key)) || ['channel', 'version', 'language'].some(key => typeof value.publication === 'object' && (typeof value.publication[key] !== 'string' || !value.publication[key].trim())))
|
|
69
|
+
if (!isConfigMapping(value.publication) || Object.keys(value.publication).some(key => !['channel', 'version', 'language', 'product'].includes(key)) || ['channel', 'version', 'language'].some(key => typeof value.publication === 'object' && (typeof value.publication[key] !== 'string' || !value.publication[key].trim())))
|
|
70
70
|
throw new Error('Export publication needs channel, version, and language');
|
|
71
|
+
if (value.publication.product !== undefined && !nonempty(value.publication.product))
|
|
72
|
+
throw new Error('Export publication product must be nonempty text');
|
|
71
73
|
publication = value.publication;
|
|
72
74
|
}
|
|
73
75
|
if (value.apiReview !== undefined && (!isConfigMapping(value.apiReview) || Object.values(value.apiReview).some(digest => typeof digest !== 'string' || !/^[a-f0-9]{64}$/.test(digest))))
|
package/dist/content-export.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { documentKey, samePublication } from './publication-identity.js';
|
|
1
2
|
import { pruneFeatureTree, profileSelection } from './deployment-profile.js';
|
|
2
3
|
import { readFile, realpath } from 'node:fs/promises';
|
|
3
4
|
import path from 'node:path';
|
|
4
5
|
import { fileURLToPath } from 'node:url';
|
|
5
6
|
import { loadConfig, explainSegments } from './config.js';
|
|
6
|
-
import { configField, isConfigMapping, requirePublicationsSection, requireSiteSection, resolvedCompilerConfig } from './compiler-config.js';
|
|
7
|
+
import { configField, isConfigMapping, requirePublicationsSection, resolvePublication, requireSiteSection, resolvedCompilerConfig } from './compiler-config.js';
|
|
7
8
|
import { defaultLanguage } from './frontmatter.js';
|
|
8
9
|
import { normalizeBasePath, sitePath } from './site-path.js';
|
|
9
10
|
import { prepareContentWorkspace } from './content-workspace.js';
|
|
@@ -32,13 +33,13 @@ import { isolateExportTree, markExportSource, exportHeadingInventory, preserveEx
|
|
|
32
33
|
import { selectSection } from './section-identity.js';
|
|
33
34
|
import { compareContentManifests } from './content-export-comparison.js';
|
|
34
35
|
const compare = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
35
|
-
const keyFor = (doc) =>
|
|
36
|
-
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
|
+
const keyFor = (doc) => documentKey(doc.frontmatter.id, doc.variant);
|
|
37
|
+
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, ...(item.doc.variant.product === undefined ? [] : [item.doc.variant.product])]);
|
|
37
38
|
// Pages and their sections share a source; named snippet instances do not.
|
|
38
|
-
const sourceKeyFor = (doc, kind = 'document') => JSON.stringify([kind, doc.frontmatter.id, doc.variant.channel, doc.variant.version, doc.variant.language]);
|
|
39
|
+
const sourceKeyFor = (doc, kind = 'document') => JSON.stringify([kind, doc.frontmatter.id, doc.variant.channel, doc.variant.version, doc.variant.language, ...(doc.variant.product === undefined ? [] : [doc.variant.product])]);
|
|
39
40
|
const selectedSourceKey = (item) => sourceKeyFor(item.doc, item.ref.kind === 'snippet' ? 'snippet' : 'document');
|
|
40
41
|
const resourceKey = (item) => `resource-${exportDigest(resourceIdentity(item)).slice(0, 24)}`;
|
|
41
|
-
const sameVariant =
|
|
42
|
+
const sameVariant = samePublication;
|
|
42
43
|
const visitTree = (node, visit) => {
|
|
43
44
|
if (!node || typeof node !== 'object')
|
|
44
45
|
return;
|
|
@@ -77,9 +78,9 @@ export async function exportContent(configFile, destination, options = {}) {
|
|
|
77
78
|
const target = validateExportTarget({ ...raw, ...(options.formats ? { formats: options.formats } : {}), ...(options.documents ? { documents: options.documents } : {}), ...(options.publication ? { publication: options.publication } : {}), ...(options.publicBase ? { publicBase: options.publicBase } : {}) }, config.readerFilters);
|
|
78
79
|
const language = defaultLanguage(config);
|
|
79
80
|
const enabled = config.publications.enabled;
|
|
80
|
-
if (!Array.isArray(enabled) || !enabled.length || enabled.some(value => !isConfigMapping(value)
|
|
81
|
+
if (!Array.isArray(enabled) || !enabled.length || enabled.some(value => !isConfigMapping(value)))
|
|
81
82
|
throw new Error('publications.enabled must declare valid publication combinations');
|
|
82
|
-
const variants = enabled.map(value => (
|
|
83
|
+
const variants = enabled.map(value => resolvePublication(publications, value, language));
|
|
83
84
|
const unique = [...new Map(variants.map(variant => [JSON.stringify(variant), variant])).values()];
|
|
84
85
|
const publication = target.publication ?? (unique.length === 1 ? unique[0] : undefined);
|
|
85
86
|
if (!publication)
|
|
@@ -431,7 +432,7 @@ export async function exportContent(configFile, destination, options = {}) {
|
|
|
431
432
|
notices += `\n${path.basename(file)}:\n${await readFile(resolvedNotice, 'utf8')}\n`;
|
|
432
433
|
}
|
|
433
434
|
artifacts.set('NOTICES.txt', notices);
|
|
434
|
-
const manifest = { schemaVersion: 1, kind: 'shoalrun-content-export', publicBase: target.publicBase, publication,
|
|
435
|
+
const manifest = { schemaVersion: publication.product === undefined ? 1 : 2, kind: 'shoalrun-content-export', publicBase: target.publicBase, publication,
|
|
435
436
|
review: { status: unreviewed.length ? 'required' : 'ok', apis: reviews.map(row => ({ apiId: row.apiId, digest: row.digest })) },
|
|
436
437
|
resources: records, assets: [...assets.records.values()].sort((a, b) => compare(a.path, b.path)),
|
|
437
438
|
files: [...artifacts].map(([filename, content]) => ({ path: filename, bytes: Buffer.byteLength(content), digest: exportDigest(content) })).sort((a, b) => compare(a.path, b.path)), diagnostics };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { samePublication } from './publication-identity.js';
|
|
1
2
|
import { ContentDeliveryError, contentRefKey } from './content-delivery-contract.js';
|
|
2
3
|
import { contentResourceKey } from './content-rest-contract.js';
|
|
3
4
|
import { validContentPublication, validContentRef, validateContentResources, safeContentPath } from './content-delivery-validation.js';
|
|
@@ -5,7 +6,6 @@ import { freeze, sha256, readBounded } from './content-delivery-transport.js';
|
|
|
5
6
|
const digestPattern = /^[a-f0-9]{64}$/;
|
|
6
7
|
const record = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
|
|
7
8
|
const exactKeys = (value, keys) => record(value) && Object.keys(value).length === keys.length && Object.keys(value).every(key => keys.includes(key));
|
|
8
|
-
const samePublication = (left, right) => left.channel === right.channel && left.version === right.version && left.language === right.language;
|
|
9
9
|
const invalid = (message) => { throw new ContentDeliveryError('invalid_manifest', message); };
|
|
10
10
|
/** Preloads a REST inventory and pins all subsequent reads to that revision. */
|
|
11
11
|
export async function openRestContentSource(options) {
|
|
@@ -39,6 +39,8 @@ export async function openRestContentSource(options) {
|
|
|
39
39
|
url.pathname = baseUrl.pathname.replace(/\/$/, '') + '/resources' + suffix;
|
|
40
40
|
for (const key of ['channel', 'version', 'language'])
|
|
41
41
|
url.searchParams.set(key, publication[key]);
|
|
42
|
+
if (publication.product !== undefined)
|
|
43
|
+
url.searchParams.set('product', publication.product);
|
|
42
44
|
if (revision !== undefined)
|
|
43
45
|
url.searchParams.set('revision', revision);
|
|
44
46
|
return url;
|
|
@@ -103,7 +105,7 @@ export async function openRestContentSource(options) {
|
|
|
103
105
|
throw error;
|
|
104
106
|
return invalid('REST inventory is not valid UTF-8 JSON.');
|
|
105
107
|
}
|
|
106
|
-
if (!exactKeys(envelope, ['schemaVersion', 'revision', 'publication', 'resources']) || envelope.schemaVersion !== 1 || !digestPattern.test(envelope.revision ?? '') || !validContentPublication(envelope.publication) || !samePublication(envelope.publication, publication))
|
|
108
|
+
if (!exactKeys(envelope, ['schemaVersion', 'revision', 'publication', 'resources']) || envelope.schemaVersion !== (publication.product === undefined ? 1 : 2) || !digestPattern.test(envelope.revision ?? '') || !validContentPublication(envelope.publication) || !samePublication(envelope.publication, publication))
|
|
107
109
|
invalid('Invalid REST inventory identity.');
|
|
108
110
|
if (requestedRevision !== undefined && requestedRevision !== envelope.revision)
|
|
109
111
|
throw new ContentDeliveryError('stale_revision', 'REST inventory differs from the requested revision.');
|
|
@@ -6,13 +6,13 @@ export type ContentRestEntry = {
|
|
|
6
6
|
resource: ContentResource;
|
|
7
7
|
};
|
|
8
8
|
export type ContentRestList = {
|
|
9
|
-
schemaVersion: 1;
|
|
9
|
+
schemaVersion: 1 | 2;
|
|
10
10
|
revision: string;
|
|
11
11
|
publication: ContentPublication;
|
|
12
12
|
resources: ContentRestEntry[];
|
|
13
13
|
};
|
|
14
14
|
export type ContentRestResource = {
|
|
15
|
-
schemaVersion: 1;
|
|
15
|
+
schemaVersion: 1 | 2;
|
|
16
16
|
revision: string;
|
|
17
17
|
publication: ContentPublication;
|
|
18
18
|
key: string;
|