@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.
Files changed (703) hide show
  1. package/AUTHORING.md +29 -0
  2. package/CHANGELOG.md +40 -0
  3. package/DEPLOYMENT-PROFILES.md +96 -5
  4. package/README.md +59 -3
  5. package/agent-docs/.well-known/shoalrun/navigation/project-updates-50f26fe22670.txt +21 -17
  6. package/agent-docs/SNAPSHOT.json +5 -5
  7. package/agent-docs/api-docs/focused-contracts.md +4 -4
  8. package/agent-docs/api-docs/generate.md +11 -11
  9. package/agent-docs/api-docs/generate.sections/add-useful-examples.md +3 -3
  10. package/agent-docs/api-docs/generate.sections/choose-generated-references-or-mdx.md +4 -4
  11. package/agent-docs/api-docs/generate.sections/describe-filters-that-do-not-use-their-openapi-parameter-name.md +1 -1
  12. package/agent-docs/api-docs/generate.sections/generate-many-pages-selectively.md +2 -2
  13. package/agent-docs/api-docs/generate.sections/link-guides-to-api-references.md +1 -1
  14. package/agent-docs/api-docs/generate.sections/map-extension-values-to-shoalrun-status.md +1 -1
  15. package/agent-docs/api-docs/generate.sections/override-generated-reference-order-in-navigation.md +4 -4
  16. package/agent-docs/api-docs/generate.sections/related-reading.md +1 -1
  17. package/agent-docs/api-docs/generate.sections/use-a-template-for-editorial-context.md +2 -2
  18. package/agent-docs/api-docs/support.md +7 -7
  19. package/agent-docs/author/add-page.md +3 -3
  20. package/agent-docs/author/agent-overview.md +3 -3
  21. package/agent-docs/author/agent-workflow.md +7 -7
  22. package/agent-docs/author/analytics.md +27 -27
  23. package/agent-docs/author/analytics.sections/adapter-exports-and-consent.md +3 -3
  24. package/agent-docs/author/analytics.sections/built-in-events.md +15 -15
  25. package/agent-docs/author/analytics.sections/configure-an-adapter.md +1 -1
  26. package/agent-docs/author/analytics.sections/custom-interactions.md +2 -2
  27. package/agent-docs/author/analytics.sections/event-format.md +2 -2
  28. package/agent-docs/author/analytics.sections/html-markdown-and-agents.md +4 -4
  29. package/agent-docs/author/analytics.sections/inspect-events-locally.md +2 -2
  30. package/agent-docs/author/analytics.sections/map-events-to-your-service.md +3 -3
  31. package/agent-docs/author/analytics.sections/posthog-example.md +3 -3
  32. package/agent-docs/author/analytics.sections/related-reading.md +1 -1
  33. package/agent-docs/author/authoring-agent.md +3 -3
  34. package/agent-docs/author/coding-agent.md +4 -4
  35. package/agent-docs/author/components/api-embeds.md +6 -6
  36. package/agent-docs/author/components/api-embeds.sections/apiexample.md +3 -3
  37. package/agent-docs/author/components/api-embeds.sections/html-markdown-and-agents.md +1 -1
  38. package/agent-docs/author/components/api-embeds.sections/related-reading.md +1 -1
  39. package/agent-docs/author/components/badge.md +2 -2
  40. package/agent-docs/author/components/callout.md +2 -2
  41. package/agent-docs/author/components/cards.md +16 -16
  42. package/agent-docs/author/components/cards.sections/add-a-lucide-icon.md +4 -4
  43. package/agent-docs/author/components/cards.sections/build-a-collection.md +7 -7
  44. package/agent-docs/author/components/cards.sections/curate-a-reading-list.md +9 -9
  45. package/agent-docs/author/components/cards.sections/html-markdown-and-agents.md +3 -3
  46. package/agent-docs/author/components/cards.sections/link-to-one-document.md +3 -3
  47. package/agent-docs/author/components/cards.sections/override-card-text.md +5 -5
  48. package/agent-docs/author/components/cards.sections/related-reading.md +3 -3
  49. package/agent-docs/author/components/code-blocks.md +2 -2
  50. package/agent-docs/author/components/collapsible.md +3 -3
  51. package/agent-docs/author/components/cookbook-chooser.md +5 -5
  52. package/agent-docs/author/components/custom/react.md +8 -8
  53. package/agent-docs/author/components/custom/react.sections/html-markdown-and-agents.md +3 -3
  54. package/agent-docs/author/components/custom/react.sections/interactive-react-example.md +2 -2
  55. package/agent-docs/author/components/custom/react.sections/registration.md +1 -1
  56. package/agent-docs/author/components/custom/react.sections/related-reading.md +1 -1
  57. package/agent-docs/author/components/custom/react.sections/share-the-model-with-the-browser.md +3 -3
  58. package/agent-docs/author/components/custom/react.sections/where-the-content-lives.md +3 -3
  59. package/agent-docs/author/components/custom.md +7 -7
  60. package/agent-docs/author/components/definition-list.md +2 -2
  61. package/agent-docs/author/components/diagrams/d2-gallery.md +2 -2
  62. package/agent-docs/author/components/diagrams/d2-gallery.sections/basic-shapes.md +2 -2
  63. package/agent-docs/author/components/diagrams/d2-gallery.sections/flows-and-structures.md +2 -2
  64. package/agent-docs/author/components/diagrams/d2-gallery.sections/html-markdown-and-agents.md +2 -2
  65. package/agent-docs/author/components/diagrams/d2-gallery.sections/layout-engines.md +2 -2
  66. package/agent-docs/author/components/diagrams/d2-gallery.sections/related-reading.md +2 -2
  67. package/agent-docs/author/components/diagrams/d2-gallery.sections/sequences-and-grids.md +2 -2
  68. package/agent-docs/author/components/diagrams/d2-gallery.sections/styles-and-code.md +2 -2
  69. package/agent-docs/author/components/diagrams/pele-gallery.md +3 -3
  70. package/agent-docs/author/components/diagrams/pele-gallery.sections/charts-and-planning.md +2 -2
  71. package/agent-docs/author/components/diagrams/pele-gallery.sections/flowchart-shapes.md +2 -2
  72. package/agent-docs/author/components/diagrams/pele-gallery.sections/flows-and-behavior.md +2 -2
  73. package/agent-docs/author/components/diagrams/pele-gallery.sections/html-markdown-and-agents.md +3 -3
  74. package/agent-docs/author/components/diagrams/pele-gallery.sections/related-reading.md +2 -2
  75. package/agent-docs/author/components/diagrams/pele-gallery.sections/specialized-diagrams.md +2 -2
  76. package/agent-docs/author/components/diagrams/pele-gallery.sections/systems-and-structures.md +2 -2
  77. package/agent-docs/author/components/diagrams.md +8 -8
  78. package/agent-docs/author/components/doc-link.md +3 -3
  79. package/agent-docs/author/components/fields.md +18 -18
  80. package/agent-docs/author/components/file-tree.md +2 -2
  81. package/agent-docs/author/components/images.md +5 -5
  82. package/agent-docs/author/components/info-hint.md +3 -3
  83. package/agent-docs/author/components/kbd.md +2 -2
  84. package/agent-docs/author/components/math.md +2 -2
  85. package/agent-docs/author/components/only.md +3 -3
  86. package/agent-docs/author/components/progress.md +3 -3
  87. package/agent-docs/author/components/steps.md +2 -2
  88. package/agent-docs/author/components/tables.md +2 -2
  89. package/agent-docs/author/components/tabs.md +5 -5
  90. package/agent-docs/author/components/timeline.md +2 -2
  91. package/agent-docs/author/components/tooltips.md +2 -2
  92. package/agent-docs/author/components/walkthroughs.md +2 -2
  93. package/agent-docs/author/components/walkthroughs.sections/attributes.md +1 -1
  94. package/agent-docs/author/components/walkthroughs.sections/build-up-code.md +1 -1
  95. package/agent-docs/author/components/walkthroughs.sections/choose-a-layout.md +2 -2
  96. package/agent-docs/author/components/walkthroughs.sections/explain-one-file.md +1 -1
  97. package/agent-docs/author/components/walkthroughs.sections/html-markdown-and-agents.md +1 -1
  98. package/agent-docs/author/components/walkthroughs.sections/related-reading.md +1 -1
  99. package/agent-docs/author/components/walkthroughs.sections/syntax.md +1 -1
  100. package/agent-docs/author/components/walkthroughs.sections/take-code-from-a-file.md +1 -1
  101. package/agent-docs/author/components.md +2 -2
  102. package/agent-docs/author/content.md +3 -3
  103. package/agent-docs/author/cookbooks.md +9 -9
  104. package/agent-docs/author/css.md +4 -4
  105. package/agent-docs/author/css.sections/borders-fields-and-navigation-tokens.md +3 -3
  106. package/agent-docs/author/css.sections/core-color-tokens.md +3 -3
  107. package/agent-docs/author/css.sections/html-markdown-and-agents.md +4 -4
  108. package/agent-docs/author/css.sections/page-attributes.md +3 -3
  109. package/agent-docs/author/css.sections/page-transitions.md +3 -3
  110. package/agent-docs/author/css.sections/responsive-behavior.md +3 -3
  111. package/agent-docs/author/css.sections/status-code-and-callout-tokens.md +3 -3
  112. package/agent-docs/author/css.sections/typography-shape-and-width-tokens.md +3 -3
  113. package/agent-docs/author/custom-metadata.md +13 -13
  114. package/agent-docs/author/custom-metadata.sections/add-a-custom-page-field.md +4 -4
  115. package/agent-docs/author/custom-metadata.sections/choose-text-for-each-surface.md +3 -3
  116. package/agent-docs/author/custom-metadata.sections/preview-changes-to-metadata-providers.md +2 -2
  117. package/agent-docs/author/custom-metadata.sections/read-metadata-from-a-project-module.md +3 -3
  118. package/agent-docs/author/custom-metadata.sections/related-reading.md +1 -1
  119. package/agent-docs/author/design-templates.md +3 -3
  120. package/agent-docs/author/design-writing-guides.md +3 -3
  121. package/agent-docs/author/frontmatter-reference.md +59 -16
  122. package/agent-docs/author/frontmatter-reference.sections/categorize-connect-and-present-the-page.md +64 -0
  123. package/agent-docs/author/frontmatter-reference.sections/choose-a-publication-and-visibility.md +14 -12
  124. package/agent-docs/author/frontmatter-reference.sections/control-output-details.md +2 -2
  125. package/agent-docs/author/frontmatter-reference.sections/feature-availability.md +59 -0
  126. package/agent-docs/author/frontmatter-reference.sections/global-defaults-and-enforced-values.md +2 -2
  127. package/agent-docs/author/frontmatter-reference.sections/html-markdown-and-agents.md +3 -3
  128. package/agent-docs/author/frontmatter-reference.sections/identify-and-route-a-page.md +2 -2
  129. package/agent-docs/author/frontmatter-reference.sections/point-agents-to-it.md +2 -2
  130. package/agent-docs/author/frontmatter-reference.sections/product-publication-fields.md +37 -0
  131. package/agent-docs/author/frontmatter-reference.sections/project-defined-fields.md +2 -2
  132. package/agent-docs/author/frontmatter-reference.sections/related-reading.md +2 -2
  133. package/agent-docs/author/frontmatter-reference.sections/use-the-local-files-while-authoring.md +4 -4
  134. package/agent-docs/author/frontmatter-reference.sections/when-the-files-update.md +2 -2
  135. package/agent-docs/author/frontmatter.md +13 -13
  136. package/agent-docs/author/frontmatter.sections/audience-badges.md +3 -3
  137. package/agent-docs/author/frontmatter.sections/give-deprecation-guidance.md +4 -4
  138. package/agent-docs/author/frontmatter.sections/global-defaults-and-enforced-values.md +1 -1
  139. package/agent-docs/author/frontmatter.sections/optional-native-fields.md +4 -4
  140. package/agent-docs/author/frontmatter.sections/publication-fields.md +2 -2
  141. package/agent-docs/author/frontmatter.sections/publishing-policy.md +1 -1
  142. package/agent-docs/author/frontmatter.sections/related-metadata-tasks.md +1 -1
  143. package/agent-docs/author/frontmatter.sections/related-reading.md +1 -1
  144. package/agent-docs/author/frontmatter.sections/required-after-inheritance.md +1 -1
  145. package/agent-docs/author/frontmatter.sections/seo-fields.md +2 -2
  146. package/agent-docs/author/frontmatter.sections/validation-rules.md +3 -3
  147. package/agent-docs/author/markdown-metadata.md +20 -20
  148. package/agent-docs/author/navigation.md +12 -12
  149. package/agent-docs/author/navigation.sections/arrange-authored-pages.md +4 -4
  150. package/agent-docs/author/navigation.sections/fill-an-api-tag-group.md +2 -2
  151. package/agent-docs/author/navigation.sections/hide-group-page-counts.md +4 -4
  152. package/agent-docs/author/navigation.sections/html-markdown-and-agents.md +4 -4
  153. package/agent-docs/author/navigation.sections/local-api-preview.md +2 -2
  154. package/agent-docs/author/navigation.sections/mix-guides-and-api-references.md +3 -3
  155. package/agent-docs/author/navigation.sections/optionally-split-a-large-menu-into-files.md +2 -2
  156. package/agent-docs/author/navigation.sections/reach-navigation-while-reading.md +2 -2
  157. package/agent-docs/author/navigation.sections/related-reading.md +2 -2
  158. package/agent-docs/author/navigation.sections/split-navigation-into-tabs.md +4 -4
  159. package/agent-docs/author/navigation.sections/subject-lifecycle-labels.md +3 -3
  160. package/agent-docs/author/reader-views.md +9 -9
  161. package/agent-docs/author/reader-views.sections/configure-the-choices.md +2 -2
  162. package/agent-docs/author/reader-views.sections/connect-your-own-control.md +1 -1
  163. package/agent-docs/author/reader-views.sections/how-it-works-for-agents.md +3 -3
  164. package/agent-docs/author/reader-views.sections/mark-pages.md +3 -3
  165. package/agent-docs/author/reader-views.sections/mark-sections-and-add-an-entry-choice.md +2 -2
  166. package/agent-docs/author/reader-views.sections/place-filter-controls.md +2 -2
  167. package/agent-docs/author/reader-views.sections/try-the-controls-here.md +2 -2
  168. package/agent-docs/author/recipe-drafts.md +5 -5
  169. package/agent-docs/author/recipe-drafts.sections/1-write-one-reusable-step.md +2 -2
  170. package/agent-docs/author/recipe-drafts.sections/2-list-the-steps-for-one-complete-goal.md +2 -2
  171. package/agent-docs/author/recipe-drafts.sections/3-generate-a-draft-and-review-it.md +1 -1
  172. package/agent-docs/author/recipe-drafts.sections/4-maintain-shoalrun-s-published-recipe-snapshots.md +2 -2
  173. package/agent-docs/author/recipe-drafts.sections/related-reading.md +1 -1
  174. package/agent-docs/author/recipe-drafts.sections/start-an-ingredient-from-an-api-example.md +2 -2
  175. package/agent-docs/author/recipes.md +9 -9
  176. package/agent-docs/author/recipes.sections/how-agents-use-this.md +3 -3
  177. package/agent-docs/author/recipes.sections/one-example-from-shoalrun.md +3 -3
  178. package/agent-docs/author/recipes.sections/related-reading.md +2 -2
  179. package/agent-docs/author/recipes.sections/try-a-complete-workflow.md +3 -3
  180. package/agent-docs/author/recipes.sections/use-recipes-for-task-oriented-how-tos.md +4 -4
  181. package/agent-docs/author/recipes.sections/what-changing-an-ingredient-updates.md +3 -3
  182. package/agent-docs/author/recipes.sections/what-each-file-does.md +2 -2
  183. package/agent-docs/author/recipes.sections/what-happens-and-when.md +3 -3
  184. package/agent-docs/author/related-reading.md +11 -11
  185. package/agent-docs/author/related-reading.sections/automatic-footers.md +3 -3
  186. package/agent-docs/author/related-reading.sections/declare-relationships.md +3 -3
  187. package/agent-docs/author/related-reading.sections/display-related-documents.md +3 -3
  188. package/agent-docs/author/related-reading.sections/html-markdown-and-agents.md +1 -1
  189. package/agent-docs/author/related-reading.sections/inspect-output-and-changes.md +2 -2
  190. package/agent-docs/author/related-reading.sections/reading-paths-in-section-markdown.md +3 -3
  191. package/agent-docs/author/related-reading.sections/related-reading.md +1 -1
  192. package/agent-docs/author/related-reading.sections/where-relationship-explanations-come-from.md +2 -2
  193. package/agent-docs/author/release-notes.md +8 -8
  194. package/agent-docs/author/search.md +82 -29
  195. package/agent-docs/author/search.sections/agent-and-mcp-search-scope.md +52 -0
  196. package/agent-docs/author/search.sections/choose-a-provider.md +8 -7
  197. package/agent-docs/author/search.sections/cli-and-mcp-ranking-details.md +4 -4
  198. package/agent-docs/author/search.sections/enable-included-semantic-search.md +66 -0
  199. package/agent-docs/author/search.sections/hosted-semantic-search-limits.md +3 -3
  200. package/agent-docs/author/search.sections/html-markdown-and-agents.md +3 -3
  201. package/agent-docs/author/search.sections/lexical-search.md +6 -6
  202. package/agent-docs/author/search.sections/local-semantic-preview.md +3 -3
  203. package/agent-docs/author/search.sections/read-a-search-result-with-an-agent.md +2 -2
  204. package/agent-docs/author/search.sections/related-reading.md +2 -2
  205. package/agent-docs/author/search.sections/reuse-the-lexical-index.md +5 -5
  206. package/agent-docs/author/search.sections/turn-search-off.md +3 -3
  207. package/agent-docs/author/search.sections/use-the-search-box.md +2 -2
  208. package/agent-docs/author/search.sections/write-a-custom-provider.md +11 -11
  209. package/agent-docs/author/snippets.md +3 -3
  210. package/agent-docs/author/taxonomy.md +3 -3
  211. package/agent-docs/author/templates.md +16 -14
  212. package/agent-docs/author/templates.sections/built-in-feature-templates.md +2 -2
  213. package/agent-docs/author/templates.sections/built-in-templates.md +2 -2
  214. package/agent-docs/author/templates.sections/choose-formatting-enforcement-for-your-project.md +7 -7
  215. package/agent-docs/author/templates.sections/create-or-edit-a-project-template.md +8 -6
  216. package/agent-docs/author/templates.sections/keep-the-four-shapes-distinct.md +2 -2
  217. package/agent-docs/author/templates.sections/project-added-templates.md +3 -3
  218. package/agent-docs/author/templates.sections/related-reading.md +2 -2
  219. package/agent-docs/author/templates.sections/scaffold-a-page.md +2 -2
  220. package/agent-docs/author/templates.sections/short-cli-and-derived-values.md +3 -3
  221. package/agent-docs/author/templates.sections/what-every-template-gives-you.md +3 -3
  222. package/agent-docs/author/workspace/commands.md +4 -4
  223. package/agent-docs/author/workspace.md +7 -7
  224. package/agent-docs/author/writing-style.md +33 -18
  225. package/agent-docs/author/writing-style.sections/adapt-this-example.md +2 -2
  226. package/agent-docs/author/writing-style.sections/choose-components-by-reader-need.md +3 -3
  227. package/agent-docs/author/writing-style.sections/evidence-and-uncertainty.md +4 -4
  228. package/agent-docs/author/writing-style.sections/example-audience-and-scope.md +2 -2
  229. package/agent-docs/author/writing-style.sections/feature-availability.md +20 -7
  230. package/agent-docs/author/writing-style.sections/ingredients-recipes-and-cookbooks.md +5 -5
  231. package/agent-docs/author/writing-style.sections/page-purpose-and-structure.md +4 -4
  232. package/agent-docs/author/writing-style.sections/procedures-and-examples.md +4 -4
  233. package/agent-docs/author/writing-style.sections/related-reading.md +2 -2
  234. package/agent-docs/author/writing-style.sections/review-a-draft.md +3 -3
  235. package/agent-docs/author/writing-style.sections/reviewed-writing-examples.md +2 -2
  236. package/agent-docs/author/writing-style.sections/voice-and-explanations.md +4 -2
  237. package/agent-docs/changelog/2026-10-14-agent-readiness.md +2 -2
  238. package/agent-docs/changelog/2026-10-15-evaluation-builds.md +9 -9
  239. package/agent-docs/changelog/2026-10-16-navigation-layouts.md +4 -4
  240. package/agent-docs/changelog/2026-10-17-mcp-hosting.md +2 -2
  241. package/agent-docs/changelog/2026-10-18-search-and-tooltips.md +3 -3
  242. package/agent-docs/changelog/2026-10-19-visual-navigation.md +3 -3
  243. package/agent-docs/changelog/2026-10-25.md +2 -2
  244. package/agent-docs/changelog/2026-10-26.md +4 -4
  245. package/agent-docs/changelog/2026-10-27.md +1 -1
  246. package/agent-docs/changelog/2026-10-28.md +3 -3
  247. package/agent-docs/changelog/2026-10-30.md +1 -1
  248. package/agent-docs/changelog/2026-11-03.md +5 -5
  249. package/agent-docs/changelog/2026-11-04-runtime-packaging.md +46 -0
  250. package/agent-docs/changelog/authoring-preview.md +3 -3
  251. package/agent-docs/changelog/authoring-search.md +1 -1
  252. package/agent-docs/changelog/authoring-tools.md +2 -2
  253. package/agent-docs/changelog/product-publications.md +60 -0
  254. package/agent-docs/changelog/working-tree-skill.md +1 -1
  255. package/agent-docs/changelog.md +17 -1
  256. package/agent-docs/chat/checks.md +11 -11
  257. package/agent-docs/chat/checks.sections/answer-ahead-of-time.md +1 -1
  258. package/agent-docs/chat/checks.sections/answer-for-one-audience.md +2 -2
  259. package/agent-docs/chat/checks.sections/answer-without-a-model.md +2 -2
  260. package/agent-docs/chat/checks.sections/follow-up-questions.md +2 -2
  261. package/agent-docs/chat/checks.sections/how-an-answer-is-checked.md +3 -3
  262. package/agent-docs/chat/checks.sections/questions-with-several-parts.md +3 -3
  263. package/agent-docs/chat/checks.sections/related-reading.md +1 -1
  264. package/agent-docs/chat/checks.sections/reuse-answers.md +4 -4
  265. package/agent-docs/chat/host.md +8 -8
  266. package/agent-docs/chat/host.sections/cap-the-daily-spend.md +2 -2
  267. package/agent-docs/chat/host.sections/keep-a-record-of-questions.md +3 -3
  268. package/agent-docs/chat/host.sections/related-reading.md +2 -2
  269. package/agent-docs/chat/passage-index.md +31 -27
  270. package/agent-docs/chat/passage-index.sections/build-the-index.md +3 -3
  271. package/agent-docs/chat/passage-index.sections/embed-passages.md +4 -4
  272. package/agent-docs/chat/passage-index.sections/how-the-default-chunker-splits-a-page.md +3 -3
  273. package/agent-docs/chat/passage-index.sections/limits.md +3 -3
  274. package/agent-docs/chat/passage-index.sections/passage-ids-and-links.md +14 -10
  275. package/agent-docs/chat/passage-index.sections/related-reading.md +3 -3
  276. package/agent-docs/chat/passage-index.sections/what-a-passage-contains.md +19 -19
  277. package/agent-docs/chat/prepared-answers.md +4 -4
  278. package/agent-docs/chat/settings.md +3 -3
  279. package/agent-docs/chat/settings.sections/choose-the-scorer.md +1 -1
  280. package/agent-docs/chat/settings.sections/configure-chat.md +1 -1
  281. package/agent-docs/chat/settings.sections/configure-retrieval.md +1 -1
  282. package/agent-docs/chat/settings.sections/related-reading.md +1 -1
  283. package/agent-docs/chat/settings.sections/send-extra-request-fields.md +2 -2
  284. package/agent-docs/chat/settings.sections/use-more-than-one-model.md +2 -2
  285. package/agent-docs/chat/settings.sections/when-the-scorer-is-down.md +1 -1
  286. package/agent-docs/chat/setup.md +2 -2
  287. package/agent-docs/chat.md +3 -3
  288. package/agent-docs/cli.md +73 -59
  289. package/agent-docs/cli.sections/audit-a-project-and-api-sources.md +11 -7
  290. package/agent-docs/cli.sections/author-pages.md +16 -12
  291. package/agent-docs/cli.sections/build-and-serve.md +30 -18
  292. package/agent-docs/cli.sections/inspect-config-and-operations.md +13 -9
  293. package/agent-docs/cli.sections/npm-scripts-in-this-repository.md +7 -3
  294. package/agent-docs/cli.sections/related-reading.md +6 -2
  295. package/agent-docs/cli.sections/search-and-chat.md +24 -18
  296. package/agent-docs/cli.sections/start-a-project.md +7 -3
  297. package/agent-docs/cli.sections/working-tree-authoring-tools.md +7 -3
  298. package/agent-docs/concepts.md +2 -2
  299. package/agent-docs/config/apis.md +2 -2
  300. package/agent-docs/config/content.md +3 -3
  301. package/agent-docs/config/content.sections/authoring.md +3 -3
  302. package/agent-docs/config/content.sections/badges.md +1 -1
  303. package/agent-docs/config/content.sections/callouts.md +1 -1
  304. package/agent-docs/config/content.sections/cookbooks.md +1 -1
  305. package/agent-docs/config/content.sections/frontmatter.md +1 -1
  306. package/agent-docs/config/content.sections/readerfilters.md +1 -1
  307. package/agent-docs/config/content.sections/related-reading.md +1 -1
  308. package/agent-docs/config/content.sections/relationships.md +1 -1
  309. package/agent-docs/config/content.sections/snippets.md +1 -1
  310. package/agent-docs/config/content.sections/templates.md +1 -1
  311. package/agent-docs/config/content.sections/variables.md +1 -1
  312. package/agent-docs/config/examples.md +4 -4
  313. package/agent-docs/config/examples.sections/feature-showcase.md +4 -4
  314. package/agent-docs/config/examples.sections/minimal-site.md +2 -2
  315. package/agent-docs/config/examples.sections/multilingual-help-center.md +2 -2
  316. package/agent-docs/config/examples.sections/parcel-api-documentation.md +2 -2
  317. package/agent-docs/config/examples.sections/related-reading.md +2 -2
  318. package/agent-docs/config/examples.sections/shared-company-preset.md +2 -2
  319. package/agent-docs/config/integrations.md +4 -4
  320. package/agent-docs/config/outputs.md +22 -16
  321. package/agent-docs/config/outputs.sections/exports.md +19 -13
  322. package/agent-docs/config/outputs.sections/metadata.md +2 -2
  323. package/agent-docs/config/outputs.sections/related-reading.md +1 -1
  324. package/agent-docs/config/publishing.md +29 -19
  325. package/agent-docs/config/publishing.sections/navigation.md +2 -2
  326. package/agent-docs/config/publishing.sections/redirects.md +8 -8
  327. package/agent-docs/config/publishing.sections/related-reading.md +2 -2
  328. package/agent-docs/config/site.md +42 -18
  329. package/agent-docs/config/site.sections/related-reading.md +1 -1
  330. package/agent-docs/config/site.sections/theme.md +1 -1
  331. package/agent-docs/config.md +2 -2
  332. package/agent-docs/configuration.md +19 -19
  333. package/agent-docs/configuration.sections/build-several-sites-from-shared-content.md +1 -1
  334. package/agent-docs/configuration.sections/change-inherited-lists-deliberately.md +5 -5
  335. package/agent-docs/configuration.sections/extract-a-section-with-include.md +1 -1
  336. package/agent-docs/configuration.sections/inspect-and-validate-changes.md +5 -5
  337. package/agent-docs/configuration.sections/related-reading.md +1 -1
  338. package/agent-docs/configuration.sections/separate-config-inheritance-from-page-metadata.md +5 -5
  339. package/agent-docs/configuration.sections/share-defaults-through-extends.md +3 -3
  340. package/agent-docs/configuration.sections/start-with-one-working-file.md +2 -2
  341. package/agent-docs/configuration.sections/understand-the-three-stages.md +3 -3
  342. package/agent-docs/configuration.sections/understand-where-paths-point.md +2 -2
  343. package/agent-docs/connect/mcp.md +24 -15
  344. package/agent-docs/content-delivery/agents.md +6 -6
  345. package/agent-docs/content-delivery/api.md +29 -16
  346. package/agent-docs/content-delivery/client.md +14 -8
  347. package/agent-docs/content-delivery/http-api/operations/get-content-representation-fa1d2e3f.md +10 -2
  348. package/agent-docs/content-delivery/http-api/operations/get-content-representation-head-4052375c.md +10 -2
  349. package/agent-docs/content-delivery/http-api/operations/get-content-resource-849f1c49.md +537 -3
  350. package/agent-docs/content-delivery/http-api/operations/get-content-resource-head-0a352acd.md +10 -2
  351. package/agent-docs/content-delivery/http-api/operations/list-content-resources-8e977ec7.md +545 -3
  352. package/agent-docs/content-delivery/http-api/operations/list-content-resources-head-b67cbad9.md +10 -2
  353. package/agent-docs/content-delivery/http-api.md +21 -7
  354. package/agent-docs/content-delivery/manifest.md +30 -8
  355. package/agent-docs/content-delivery/publish.md +5 -5
  356. package/agent-docs/content-delivery/render.md +6 -6
  357. package/agent-docs/content-delivery/rest.md +16 -8
  358. package/agent-docs/content-delivery/sections.md +11 -11
  359. package/agent-docs/content-delivery/select.md +6 -6
  360. package/agent-docs/content-delivery.md +4 -4
  361. package/agent-docs/contribute/agent-skills.md +3 -3
  362. package/agent-docs/cookbooks/authoring.md +3 -3
  363. package/agent-docs/cookbooks/site-workflows.md +2 -2
  364. package/agent-docs/cookbooks/welcome-email.md +14 -11
  365. package/agent-docs/documents.json +2445 -1942
  366. package/agent-docs/example-api/cedar.md +4 -4
  367. package/agent-docs/features.md +49 -0
  368. package/agent-docs/glossary.md +22 -22
  369. package/agent-docs/index.md +5 -5
  370. package/agent-docs/ingredients/audit-site.md +2 -2
  371. package/agent-docs/ingredients/build-site.md +2 -2
  372. package/agent-docs/ingredients/complete-page.md +2 -2
  373. package/agent-docs/ingredients/refresh-agent-bundle.md +2 -2
  374. package/agent-docs/non-goals.md +4 -4
  375. package/agent-docs/provenance.json +10 -4
  376. package/agent-docs/publish/agent-discovery.md +8 -2
  377. package/agent-docs/publish/agent-friendliness.md +21 -21
  378. package/agent-docs/publish/agent-friendliness.sections/discover-a-page-with-a-small-context-budget.md +5 -5
  379. package/agent-docs/publish/agent-friendliness.sections/distinguish-examples-from-a-real-service.md +5 -5
  380. package/agent-docs/publish/agent-friendliness.sections/evidence-has-a-scope.md +5 -5
  381. package/agent-docs/publish/agent-friendliness.sections/keep-shared-instructions-complete.md +5 -5
  382. package/agent-docs/publish/agent-friendliness.sections/related-reading.md +3 -3
  383. package/agent-docs/publish/agent-friendliness.sections/secret-handshake.md +3 -3
  384. package/agent-docs/publish/agent-friendliness.sections/try-the-page-controls.md +3 -3
  385. package/agent-docs/publish/agent-friendliness.sections/use-the-transport-your-client-supports.md +4 -4
  386. package/agent-docs/publish/agent-friendliness.sections/verify-the-page-and-detect-changes.md +9 -9
  387. package/agent-docs/publish/agent-friendliness.sections/what-an-agent-reads.md +5 -5
  388. package/agent-docs/publish/agent-friendliness.sections/what-happens-to-an-unsupported-component.md +4 -4
  389. package/agent-docs/publish/api-references.md +5 -5
  390. package/agent-docs/publish/api-references.sections/author-the-reference-page.md +2 -2
  391. package/agent-docs/publish/api-references.sections/build-and-verify-the-output.md +3 -3
  392. package/agent-docs/publish/api-references.sections/inspect-the-machine-readable-contract.md +2 -2
  393. package/agent-docs/publish/api-references.sections/next-steps.md +2 -2
  394. package/agent-docs/publish/api-references.sections/preview-a-small-api-reference.md +2 -2
  395. package/agent-docs/publish/api-references.sections/put-the-spec-in-your-project.md +2 -2
  396. package/agent-docs/publish/api-references.sections/register-the-operation.md +2 -2
  397. package/agent-docs/publish/api-references.sections/related-reading.md +2 -2
  398. package/agent-docs/publish/api-references.sections/review-imported-content-before-publishing.md +3 -3
  399. package/agent-docs/publish/api-references.sections/what-readers-get.md +3 -3
  400. package/agent-docs/publish/audit.md +8 -8
  401. package/agent-docs/publish/audit.sections/add-project-tests.md +2 -2
  402. package/agent-docs/publish/audit.sections/check-agent-evaluation-reports.md +2 -2
  403. package/agent-docs/publish/audit.sections/check-before-pushing.md +3 -3
  404. package/agent-docs/publish/audit.sections/connect-a-documentation-test-suite.md +2 -2
  405. package/agent-docs/publish/audit.sections/read-the-report.md +3 -3
  406. package/agent-docs/publish/audit.sections/related-reading.md +1 -1
  407. package/agent-docs/publish/content-export.md +37 -15
  408. package/agent-docs/publish/content-export.sections/assets-downloads-and-notices.md +4 -4
  409. package/agent-docs/publish/content-export.sections/check-the-result.md +2 -2
  410. package/agent-docs/publish/content-export.sections/inspect-the-manifest.md +3 -3
  411. package/agent-docs/publish/content-export.sections/prerequisites.md +4 -4
  412. package/agent-docs/publish/content-export.sections/related-reading.md +2 -2
  413. package/agent-docs/publish/content-export.sections/review-exported-api-material.md +3 -3
  414. package/agent-docs/publish/content-export.sections/try-the-help-drawer-example.md +2 -2
  415. package/agent-docs/publish/content-export.sections/what-the-representations-retain.md +4 -4
  416. package/agent-docs/publish/content-negotiation.md +10 -10
  417. package/agent-docs/publish/content-negotiation.sections/hosting-contract.md +2 -2
  418. package/agent-docs/publish/content-negotiation.sections/missing-pages.md +3 -3
  419. package/agent-docs/publish/content-negotiation.sections/related-reading.md +1 -1
  420. package/agent-docs/publish/content-negotiation.sections/validators-and-manifest-links.md +2 -2
  421. package/agent-docs/publish/content-negotiation.sections/verify-the-deployed-url.md +2 -2
  422. package/agent-docs/publish/content-negotiation.sections/what-if-the-host-cannot-negotiate.md +3 -3
  423. package/agent-docs/publish/content-negotiation.sections/what-shoalrun-builds-and-what-the-host-does.md +2 -2
  424. package/agent-docs/publish/content-negotiation.sections/why-this-matters.md +2 -2
  425. package/agent-docs/publish/deployment-check.md +6 -6
  426. package/agent-docs/publish/deployment-profiles.md +60 -26
  427. package/agent-docs/publish/deployment-profiles.sections/before-you-begin.md +5 -5
  428. package/agent-docs/publish/deployment-profiles.sections/build-and-inspect-the-edition.md +9 -9
  429. package/agent-docs/publish/deployment-profiles.sections/check-the-result.md +7 -7
  430. package/agent-docs/publish/deployment-profiles.sections/choose-navigation-labels.md +6 -6
  431. package/agent-docs/publish/deployment-profiles.sections/current-limits.md +7 -7
  432. package/agent-docs/publish/deployment-profiles.sections/define-the-shared-sku-manifest.md +6 -6
  433. package/agent-docs/publish/deployment-profiles.sections/html-markdown-and-agents.md +7 -7
  434. package/agent-docs/publish/deployment-profiles.sections/mark-pages-and-shared-sections.md +13 -13
  435. package/agent-docs/publish/deployment-profiles.sections/preview-and-edit-a-customer-edition.md +55 -0
  436. package/agent-docs/publish/deployment-profiles.sections/related-reading.md +6 -6
  437. package/agent-docs/publish/deployment-profiles.sections/select-each-product-release.md +55 -0
  438. package/agent-docs/publish/deployment-profiles.sections/supply-the-profile-from-the-deployment.md +6 -6
  439. package/agent-docs/publish/evals.md +16 -16
  440. package/agent-docs/publish/evals.sections/add-the-audit-hook.md +5 -5
  441. package/agent-docs/publish/evals.sections/check-the-report.md +4 -4
  442. package/agent-docs/publish/evals.sections/define-a-task-file.md +5 -5
  443. package/agent-docs/publish/evals.sections/diagnose-a-different-build.md +5 -5
  444. package/agent-docs/publish/evals.sections/prepare-a-report-for-the-built-site.md +5 -5
  445. package/agent-docs/publish/evals.sections/related-reading.md +3 -3
  446. package/agent-docs/publish/evals.sections/run-and-review-the-tasks.md +4 -4
  447. package/agent-docs/publish/evals.sections/shoalrun-s-own-example.md +6 -6
  448. package/agent-docs/publish/host-adapters.md +6 -6
  449. package/agent-docs/publish/manni.md +16 -16
  450. package/agent-docs/publish/manni.sections/check-the-result.md +3 -3
  451. package/agent-docs/publish/manni.sections/how-this-site-uses-manni.md +6 -6
  452. package/agent-docs/publish/manni.sections/optional-custom-policies.md +4 -4
  453. package/agent-docs/publish/manni.sections/prerequisites.md +2 -2
  454. package/agent-docs/publish/mcp-analytics.md +12 -12
  455. package/agent-docs/publish/mcp-analytics.sections/adapter-exports.md +4 -4
  456. package/agent-docs/publish/mcp-analytics.sections/enable-analytics.md +4 -4
  457. package/agent-docs/publish/mcp-analytics.sections/event-fields-and-service-mappings.md +4 -4
  458. package/agent-docs/publish/mcp-analytics.sections/optionally-collect-intent-and-group-calls.md +4 -4
  459. package/agent-docs/publish/mcp-analytics.sections/optionally-identify-the-client-and-model.md +5 -5
  460. package/agent-docs/publish/mcp-analytics.sections/related-reading.md +3 -3
  461. package/agent-docs/publish/mcp-analytics.sections/safeguards-and-limits.md +5 -5
  462. package/agent-docs/publish/mcp.md +56 -29
  463. package/agent-docs/publish/mcp.sections/check-budgets-and-errors.md +8 -8
  464. package/agent-docs/publish/mcp.sections/choose-the-documentation-source.md +4 -4
  465. package/agent-docs/publish/mcp.sections/configure-the-client.md +4 -4
  466. package/agent-docs/publish/mcp.sections/discover-product-releases-before-searching.md +52 -0
  467. package/agent-docs/publish/mcp.sections/generate-a-vercel-endpoint.md +6 -6
  468. package/agent-docs/publish/mcp.sections/html-markdown-and-agents.md +38 -0
  469. package/agent-docs/publish/mcp.sections/related-reading.md +3 -3
  470. package/agent-docs/publish/mcp.sections/search-then-read.md +13 -12
  471. package/agent-docs/publish/mcp.sections/serve-a-public-endpoint-on-node.md +12 -8
  472. package/agent-docs/publish/mcp.sections/verify-the-connection.md +4 -4
  473. package/agent-docs/publish/mcp.sections/why-offer-mcp-for-public-docs.md +4 -4
  474. package/agent-docs/publish/openapi-extension-mappings.md +12 -12
  475. package/agent-docs/publish/output.md +20 -20
  476. package/agent-docs/publish/output.sections/api-contracts.md +1 -1
  477. package/agent-docs/publish/output.sections/code-highlighting.md +1 -1
  478. package/agent-docs/publish/output.sections/current-limits.md +1 -1
  479. package/agent-docs/publish/output.sections/incremental-sync.md +4 -4
  480. package/agent-docs/publish/output.sections/manifest-records-and-sections.md +3 -3
  481. package/agent-docs/publish/output.sections/navigation-section-indexes.md +1 -1
  482. package/agent-docs/publish/output.sections/page-formats.md +2 -2
  483. package/agent-docs/publish/output.sections/published-output-contract.md +5 -5
  484. package/agent-docs/publish/output.sections/reader-appearance-and-controls.md +1 -1
  485. package/agent-docs/publish/output.sections/related-reading.md +1 -1
  486. package/agent-docs/publish/output.sections/response-identity.md +1 -1
  487. package/agent-docs/publish/output.sections/site-files.md +6 -6
  488. package/agent-docs/publish/output.sections/validate-an-existing-build-locally.md +3 -3
  489. package/agent-docs/publish/output.sections/where-files-go.md +3 -3
  490. package/agent-docs/publish/publications.md +108 -19
  491. package/agent-docs/publish/publications.sections/add-a-language.md +60 -0
  492. package/agent-docs/publish/publications.sections/change-just-one-part-of-a-shared-page.md +63 -0
  493. package/agent-docs/publish/publications.sections/give-each-api-version-its-own-contract.md +34 -0
  494. package/agent-docs/publish/publications.sections/keep-an-unchanged-page-in-one-file.md +53 -0
  495. package/agent-docs/publish/publications.sections/publish-versions-without-a-product-catalog.md +49 -0
  496. package/agent-docs/publish/publications.sections/related-reading.md +42 -0
  497. package/agent-docs/publish/publications.sections/version-products-independently.md +115 -0
  498. package/agent-docs/publish/publications.sections/what-agents-receive.md +38 -0
  499. package/agent-docs/publish/revisions.md +4 -4
  500. package/agent-docs/publish/seo.md +10 -10
  501. package/agent-docs/publish/seo.sections/related-reading.md +2 -2
  502. package/agent-docs/publish/seo.sections/set-the-public-address.md +3 -3
  503. package/agent-docs/publish/seo.sections/what-agents-receive.md +3 -3
  504. package/agent-docs/publish/seo.sections/what-the-build-adds.md +2 -2
  505. package/agent-docs/publish/seo.sections/write-the-page-title-and-summary.md +2 -2
  506. package/agent-docs/publish/single-source-sites.md +5 -5
  507. package/agent-docs/publish/troubleshooting.md +10 -10
  508. package/agent-docs/publish/vercel.md +5 -5
  509. package/agent-docs/publish/vercel.sections/check-the-deployment.md +1 -1
  510. package/agent-docs/publish/vercel.sections/include-an-mcp-endpoint.md +2 -2
  511. package/agent-docs/publish/vercel.sections/prepare-your-project.md +2 -2
  512. package/agent-docs/publish/vercel.sections/related-reading.md +1 -1
  513. package/agent-docs/publish.md +2 -2
  514. package/agent-docs/recipes/add-page.md +5 -5
  515. package/agent-docs/recipes/add-page.sections/audit-the-shoalrun-docs-project.md +2 -2
  516. package/agent-docs/recipes/add-page.sections/before-you-start.md +1 -1
  517. package/agent-docs/recipes/add-page.sections/build-the-shoalrun-docs-site.md +2 -2
  518. package/agent-docs/recipes/add-page.sections/check-agent-search-and-page-lookup.md +1 -1
  519. package/agent-docs/recipes/add-page.sections/check-the-built-page-artifacts.md +1 -1
  520. package/agent-docs/recipes/add-page.sections/check-the-outcome.md +1 -1
  521. package/agent-docs/recipes/add-page.sections/complete-the-guide-and-add-navigation.md +2 -2
  522. package/agent-docs/recipes/add-page.sections/install-the-site-dependencies.md +1 -1
  523. package/agent-docs/recipes/add-page.sections/regenerate-the-agent-documentation-bundle.md +2 -2
  524. package/agent-docs/recipes/add-page.sections/related-reading.md +1 -1
  525. package/agent-docs/recipes/add-page.sections/scaffold-a-new-guide.md +1 -1
  526. package/agent-docs/recipes/audit-docs.md +4 -4
  527. package/agent-docs/recipes/build-docs.md +2 -2
  528. package/agent-docs/recipes/preview-hybrid-search.md +5 -5
  529. package/agent-docs/recipes/preview-page.md +2 -2
  530. package/agent-docs/recipes/queue-email.md +3 -3
  531. package/agent-docs/recipes/refresh-agent-docs.md +4 -4
  532. package/agent-docs/recipes/send-welcome-email.md +15 -15
  533. package/agent-docs/reference/agent-skills.md +7 -7
  534. package/agent-docs/search-and-chat.md +4 -4
  535. package/agent-docs/search-index.json +1 -1
  536. package/agent-docs/start.md +5 -5
  537. package/agent-docs/start.sections/add-the-page-to-navigation.md +3 -3
  538. package/agent-docs/start.sections/build-and-check-both-outputs.md +3 -3
  539. package/agent-docs/start.sections/build-this-site.md +2 -2
  540. package/agent-docs/start.sections/check-writing-style.md +2 -2
  541. package/agent-docs/start.sections/create-a-page.md +2 -2
  542. package/agent-docs/start.sections/make-it-yours.md +2 -2
  543. package/agent-docs/start.sections/migrating-from-github-packages.md +2 -2
  544. package/agent-docs/start.sections/prerequisites.md +2 -2
  545. package/agent-docs/start.sections/related-reading.md +2 -2
  546. package/agent-docs/start.sections/start-your-own-project.md +3 -3
  547. package/agent-docs/status.md +14 -4
  548. package/agent-docs/styling/color-modes.md +2 -2
  549. package/agent-docs/styling/footer.md +2 -2
  550. package/agent-docs/styling/header.md +2 -2
  551. package/agent-docs/styling/layouts.md +3 -3
  552. package/agent-docs/styling/layouts.sections/build-a-landing-page.md +1 -1
  553. package/agent-docs/styling/layouts.sections/build-a-splash-page.md +1 -1
  554. package/agent-docs/styling/layouts.sections/control-navigation-tabs.md +2 -2
  555. package/agent-docs/styling/layouts.sections/customize-the-hero.md +1 -1
  556. package/agent-docs/styling/layouts.sections/hero.md +1 -1
  557. package/agent-docs/styling/layouts.sections/hide-the-table-of-contents-or-give-content-more-room.md +1 -1
  558. package/agent-docs/styling/layouts.sections/html-markdown-and-agents.md +2 -2
  559. package/agent-docs/styling/layouts.sections/related-reading.md +1 -1
  560. package/agent-docs/styling/palettes.md +3 -3
  561. package/agent-docs/styling/share-images.md +3 -3
  562. package/agent-docs/styling/themes.md +2 -2
  563. package/agent-docs/styling/try.md +2 -2
  564. package/agent-docs/what-is-shoalrun.md +7 -3
  565. package/assets/ask-widget.js +20 -6
  566. package/assets/navigation.js +5 -0
  567. package/dist/ai-directory.d.ts +1 -0
  568. package/dist/ai-directory.js +12 -0
  569. package/dist/answer-cards.js +1 -1
  570. package/dist/api-materialize.d.ts +2 -1
  571. package/dist/api-materialize.js +21 -9
  572. package/dist/api-publication-plan.d.ts +2 -0
  573. package/dist/api-publication-plan.js +23 -7
  574. package/dist/api-publication-review.js +4 -3
  575. package/dist/api-selection.d.ts +5 -2
  576. package/dist/api-selection.js +18 -11
  577. package/dist/artifact-bundle.js +9 -6
  578. package/dist/ask-function.d.ts +4 -18
  579. package/dist/ask-function.js +12 -71
  580. package/dist/ask-runtime.d.ts +46 -0
  581. package/dist/ask-runtime.js +101 -0
  582. package/dist/ask-setup.d.ts +3 -42
  583. package/dist/ask-setup.js +5 -93
  584. package/dist/authored-change.js +2 -1
  585. package/dist/authoring-project.js +1 -1
  586. package/dist/cards.js +2 -1
  587. package/dist/cli-discovery.d.ts +2 -2
  588. package/dist/cli-discovery.js +9 -4
  589. package/dist/cli.js +48 -23
  590. package/dist/compiler-config.d.ts +17 -0
  591. package/dist/compiler-config.js +43 -2
  592. package/dist/compiler.d.ts +21 -0
  593. package/dist/compiler.js +16 -12
  594. package/dist/component-transform.d.ts +2 -4
  595. package/dist/component-transform.js +20 -7
  596. package/dist/config.d.ts +1 -0
  597. package/dist/config.js +2 -1
  598. package/dist/content-delivery-contract.d.ts +2 -1
  599. package/dist/content-delivery-validation.d.ts +2 -2
  600. package/dist/content-delivery-validation.js +6 -4
  601. package/dist/content-export-command.d.ts +1 -1
  602. package/dist/content-export-command.js +4 -4
  603. package/dist/content-export-comparison.js +6 -5
  604. package/dist/content-export-config.js +3 -1
  605. package/dist/content-export.js +9 -8
  606. package/dist/content-rest-client.js +4 -2
  607. package/dist/content-rest-contract.d.ts +2 -2
  608. package/dist/content-rest-server.js +11 -6
  609. package/dist/content-source.d.ts +13 -0
  610. package/dist/content-source.js +5 -2
  611. package/dist/content-workspace.d.ts +12 -0
  612. package/dist/content-workspace.js +2 -1
  613. package/dist/content.js +3 -2
  614. package/dist/cookbook-chooser.js +2 -1
  615. package/dist/deployment-profile.d.ts +2 -1
  616. package/dist/deployment-profile.js +38 -8
  617. package/dist/dev.d.ts +3 -1
  618. package/dist/dev.js +99 -12
  619. package/dist/docs-author.js +2 -1
  620. package/dist/docs-command.js +2 -2
  621. package/dist/docs-eval.d.ts +1 -0
  622. package/dist/docs-eval.js +2 -2
  623. package/dist/docs-mcp.d.ts +1 -0
  624. package/dist/docs-mcp.js +10 -5
  625. package/dist/docs-tool.d.ts +4 -10
  626. package/dist/document-sync.d.ts +1 -0
  627. package/dist/document-sync.js +2 -2
  628. package/dist/documentation-core.d.ts +29 -10
  629. package/dist/documentation-core.js +38 -4
  630. package/dist/embeddings.d.ts +1 -1
  631. package/dist/embeddings.js +1 -1
  632. package/dist/freshness.js +2 -2
  633. package/dist/frontmatter.js +13 -7
  634. package/dist/function-package.js +5 -0
  635. package/dist/function-runtime.d.ts +24 -0
  636. package/dist/function-runtime.js +45 -0
  637. package/dist/index-build.d.ts +2 -2
  638. package/dist/index-build.js +5 -13
  639. package/dist/ingredient-draft.js +20 -10
  640. package/dist/mcp-analytics.d.ts +1 -0
  641. package/dist/mcp-artifacts.js +13 -4
  642. package/dist/mcp-config.d.ts +1 -0
  643. package/dist/mcp-config.js +3 -1
  644. package/dist/mcp-http.js +1 -1
  645. package/dist/page-materialization.d.ts +3 -4
  646. package/dist/page-materialization.js +15 -8
  647. package/dist/page-renderer.d.ts +6 -0
  648. package/dist/page-renderer.js +16 -5
  649. package/dist/project-navigation.js +2 -1
  650. package/dist/publication-identity.d.ts +12 -0
  651. package/dist/publication-identity.js +17 -0
  652. package/dist/publication-manifest.d.ts +24 -1
  653. package/dist/publication-manifest.js +14 -6
  654. package/dist/publication-plan.js +21 -9
  655. package/dist/publication-render.js +24 -8
  656. package/dist/recipe-draft.js +9 -6
  657. package/dist/retrieval-runtime.d.ts +5 -0
  658. package/dist/retrieval-runtime.js +21 -0
  659. package/dist/scaffold.d.ts +7 -4
  660. package/dist/scaffold.js +16 -16
  661. package/dist/search-function.d.ts +2 -0
  662. package/dist/search-function.js +30 -0
  663. package/dist/search-handler.js +2 -2
  664. package/dist/search-identifier-core.d.ts +4 -0
  665. package/dist/search-identifier-core.js +30 -0
  666. package/dist/search-identifier.d.ts +3 -3
  667. package/dist/search-identifier.js +7 -30
  668. package/dist/search-literal.js +1 -1
  669. package/dist/search-query.d.ts +4 -10
  670. package/dist/search-query.js +10 -9
  671. package/dist/search-results.js +1 -1
  672. package/dist/search-snippet.d.ts +1 -1
  673. package/dist/search-snippet.js +2 -14
  674. package/dist/search-text.d.ts +1 -0
  675. package/dist/search-text.js +14 -0
  676. package/dist/server.d.ts +8 -0
  677. package/dist/server.js +14 -3
  678. package/dist/subject-deprecation.js +2 -1
  679. package/dist/vercel-function.js +11 -3
  680. package/example-configs/products/README.md +37 -0
  681. package/example-configs/products/content/operations.mdx +50 -0
  682. package/example-configs/products/content/payments-v2.mdx +30 -0
  683. package/example-configs/products/content/payments-v3.mdx +38 -0
  684. package/example-configs/products/content/priority-settlement.mdx +23 -0
  685. package/example-configs/products/content/reporting-v1.mdx +36 -0
  686. package/example-configs/products/content/scheduled-exports.mdx +23 -0
  687. package/example-configs/products/docs.config.yaml +56 -0
  688. package/example-configs/products/profiles/all-releases.yaml +9 -0
  689. package/example-configs/products/profiles/customer-a.yaml +13 -0
  690. package/example-configs/products/profiles/customer-b.yaml +13 -0
  691. package/example-configs/products/skus.yaml +11 -0
  692. package/examples/content-delivery/preview.mjs +1 -1
  693. package/package.json +1 -1
  694. package/schemas/content-export.schema.json +41 -3
  695. package/schemas/content-rest.openapi.json +184 -37
  696. package/skills/shoalrun-author/SKILL.md +6 -2
  697. package/skills/shoalrun-author/references/customer-editions.md +34 -4
  698. package/skills/shoalrun-author/references/publications.md +60 -0
  699. package/skills/shoalrun-recipes/SKILL.md +2 -0
  700. package/skills/shoalrun-setup/SKILL.md +3 -1
  701. package/styles/header.css +3 -0
  702. package/styles/site.css +3 -0
  703. package/agent-docs/publish/content-export.sections/export-selected-pages.md +0 -116
