@shoalrun/cli 0.1.0-alpha.11 → 0.1.0-alpha.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +52 -0
- package/README.md +59 -17
- package/agent-docs/.well-known/shoalrun/navigation/examples-tab-50f26fe22670.txt +22 -0
- package/agent-docs/.well-known/shoalrun/navigation/project-updates-50f26fe22670.txt +33 -3
- package/agent-docs/.well-known/shoalrun/navigation/reference-tab-50f26fe22670.txt +22 -0
- package/agent-docs/SNAPSHOT.json +5 -5
- package/agent-docs/api-docs/focused-contracts.md +2 -2
- package/agent-docs/api-docs/generate.md +6 -6
- package/agent-docs/api-docs/generate.sections/add-useful-examples.md +2 -2
- package/agent-docs/api-docs/generate.sections/choose-generated-references-or-mdx.md +5 -5
- package/agent-docs/api-docs/generate.sections/describe-filters-that-do-not-use-their-openapi-parameter-name.md +2 -2
- package/agent-docs/api-docs/generate.sections/generate-many-pages-selectively.md +2 -2
- package/agent-docs/api-docs/generate.sections/link-guides-to-api-references.md +2 -2
- package/agent-docs/api-docs/generate.sections/map-extension-values-to-shoalrun-status.md +2 -2
- package/agent-docs/api-docs/generate.sections/override-generated-reference-order-in-navigation.md +3 -3
- package/agent-docs/api-docs/generate.sections/related-reading.md +2 -2
- package/agent-docs/api-docs/generate.sections/use-a-template-for-editorial-context.md +2 -2
- package/agent-docs/api-docs/support.md +14 -13
- package/agent-docs/author/add-page.md +8 -6
- package/agent-docs/author/agent-overview.md +1 -1
- package/agent-docs/author/agent-workflow.md +1 -1
- package/agent-docs/author/analytics.md +1 -1
- package/agent-docs/author/analytics.sections/adapter-exports-and-consent.md +1 -1
- package/agent-docs/author/analytics.sections/built-in-events.md +1 -1
- package/agent-docs/author/analytics.sections/configure-an-adapter.md +1 -1
- package/agent-docs/author/analytics.sections/custom-interactions.md +1 -1
- package/agent-docs/author/analytics.sections/event-format.md +1 -1
- package/agent-docs/author/analytics.sections/html-markdown-and-agents.md +1 -1
- package/agent-docs/author/analytics.sections/inspect-events-locally.md +1 -1
- package/agent-docs/author/analytics.sections/map-events-to-your-service.md +1 -1
- package/agent-docs/author/analytics.sections/posthog-example.md +1 -1
- package/agent-docs/author/analytics.sections/related-reading.md +1 -1
- package/agent-docs/author/authoring-agent.md +1 -1
- package/agent-docs/author/coding-agent.md +1 -1
- package/agent-docs/author/components/action-link.md +9 -3
- package/agent-docs/author/components/api-embeds.md +11 -3
- package/agent-docs/author/components/api-embeds.sections/apiexample.md +7 -3
- package/agent-docs/author/components/api-embeds.sections/html-markdown-and-agents.md +3 -3
- package/agent-docs/author/components/api-embeds.sections/related-reading.md +3 -3
- package/agent-docs/author/components/badge.md +8 -4
- package/agent-docs/author/components/breadcrumbs.md +1 -1
- package/agent-docs/author/components/callout.md +8 -4
- package/agent-docs/author/components/cards.md +2 -2
- package/agent-docs/author/components/cards.sections/add-a-lucide-icon.md +2 -2
- package/agent-docs/author/components/cards.sections/build-a-collection.md +2 -2
- package/agent-docs/author/components/cards.sections/curate-a-reading-list.md +2 -2
- package/agent-docs/author/components/cards.sections/html-markdown-and-agents.md +2 -2
- package/agent-docs/author/components/cards.sections/link-to-one-document.md +2 -2
- package/agent-docs/author/components/cards.sections/override-card-text.md +2 -2
- package/agent-docs/author/components/cards.sections/related-reading.md +2 -2
- package/agent-docs/author/components/code-blocks.md +8 -4
- package/agent-docs/author/components/collapsible.md +7 -3
- package/agent-docs/author/components/cookbook-chooser.md +7 -3
- package/agent-docs/author/components/custom/react.md +1 -1
- package/agent-docs/author/components/custom/react.sections/html-markdown-and-agents.md +1 -1
- package/agent-docs/author/components/custom/react.sections/interactive-react-example.md +1 -1
- package/agent-docs/author/components/custom/react.sections/registration.md +1 -1
- package/agent-docs/author/components/custom/react.sections/related-reading.md +1 -1
- package/agent-docs/author/components/custom/react.sections/share-the-model-with-the-browser.md +1 -1
- package/agent-docs/author/components/custom/react.sections/where-the-content-lives.md +1 -1
- package/agent-docs/author/components/custom.md +1 -1
- package/agent-docs/author/components/definition-list.md +5 -3
- package/agent-docs/author/components/diagrams/d2-gallery.md +2 -2
- package/agent-docs/author/components/diagrams/d2-gallery.sections/basic-shapes.md +2 -2
- package/agent-docs/author/components/diagrams/d2-gallery.sections/flows-and-structures.md +2 -2
- package/agent-docs/author/components/diagrams/d2-gallery.sections/html-markdown-and-agents.md +2 -2
- package/agent-docs/author/components/diagrams/d2-gallery.sections/layout-engines.md +2 -2
- package/agent-docs/author/components/diagrams/d2-gallery.sections/related-reading.md +2 -2
- package/agent-docs/author/components/diagrams/d2-gallery.sections/sequences-and-grids.md +2 -2
- package/agent-docs/author/components/diagrams/d2-gallery.sections/styles-and-code.md +2 -2
- package/agent-docs/author/components/diagrams/pele-gallery.md +2 -2
- package/agent-docs/author/components/diagrams/pele-gallery.sections/charts-and-planning.md +2 -2
- package/agent-docs/author/components/diagrams/pele-gallery.sections/flowchart-shapes.md +2 -2
- package/agent-docs/author/components/diagrams/pele-gallery.sections/flows-and-behavior.md +2 -2
- package/agent-docs/author/components/diagrams/pele-gallery.sections/html-markdown-and-agents.md +2 -2
- package/agent-docs/author/components/diagrams/pele-gallery.sections/related-reading.md +2 -2
- package/agent-docs/author/components/diagrams/pele-gallery.sections/specialized-diagrams.md +2 -2
- package/agent-docs/author/components/diagrams/pele-gallery.sections/systems-and-structures.md +2 -2
- package/agent-docs/author/components/diagrams.md +13 -5
- package/agent-docs/author/components/doc-link.md +7 -3
- package/agent-docs/author/components/fields.md +6 -4
- package/agent-docs/author/components/file-tree.md +7 -3
- package/agent-docs/author/components/images.md +5 -3
- package/agent-docs/author/components/info-hint.md +7 -3
- package/agent-docs/author/components/kbd.md +5 -3
- package/agent-docs/author/components/math.md +7 -3
- package/agent-docs/author/components/only.md +9 -5
- package/agent-docs/author/components/progress.md +7 -3
- package/agent-docs/author/components/related-reading.md +7 -3
- package/agent-docs/author/components/steps.md +9 -3
- package/agent-docs/author/components/tables.md +7 -3
- package/agent-docs/author/components/tabs.md +7 -3
- package/agent-docs/author/components/timeline.md +10 -4
- package/agent-docs/author/components/tooltips.md +7 -3
- package/agent-docs/author/components/walkthroughs.md +5 -3
- package/agent-docs/author/components/walkthroughs.sections/attributes.md +3 -3
- package/agent-docs/author/components/walkthroughs.sections/build-up-code.md +3 -3
- package/agent-docs/author/components/walkthroughs.sections/choose-a-layout.md +3 -3
- package/agent-docs/author/components/walkthroughs.sections/explain-one-file.md +3 -3
- package/agent-docs/author/components/walkthroughs.sections/html-markdown-and-agents.md +3 -3
- package/agent-docs/author/components/walkthroughs.sections/related-reading.md +3 -3
- package/agent-docs/author/components/walkthroughs.sections/syntax.md +51 -0
- package/agent-docs/author/components/walkthroughs.sections/take-code-from-a-file.md +3 -22
- package/agent-docs/author/components.md +19 -4
- package/agent-docs/author/css.md +13 -10
- package/agent-docs/author/css.sections/borders-fields-and-navigation-tokens.md +3 -3
- package/agent-docs/author/css.sections/core-color-tokens.md +3 -3
- package/agent-docs/author/css.sections/html-markdown-and-agents.md +54 -0
- package/agent-docs/author/css.sections/page-attributes.md +9 -9
- package/agent-docs/author/css.sections/page-transitions.md +3 -3
- package/agent-docs/author/css.sections/responsive-behavior.md +3 -3
- package/agent-docs/author/css.sections/status-code-and-callout-tokens.md +3 -3
- package/agent-docs/author/css.sections/typography-shape-and-width-tokens.md +3 -3
- package/agent-docs/author/custom-metadata.md +2 -2
- package/agent-docs/author/custom-metadata.sections/add-a-custom-page-field.md +2 -2
- package/agent-docs/author/custom-metadata.sections/choose-text-for-each-surface.md +2 -2
- package/agent-docs/author/custom-metadata.sections/preview-changes-to-metadata-providers.md +2 -2
- package/agent-docs/author/custom-metadata.sections/read-metadata-from-a-project-module.md +2 -2
- package/agent-docs/author/custom-metadata.sections/related-reading.md +2 -2
- package/agent-docs/author/design-templates.md +1 -1
- package/agent-docs/author/design-writing-guides.md +1 -1
- package/agent-docs/author/frontmatter-reference.md +34 -27
- package/agent-docs/author/frontmatter-reference.sections/choose-a-publication-and-visibility.md +5 -3
- package/agent-docs/author/frontmatter-reference.sections/control-output-details.md +5 -3
- package/agent-docs/author/frontmatter-reference.sections/global-defaults-and-enforced-values.md +5 -3
- package/agent-docs/author/frontmatter-reference.sections/html-markdown-and-agents.md +33 -0
- package/agent-docs/author/frontmatter-reference.sections/identify-and-route-a-page.md +5 -3
- package/agent-docs/author/frontmatter-reference.sections/point-agents-to-it.md +5 -3
- package/agent-docs/author/frontmatter-reference.sections/project-defined-fields.md +5 -3
- package/agent-docs/author/frontmatter-reference.sections/related-reading.md +5 -3
- package/agent-docs/author/frontmatter-reference.sections/use-the-local-files-while-authoring.md +5 -3
- package/agent-docs/author/frontmatter-reference.sections/when-the-files-update.md +5 -3
- package/agent-docs/author/frontmatter.md +7 -4
- package/agent-docs/author/frontmatter.sections/audience-badges.md +3 -3
- package/agent-docs/author/frontmatter.sections/give-deprecation-guidance.md +3 -3
- package/agent-docs/author/frontmatter.sections/global-defaults-and-enforced-values.md +3 -3
- package/agent-docs/author/frontmatter.sections/optional-native-fields.md +7 -4
- package/agent-docs/author/frontmatter.sections/publication-fields.md +3 -3
- package/agent-docs/author/frontmatter.sections/publishing-policy.md +3 -3
- package/agent-docs/author/frontmatter.sections/related-metadata-tasks.md +3 -3
- package/agent-docs/author/frontmatter.sections/related-reading.md +3 -3
- package/agent-docs/author/frontmatter.sections/required-after-inheritance.md +3 -3
- package/agent-docs/author/frontmatter.sections/seo-fields.md +3 -3
- package/agent-docs/author/frontmatter.sections/validation-rules.md +3 -3
- package/agent-docs/author/markdown-metadata.md +17 -9
- package/agent-docs/author/navigation.md +13 -2
- package/agent-docs/author/navigation.sections/arrange-authored-pages.md +2 -2
- package/agent-docs/author/navigation.sections/fill-an-api-tag-group.md +2 -2
- package/agent-docs/author/navigation.sections/hide-group-page-counts.md +13 -2
- package/agent-docs/author/navigation.sections/html-markdown-and-agents.md +2 -2
- package/agent-docs/author/navigation.sections/local-api-preview.md +2 -2
- package/agent-docs/author/navigation.sections/mix-guides-and-api-references.md +2 -2
- package/agent-docs/author/navigation.sections/optionally-split-a-large-menu-into-files.md +2 -2
- package/agent-docs/author/navigation.sections/reach-navigation-while-reading.md +2 -2
- package/agent-docs/author/navigation.sections/related-reading.md +2 -2
- package/agent-docs/author/navigation.sections/split-navigation-into-tabs.md +2 -2
- package/agent-docs/author/navigation.sections/subject-lifecycle-labels.md +2 -2
- package/agent-docs/author/recipe-drafts.md +16 -16
- package/agent-docs/author/recipe-drafts.sections/1-write-one-reusable-step.md +5 -5
- package/agent-docs/author/recipe-drafts.sections/2-list-the-steps-for-one-complete-goal.md +3 -3
- package/agent-docs/author/recipe-drafts.sections/3-generate-a-draft-and-review-it.md +4 -4
- package/agent-docs/author/recipe-drafts.sections/4-maintain-shoalrun-s-published-recipe-snapshots.md +3 -3
- package/agent-docs/author/recipe-drafts.sections/related-reading.md +1 -1
- package/agent-docs/author/recipe-drafts.sections/start-an-ingredient-from-an-api-example.md +5 -5
- package/agent-docs/author/recipes.md +4 -4
- package/agent-docs/author/recipes.sections/how-agents-use-this.md +1 -1
- package/agent-docs/author/recipes.sections/one-example-from-shoalrun.md +4 -4
- package/agent-docs/author/recipes.sections/related-reading.md +1 -1
- package/agent-docs/author/recipes.sections/try-a-complete-workflow.md +1 -1
- package/agent-docs/author/recipes.sections/use-recipes-for-task-oriented-how-tos.md +1 -1
- package/agent-docs/author/recipes.sections/what-changing-an-ingredient-updates.md +1 -1
- package/agent-docs/author/recipes.sections/what-each-file-does.md +1 -1
- package/agent-docs/author/recipes.sections/what-happens-and-when.md +1 -1
- package/agent-docs/author/related-reading.md +5 -1
- package/agent-docs/author/related-reading.sections/automatic-footers.md +1 -1
- package/agent-docs/author/related-reading.sections/declare-relationships.md +1 -1
- package/agent-docs/author/related-reading.sections/display-related-documents.md +1 -1
- package/agent-docs/author/related-reading.sections/html-markdown-and-agents.md +28 -0
- package/agent-docs/author/related-reading.sections/inspect-output-and-changes.md +1 -1
- package/agent-docs/author/related-reading.sections/reading-paths-in-section-markdown.md +1 -1
- package/agent-docs/author/related-reading.sections/related-reading.md +1 -1
- package/agent-docs/author/related-reading.sections/where-relationship-explanations-come-from.md +1 -1
- package/agent-docs/author/search.md +1 -1
- package/agent-docs/author/search.sections/choose-a-provider.md +1 -1
- package/agent-docs/author/search.sections/cli-and-mcp-ranking-details.md +1 -1
- package/agent-docs/author/search.sections/hosted-semantic-search-limits.md +1 -1
- package/agent-docs/author/search.sections/html-markdown-and-agents.md +1 -1
- package/agent-docs/author/search.sections/lexical-search.md +1 -1
- package/agent-docs/author/search.sections/local-semantic-preview.md +1 -1
- package/agent-docs/author/search.sections/read-a-search-result-with-an-agent.md +1 -1
- package/agent-docs/author/search.sections/related-reading.md +1 -1
- package/agent-docs/author/search.sections/reuse-the-lexical-index.md +1 -1
- package/agent-docs/author/search.sections/turn-search-off.md +1 -1
- package/agent-docs/author/search.sections/use-the-search-box.md +1 -1
- package/agent-docs/author/search.sections/write-a-custom-provider.md +1 -1
- package/agent-docs/author/snippets.md +5 -1
- package/agent-docs/author/taxonomy.md +1 -1
- package/agent-docs/author/templates.md +16 -8
- package/agent-docs/author/templates.sections/built-in-feature-templates.md +3 -3
- package/agent-docs/author/templates.sections/built-in-templates.md +3 -3
- package/agent-docs/author/templates.sections/choose-formatting-enforcement-for-your-project.md +3 -3
- package/agent-docs/author/templates.sections/create-or-edit-a-project-template.md +12 -4
- package/agent-docs/author/templates.sections/keep-the-four-shapes-distinct.md +3 -3
- package/agent-docs/author/templates.sections/project-added-templates.md +3 -3
- package/agent-docs/author/templates.sections/related-reading.md +3 -3
- package/agent-docs/author/templates.sections/scaffold-a-page.md +7 -7
- package/agent-docs/author/templates.sections/short-cli-and-derived-values.md +3 -3
- package/agent-docs/author/templates.sections/what-every-template-gives-you.md +3 -3
- package/agent-docs/author/workspace/commands.md +2 -2
- package/agent-docs/author/workspace.md +8 -2
- package/agent-docs/author/writing-style.md +27 -5
- package/agent-docs/author/writing-style.sections/adapt-this-example.md +3 -3
- package/agent-docs/author/writing-style.sections/choose-components-by-reader-need.md +6 -4
- package/agent-docs/author/writing-style.sections/evidence-and-uncertainty.md +3 -3
- package/agent-docs/author/writing-style.sections/example-audience-and-scope.md +3 -3
- package/agent-docs/author/writing-style.sections/feature-availability.md +36 -0
- package/agent-docs/author/writing-style.sections/ingredients-recipes-and-cookbooks.md +3 -3
- package/agent-docs/author/writing-style.sections/page-purpose-and-structure.md +12 -4
- package/agent-docs/author/writing-style.sections/procedures-and-examples.md +3 -3
- package/agent-docs/author/writing-style.sections/related-reading.md +3 -3
- package/agent-docs/author/writing-style.sections/review-a-draft.md +3 -3
- package/agent-docs/author/writing-style.sections/reviewed-writing-examples.md +3 -3
- package/agent-docs/author/writing-style.sections/voice-and-explanations.md +3 -3
- package/agent-docs/changelog/2026-10-14-agent-readiness.md +2 -2
- package/agent-docs/changelog/2026-10-15-evaluation-builds.md +2 -2
- package/agent-docs/changelog/2026-10-16-navigation-layouts.md +2 -2
- package/agent-docs/changelog/2026-10-17-mcp-hosting.md +2 -2
- package/agent-docs/changelog/2026-10-18-search-and-tooltips.md +2 -2
- package/agent-docs/changelog/2026-10-19-visual-navigation.md +2 -2
- package/agent-docs/changelog/2026-10-25.md +2 -2
- package/agent-docs/changelog/2026-10-26.md +2 -2
- package/agent-docs/changelog/2026-10-27.md +2 -2
- package/agent-docs/changelog/2026-10-28.md +89 -0
- package/agent-docs/changelog/authoring-preview.md +2 -2
- package/agent-docs/changelog/authoring-search.md +3 -3
- package/agent-docs/changelog/authoring-tools.md +2 -2
- package/agent-docs/changelog/working-tree-skill.md +2 -2
- package/agent-docs/changelog.md +11 -3
- package/agent-docs/chat/checks.md +1 -1
- package/agent-docs/chat/checks.sections/answer-ahead-of-time.md +1 -1
- package/agent-docs/chat/checks.sections/answer-for-one-audience.md +1 -1
- package/agent-docs/chat/checks.sections/answer-without-a-model.md +1 -1
- package/agent-docs/chat/checks.sections/follow-up-questions.md +1 -1
- package/agent-docs/chat/checks.sections/how-an-answer-is-checked.md +1 -1
- package/agent-docs/chat/checks.sections/questions-with-several-parts.md +1 -1
- package/agent-docs/chat/checks.sections/related-reading.md +1 -1
- package/agent-docs/chat/checks.sections/reuse-answers.md +1 -1
- package/agent-docs/chat/host.md +1 -1
- package/agent-docs/chat/host.sections/cap-the-daily-spend.md +1 -1
- package/agent-docs/chat/host.sections/keep-a-record-of-questions.md +1 -1
- package/agent-docs/chat/host.sections/related-reading.md +1 -1
- package/agent-docs/chat/passage-index.md +2 -2
- package/agent-docs/chat/passage-index.sections/build-the-index.md +2 -2
- package/agent-docs/chat/passage-index.sections/embed-passages.md +2 -2
- package/agent-docs/chat/passage-index.sections/how-the-default-chunker-splits-a-page.md +2 -2
- package/agent-docs/chat/passage-index.sections/limits.md +2 -2
- package/agent-docs/chat/passage-index.sections/passage-ids-and-links.md +2 -2
- package/agent-docs/chat/passage-index.sections/related-reading.md +2 -2
- package/agent-docs/chat/passage-index.sections/what-a-passage-contains.md +2 -2
- package/agent-docs/chat/prepared-answers.md +1 -1
- package/agent-docs/chat/settings.md +2 -2
- package/agent-docs/chat/settings.sections/choose-the-scorer.md +2 -2
- package/agent-docs/chat/settings.sections/configure-chat.md +2 -2
- package/agent-docs/chat/settings.sections/configure-retrieval.md +2 -2
- package/agent-docs/chat/settings.sections/related-reading.md +2 -2
- package/agent-docs/chat/settings.sections/send-extra-request-fields.md +2 -2
- package/agent-docs/chat/settings.sections/use-more-than-one-model.md +2 -2
- package/agent-docs/chat/settings.sections/when-the-scorer-is-down.md +2 -2
- package/agent-docs/chat/setup.md +1 -1
- package/agent-docs/chat.md +1 -1
- package/agent-docs/cli.md +2 -2
- package/agent-docs/cli.sections/audit-a-project-and-api-sources.md +2 -2
- package/agent-docs/cli.sections/author-pages.md +2 -2
- package/agent-docs/cli.sections/build-and-serve.md +2 -2
- package/agent-docs/cli.sections/inspect-config-and-operations.md +2 -2
- package/agent-docs/cli.sections/npm-scripts-in-this-repository.md +2 -2
- package/agent-docs/cli.sections/related-reading.md +2 -2
- package/agent-docs/cli.sections/search-and-chat.md +2 -2
- package/agent-docs/cli.sections/start-a-project.md +2 -2
- package/agent-docs/cli.sections/working-tree-authoring-tools.md +2 -2
- package/agent-docs/config/apis.md +2 -2
- package/agent-docs/config/content.md +2 -2
- package/agent-docs/config/content.sections/authoring.md +2 -2
- package/agent-docs/config/content.sections/badges.md +2 -2
- package/agent-docs/config/content.sections/callouts.md +2 -2
- package/agent-docs/config/content.sections/cookbooks.md +2 -2
- package/agent-docs/config/content.sections/frontmatter.md +2 -2
- package/agent-docs/config/content.sections/readerfilters.md +2 -2
- package/agent-docs/config/content.sections/related-reading.md +2 -2
- package/agent-docs/config/content.sections/relationships.md +2 -2
- package/agent-docs/config/content.sections/snippets.md +2 -2
- package/agent-docs/config/content.sections/templates.md +2 -2
- package/agent-docs/config/content.sections/variables.md +2 -2
- package/agent-docs/config/examples.md +22 -14
- package/agent-docs/config/examples.sections/feature-showcase.md +21 -13
- package/agent-docs/config/examples.sections/minimal-site.md +15 -10
- package/agent-docs/config/examples.sections/multilingual-help-center.md +15 -10
- package/agent-docs/config/examples.sections/parcel-api-documentation.md +15 -10
- package/agent-docs/config/examples.sections/related-reading.md +15 -10
- package/agent-docs/config/examples.sections/shared-company-preset.md +16 -11
- package/agent-docs/config/integrations.md +2 -2
- package/agent-docs/config/outputs.md +17 -13
- package/agent-docs/config/outputs.sections/exports.md +16 -13
- package/agent-docs/config/outputs.sections/metadata.md +3 -3
- package/agent-docs/config/outputs.sections/related-reading.md +3 -3
- package/agent-docs/config/publishing.md +2 -2
- package/agent-docs/config/publishing.sections/navigation.md +2 -2
- package/agent-docs/config/publishing.sections/redirects.md +2 -2
- package/agent-docs/config/publishing.sections/related-reading.md +2 -2
- package/agent-docs/config/site.md +2 -2
- package/agent-docs/config/site.sections/related-reading.md +2 -2
- package/agent-docs/config/site.sections/theme.md +2 -2
- package/agent-docs/config.md +2 -2
- package/agent-docs/configuration.md +22 -20
- package/agent-docs/configuration.sections/build-several-sites-from-shared-content.md +2 -2
- package/agent-docs/configuration.sections/change-inherited-lists-deliberately.md +5 -5
- package/agent-docs/configuration.sections/extract-a-section-with-include.md +4 -4
- package/agent-docs/configuration.sections/inspect-and-validate-changes.md +6 -6
- package/agent-docs/configuration.sections/related-reading.md +2 -2
- package/agent-docs/configuration.sections/separate-config-inheritance-from-page-metadata.md +2 -2
- package/agent-docs/configuration.sections/share-defaults-through-extends.md +7 -7
- package/agent-docs/configuration.sections/start-with-one-working-file.md +8 -6
- package/agent-docs/configuration.sections/understand-the-three-stages.md +2 -2
- package/agent-docs/configuration.sections/understand-where-paths-point.md +2 -2
- package/agent-docs/connect/mcp.md +1 -1
- package/agent-docs/content-delivery/agents.md +86 -0
- package/agent-docs/content-delivery/api.md +130 -0
- package/agent-docs/content-delivery/client.md +79 -0
- package/agent-docs/content-delivery/http-api/operations/get-content-representation-fa1d2e3f.md +394 -0
- package/agent-docs/content-delivery/http-api/operations/get-content-representation-head-4052375c.md +256 -0
- package/agent-docs/content-delivery/http-api/operations/get-content-resource-849f1c49.md +911 -0
- package/agent-docs/content-delivery/http-api/operations/get-content-resource-head-0a352acd.md +246 -0
- package/agent-docs/content-delivery/http-api/operations/list-content-resources-8e977ec7.md +913 -0
- package/agent-docs/content-delivery/http-api/operations/list-content-resources-head-b67cbad9.md +236 -0
- package/agent-docs/content-delivery/http-api.md +78 -0
- package/agent-docs/content-delivery/manifest.md +79 -0
- package/agent-docs/content-delivery/publish.md +72 -0
- package/agent-docs/content-delivery/render.md +73 -0
- package/agent-docs/content-delivery/rest.md +108 -0
- package/agent-docs/content-delivery/sections.md +110 -0
- package/agent-docs/content-delivery/select.md +100 -0
- package/agent-docs/content-delivery.md +79 -0
- package/agent-docs/contribute/agent-skills.md +1 -1
- package/agent-docs/cookbooks/authoring.md +7 -3
- package/agent-docs/cookbooks/site-workflows.md +8 -4
- package/agent-docs/cookbooks/welcome-email.md +7 -3
- package/agent-docs/documents.json +7707 -6283
- package/agent-docs/example-api/cedar/create-enrollment-7af3e5d2.md +2 -2
- package/agent-docs/example-api/cedar/get-legacy-parcel-6758d051.md +2 -2
- package/agent-docs/example-api/cedar/get-parcel-edee10e6.md +2 -2
- package/agent-docs/example-api/cedar/list-parcels-0345fb5f.md +2 -2
- package/agent-docs/example-api/cedar/parcel-delivered-7d1ba6db.md +2 -2
- package/agent-docs/example-api/cedar/upload-manifest-1af17891.md +2 -2
- package/agent-docs/example-api/cedar.md +2 -2
- package/agent-docs/example-api/create-note.md +2 -2
- package/agent-docs/example-api/generated/get-note-cbedb319.md +2 -2
- package/agent-docs/example-api/write-note.md +2 -2
- package/agent-docs/explore.md +2 -2
- package/agent-docs/glossary.md +3 -7
- package/agent-docs/ingredients/audit-site.md +2 -2
- package/agent-docs/ingredients/build-site.md +2 -2
- package/agent-docs/ingredients/compile-framework.md +2 -2
- package/agent-docs/ingredients/complete-page.md +2 -2
- package/agent-docs/ingredients/inspect-agent-bundle.md +2 -2
- package/agent-docs/ingredients/inspect-build.md +2 -2
- package/agent-docs/ingredients/preview-site.md +2 -2
- package/agent-docs/ingredients/refresh-agent-bundle.md +2 -2
- package/agent-docs/ingredients/scaffold-page.md +2 -2
- package/agent-docs/non-goals.md +2 -2
- package/agent-docs/provenance.json +4 -4
- package/agent-docs/publish/agent-discovery.md +1 -1
- package/agent-docs/publish/agent-friendliness.md +1 -1
- package/agent-docs/publish/agent-friendliness.sections/discover-a-page-with-a-small-context-budget.md +1 -1
- package/agent-docs/publish/agent-friendliness.sections/distinguish-examples-from-a-real-service.md +1 -1
- package/agent-docs/publish/agent-friendliness.sections/evidence-has-a-scope.md +1 -1
- package/agent-docs/publish/agent-friendliness.sections/keep-shared-instructions-complete.md +1 -1
- package/agent-docs/publish/agent-friendliness.sections/related-reading.md +1 -1
- package/agent-docs/publish/agent-friendliness.sections/secret-handshake.md +1 -1
- package/agent-docs/publish/agent-friendliness.sections/try-the-page-controls.md +1 -1
- package/agent-docs/publish/agent-friendliness.sections/use-the-transport-your-client-supports.md +1 -1
- package/agent-docs/publish/agent-friendliness.sections/verify-the-page-and-detect-changes.md +1 -1
- package/agent-docs/publish/agent-friendliness.sections/what-an-agent-reads.md +1 -1
- package/agent-docs/publish/agent-friendliness.sections/what-happens-to-an-unsupported-component.md +1 -1
- package/agent-docs/publish/api-references.md +10 -8
- package/agent-docs/publish/api-references.sections/author-the-reference-page.md +1 -1
- package/agent-docs/publish/api-references.sections/build-and-verify-the-output.md +1 -1
- package/agent-docs/publish/api-references.sections/inspect-the-machine-readable-contract.md +1 -1
- package/agent-docs/publish/api-references.sections/{generate-many-pages-selectively.md → next-steps.md} +28 -2
- package/agent-docs/publish/api-references.sections/preview-a-small-api-reference.md +1 -1
- package/agent-docs/publish/api-references.sections/put-the-spec-in-your-project.md +1 -1
- package/agent-docs/publish/api-references.sections/register-the-operation.md +1 -1
- package/agent-docs/publish/api-references.sections/related-reading.md +1 -1
- package/agent-docs/publish/api-references.sections/review-imported-content-before-publishing.md +1 -1
- package/agent-docs/publish/api-references.sections/what-readers-get.md +1 -1
- package/agent-docs/publish/audit.md +1 -1
- package/agent-docs/publish/audit.sections/add-project-tests.md +1 -1
- package/agent-docs/publish/audit.sections/check-agent-evaluation-reports.md +1 -1
- package/agent-docs/publish/audit.sections/check-before-pushing.md +1 -1
- package/agent-docs/publish/audit.sections/connect-a-documentation-test-suite.md +1 -1
- package/agent-docs/publish/audit.sections/read-the-report.md +1 -1
- package/agent-docs/publish/audit.sections/related-reading.md +1 -1
- package/agent-docs/publish/content-export.md +33 -17
- package/agent-docs/publish/content-export.sections/assets-downloads-and-notices.md +4 -4
- package/agent-docs/publish/content-export.sections/check-the-result.md +3 -3
- package/agent-docs/publish/content-export.sections/export-selected-pages.md +13 -10
- package/agent-docs/publish/content-export.sections/inspect-the-manifest.md +6 -4
- package/agent-docs/publish/content-export.sections/prerequisites.md +4 -4
- package/agent-docs/publish/content-export.sections/related-reading.md +3 -3
- package/agent-docs/publish/content-export.sections/review-exported-api-material.md +4 -4
- package/agent-docs/publish/content-export.sections/try-the-help-drawer-example.md +4 -4
- package/agent-docs/publish/content-export.sections/upgrade-an-existing-integration.md +34 -0
- package/agent-docs/publish/content-export.sections/what-the-representations-retain.md +5 -5
- package/agent-docs/publish/content-negotiation.md +2 -2
- package/agent-docs/publish/content-negotiation.sections/hosting-contract.md +2 -2
- package/agent-docs/publish/content-negotiation.sections/missing-pages.md +2 -2
- package/agent-docs/publish/content-negotiation.sections/related-reading.md +2 -2
- package/agent-docs/publish/content-negotiation.sections/validators-and-manifest-links.md +2 -2
- package/agent-docs/publish/content-negotiation.sections/verify-the-deployed-url.md +2 -2
- package/agent-docs/publish/content-negotiation.sections/what-if-the-host-cannot-negotiate.md +2 -2
- package/agent-docs/publish/content-negotiation.sections/what-shoalrun-builds-and-what-the-host-does.md +2 -2
- package/agent-docs/publish/content-negotiation.sections/why-this-matters.md +2 -2
- package/agent-docs/publish/deployment-check.md +2 -2
- package/agent-docs/publish/evals.md +1 -1
- package/agent-docs/publish/evals.sections/add-the-audit-hook.md +1 -1
- package/agent-docs/publish/evals.sections/check-the-report.md +1 -1
- package/agent-docs/publish/evals.sections/define-a-task-file.md +1 -1
- package/agent-docs/publish/evals.sections/diagnose-a-different-build.md +1 -1
- package/agent-docs/publish/evals.sections/prepare-a-report-for-the-built-site.md +1 -1
- package/agent-docs/publish/evals.sections/related-reading.md +1 -1
- package/agent-docs/publish/evals.sections/run-and-review-the-tasks.md +1 -1
- package/agent-docs/publish/evals.sections/shoalrun-s-own-example.md +1 -1
- package/agent-docs/publish/host-adapters.md +1 -1
- package/agent-docs/publish/manni.md +1 -1
- package/agent-docs/publish/manni.sections/check-the-result.md +1 -1
- package/agent-docs/publish/manni.sections/how-this-site-uses-manni.md +1 -1
- package/agent-docs/publish/manni.sections/optional-custom-policies.md +1 -1
- package/agent-docs/publish/manni.sections/prerequisites.md +1 -1
- package/agent-docs/publish/mcp-analytics.md +1 -1
- package/agent-docs/publish/mcp-analytics.sections/adapter-exports.md +1 -1
- package/agent-docs/publish/mcp-analytics.sections/enable-analytics.md +1 -1
- package/agent-docs/publish/mcp-analytics.sections/event-fields-and-service-mappings.md +1 -1
- package/agent-docs/publish/mcp-analytics.sections/optionally-collect-intent-and-group-calls.md +1 -1
- package/agent-docs/publish/mcp-analytics.sections/optionally-identify-the-client-and-model.md +1 -1
- package/agent-docs/publish/mcp-analytics.sections/related-reading.md +1 -1
- package/agent-docs/publish/mcp-analytics.sections/safeguards-and-limits.md +1 -1
- package/agent-docs/publish/mcp.md +12 -10
- package/agent-docs/publish/mcp.sections/check-budgets-and-errors.md +2 -2
- package/agent-docs/publish/mcp.sections/choose-the-documentation-source.md +7 -7
- package/agent-docs/publish/mcp.sections/configure-the-client.md +5 -5
- package/agent-docs/publish/mcp.sections/generate-a-vercel-endpoint.md +2 -2
- package/agent-docs/publish/mcp.sections/related-reading.md +4 -2
- package/agent-docs/publish/mcp.sections/search-then-read.md +2 -2
- package/agent-docs/publish/mcp.sections/serve-a-public-endpoint-on-node.md +2 -2
- package/agent-docs/publish/mcp.sections/verify-the-connection.md +2 -2
- package/agent-docs/publish/mcp.sections/why-offer-mcp-for-public-docs.md +2 -2
- package/agent-docs/publish/openapi-extension-mappings.md +2 -2
- package/agent-docs/publish/output.md +14 -14
- package/agent-docs/publish/output.sections/api-contracts.md +3 -3
- package/agent-docs/publish/output.sections/code-highlighting.md +3 -3
- package/agent-docs/publish/output.sections/current-limits.md +4 -4
- package/agent-docs/publish/output.sections/incremental-sync.md +3 -3
- package/agent-docs/publish/output.sections/manifest-records-and-sections.md +3 -3
- package/agent-docs/publish/output.sections/navigation-section-indexes.md +3 -3
- package/agent-docs/publish/output.sections/page-formats.md +3 -3
- package/agent-docs/publish/output.sections/published-output-contract.md +3 -3
- package/agent-docs/publish/output.sections/reader-appearance-and-controls.md +3 -3
- package/agent-docs/publish/output.sections/related-reading.md +3 -3
- package/agent-docs/publish/output.sections/response-identity.md +3 -3
- package/agent-docs/publish/output.sections/site-files.md +3 -3
- package/agent-docs/publish/output.sections/validate-an-existing-build-locally.md +5 -5
- package/agent-docs/publish/output.sections/where-files-go.md +11 -11
- package/agent-docs/publish/publications.md +1 -1
- package/agent-docs/publish/revisions.md +1 -1
- package/agent-docs/publish/seo.md +17 -3
- package/agent-docs/publish/seo.sections/related-reading.md +28 -0
- package/agent-docs/publish/seo.sections/set-the-public-address.md +36 -0
- package/agent-docs/publish/seo.sections/what-agents-receive.md +28 -0
- package/agent-docs/publish/seo.sections/what-the-build-adds.md +42 -0
- package/agent-docs/publish/seo.sections/write-the-page-title-and-summary.md +43 -0
- package/agent-docs/publish/single-source-sites.md +1 -1
- package/agent-docs/publish/troubleshooting.md +1 -1
- package/agent-docs/publish/vercel.md +1 -1
- package/agent-docs/publish/vercel.sections/check-the-deployment.md +1 -1
- package/agent-docs/publish/vercel.sections/include-an-mcp-endpoint.md +1 -1
- package/agent-docs/publish/vercel.sections/prepare-your-project.md +1 -1
- package/agent-docs/publish/vercel.sections/related-reading.md +1 -1
- package/agent-docs/publish.md +1 -1
- package/agent-docs/recipes/add-page.md +3 -3
- package/agent-docs/recipes/add-page.sections/audit-the-shoalrun-docs-project.md +2 -2
- package/agent-docs/recipes/add-page.sections/before-you-start.md +2 -3
- package/agent-docs/recipes/add-page.sections/build-the-shoalrun-docs-site.md +2 -2
- package/agent-docs/recipes/add-page.sections/check-agent-search-and-page-lookup.md +2 -2
- package/agent-docs/recipes/add-page.sections/check-the-built-page-artifacts.md +2 -2
- package/agent-docs/recipes/add-page.sections/check-the-outcome.md +2 -2
- package/agent-docs/recipes/add-page.sections/complete-the-guide-and-add-navigation.md +2 -2
- package/agent-docs/recipes/add-page.sections/install-the-site-dependencies.md +2 -2
- package/agent-docs/recipes/add-page.sections/regenerate-the-agent-documentation-bundle.md +3 -2
- package/agent-docs/recipes/add-page.sections/related-reading.md +2 -2
- package/agent-docs/recipes/add-page.sections/scaffold-a-new-guide.md +2 -2
- package/agent-docs/recipes/audit-docs.md +2 -3
- package/agent-docs/recipes/build-docs.md +2 -3
- package/agent-docs/recipes/preview-hybrid-search.md +2 -2
- package/agent-docs/recipes/preview-page.md +2 -3
- package/agent-docs/recipes/queue-email.md +2 -2
- package/agent-docs/recipes/refresh-agent-docs.md +21 -3
- package/agent-docs/recipes/send-welcome-email.md +2 -2
- package/agent-docs/reference/agent-skills.md +2 -2
- package/agent-docs/search-and-chat.md +1 -1
- package/agent-docs/search-index.json +1 -1
- package/agent-docs/start.md +7 -3
- package/agent-docs/start.sections/build-this-site.md +1 -1
- package/agent-docs/start.sections/migrating-from-github-packages.md +35 -0
- package/agent-docs/start.sections/prerequisites.md +1 -1
- package/agent-docs/start.sections/start-your-own-project.md +1 -1
- package/agent-docs/status.md +2 -2
- package/agent-docs/styling/color-modes.md +6 -2
- package/agent-docs/styling/footer.md +10 -8
- package/agent-docs/styling/header.md +5 -3
- package/agent-docs/styling/layouts.md +27 -5
- package/agent-docs/styling/layouts.sections/build-a-landing-page.md +7 -4
- package/agent-docs/styling/layouts.sections/build-a-splash-page.md +7 -4
- package/agent-docs/styling/layouts.sections/control-navigation-tabs.md +7 -4
- package/agent-docs/styling/layouts.sections/customize-the-hero.md +7 -4
- package/agent-docs/styling/layouts.sections/hero.md +8 -5
- package/agent-docs/styling/layouts.sections/hide-the-table-of-contents-or-give-content-more-room.md +54 -0
- package/agent-docs/styling/layouts.sections/html-markdown-and-agents.md +43 -0
- package/agent-docs/styling/layouts.sections/related-reading.md +7 -4
- package/agent-docs/styling/palettes.md +6 -2
- package/agent-docs/styling/share-images.md +6 -2
- package/agent-docs/styling/themes.md +6 -3
- package/agent-docs/styling/try.md +3 -15
- package/dist/api.js +70 -3
- package/dist/authoring-hints.d.ts +3 -0
- package/dist/authoring-hints.js +35 -0
- package/dist/authoring-project.d.ts +1 -1
- package/dist/authoring-project.js +2 -0
- package/dist/authoring-validation.js +2 -0
- package/dist/code-samples.js +22 -11
- package/dist/compiler-config.d.ts +1 -0
- package/dist/compiler-config.js +13 -0
- package/dist/compiler.js +2 -1
- package/dist/component-names.js +1 -1
- package/dist/component-transform.js +7 -1
- package/dist/content-delivery-contract.d.ts +108 -0
- package/dist/content-delivery-contract.js +15 -0
- package/dist/content-delivery-transport.d.ts +3 -0
- package/dist/content-delivery-transport.js +47 -0
- package/dist/content-delivery-validation.d.ts +7 -0
- package/dist/content-delivery-validation.js +122 -0
- package/dist/content-delivery.d.ts +21 -0
- package/dist/content-delivery.js +119 -0
- package/dist/content-export-anchors.d.ts +11 -0
- package/dist/content-export-anchors.js +79 -0
- package/dist/content-export-command.d.ts +4 -2
- package/dist/content-export-command.js +15 -2
- package/dist/content-export-comparison.d.ts +16 -0
- package/dist/content-export-comparison.js +48 -0
- package/dist/content-export-config.d.ts +17 -0
- package/dist/content-export-config.js +47 -3
- package/dist/content-export-render.js +20 -1
- package/dist/content-export.d.ts +5 -1
- package/dist/content-export.js +193 -40
- package/dist/content-mount.d.ts +11 -0
- package/dist/content-mount.js +73 -0
- package/dist/content-rest-client.d.ts +12 -0
- package/dist/content-rest-client.js +162 -0
- package/dist/content-rest-contract.d.ts +27 -0
- package/dist/content-rest-contract.js +9 -0
- package/dist/content-rest-server.d.ts +7 -0
- package/dist/content-rest-server.js +99 -0
- package/dist/content-source.d.ts +3 -1
- package/dist/frontmatter.js +8 -7
- package/dist/html-renderer.js +25 -0
- package/dist/markdown-sections.d.ts +2 -1
- package/dist/markdown-sections.js +8 -18
- package/dist/page-renderer.js +5 -3
- package/dist/publication-plan.js +2 -1
- package/dist/scaffold-placeholders.d.ts +2 -0
- package/dist/scaffold-placeholders.js +19 -0
- package/dist/section-identity.d.ts +24 -0
- package/dist/section-identity.js +137 -0
- package/examples/content-delivery/README.md +87 -0
- package/examples/content-delivery/app.js +91 -0
- package/examples/content-delivery/content/billing.mdx +22 -0
- package/examples/content-delivery/docs.config.yaml +36 -0
- package/examples/content-delivery/index.html +25 -0
- package/examples/content-delivery/preview.mjs +86 -0
- package/examples/content-delivery/snippets/refund-window.mdx +3 -0
- package/examples/help-drawer/README.md +2 -2
- package/examples/help-drawer/app.js +3 -3
- package/package.json +6 -3
- package/schemas/content-export.schema.json +469 -33
- package/schemas/content-rest.openapi.json +1627 -0
- package/skills/shoalrun-author/SKILL.md +2 -0
- package/styles/site.css +4 -1
- package/agent-docs/.well-known/shoalrun/navigation/changelog-tab-50f26fe22670.txt +0 -33
- package/agent-docs/publish/api-references.sections/add-useful-examples.md +0 -36
- package/agent-docs/publish/api-references.sections/describe-filters-that-do-not-use-their-openapi-parameter-name.md +0 -36
- package/agent-docs/publish/api-references.sections/link-guides-to-api-references.md +0 -36
- package/agent-docs/publish/api-references.sections/map-extension-values-to-shoalrun-status.md +0 -36
- package/agent-docs/publish/api-references.sections/publish-several-versions.md +0 -36
- package/agent-docs/publish/api-references.sections/use-a-template-for-editorial-context.md +0 -36
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
export const validSectionId = (value) => typeof value === 'string' && /^[a-z0-9][a-z0-9-]{0,511}$/.test(value);
|
|
2
|
+
const textOf = (node) => typeof node.value === 'string' ? node.value : (node.children ?? []).map(textOf).join('');
|
|
3
|
+
const marker = (node) => ['mdxJsxTextElement', 'mdxJsxFlowElement'].includes(node.type) && node.name === 'Anchor';
|
|
4
|
+
/** Consume only a direct trailing marker on an authored root H2. Code stays inert. */
|
|
5
|
+
export function lowerSectionMarkers(tree, label = 'document') {
|
|
6
|
+
const allowed = new Set();
|
|
7
|
+
const children = (tree.children ?? []).map((node) => {
|
|
8
|
+
if (node.type !== 'heading' || node.depth !== 2)
|
|
9
|
+
return node;
|
|
10
|
+
const parts = [...(node.children ?? [])];
|
|
11
|
+
while (parts.at(-1)?.type === 'text' && !parts.at(-1).value.trim())
|
|
12
|
+
parts.pop();
|
|
13
|
+
const last = parts.at(-1);
|
|
14
|
+
if (!last || !marker(last))
|
|
15
|
+
return node;
|
|
16
|
+
const attributes = last.attributes ?? [];
|
|
17
|
+
if (last.type !== 'mdxJsxTextElement' || last.children?.length || attributes.length !== 1 || attributes[0].type !== 'mdxJsxAttribute' || attributes[0].name !== 'id' || !validSectionId(attributes[0].value)) {
|
|
18
|
+
throw new Error(`${label}: <Anchor> needs only a literal id of 1–512 lowercase letters, numbers, or dashes and no children`);
|
|
19
|
+
}
|
|
20
|
+
allowed.add(last);
|
|
21
|
+
parts.pop();
|
|
22
|
+
if (parts.at(-1)?.type === 'text')
|
|
23
|
+
parts[parts.length - 1] = { ...parts.at(-1), value: parts.at(-1).value.trimEnd() };
|
|
24
|
+
if (!parts.map(textOf).join('').trim())
|
|
25
|
+
throw new Error(`${label}: an anchored heading needs a title`);
|
|
26
|
+
const id = attributes[0].value;
|
|
27
|
+
return { ...node, children: parts, data: { ...node.data, sectionId: id, hProperties: { ...node.data?.hProperties, 'data-shoalrun-section-id': id } } };
|
|
28
|
+
});
|
|
29
|
+
const check = (node) => {
|
|
30
|
+
if (marker(node) && !allowed.has(node))
|
|
31
|
+
throw new Error(`${label}: <Anchor> must be the single trailing marker of a root level-two heading`);
|
|
32
|
+
node.children?.forEach(check);
|
|
33
|
+
};
|
|
34
|
+
check(tree);
|
|
35
|
+
return { ...tree, children };
|
|
36
|
+
}
|
|
37
|
+
export function sectionIdentities(tree, label = 'document') {
|
|
38
|
+
const children = tree.children ?? [];
|
|
39
|
+
const starts = children.flatMap((node, index) => node.type === 'heading' && node.depth === 2 ? [index] : []);
|
|
40
|
+
const used = new Set();
|
|
41
|
+
const sections = starts.map(start => {
|
|
42
|
+
const node = children[start];
|
|
43
|
+
const title = textOf(node).trim();
|
|
44
|
+
const stem = title.normalize('NFKD').toLowerCase().replace(/[\u0300-\u036f]/g, '').replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '').slice(0, 80).replace(/-$/, '') || 'section';
|
|
45
|
+
let generated = stem;
|
|
46
|
+
for (let suffix = 2; used.has(generated); suffix++)
|
|
47
|
+
generated = `${stem}-${suffix}`;
|
|
48
|
+
used.add(generated);
|
|
49
|
+
const explicit = node.data?.sectionId !== undefined;
|
|
50
|
+
if (explicit && !validSectionId(node.data.sectionId))
|
|
51
|
+
throw new Error(`${label}: invalid explicit section ID`);
|
|
52
|
+
const end = children.findIndex((child, index) => index > start && child.type === 'heading' && child.depth <= 2);
|
|
53
|
+
return { id: explicit ? node.data.sectionId : generated, title, depth: 2, start, end: end < 0 ? children.length : end, explicit, generated };
|
|
54
|
+
});
|
|
55
|
+
const owners = new Map();
|
|
56
|
+
for (const item of sections) {
|
|
57
|
+
if (owners.has(item.id))
|
|
58
|
+
throw new Error(`${label}: duplicate section ID ${item.id}`);
|
|
59
|
+
owners.set(item.id, item.start);
|
|
60
|
+
if (item.explicit && sections.some(other => other.start !== item.start && other.generated === item.id))
|
|
61
|
+
throw new Error(`${label}: explicit section ID ${item.id} conflicts with another heading's derived ID`);
|
|
62
|
+
}
|
|
63
|
+
return sections.map(({ generated, ...section }) => section);
|
|
64
|
+
}
|
|
65
|
+
export function validateStandaloneSectionDeclarations(value, label = 'document') {
|
|
66
|
+
if (value === undefined)
|
|
67
|
+
return;
|
|
68
|
+
if (!Array.isArray(value))
|
|
69
|
+
throw new Error(`${label}: standaloneSections must be an array`);
|
|
70
|
+
const seen = new Set();
|
|
71
|
+
for (const item of value) {
|
|
72
|
+
const legacy = typeof item === 'string';
|
|
73
|
+
if (legacy ? !item.trim() || item !== item.trim() : !item || typeof item !== 'object' || Array.isArray(item) || Object.keys(item).sort().join(',') !== 'context,id' || item.context !== 'section' || !validSectionId(item.id)) {
|
|
74
|
+
throw new Error(`${label}: standaloneSections needs trimmed heading titles or { id, context: section } declarations`);
|
|
75
|
+
}
|
|
76
|
+
const key = legacy ? `title:${item}` : `id:${item.id}`;
|
|
77
|
+
if (seen.has(key))
|
|
78
|
+
throw new Error(`${label}: standaloneSections declarations must be unique`);
|
|
79
|
+
seen.add(key);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
export function validateStandaloneSections(tree, declarations = [], label = 'document') {
|
|
83
|
+
validateStandaloneSectionDeclarations(declarations, label);
|
|
84
|
+
const sections = sectionIdentities(tree, label);
|
|
85
|
+
const seen = new Set();
|
|
86
|
+
for (const declaration of declarations) {
|
|
87
|
+
const matches = sections.filter(section => typeof declaration === 'string' ? section.title === declaration : section.id === declaration.id);
|
|
88
|
+
if (matches.length !== 1)
|
|
89
|
+
throw new Error(`${label}: standaloneSections ${typeof declaration === 'string' ? `title "${declaration}"` : `ID "${declaration.id}"`} must match exactly one top-level level-two heading`);
|
|
90
|
+
if (seen.has(matches[0].start))
|
|
91
|
+
throw new Error(`${label}: standaloneSections declares the same heading more than once`);
|
|
92
|
+
seen.add(matches[0].start);
|
|
93
|
+
}
|
|
94
|
+
return sections;
|
|
95
|
+
}
|
|
96
|
+
/** Slice-only delivery is a distinct author approval from contextual discovery. */
|
|
97
|
+
export function selectSection(tree, id, declarations = [], label = 'document') {
|
|
98
|
+
const section = validateStandaloneSections(tree, declarations, label).find(item => item.id === id);
|
|
99
|
+
if (!section)
|
|
100
|
+
throw new Error(`${label}: unknown section ${id}`);
|
|
101
|
+
if (!declarations.some(item => typeof item !== 'string' && item.id === id && item.context === 'section'))
|
|
102
|
+
throw new Error(`${label}: section ${id} needs standaloneSections: [{ id: ${id}, context: section }] approval`);
|
|
103
|
+
const definitions = new Map();
|
|
104
|
+
const key = (node) => `${node.type === 'footnoteDefinition' || node.type === 'footnoteReference' ? 'footnote' : 'link'}:${node.identifier}`;
|
|
105
|
+
const comparable = (value) => Array.isArray(value) ? value.map(comparable) : value && typeof value === 'object' ? Object.fromEntries(Object.entries(value).filter(([name]) => name !== 'position' && name !== 'exportSourceKey').map(([name, item]) => [name, comparable(item)])) : value;
|
|
106
|
+
const collect = (node) => {
|
|
107
|
+
if (['definition', 'footnoteDefinition'].includes(node.type)) {
|
|
108
|
+
const previous = definitions.get(key(node));
|
|
109
|
+
if (previous && JSON.stringify(comparable(previous)) !== JSON.stringify(comparable(node)))
|
|
110
|
+
throw new Error(`${label}: ambiguous definition ${node.identifier} for section ${id}`);
|
|
111
|
+
if (!previous)
|
|
112
|
+
definitions.set(key(node), node);
|
|
113
|
+
}
|
|
114
|
+
node.children?.forEach(collect);
|
|
115
|
+
};
|
|
116
|
+
collect(tree);
|
|
117
|
+
const strip = (node) => ['definition', 'footnoteDefinition'].includes(node.type) ? [] : [{ ...node, ...(node.children ? { children: node.children.flatMap(strip) } : {}) }];
|
|
118
|
+
const nodes = tree.children.slice(section.start, section.end).flatMap(strip);
|
|
119
|
+
const included = new Set();
|
|
120
|
+
const closure = [];
|
|
121
|
+
const visit = (node) => {
|
|
122
|
+
if (['linkReference', 'imageReference', 'footnoteReference'].includes(node.type)) {
|
|
123
|
+
const identity = key(node);
|
|
124
|
+
if (!included.has(identity)) {
|
|
125
|
+
included.add(identity);
|
|
126
|
+
const definition = definitions.get(identity);
|
|
127
|
+
if (!definition)
|
|
128
|
+
throw new Error(`${label}: section ${id} has an unresolved reference ${node.identifier}`);
|
|
129
|
+
closure.push(definition);
|
|
130
|
+
visit(definition);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
node.children?.forEach(visit);
|
|
134
|
+
};
|
|
135
|
+
nodes.forEach(visit);
|
|
136
|
+
return { section, tree: { type: 'root', children: [...nodes, ...closure] } };
|
|
137
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Use pages, sections, and snippets in an application
|
|
2
|
+
|
|
3
|
+
This example uses the public `@shoalrun/cli/content` client to show a whole
|
|
4
|
+
billing guide, its independently approved refund section, and two simultaneous
|
|
5
|
+
copies of one reusable policy snippet. The app owns the drawer, buttons, focus,
|
|
6
|
+
and styling. Shoalrun supplies passive content and typed resource references.
|
|
7
|
+
|
|
8
|
+
Copy this directory into a project with Shoalrun installed. From the copied
|
|
9
|
+
example directory, run:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npx --no-install shoalrun export docs.config.yaml --target app-help --out public/help/releases/demo
|
|
13
|
+
node preview.mjs
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Open `http://127.0.0.1:8775/settings/billing`. Choose **Billing guide** to read the
|
|
17
|
+
page or **How to request a refund** to read only its named section. Follow the
|
|
18
|
+
section's billing-overview link. Both cards display the same snippet, with
|
|
19
|
+
independent footnote anchors. Escape closes the drawer and restores focus.
|
|
20
|
+
|
|
21
|
+
The preview resolves the installed package's public `@shoalrun/cli/content`
|
|
22
|
+
entrypoint and serves only its browser-safe modules. It does not serve arbitrary
|
|
23
|
+
package or project files. In a real app, import that entrypoint through your
|
|
24
|
+
existing browser bundler.
|
|
25
|
+
|
|
26
|
+
## Author the resources
|
|
27
|
+
|
|
28
|
+
The page gives its root heading a stable ID with
|
|
29
|
+
`## Request a refund <Anchor id="refunds" />`. Its page metadata separately
|
|
30
|
+
declares `{ id: refunds, context: section }` in `standaloneSections`, approving
|
|
31
|
+
that section as useful without the page introduction.
|
|
32
|
+
|
|
33
|
+
The export target selects a page reference, a section reference, and a named
|
|
34
|
+
snippet instance with a fixed `days` value. `snippets/refund-window.mdx` is also
|
|
35
|
+
included in the page, so the reusable wording stays in one source. Snippet
|
|
36
|
+
content is block content; this example does not insert it inside a button or
|
|
37
|
+
promise that arbitrary snippets are suitable for inline tooltips.
|
|
38
|
+
|
|
39
|
+
## Keep serving independent from presentation
|
|
40
|
+
|
|
41
|
+
`app.js` opens a snapshot with `openManifestContentSource`, reads resources by
|
|
42
|
+
typed reference, and uses `mountContent` for the HTML. Each mount receives fresh
|
|
43
|
+
DOM IDs and remapped anchors. The drawer aborts superseded requests and ignores
|
|
44
|
+
late results after closing. These are application behaviors, not server duties.
|
|
45
|
+
|
|
46
|
+
The preview also serves the read-only REST API at `/content/v1`. Open
|
|
47
|
+
`http://127.0.0.1:8775/settings/billing?delivery=rest` to use
|
|
48
|
+
`openRestContentSource` through the same snapshot interface. Both modes deliver
|
|
49
|
+
identical content and use the same application rendering code.
|
|
50
|
+
|
|
51
|
+
The server uses `createContentRestHandler` from `@shoalrun/cli/content/server`.
|
|
52
|
+
It pins one approved snapshot per publication at startup and retains no revision
|
|
53
|
+
history. All requests select `channel`, `version`, and `language`. List resources
|
|
54
|
+
first, then use the returned key and revision for subsequent reads:
|
|
55
|
+
|
|
56
|
+
```sh
|
|
57
|
+
curl 'http://127.0.0.1:8775/content/v1/resources?channel=production&version=current&language=en'
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`GET /resources/{key}` returns metadata; `GET
|
|
61
|
+
/resources/{key}/representations/{format}` returns HTML or Markdown. Append the
|
|
62
|
+
same publication parameters and `revision` returned by the list. HEAD and
|
|
63
|
+
conditional requests with `If-None-Match` are supported. The complete
|
|
64
|
+
[OpenAPI contract](../../schemas/content-rest.openapi.json) describes responses,
|
|
65
|
+
errors, and caching. The HTTP contract's `v1` is separate from package versions.
|
|
66
|
+
|
|
67
|
+
Keep `/help/releases/demo/` served alongside the API: the REST adapter preserves
|
|
68
|
+
exported bytes, including static links and asset URLs. Browser clients require
|
|
69
|
+
the application origin and HTTPS or localhost. This local example does not add
|
|
70
|
+
authentication, search, editing, or a production hosting service.
|
|
71
|
+
|
|
72
|
+
## Publish complete revisions
|
|
73
|
+
|
|
74
|
+
The example uses `/help/releases/demo/` as a fixed demonstration revision.
|
|
75
|
+
Production should use a new directory and matching `publicBase` for each release,
|
|
76
|
+
upload the complete export, and only then update the app's manifest URL or
|
|
77
|
+
release pointer. Retain revisions still used by open clients. Do not overwrite
|
|
78
|
+
files underneath an existing snapshot.
|
|
79
|
+
|
|
80
|
+
Use `--previous-manifest PATH --fail-on-removed` to detect removed public resource
|
|
81
|
+
references before replacing output. Without a baseline, the export reports that
|
|
82
|
+
removal coverage was unavailable. API review candidates are not approved content:
|
|
83
|
+
the client refuses a manifest whose review status is `required`.
|
|
84
|
+
|
|
85
|
+
The content comes from this project's trusted build. The client checks the
|
|
86
|
+
manifest and content digests; these establish consistency with that manifest,
|
|
87
|
+
not trust in an arbitrary third-party publisher. Preserve the export's notices.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { openManifestContentSource, openRestContentSource, mountContent } from '/shoalrun/content-delivery.js';
|
|
2
|
+
|
|
3
|
+
// The app owns interaction. A future server-backed source can supply this same
|
|
4
|
+
// snapshot interface; the drawer does not depend on manifest layout or filenames.
|
|
5
|
+
const lifetime = new AbortController();
|
|
6
|
+
const source = new URLSearchParams(location.search).get('delivery') === 'rest'
|
|
7
|
+
? openRestContentSource({ baseUrl: '/content/v1', publication: { channel: 'production', version: 'current', language: 'en' }, signal: lifetime.signal })
|
|
8
|
+
: openManifestContentSource({ manifestUrl: '/help/releases/demo/manifest.json', signal: lifetime.signal });
|
|
9
|
+
const drawer = document.querySelector('#drawer');
|
|
10
|
+
const container = document.querySelector('#help-content');
|
|
11
|
+
let generation = 0;
|
|
12
|
+
let pending;
|
|
13
|
+
let mounted;
|
|
14
|
+
let opener;
|
|
15
|
+
let snapshot;
|
|
16
|
+
let disposed = false;
|
|
17
|
+
const notes = [];
|
|
18
|
+
|
|
19
|
+
async function openHelp(ref, fragment) {
|
|
20
|
+
if (disposed) return;
|
|
21
|
+
const ticket = ++generation;
|
|
22
|
+
pending?.abort();
|
|
23
|
+
const controller = new AbortController();
|
|
24
|
+
pending = controller;
|
|
25
|
+
try {
|
|
26
|
+
const content = await source;
|
|
27
|
+
if (ticket !== generation) return;
|
|
28
|
+
const result = await content.get(ref, { format: 'html', signal: controller.signal });
|
|
29
|
+
if (ticket !== generation) return;
|
|
30
|
+
mounted?.unmount();
|
|
31
|
+
mounted = mountContent(container, result);
|
|
32
|
+
drawer.hidden = false;
|
|
33
|
+
const anchor = fragment && mounted.anchors.find(item => item.id === fragment || item.exportedId === fragment);
|
|
34
|
+
const target = anchor ? container.querySelector(`#${CSS.escape(anchor.exportedId)}`) : container.querySelector('h1,h2,h3') ?? container;
|
|
35
|
+
// Stable aliases precede the visible heading. Focus the heading rather than
|
|
36
|
+
// an empty aria-hidden alias so keyboard and screen-reader users get context.
|
|
37
|
+
const focus = target?.getAttribute('aria-hidden') === 'true' && target.nextElementSibling?.matches('h1,h2,h3,h4,h5,h6')
|
|
38
|
+
? target.nextElementSibling : target;
|
|
39
|
+
if (focus) { focus.tabIndex = -1; focus.focus({ preventScroll: true }); }
|
|
40
|
+
if (anchor) focus?.scrollIntoView();
|
|
41
|
+
else drawer.scrollTop = 0;
|
|
42
|
+
} catch (error) {
|
|
43
|
+
if (ticket !== generation || controller.signal.aborted) return;
|
|
44
|
+
mounted?.unmount();
|
|
45
|
+
mounted = undefined;
|
|
46
|
+
container.textContent = `Help could not be loaded: ${error.message}`;
|
|
47
|
+
drawer.hidden = false;
|
|
48
|
+
document.querySelector('#close').focus();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function closeHelp() {
|
|
52
|
+
++generation;
|
|
53
|
+
pending?.abort();
|
|
54
|
+
mounted?.unmount();
|
|
55
|
+
mounted = undefined;
|
|
56
|
+
drawer.hidden = true;
|
|
57
|
+
opener?.focus();
|
|
58
|
+
}
|
|
59
|
+
for (const [id, ref] of [
|
|
60
|
+
['page-help', { kind: 'page', documentId: 'guide.billing' }],
|
|
61
|
+
['section-help', { kind: 'section', documentId: 'guide.billing', sectionId: 'refunds' }],
|
|
62
|
+
]) document.getElementById(id).addEventListener('click', event => { opener = event.currentTarget; openHelp(ref); });
|
|
63
|
+
container.addEventListener('click', event => {
|
|
64
|
+
const anchor = event.target.closest('a[data-export-link]');
|
|
65
|
+
const link = anchor && mounted?.links.find(item => item.key === anchor.dataset.exportLink);
|
|
66
|
+
if (link?.kind !== 'resource') return;
|
|
67
|
+
event.preventDefault();
|
|
68
|
+
openHelp(link.ref, link.fragment);
|
|
69
|
+
});
|
|
70
|
+
document.querySelector('#close').addEventListener('click', closeHelp);
|
|
71
|
+
drawer.addEventListener('keydown', event => { if (event.key === 'Escape') { event.preventDefault(); closeHelp(); } });
|
|
72
|
+
|
|
73
|
+
source.then(async content => {
|
|
74
|
+
if (disposed) { content.dispose(); return; }
|
|
75
|
+
snapshot = content;
|
|
76
|
+
const result = await content.get({ kind: 'snippet', id: 'billing.refund-window' }, { format: 'html', signal: lifetime.signal });
|
|
77
|
+
if (disposed) return;
|
|
78
|
+
for (const id of ['plan-note', 'invoice-note']) notes.push(mountContent(document.getElementById(id), result));
|
|
79
|
+
}).catch(error => { if (!disposed) document.querySelector('#status').textContent = `Help could not be loaded: ${error.message}`; });
|
|
80
|
+
window.addEventListener('pagehide', event => {
|
|
81
|
+
// A back/forward-cache entry resumes this same module and snapshot. Preserve
|
|
82
|
+
// its state while the browser freezes it; only tear down a discarded page.
|
|
83
|
+
if (event.persisted) return;
|
|
84
|
+
disposed = true;
|
|
85
|
+
++generation;
|
|
86
|
+
lifetime.abort();
|
|
87
|
+
pending?.abort();
|
|
88
|
+
mounted?.unmount();
|
|
89
|
+
notes.forEach(note => note.unmount());
|
|
90
|
+
snapshot?.dispose();
|
|
91
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: guide.billing
|
|
3
|
+
title: Billing help
|
|
4
|
+
summary: Find invoices and request a refund for your workspace.
|
|
5
|
+
slug: /billing
|
|
6
|
+
standaloneSections:
|
|
7
|
+
- { id: refunds, context: section }
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
Use this guide to manage payments for your workspace.
|
|
11
|
+
|
|
12
|
+
## Find an invoice
|
|
13
|
+
|
|
14
|
+
Open **Settings → Billing → Invoices** and choose the payment date.
|
|
15
|
+
|
|
16
|
+
## Request a refund <Anchor id="refunds" />
|
|
17
|
+
|
|
18
|
+
<Snippet id="shared.refund-window" />
|
|
19
|
+
|
|
20
|
+
The workspace owner can open **Settings → Billing → Contact support** and provide the invoice number. Support confirms eligibility before issuing a refund.
|
|
21
|
+
|
|
22
|
+
[Read the billing overview](doc:guide.billing).
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
schemaVersion: 1
|
|
2
|
+
site:
|
|
3
|
+
title: Acme billing help
|
|
4
|
+
origin: https://docs.example.com
|
|
5
|
+
publications:
|
|
6
|
+
defaults: { channel: production, version: current, language: en }
|
|
7
|
+
channels:
|
|
8
|
+
production: { pathPrefix: "" }
|
|
9
|
+
versions:
|
|
10
|
+
current: { pathPrefix: "" }
|
|
11
|
+
enabled:
|
|
12
|
+
- { channel: production, version: current }
|
|
13
|
+
frontmatter:
|
|
14
|
+
defaults:
|
|
15
|
+
type: guide
|
|
16
|
+
channel: production
|
|
17
|
+
version: current
|
|
18
|
+
access: { policy: public }
|
|
19
|
+
snippets:
|
|
20
|
+
shared.refund-window:
|
|
21
|
+
file: ./snippets/refund-window.mdx
|
|
22
|
+
variables:
|
|
23
|
+
days: { type: number, default: 30 }
|
|
24
|
+
exports:
|
|
25
|
+
app-help:
|
|
26
|
+
formats: [html, markdown]
|
|
27
|
+
publicBase: /help/releases/demo/
|
|
28
|
+
resources:
|
|
29
|
+
- { kind: page, documentId: guide.billing }
|
|
30
|
+
- { kind: section, documentId: guide.billing, sectionId: refunds }
|
|
31
|
+
- kind: snippet
|
|
32
|
+
id: billing.refund-window
|
|
33
|
+
snippetId: shared.refund-window
|
|
34
|
+
title: Refund window
|
|
35
|
+
summary: When a workspace can request a refund.
|
|
36
|
+
values: { days: 30 }
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<meta charset="utf-8">
|
|
4
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
5
|
+
<title>Acme billing · Content delivery example</title>
|
|
6
|
+
<style>
|
|
7
|
+
*{box-sizing:border-box}body{font:16px/1.6 system-ui,sans-serif;color:#193b2c;background:#f4f7f4;margin:0}main{max-width:60rem;margin:3rem auto;padding:0 1.5rem}h1{line-height:1.2}button,a{color:#205b3b}button{font:inherit;cursor:pointer;padding:.5rem .8rem;border:1px solid #aac5b2;border-radius:.4rem;background:white}button:focus-visible,a:focus-visible{outline:3px solid #47926b;outline-offset:3px}.cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(16rem,1fr));gap:1rem}.card{padding:1.5rem;border:1px solid #d6e3d9;border-radius:.75rem;background:white}.card h2{margin-top:0}.help-content{font-size:.95rem}.help-content h2{font-size:1.3rem}.help-content a{overflow-wrap:anywhere}#drawer{position:fixed;inset:0 0 0 auto;width:min(36rem,95vw);padding:1.5rem;background:white;overflow:auto;box-shadow:-1rem 0 3rem #193b2c22}#drawer[hidden]{display:none}.drawer-header{display:flex;align-items:center;justify-content:space-between;gap:1rem;border-bottom:1px solid #d6e3d9;padding-bottom:1rem}.muted{color:#526f5d}#status{min-height:1.5em}
|
|
8
|
+
</style>
|
|
9
|
+
<main>
|
|
10
|
+
<p class="muted">Acme workspace</p>
|
|
11
|
+
<h1>Billing</h1>
|
|
12
|
+
<p>Manage your plan and recent payments.</p>
|
|
13
|
+
<p><button id="page-help">Billing guide</button> <button id="section-help">How to request a refund</button></p>
|
|
14
|
+
<div class="cards">
|
|
15
|
+
<section class="card" aria-labelledby="plan-title"><h2 id="plan-title">Current plan</h2><p>Team · $24 per month</p><div id="plan-note" class="help-content" aria-label="Plan refund policy"></div></section>
|
|
16
|
+
<section class="card" aria-labelledby="invoice-title"><h2 id="invoice-title">Recent payment</h2><p>Invoice INV-1042 · $24</p><div id="invoice-note" class="help-content" aria-label="Invoice refund policy"></div></section>
|
|
17
|
+
</div>
|
|
18
|
+
<p id="status" role="status" class="muted"></p>
|
|
19
|
+
</main>
|
|
20
|
+
<aside id="drawer" aria-label="Billing help" hidden>
|
|
21
|
+
<div class="drawer-header"><strong>Billing help</strong><button id="close">Close help</button></div>
|
|
22
|
+
<div id="help-content" class="help-content" aria-live="polite"></div>
|
|
23
|
+
</aside>
|
|
24
|
+
<script type="module" src="/app.js"></script>
|
|
25
|
+
</html>
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { createServer } from 'node:http';
|
|
2
|
+
import { readFile, realpath } from 'node:fs/promises';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { openManifestContentSource } from '@shoalrun/cli/content';
|
|
6
|
+
import { createContentRestHandler } from '@shoalrun/cli/content/server';
|
|
7
|
+
|
|
8
|
+
const root = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
let port = 8775;
|
|
10
|
+
let directory = path.join(root, 'public/help/releases/demo');
|
|
11
|
+
const args = process.argv.slice(2);
|
|
12
|
+
for (let index = 0; index < args.length; index++) {
|
|
13
|
+
if (args[index] === '--help') { console.log('Usage: node preview.mjs [--port PORT] [--help-directory DIRECTORY]'); process.exit(0); }
|
|
14
|
+
if (args[index] === '--port') port = Number(args[++index]);
|
|
15
|
+
else if (args[index] === '--help-directory' && args[index + 1]) directory = path.resolve(args[++index]);
|
|
16
|
+
else throw new Error('Unknown preview option');
|
|
17
|
+
}
|
|
18
|
+
if (!Number.isInteger(port) || port < 0 || port > 65535) throw new Error('Invalid port');
|
|
19
|
+
const help = await realpath(directory);
|
|
20
|
+
const clientEntry = fileURLToPath(import.meta.resolve('@shoalrun/cli/content'));
|
|
21
|
+
const clientDirectory = path.dirname(clientEntry);
|
|
22
|
+
// Serve only the public browser entry and its browser-safe dependencies.
|
|
23
|
+
// This is deliberately not a generic node_modules or repository file server.
|
|
24
|
+
const clientFiles = new Map([
|
|
25
|
+
['/shoalrun/content-delivery.js', clientEntry],
|
|
26
|
+
['/shoalrun/content-delivery-contract.js', path.join(clientDirectory, 'content-delivery-contract.js')],
|
|
27
|
+
...['content-mount', 'content-delivery-validation', 'content-delivery-transport', 'content-rest-client', 'content-rest-contract'].map(name => [`/shoalrun/${name}.js`, path.join(clientDirectory, `${name}.js`)]),
|
|
28
|
+
]);
|
|
29
|
+
const mount = '/help/releases/demo/';
|
|
30
|
+
const types = { '.html': 'text/html; charset=utf-8', '.js': 'text/javascript; charset=utf-8', '.json': 'application/json', '.svg': 'image/svg+xml', '.md': 'text/markdown; charset=utf-8', '.png': 'image/png' };
|
|
31
|
+
// Pin one approved bundle at startup. The injected transport reads only this
|
|
32
|
+
// bundle; realpath containment applies even to symlinks. It does not fetch URLs.
|
|
33
|
+
const source = await openManifestContentSource({
|
|
34
|
+
manifestUrl: `http://content.local${mount}manifest.json`,
|
|
35
|
+
fetch: async (input, options) => {
|
|
36
|
+
options?.signal?.throwIfAborted();
|
|
37
|
+
const url = new URL(String(input));
|
|
38
|
+
if (url.origin !== 'http://content.local' || !url.pathname.startsWith(mount)) throw new Error('Outside bundle');
|
|
39
|
+
try {
|
|
40
|
+
const file = await realpath(path.join(help, url.pathname.slice(mount.length)));
|
|
41
|
+
if (!file.startsWith(help + path.sep)) throw new Error('Outside bundle');
|
|
42
|
+
const body = await readFile(file, { signal: options?.signal ?? undefined });
|
|
43
|
+
return new Response(body, { headers: { 'Content-Type': types[path.extname(file)] ?? 'application/octet-stream' } });
|
|
44
|
+
} catch (error) {
|
|
45
|
+
options?.signal?.throwIfAborted();
|
|
46
|
+
return new Response(null, { status: 404 });
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
const rest = createContentRestHandler({ sources: [source] });
|
|
51
|
+
const server = createServer(async (request, response) => {
|
|
52
|
+
const url = new URL(request.url, 'http://127.0.0.1');
|
|
53
|
+
if (url.pathname === '/content/v1' || url.pathname.startsWith('/content/v1/')) {
|
|
54
|
+
const controller = new AbortController();
|
|
55
|
+
request.once('aborted', () => controller.abort());
|
|
56
|
+
response.once('close', () => { if (!response.writableEnded) controller.abort(); });
|
|
57
|
+
try {
|
|
58
|
+
const headers = new Headers();
|
|
59
|
+
for (const [name, value] of Object.entries(request.headers)) if (value !== undefined) headers.set(name, Array.isArray(value) ? value.join(', ') : value);
|
|
60
|
+
const result = await rest(new Request(url, { method: request.method, headers, signal: controller.signal }));
|
|
61
|
+
response.writeHead(result.status, Object.fromEntries(result.headers));
|
|
62
|
+
response.end(Buffer.from(await result.arrayBuffer()));
|
|
63
|
+
} catch {
|
|
64
|
+
if (!response.destroyed) { response.writeHead(500, { 'Cache-Control': 'no-store' }); response.end(); }
|
|
65
|
+
}
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (!['GET', 'HEAD'].includes(request.method)) { response.writeHead(405, { Allow: 'GET, HEAD' }); response.end(); return; }
|
|
69
|
+
try {
|
|
70
|
+
const pathname = decodeURIComponent(new URL(request.url, 'http://localhost').pathname);
|
|
71
|
+
let file = clientFiles.get(pathname);
|
|
72
|
+
if (!file && pathname.startsWith(mount)) {
|
|
73
|
+
file = await realpath(path.join(help, pathname.slice(mount.length)));
|
|
74
|
+
if (!file.startsWith(help + path.sep)) throw new Error('Invalid path');
|
|
75
|
+
}
|
|
76
|
+
if (!file && pathname === '/app.js') file = path.join(root, 'app.js');
|
|
77
|
+
if (!file && (pathname === '/' || pathname === '/settings/billing')) file = path.join(root, 'index.html');
|
|
78
|
+
if (!file) throw new Error('Not found');
|
|
79
|
+
const body = await readFile(file);
|
|
80
|
+
response.writeHead(200, { 'Content-Type': types[path.extname(file)] ?? 'application/octet-stream', 'X-Content-Type-Options': 'nosniff' });
|
|
81
|
+
response.end(request.method === 'HEAD' ? undefined : body);
|
|
82
|
+
} catch { response.writeHead(404); response.end('Not found'); }
|
|
83
|
+
});
|
|
84
|
+
server.listen(port, '127.0.0.1', () => console.log(`Content delivery demo: http://127.0.0.1:${server.address().port}/settings/billing`));
|
|
85
|
+
process.on('SIGINT', () => server.close(() => { source.dispose(); process.exit(0); }));
|
|
86
|
+
process.on('SIGTERM', () => server.close(() => { source.dispose(); process.exit(0); }));
|
|
@@ -18,10 +18,10 @@ billing help buttons; follow the in-drawer links and inspect the images.
|
|
|
18
18
|
The full account guide is omitted from the export and links to the configured
|
|
19
19
|
example documentation host; replace that origin for your own project.
|
|
20
20
|
|
|
21
|
-
`manifest.json` maps
|
|
21
|
+
`manifest.json` maps typed page references to representation files in its `resources` array. `app.js`
|
|
22
22
|
fetches the HTML, inserts it into one content container, and intercepts anchors
|
|
23
23
|
marked `data-export-link`. The corresponding manifest link supplies the target
|
|
24
|
-
|
|
24
|
+
page reference and original fragment. Other links use their ordinary destinations.
|
|
25
25
|
|
|
26
26
|
`/help/` is an example path, not a required Shoalrun directory. You can choose
|
|
27
27
|
another root-relative path, such as `/resources/`. Set `publicBase` to that path,
|
|
@@ -14,7 +14,7 @@ let current;
|
|
|
14
14
|
let request = 0;
|
|
15
15
|
let opener;
|
|
16
16
|
async function openHelp(id, fragment) {
|
|
17
|
-
const document = manifest.
|
|
17
|
+
const document = manifest.resources.find(resource => resource.ref.kind === 'page' && resource.ref.documentId === id);
|
|
18
18
|
if (!document?.representations.html) throw new Error(`No HTML help for ${id}`);
|
|
19
19
|
const ticket = ++request;
|
|
20
20
|
const response = await fetch(manifest.publicBase + document.representations.html.path);
|
|
@@ -43,9 +43,9 @@ content.addEventListener('click', event => {
|
|
|
43
43
|
const anchor = event.target.closest('a[data-export-link]');
|
|
44
44
|
if (!anchor) return;
|
|
45
45
|
const link = current?.representations.html.links.find(link => link.key === anchor.dataset.exportLink);
|
|
46
|
-
if (link?.kind !== '
|
|
46
|
+
if (link?.kind !== 'resource' || link.ref?.kind !== 'page') return; // Canonical fallbacks open as ordinary links.
|
|
47
47
|
event.preventDefault();
|
|
48
|
-
openHelp(link.documentId, link.fragment).catch(showError);
|
|
48
|
+
openHelp(link.ref.documentId, link.fragment).catch(showError);
|
|
49
49
|
});
|
|
50
50
|
function closeHelp() { request++; drawer.hidden = true; opener?.focus(); }
|
|
51
51
|
document.querySelector('#close').addEventListener('click', closeHelp);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shoalrun/cli",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.13",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"registry": "https://registry.npmjs.org",
|
|
6
6
|
"access": "public"
|
|
@@ -11,9 +11,11 @@
|
|
|
11
11
|
"license": "Apache-2.0",
|
|
12
12
|
"type": "module",
|
|
13
13
|
"exports": {
|
|
14
|
+
"./content": "./dist/content-delivery.js",
|
|
14
15
|
"./authoring": "./dist/authoring-api.js",
|
|
15
16
|
"./*": "./*",
|
|
16
|
-
"./components": "./dist/components.js"
|
|
17
|
+
"./components": "./dist/components.js",
|
|
18
|
+
"./content/server": "./dist/content-rest-server.js"
|
|
17
19
|
},
|
|
18
20
|
"files": [
|
|
19
21
|
"dist",
|
|
@@ -23,7 +25,7 @@
|
|
|
23
25
|
"styles",
|
|
24
26
|
"templates",
|
|
25
27
|
"examples",
|
|
26
|
-
"!examples
|
|
28
|
+
"!examples/**/public/**",
|
|
27
29
|
"!examples/**/node_modules/**",
|
|
28
30
|
"example-configs",
|
|
29
31
|
"!example-configs/**/.shoalrun/**",
|
|
@@ -32,6 +34,7 @@
|
|
|
32
34
|
"README.md",
|
|
33
35
|
"AUTHORING.md",
|
|
34
36
|
"schemas/content-export.schema.json",
|
|
37
|
+
"schemas/content-rest.openapi.json",
|
|
35
38
|
"CHANGELOG.md",
|
|
36
39
|
"!**/*.local.md",
|
|
37
40
|
"!**/*.override.md",
|