@@ -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
+ }
@@ -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 = (id, variant) => `${id}|${variant.channel}|${variant.version}|${variant.language}`;
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) || typeof variant.channel !== 'string' || typeof variant.version !== 'string' || (variant.language !== undefined && typeof variant.language !== 'string'))
219
- throw new Error('publications.enabled needs channel, version, and optional language');
220
- return { ...variant, channel: variant.channel, version: variant.version, language: variant.language ?? language };
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.channel === variant.channel && b.version === variant.version && b.language === variant.language);
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
- for (const item of attributes)
146
- if ((item.name === 'channel' || item.name === 'version') && publicationConfig && !Object.hasOwn(publicationConfig[item.name === 'channel' ? 'channels' : 'versions'], item.value)) {
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 target = registry.get(attr(node, 'doc'));
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
@@ -10,6 +10,7 @@ export declare class ConfigError extends Error {
10
10
  }
11
11
  export declare function loadConfig(file: string, options?: {
12
12
  profile?: string;
13
+ onDependency?: (file: string) => void;
13
14
  }): Promise<{
14
15
  value: Record<string, unknown>;
15
16
  tree: Tree;
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) => boolean;
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) => object(value) && Object.keys(value).length === 3 && ['channel', 'version', 'language'].every(key => nonempty(value[key]));
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 !== 1 || value.kind !== 'shoalrun-content-export' || !digestPattern.test(value.digest ?? ''))
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 (!object(publication) || Object.keys(publication).length !== 3 || !['channel', 'version', 'language'].every(key => nonempty(publication[key])))
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 (Object.keys(resource.publication).length !== 3 || !['channel', 'version', 'language'].every(key => resource.publication && resource.publication[key] === publication[key]))
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))))
@@ -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) => `${doc.frontmatter.id}|${doc.variant.channel}|${doc.variant.version}|${doc.variant.language}`;
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 = (a, b) => ['channel', 'version', 'language'].every(key => a[key] === b[key]);
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) || typeof value.channel !== 'string' || typeof value.version !== 'string' || value.language !== undefined && typeof value.language !== 'string'))
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 => ({ channel: value.channel, version: value.version, language: value.language ?? language }));
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;