camox 0.43.0 → 0.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (412) hide show
  1. package/bin/camox.mjs +9 -1
  2. package/dist/components/AuthGate.js +0 -6
  3. package/dist/components/DeviceSelector.js +96 -0
  4. package/dist/components/PlatformLabel.js +20 -24
  5. package/dist/core/components/lexical/HighlightNode.js +1 -1
  6. package/dist/core/components/lexical/InlineContentEditable.js +15 -19
  7. package/dist/core/components/lexical/InlineLexicalEditor.js +54 -74
  8. package/dist/core/components/lexical/InlineStylesPlugin.js +57 -41
  9. package/dist/core/components/lexical/MaxLengthPlugin.js +59 -0
  10. package/dist/core/components/lexical/SelectionBroadcaster.js +55 -56
  11. package/dist/core/components/lexical/SidebarLexicalEditor.js +327 -234
  12. package/dist/core/components/lexical/SummaryToggleGuard.js +42 -0
  13. package/dist/core/components/lexical/TextLinkPopover.js +169 -180
  14. package/dist/core/createApp.d.ts +254 -299
  15. package/dist/core/createApp.js +123 -29
  16. package/dist/core/createBlock.d.ts +5 -5
  17. package/dist/core/createBlock.js +399 -152
  18. package/dist/core/createCollection.d.ts +55 -0
  19. package/dist/core/createCollection.js +93 -0
  20. package/dist/core/createLayout.d.ts +197 -61
  21. package/dist/core/createLayout.js +114 -56
  22. package/dist/core/defineDocument.d.ts +3 -5
  23. package/dist/core/derivedRoutes.js +49 -1
  24. package/dist/core/dom.d.ts +13 -4
  25. package/dist/core/dom.js +44 -1
  26. package/dist/core/editing/BlockEditingRuntime.d.ts +16 -0
  27. package/dist/core/editing/BlockEditingRuntime.js +6 -15
  28. package/dist/core/editing/CompleteBlockEditingRuntime.js +28 -23
  29. package/dist/core/editing/createEditableBlock.d.ts +820 -565
  30. package/dist/core/editing/createEditableBlock.js +2153 -971
  31. package/dist/core/editing/referenceWrites.js +51 -0
  32. package/dist/core/editing/useLatestRecord.js +90 -0
  33. package/dist/core/hooks/useArtifactHost.js +139 -0
  34. package/dist/core/hooks/useFieldSelection.js +43 -18
  35. package/dist/core/hooks/useIsEditable.js +12 -10
  36. package/dist/core/hooks/useOverlayMessage.js +15 -19
  37. package/dist/core/lib/artifact.d.ts +21 -0
  38. package/dist/core/lib/artifact.js +154 -0
  39. package/dist/core/lib/artifactColors.js +123 -0
  40. package/dist/core/lib/artifactData.d.ts +1 -0
  41. package/dist/core/lib/artifactData.js +131 -0
  42. package/dist/core/lib/artifactHost.js +205 -0
  43. package/dist/core/lib/artifactRuntime.js +36 -0
  44. package/dist/core/lib/artifactTheme.js +57 -0
  45. package/dist/core/lib/contentType.d.ts +304 -103
  46. package/dist/core/lib/contentType.js +207 -168
  47. package/dist/core/lib/fieldTypes.js +4 -0
  48. package/dist/core/lib/iconTypes.d.ts +13 -0
  49. package/dist/core/lib/icons.d.ts +6 -0
  50. package/dist/core/lib/icons.js +126 -0
  51. package/dist/core/lib/imagePlaceholder.js +177 -0
  52. package/dist/core/lib/imageTransform.js +1 -1
  53. package/dist/core/lib/lexicalReact.d.ts +3 -1
  54. package/dist/core/lib/lexicalState.js +7 -7
  55. package/dist/core/lib/modifierFormats.js +1 -1
  56. package/dist/core/lib/previewPaused.js +9 -0
  57. package/dist/core/lib/recordScope.js +316 -0
  58. package/dist/core/lib/reference.d.ts +81 -0
  59. package/dist/core/lib/reference.js +29 -0
  60. package/dist/core/lib/textLinks.js +7 -5
  61. package/dist/core/lib/textStyles.d.ts +6 -8
  62. package/dist/core/lib/textStyles.js +5 -5
  63. package/dist/core/notFound.d.ts +7 -0
  64. package/dist/core/notFound.js +11 -0
  65. package/dist/core/pageDestinations.js +6 -3
  66. package/dist/core/recordItem.js +34 -0
  67. package/dist/core/requestContext.d.ts +26 -0
  68. package/dist/core/requestContext.js +20 -0
  69. package/dist/features/canvas/CamoxCanvas.js +1734 -0
  70. package/dist/features/canvas/CanvasBlockFrame.js +353 -0
  71. package/dist/features/canvas/CanvasBlockHeader.js +55 -0
  72. package/dist/features/canvas/CanvasLoadingScreen.js +35 -0
  73. package/dist/features/canvas/CanvasOverlays.js +254 -0
  74. package/dist/features/canvas/CanvasPageEdge.js +87 -0
  75. package/dist/features/canvas/CanvasPageFrame.js +335 -0
  76. package/dist/features/canvas/CanvasPageHeader.js +125 -0
  77. package/dist/features/canvas/CanvasPreviewPageSlot.js +103 -0
  78. package/dist/features/canvas/CanvasShelfMarker.js +255 -0
  79. package/dist/features/canvas/DerivedPagePathInput.js +238 -0
  80. package/dist/features/canvas/canvasCamera.js +229 -0
  81. package/dist/features/canvas/canvasFlight.js +104 -0
  82. package/dist/features/canvas/canvasFrameCapture.js +364 -0
  83. package/dist/features/canvas/canvasFrameDocument.js +317 -0
  84. package/dist/features/canvas/canvasFrameMode.js +53 -0
  85. package/dist/features/canvas/canvasInsertionSeams.js +44 -0
  86. package/dist/features/canvas/canvasItems.js +120 -0
  87. package/dist/features/canvas/canvasOverlayGeometry.js +240 -0
  88. package/dist/features/canvas/canvasPages.js +79 -0
  89. package/dist/features/canvas/canvasScreenSpace.js +26 -0
  90. package/dist/features/canvas/canvasSelection.js +18 -0
  91. package/dist/features/canvas/canvasStore.js +149 -0
  92. package/dist/features/canvas/canvasThumbnails.js +304 -0
  93. package/dist/features/canvas/canvasZoom.js +10 -0
  94. package/dist/features/canvas/sidebar/CanvasInspector.js +202 -0
  95. package/dist/features/canvas/sidebar/CanvasNavigator.js +226 -0
  96. package/dist/features/canvas/sidebar/CanvasSidebar.js +60 -0
  97. package/dist/features/canvas/sidebar/CanvasSidebarFrame.js +48 -0
  98. package/dist/features/canvas/sidebar/CanvasSidebarSkeleton.js +39 -0
  99. package/dist/features/canvas/sidebar/CatalogBlockInspector.js +189 -0
  100. package/dist/features/canvas/sidebar/CuratedPageInspector.js +69 -0
  101. package/dist/features/canvas/sidebar/DerivedPageInspector.js +37 -0
  102. package/dist/features/canvas/sidebar/LayoutPageBlocks.js +78 -0
  103. package/dist/features/canvas/sidebar/LayoutPageOverview.js +71 -0
  104. package/dist/features/canvas/sidebar/PageInspector.js +157 -0
  105. package/dist/features/canvas/sidebar/PageInspectorSkeleton.js +90 -0
  106. package/dist/features/canvas/sidebar/PageOverview.js +27 -0
  107. package/dist/features/canvas/sidebar/SingletonPageInspector.js +31 -0
  108. package/dist/features/canvas/useCanvasCamera.js +803 -0
  109. package/dist/features/canvas/useCanvasFrame.js +149 -0
  110. package/dist/features/canvas/useCanvasFrameInput.js +97 -0
  111. package/dist/features/canvas/useCanvasNearness.js +57 -0
  112. package/dist/features/canvas/useDiscoveredPreviewPaths.js +62 -0
  113. package/dist/features/content/CamoxContent.d.ts +2 -5
  114. package/dist/features/content/CamoxContent.js +174 -271
  115. package/dist/features/content/CollectionItemSheetContext.js +106 -0
  116. package/dist/features/content/ContentAssets.js +315 -0
  117. package/dist/features/content/ContentCollection.js +663 -0
  118. package/dist/features/content/collection-form.js +58 -0
  119. package/dist/features/content/components/AssetCard.js +101 -69
  120. package/dist/features/content/components/AssetCardSkeleton.js +4 -8
  121. package/dist/features/content/components/ContentSidebar.js +129 -18
  122. package/dist/features/content/components/ContentSidebarGroup.js +37 -0
  123. package/dist/features/content/components/DeleteCollectionItemButton.js +202 -0
  124. package/dist/features/content/components/MissingFromLocale.js +282 -0
  125. package/dist/features/content/components/UploadDropZone.js +27 -31
  126. package/dist/features/content/components/UploadProgressDrawer.js +90 -98
  127. package/dist/features/navigation/navigation.d.ts +66 -20
  128. package/dist/features/navigation/navigation.js +257 -90
  129. package/dist/features/og/defaultFonts.js +8 -8
  130. package/dist/features/og/geist-variable-ttf-base64.js +1 -1
  131. package/dist/features/og/imageResponse.d.ts +8 -0
  132. package/dist/features/og/imageResponse.js +26 -0
  133. package/dist/features/page/CuratedPageContent.js +167 -0
  134. package/dist/features/page/DerivedPageContent.js +26 -30
  135. package/dist/features/page/SharedLayoutContent.js +25 -27
  136. package/dist/features/preview/CamoxPreview.d.ts +23 -61
  137. package/dist/features/preview/CamoxPreview.js +811 -507
  138. package/dist/features/preview/EditablePageContent.js +1 -1
  139. package/dist/features/preview/EditablePageExperience.js +16 -22
  140. package/dist/features/preview/components/AddBlockDialog.js +270 -0
  141. package/dist/features/preview/components/AssetFieldEditor.js +173 -154
  142. package/dist/features/preview/components/AssetLightbox.js +194 -136
  143. package/dist/features/preview/components/AssetPickerModal.js +153 -170
  144. package/dist/features/preview/components/BlockActionsPopover.js +150 -149
  145. package/dist/features/preview/components/BlockErrorBoundary.js +8 -12
  146. package/dist/features/preview/components/BlockThumbnail.js +176 -100
  147. package/dist/features/preview/components/CanvasPreview.js +243 -0
  148. package/dist/features/preview/components/CreatePageModal.js +128 -137
  149. package/dist/features/preview/components/DebouncedFieldEditor.js +29 -33
  150. package/dist/features/preview/components/DerivedLayoutDialog.js +46 -29
  151. package/dist/features/preview/components/DrillRow.js +150 -0
  152. package/dist/features/preview/components/FieldOverlayStyles.js +33 -10
  153. package/dist/features/preview/components/FieldToolbar.js +166 -116
  154. package/dist/features/preview/components/Frame.js +108 -20
  155. package/dist/features/preview/components/IconFieldEditor.js +227 -0
  156. package/dist/features/preview/components/ItemFieldsEditor.js +238 -205
  157. package/dist/features/preview/components/LinkFieldEditor.js +135 -139
  158. package/dist/features/preview/components/Metadata.js +22 -30
  159. package/dist/features/preview/components/MobilePreviewDrawer.js +89 -108
  160. package/dist/features/preview/components/MultipleAssetFieldEditor.js +334 -246
  161. package/dist/features/preview/components/OverlayTracker.js +10 -42
  162. package/dist/features/preview/components/Overlays.js +81 -69
  163. package/dist/features/preview/components/PageInfo.js +1748 -0
  164. package/dist/features/preview/components/PageInfoSkeleton.js +51 -0
  165. package/dist/features/preview/components/PageLocationFieldset.js +112 -116
  166. package/dist/features/preview/components/PageNavigatorHeader.js +24 -0
  167. package/dist/features/preview/components/PageNicknameField.js +22 -26
  168. package/dist/features/preview/components/PagePicker.js +145 -147
  169. package/dist/features/preview/components/PageTree.js +525 -532
  170. package/dist/features/preview/components/PreviewActivation.js +28 -32
  171. package/dist/features/preview/components/PreviewPanel.js +620 -319
  172. package/dist/features/preview/components/PreviewToolbar.js +111 -340
  173. package/dist/features/preview/components/RecordCard.js +80 -0
  174. package/dist/features/preview/components/RecordCombobox.js +178 -0
  175. package/dist/features/preview/components/ReferenceFieldEditor.js +149 -0
  176. package/dist/features/preview/components/ReferenceListFieldEditor.js +432 -0
  177. package/dist/features/preview/components/RemovedBlockPlaceholder.js +95 -0
  178. package/dist/features/preview/components/RepeatableItemsList.js +125 -138
  179. package/dist/features/preview/components/SelectionEditor.js +993 -0
  180. package/dist/features/preview/components/ShikiMarkdown.js +14 -18
  181. package/dist/features/preview/components/SidebarSection.js +52 -64
  182. package/dist/features/preview/components/StudioEditingFallback.js +56 -0
  183. package/dist/features/preview/components/UnlinkAssetButton.js +104 -107
  184. package/dist/features/preview/components/blockGridNavigation.js +15 -0
  185. package/dist/features/preview/components/contentFieldSchema.js +8 -0
  186. package/dist/features/preview/components/useFieldWriter.js +200 -0
  187. package/dist/features/preview/components/useRecordView.js +383 -0
  188. package/dist/features/preview/components/useRepeatableItemActions.js +35 -37
  189. package/dist/features/preview/components/useUpdateBlockPosition.js +37 -37
  190. package/dist/features/preview/editingFrame.js +197 -0
  191. package/dist/features/preview/overlayHighlights.js +27 -0
  192. package/dist/features/preview/overlayMessages.js +72 -1
  193. package/dist/features/preview/pageRecord.js +189 -0
  194. package/dist/features/preview/previewConstants.js +6 -2
  195. package/dist/features/preview/previewPageFrame.js +95 -0
  196. package/dist/features/preview/previewPreparation.js +7 -0
  197. package/dist/features/preview/previewSelection.js +33 -59
  198. package/dist/features/preview/previewStore.js +225 -123
  199. package/dist/features/preview/referencePickerFocus.js +29 -0
  200. package/dist/features/preview/repeatableItemTargets.js +56 -0
  201. package/dist/features/preview/selectionReveal.js +21 -0
  202. package/dist/features/preview/usePreviewViewportActions.js +114 -0
  203. package/dist/features/preview/viewportContinuity.js +109 -0
  204. package/dist/features/provider/AuthenticatedCamoxProvider.js +69 -44
  205. package/dist/features/provider/CamoxProvider.d.ts +3 -6
  206. package/dist/features/provider/CamoxProvider.js +38 -50
  207. package/dist/features/provider/CoreCamoxProvider.js +71 -23
  208. package/dist/features/provider/LocalhostPreviewProvider.js +73 -73
  209. package/dist/features/provider/PreviewSignInPage.js +54 -0
  210. package/dist/features/provider/components/CamoxAppContext.js +11 -11
  211. package/dist/features/provider/components/CommandPalette.js +87 -143
  212. package/dist/features/provider/useAdminShortcuts.js +7 -11
  213. package/dist/features/routes/pageRuntime.d.ts +44 -4
  214. package/dist/features/routes/pageRuntime.js +244 -137
  215. package/dist/features/runtime/RuntimeChrome.js +117 -115
  216. package/dist/features/runtime/alternates.js +64 -0
  217. package/dist/features/runtime/analytics.d.ts +7 -0
  218. package/dist/features/runtime/analytics.js +66 -0
  219. package/dist/features/runtime/artifactSources.js +87 -0
  220. package/dist/features/runtime/editingFallback.js +20 -0
  221. package/dist/features/runtime/linkPrefetch.js +97 -0
  222. package/dist/features/runtime/livePages.js +62 -0
  223. package/dist/features/runtime/llmsTxt.js +40 -0
  224. package/dist/features/runtime/loopbackFetch.js +18 -0
  225. package/dist/features/runtime/navigationAccessibility.js +51 -0
  226. package/dist/features/runtime/navigationTarget.js +23 -2
  227. package/dist/features/runtime/pageApp.js +216 -141
  228. package/dist/features/runtime/pageBlockTypes.js +20 -0
  229. package/dist/features/runtime/pageClient.d.ts +2 -4
  230. package/dist/features/runtime/pageClient.js +18 -3
  231. package/dist/features/runtime/pageNavigation.js +254 -32
  232. package/dist/features/runtime/pageServer.d.ts +2 -4
  233. package/dist/features/runtime/pageServer.js +8 -1
  234. package/dist/features/runtime/pageViewport.js +7 -0
  235. package/dist/features/runtime/runtime.d.ts +60 -23
  236. package/dist/features/runtime/runtime.js +779 -166
  237. package/dist/features/runtime/runtimeChromeLoader.js +58 -0
  238. package/dist/features/runtime/runtimeRoutes.d.ts +19 -0
  239. package/dist/features/runtime/runtimeRoutes.js +25 -0
  240. package/dist/features/runtime/scrollRestoration.js +133 -0
  241. package/dist/features/runtime/studioApp.d.ts +4 -3
  242. package/dist/features/runtime/studioApp.js +5 -9
  243. package/dist/features/runtime/studioClient.d.ts +2 -4
  244. package/dist/features/runtime/studioClient.js +12 -3
  245. package/dist/features/runtime/studioServer.d.ts +2 -4
  246. package/dist/features/runtime/studioServer.js +6 -1
  247. package/dist/features/runtime/worker.d.ts +6 -0
  248. package/dist/features/runtime/worker.js +23 -0
  249. package/dist/features/runtime/workerRequest.js +44 -0
  250. package/dist/features/studio/CamoxStudio.d.ts +2 -6
  251. package/dist/features/studio/CamoxStudio.js +34 -49
  252. package/dist/features/studio/FollowAgentProvider.js +338 -0
  253. package/dist/features/studio/components/ChatSidebar.js +356 -0
  254. package/dist/features/studio/components/DraftsControl.js +676 -0
  255. package/dist/features/studio/components/FaviconDialog.js +318 -0
  256. package/dist/features/studio/components/LocalePicker.js +785 -0
  257. package/dist/features/studio/components/Navbar.js +123 -103
  258. package/dist/features/studio/components/ProjectMenu.js +239 -260
  259. package/dist/features/studio/components/RenameDraftDialog.js +206 -0
  260. package/dist/features/studio/components/ReviewDraftSheet.js +1472 -0
  261. package/dist/features/studio/components/ThreadComposer.js +157 -0
  262. package/dist/features/studio/components/ThreadMarkdown.js +113 -0
  263. package/dist/features/studio/components/ThreadMessages.js +270 -0
  264. package/dist/features/studio/components/UserButton.js +34 -23
  265. package/dist/features/studio/draftLabel.js +33 -0
  266. package/dist/features/studio/draftNotice.js +13 -0
  267. package/dist/features/studio/followAgent.js +250 -0
  268. package/dist/features/studio/followAgentContext.js +7 -0
  269. package/dist/features/studio/localeOptions.js +118 -0
  270. package/dist/features/studio/localeSwitch.js +19 -0
  271. package/dist/features/studio/routes.js +48 -1
  272. package/dist/features/studio/studioStore.js +64 -1
  273. package/dist/features/studio/useTheme.js +24 -27
  274. package/dist/features/vite/artifactRuntimeMinification.js +36 -0
  275. package/dist/features/vite/auth.js +1 -50
  276. package/dist/features/vite/blockBoilerplate.js +6 -5
  277. package/dist/features/vite/blockChunks.js +31 -0
  278. package/dist/features/vite/bundlerLogs.js +17 -0
  279. package/dist/features/vite/definitionsSync.js +158 -226
  280. package/dist/features/vite/devAuthentication.js +4 -16
  281. package/dist/features/vite/devSignIn.js +87 -0
  282. package/dist/features/vite/iconGeneration.js +16 -0
  283. package/dist/features/vite/layoutGeneration.js +11 -1
  284. package/dist/features/vite/publishSeededContent.js +30 -0
  285. package/dist/features/vite/routeGeneration.js +6 -7
  286. package/dist/features/vite/runtimeDev.js +80 -99
  287. package/dist/features/vite/vite.d.ts +53 -31
  288. package/dist/features/vite/vite.js +230 -116
  289. package/dist/features/vite/workerBuild.js +39 -0
  290. package/dist/hooks/use-debounced-field.js +116 -47
  291. package/dist/hooks/use-file-upload.js +114 -67
  292. package/dist/hooks/use-marquee-selection.js +32 -36
  293. package/dist/hooks/use-page-destinations.js +69 -37
  294. package/dist/lib/api-client-server.d.ts +5 -0
  295. package/dist/lib/api-client-server.js +10 -4
  296. package/dist/lib/api-client.d.ts +6 -0
  297. package/dist/lib/api-client.js +51 -16
  298. package/dist/lib/api-socket.js +17 -0
  299. package/dist/lib/auth-page-styles.js +39 -0
  300. package/dist/lib/auth.js +139 -60
  301. package/dist/lib/collection-cache.js +23 -0
  302. package/dist/lib/draft-scope.d.ts +4 -0
  303. package/dist/lib/draft-scope.js +222 -0
  304. package/dist/lib/html.js +12 -0
  305. package/dist/lib/link-pages.js +154 -0
  306. package/dist/lib/locale-path.d.ts +22 -0
  307. package/dist/lib/locale-path.js +57 -0
  308. package/dist/lib/normalized-data.js +252 -152
  309. package/dist/lib/preview-handoff.js +13 -0
  310. package/dist/lib/queries.d.ts +11 -0
  311. package/dist/lib/queries.js +71 -131
  312. package/dist/lib/studio-reads.d.ts +14 -0
  313. package/dist/lib/studio-reads.js +574 -0
  314. package/dist/lib/use-project-room.js +50 -47
  315. package/dist/lib/use-thread.js +310 -0
  316. package/dist/lib/utils.js +25 -29
  317. package/dist/lib/view-locale-context.js +22 -0
  318. package/dist/lib/view-locale.js +46 -0
  319. package/dist/package.js +5 -0
  320. package/dist/studio-overlays.css +41 -147
  321. package/dist/studio.css +2 -2
  322. package/package.json +70 -72
  323. package/skills/camox/SKILL.md +16 -5
  324. package/skills/camox/references/artifacts.md +179 -0
  325. package/skills/camox/references/block-definitions.md +98 -55
  326. package/skills/camox/references/cli-common.md +18 -6
  327. package/skills/camox/references/cli-content.md +92 -58
  328. package/skills/camox/references/cli-publishing.md +26 -0
  329. package/skills/camox/references/dom-integrations.md +27 -0
  330. package/skills/camox/references/field-styling.md +7 -7
  331. package/skills/camox/references/layout-definitions.md +16 -14
  332. package/skills/camox/references/localization.md +56 -0
  333. package/skills/camox/references/routed-layouts.md +133 -15
  334. package/skills/camox-expand/SKILL.md +69 -0
  335. package/skills/camox-expand/references/jobs.md +39 -0
  336. package/skills/camoxify/SKILL.md +38 -2
  337. package/dist/core/components/AddBlockControlBar.js +0 -78
  338. package/dist/core/hooks/useRequireDraftSource.js +0 -23
  339. package/dist/features/metadata/sitemap.d.ts +0 -8
  340. package/dist/features/metadata/sitemap.js +0 -17
  341. package/dist/features/og/imageResponse.node.d.ts +0 -12
  342. package/dist/features/og/imageResponse.node.js +0 -49
  343. package/dist/features/og/imageResponse.workerd.d.ts +0 -12
  344. package/dist/features/og/imageResponse.workerd.js +0 -40
  345. package/dist/features/page/PublishedPageContent.js +0 -205
  346. package/dist/features/page/PublishedPageExperience.js +0 -23
  347. package/dist/features/preview/DerivedPreview.js +0 -134
  348. package/dist/features/preview/commentsEnabled.js +0 -8
  349. package/dist/features/preview/components/AddBlockSidebar.js +0 -381
  350. package/dist/features/preview/components/AttachedComments.js +0 -194
  351. package/dist/features/preview/components/CommentHeader.js +0 -122
  352. package/dist/features/preview/components/CommentSidebar.js +0 -29
  353. package/dist/features/preview/components/CommentTargetQuote.js +0 -166
  354. package/dist/features/preview/components/DerivedLayoutSidebar.d.ts +0 -5
  355. package/dist/features/preview/components/DerivedLayoutSidebar.js +0 -179
  356. package/dist/features/preview/components/DerivedPageInfoSidebar.js +0 -69
  357. package/dist/features/preview/components/LeftSidebar.js +0 -68
  358. package/dist/features/preview/components/PageEditorSidebar.js +0 -563
  359. package/dist/features/preview/components/PageInfoSidebar.js +0 -1551
  360. package/dist/features/preview/components/PageNavigatorSidebar.js +0 -78
  361. package/dist/features/preview/components/PageStatusBadge.js +0 -97
  362. package/dist/features/preview/components/PeekedBlock.js +0 -217
  363. package/dist/features/preview/components/PreviewComments.js +0 -56
  364. package/dist/features/preview/components/PreviewToolbarSpacer.js +0 -43
  365. package/dist/features/preview/components/PublicationRow.js +0 -422
  366. package/dist/features/preview/components/PublishDialog.js +0 -194
  367. package/dist/features/preview/components/RightSidebar.js +0 -59
  368. package/dist/features/preview/previewCommentsStore.js +0 -115
  369. package/dist/features/preview/publication.js +0 -81
  370. package/dist/features/runtime/SharedChromeContext.js +0 -7
  371. package/dist/features/studio/components/EnvironmentMenu.js +0 -413
  372. package/dist/features/vite/appGeneration.js +0 -89
  373. package/dist/lib/view-queries.js +0 -28
  374. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/Matches.d.ts +0 -114
  375. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/RouterProvider.d.ts +0 -25
  376. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/config.d.ts +0 -1
  377. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/defer.d.ts +0 -1
  378. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/fileRoute.d.ts +0 -20
  379. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/global.d.ts +0 -8
  380. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/hash-scroll.d.ts +0 -1
  381. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/index.d.ts +0 -18
  382. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/link.d.ts +0 -161
  383. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/load-matches.d.ts +0 -6
  384. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/location.d.ts +0 -54
  385. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/lru-cache.d.ts +0 -8
  386. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/manifest.d.ts +0 -32
  387. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/new-process-route-tree.d.ts +0 -115
  388. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/not-found.d.ts +0 -1
  389. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/redirect.d.ts +0 -49
  390. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/rewrite.d.ts +0 -1
  391. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/root.d.ts +0 -6
  392. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/route.d.ts +0 -343
  393. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/routeInfo.d.ts +0 -48
  394. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/router.d.ts +0 -695
  395. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/scroll-restoration.d.ts +0 -1
  396. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/searchMiddleware.d.ts +0 -1
  397. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/searchParams.d.ts +0 -5
  398. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/ssr/serializer/RawStream.d.ts +0 -38
  399. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/ssr/serializer/seroval-plugins.d.ts +0 -1
  400. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/ssr/serializer/transformer.d.ts +0 -65
  401. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/stores.d.ts +0 -69
  402. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/structuralSharing.d.ts +0 -1
  403. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/typePrimitives.d.ts +0 -1
  404. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/useLoaderData.d.ts +0 -1
  405. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/useLoaderDeps.d.ts +0 -1
  406. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/useNavigate.d.ts +0 -10
  407. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/useParams.d.ts +0 -1
  408. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/useRouteContext.d.ts +0 -1
  409. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/useSearch.d.ts +0 -1
  410. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/utils.d.ts +0 -28
  411. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/validators.d.ts +0 -49
  412. package/skills/camox/references/cli-environments.md +0 -37
@@ -9,15 +9,11 @@ import { useSelector } from "@xstate/store-react";
9
9
  * Hook that listens for global keyboard shortcuts defined in the actionsStore
10
10
  */
11
11
  function useAdminShortcuts() {
12
- const $ = c(4);
13
- if ($[0] !== "bebc7f337697130a10955205113d613ef306f5f46f2a4a506e5e0a4faba82906") {
14
- for (let $i = 0; $i < 4; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
15
- $[0] = "bebc7f337697130a10955205113d613ef306f5f46f2a4a506e5e0a4faba82906";
16
- }
12
+ const $ = c(3);
17
13
  const actions = useSelector(actionsStore, _temp);
18
14
  let t0;
19
15
  let t1;
20
- if ($[1] !== actions) {
16
+ if ($[0] !== actions) {
21
17
  t0 = () => {
22
18
  const handleKeyDown = (event) => {
23
19
  const matchingAction = actions.find((action) => {
@@ -62,12 +58,12 @@ function useAdminShortcuts() {
62
58
  };
63
59
  };
64
60
  t1 = [actions];
65
- $[1] = actions;
66
- $[2] = t0;
67
- $[3] = t1;
61
+ $[0] = actions;
62
+ $[1] = t0;
63
+ $[2] = t1;
68
64
  } else {
69
- t0 = $[2];
70
- t1 = $[3];
65
+ t0 = $[1];
66
+ t1 = $[2];
71
67
  }
72
68
  React.useEffect(t0, t1);
73
69
  }
@@ -1,10 +1,50 @@
1
- import { QueryClient } from "@tanstack/react-query";
1
+ import "../../core/createLayout.js";
2
+ import "../../core/createApp.js";
3
+ import { LocaleView } from "../../lib/locale-path.js";
4
+ import "../../lib/studio-reads.js";
2
5
  import { Router } from "@camox/api-contract";
6
+ import { EndedDraft } from "@camox/api-contract/drafts";
7
+ import { QueryClient } from "@tanstack/react-query";
3
8
  import { RouterClient } from "@orpc/server";
4
-
5
9
  //#region src/features/routes/pageRuntime.d.ts
6
- declare function createServerApiClient(apiUrl: string, environmentName?: string, options?: {
10
+ type PageWithBlocks = Awaited<ReturnType<RouterClient<Router>["pages"]["getByPath"]>>;
11
+ export type MemberProject = Awaited<ReturnType<RouterClient<Router>["projects"]["getByUuid"]>>;
12
+ export type PageStructure = {
13
+ page: PageWithBlocks["page"];
14
+ layout: PageWithBlocks["layout"];
15
+ projectName: string;
16
+ project: PageWithBlocks["project"];
17
+ };
18
+ /**
19
+ * Why a member can't see the draft a URL names: it doesn't exist, it's someone else's
20
+ * development draft, or it was published or discarded (ADR 0011). In dev mode, the caller's
21
+ * own development draft doesn't exist until the dev server's first sync creates it.
22
+ */
23
+ export type DraftNotice = {
24
+ reason: "missing";
25
+ } | {
26
+ reason: "noDevelopmentDraft";
27
+ } | {
28
+ reason: "forbidden";
29
+ } | ({
30
+ reason: "ended";
31
+ } & EndedDraft);
32
+ /** Which draft a render read: the URL's, or Live when there was none or it couldn't be read. */
33
+ export interface DraftRead {
34
+ /** The draft the render read. Absent for Live. */
35
+ draftId?: string;
36
+ /**
37
+ * Present when the URL named a draft the render couldn't read, so it read Live instead. Only a
38
+ * member gets a notice explaining why; anyone else sees Live as if the URL named no draft.
39
+ */
40
+ refusedDraft?: {
41
+ notice: DraftNotice | null;
42
+ };
43
+ }
44
+ export declare function createServerApiClient(apiUrl: string, options?: {
7
45
  authCookieHeader?: string;
46
+ draftId?: string;
47
+ locale?: LocaleView;
8
48
  }): RouterClient<Router>;
9
49
  //#endregion
10
- export { createServerApiClient };
50
+ export {};
@@ -1,4 +1,8 @@
1
- import { queryKeys } from "@camox/api-contract/query-keys";
1
+ import { localeHeaders, localizedPath } from "../../lib/locale-path.js";
2
+ import { createDraftScope, withoutDraft } from "../../lib/draft-scope.js";
3
+ import { createStudioCache, reads } from "../../lib/studio-reads.js";
4
+ import { linkFallbackLocale } from "../../lib/link-pages.js";
5
+ import { DRAFT_ENDED_ERROR_CODE, DRAFT_HEADER, NO_DEVELOPMENT_DRAFT_ERROR } from "@camox/api-contract/drafts";
2
6
  import { createORPCClient } from "@orpc/client";
3
7
  import { RPCLink } from "@orpc/client/fetch";
4
8
 
@@ -17,9 +21,20 @@ function prefersMarkdown(accept) {
17
21
  }
18
22
  return markdownQ > 0 && markdownQ >= htmlQ;
19
23
  }
20
- function createServerApiClient(apiUrl, environmentName, options) {
21
- const headers = {};
22
- if (environmentName) headers["x-environment-name"] = environmentName;
24
+ /** Where a page's Markdown Representation lives: `/index.md` for the home page, `<path>.md` otherwise. */
25
+ function getMarkdownPath(pageFullPath) {
26
+ const path = pageFullPath.replace(/\/+$/, "");
27
+ return path ? `${path}.md` : "/index.md";
28
+ }
29
+ /** The page path a Markdown URL represents, or null when the URL isn't one. */
30
+ function parseMarkdownPath(pathname) {
31
+ if (!pathname.endsWith(".md")) return null;
32
+ if (pathname === "/index.md") return "/";
33
+ return pathname.slice(0, -3) || null;
34
+ }
35
+ function createServerApiClient(apiUrl, options) {
36
+ const headers = localeHeaders(options?.locale);
37
+ if (options?.draftId && options.authCookieHeader) headers[DRAFT_HEADER] = options.draftId;
23
38
  return createORPCClient(new RPCLink({
24
39
  url: `${apiUrl}/rpc`,
25
40
  headers,
@@ -49,163 +64,235 @@ function isNotFoundError(error) {
49
64
  const { code, status } = getErrorDetails(error);
50
65
  return code === "NOT_FOUND" || status === 404;
51
66
  }
52
- function visitForFileIds(value, ids) {
53
- if (value == null || typeof value !== "object") return;
54
- if ("_fileId" in value && typeof value._fileId === "number") {
55
- ids.add(value._fileId);
56
- return;
57
- }
58
- if (Array.isArray(value)) {
59
- for (const item of value) visitForFileIds(item, ids);
60
- return;
61
- }
62
- for (const child of Object.values(value)) visitForFileIds(child, ids);
63
- }
64
- function collectFileIdsFromContent(content, ids) {
65
- for (const value of Object.values(content)) visitForFileIds(value, ids);
66
- }
67
- function seedBlockCaches(queryClient, pageData, source = "draft") {
68
- const filesById = new Map(pageData.files.map((f) => [f.id, f]));
69
- for (const block of pageData.blocks) {
70
- const blockItems = pageData.repeatableItems.filter((i) => i.blockId === block.id);
71
- const fileIds = /* @__PURE__ */ new Set();
72
- collectFileIdsFromContent(block.content, fileIds);
73
- for (const item of blockItems) collectFileIdsFromContent(item.content, fileIds);
74
- const blockFiles = [...fileIds].map((id) => filesById.get(id)).filter((f) => f != null);
75
- queryClient.setQueryData(queryKeys.blocks.get(block.id, source), {
76
- block,
77
- repeatableItems: blockItems,
78
- files: blockFiles
79
- });
80
- for (const file of blockFiles) queryClient.setQueryData(queryKeys.files.get(file.id), file);
67
+ /**
68
+ * The notice for an API error refusing the draft a member named, or undefined when the error
69
+ * isn't about the draft.
70
+ */
71
+ function draftRefusalNotice(error, draftId) {
72
+ const { code, status } = getErrorDetails(error);
73
+ const data = error?.data;
74
+ if (code === DRAFT_ENDED_ERROR_CODE && data) return {
75
+ reason: "ended",
76
+ ...data
77
+ };
78
+ if (code === NO_DEVELOPMENT_DRAFT_ERROR) return { reason: "noDevelopmentDraft" };
79
+ if (isNotFoundError(error) && data?.draftId === draftId) return { reason: "missing" };
80
+ if (code === "FORBIDDEN" || status === 403) return { reason: "forbidden" };
81
+ if (code === "UNAUTHORIZED" || status === 401) return null;
82
+ }
83
+ /**
84
+ * Reads with the draft a URL names, or Live (ADR 0011). Only a member's request names the draft;
85
+ * anyone else reads Live. When the API refuses the draft, the same response reads Live instead.
86
+ */
87
+ async function readDraftOrLive(draftId, member, read) {
88
+ if (!draftId) return { value: await read(void 0) };
89
+ if (!member) return {
90
+ value: await read(void 0),
91
+ refusedDraft: { notice: null }
92
+ };
93
+ try {
94
+ return {
95
+ value: await read(draftId),
96
+ draftId
97
+ };
98
+ } catch (error) {
99
+ const notice = draftRefusalNotice(error, draftId);
100
+ if (notice === void 0) throw error;
101
+ return {
102
+ value: await read(void 0),
103
+ refusedDraft: { notice }
104
+ };
81
105
  }
82
106
  }
83
- async function loadCamoxPage({ apiUrl, authCookieHeader, environmentName, pathname, projectSlug, queryClient, source }) {
84
- const serverApi = createServerApiClient(apiUrl, environmentName, { authCookieHeader });
85
- return queryClient.ensureQueryData({
86
- queryKey: queryKeys.pages.getByPath(pathname, source),
87
- queryFn: async () => {
88
- const [data, pagesList] = await Promise.all([serverApi.pages.getByPath({
89
- path: pathname,
90
- projectSlug,
91
- source
92
- }), serverApi.pages.listBySlug({ projectSlug }).catch(() => null)]);
93
- seedBlockCaches(queryClient, data, source);
94
- queryClient.setQueryData(queryKeys.pages.getByPath(pathname, source), {
95
- page: data.page,
96
- layout: data.layout,
97
- projectName: data.projectName,
98
- project: data.project
99
- });
100
- if (source === "live") {
101
- seedBlockCaches(queryClient, data, "draft");
102
- queryClient.setQueryData(queryKeys.pages.getByPath(pathname, "draft"), {
103
- page: data.page,
104
- layout: data.layout,
105
- projectName: data.projectName,
106
- project: data.project
107
- });
108
- }
109
- if (pagesList) queryClient.setQueryData(queryKeys.pages.list, pagesList);
110
- return {
111
- page: data.page,
112
- layout: data.layout,
113
- projectName: data.projectName,
114
- project: data.project
115
- };
116
- },
117
- staleTime: Infinity
107
+ /** The URL a render shows: without the draft param when the draft couldn't be read. */
108
+ function renderedHref(url, read) {
109
+ return read.refusedDraft ? withoutDraft(url) : url;
110
+ }
111
+ async function loadCamoxPage({ apiUrl, authCookieHeader, draftId, locale, pathname, projectUuid, queryClient }) {
112
+ const studioCache = createServerStudioCache(queryClient, {
113
+ apiUrl,
114
+ authCookieHeader,
115
+ locale
118
116
  });
117
+ const inDraft = { in: draftId && authCookieHeader ? draftId : null };
118
+ const fallback = locale && linkFallbackLocale(locale);
119
+ const [page] = await Promise.all([
120
+ studioCache.ensure(reads.pageStructure({
121
+ path: pathname,
122
+ projectUuid
123
+ }), inDraft),
124
+ studioCache.ensure(reads.pageList({ projectUuid }), inDraft).catch(() => null),
125
+ fallback && studioCache.ensure(reads.pageList({ projectUuid }), {
126
+ ...inDraft,
127
+ locale: fallback
128
+ }).catch(() => null)
129
+ ]);
130
+ return page;
119
131
  }
120
- async function loadLivePage(options) {
121
- return loadCamoxPage({
122
- ...options,
123
- source: "live"
132
+ /**
133
+ * The studio's reads for one server request, read with its session. Each operation names the
134
+ * draft it acts in, once the request settled which one it reads.
135
+ */
136
+ function createServerStudioCache(queryClient, { apiUrl, authCookieHeader, locale }) {
137
+ return createStudioCache({
138
+ queryClient,
139
+ scope: createDraftScope({ queryClient }),
140
+ api: (draft, inLocale) => createServerApiClient(apiUrl, {
141
+ authCookieHeader,
142
+ draftId: draft ?? void 0,
143
+ locale: inLocale
144
+ }),
145
+ ...locale && { locale: () => locale }
124
146
  });
125
147
  }
148
+ /**
149
+ * The locales of the scope a request reads: the URL's draft's for a session naming one, else
150
+ * Live's. A draft the API refuses reads Live's, as the request's other reads then do.
151
+ */
152
+ async function readScopeLocales({ apiUrl, authCookieHeader, draftId, projectUuid }) {
153
+ const { value } = await readDraftOrLive(draftId, !!authCookieHeader, (readDraftId) => createServerApiClient(apiUrl, {
154
+ authCookieHeader: readDraftId ? authCookieHeader : void 0,
155
+ draftId: readDraftId
156
+ }).locales.list({ projectUuid }));
157
+ return value;
158
+ }
159
+ /**
160
+ * The project, when the auth cookie is a valid session of one of its members. A successful
161
+ * protected project lookup validates both session and project access: cookie presence alone
162
+ * is not proof of authentication. An invalid session asks for the cookie to be cleared.
163
+ */
164
+ async function resolveMemberProject({ apiUrl, authCookieHeader, projectUuid }) {
165
+ if (!authCookieHeader) return { clearAuthCookie: false };
166
+ try {
167
+ return {
168
+ project: await createServerApiClient(apiUrl, { authCookieHeader }).projects.getByUuid({ projectUuid }),
169
+ clearAuthCookie: false
170
+ };
171
+ } catch (error) {
172
+ if (!isAuthSessionError(error)) throw error;
173
+ return { clearAuthCookie: true };
174
+ }
175
+ }
176
+ /**
177
+ * The project's favicon, which falls back to the Camox mark when none was uploaded. Pass
178
+ * `placeholder: false` to get a 404 instead, to learn whether there is one.
179
+ */
180
+ function buildFaviconUrl(apiUrl, project, { placeholder = true } = {}) {
181
+ const url = `${apiUrl}/favicons/${project.id}?v=${project.updatedAt}`;
182
+ return placeholder ? `${url}&placeholder=camox` : url;
183
+ }
184
+ /** The Camox mark a project without a favicon shows. */
185
+ function buildFaviconPlaceholderUrl(apiUrl) {
186
+ return `${apiUrl}/favicons/placeholder`;
187
+ }
126
188
  function buildCamoxPageLoaderData(apiUrl, page, origin) {
127
189
  return {
128
190
  page,
129
191
  origin,
130
- faviconUrl: `${apiUrl}/favicons/${page.project.id}?v=${page.project.updatedAt}`
192
+ faviconUrl: buildFaviconUrl(apiUrl, page.project)
131
193
  };
132
194
  }
133
- async function loadCamoxPageForRequest({ apiUrl, authCookieHeader, environmentName, origin, pathname, projectSlug, queryClient }) {
134
- const loadOptions = {
195
+ async function loadCamoxPageForRequest({ apiUrl, authCookieHeader, draftId, locale, origin, pathname, projectUuid, queryClient }) {
196
+ const member = await resolveMemberProject({
135
197
  apiUrl,
136
- environmentName,
198
+ authCookieHeader,
199
+ projectUuid
200
+ });
201
+ if (member.clearAuthCookie) console.warn("[camox] Ignoring stale camox_auth_cookie.");
202
+ const { value: page, ...read } = await readDraftOrLive(draftId, !!member.project, (readDraftId) => loadCamoxPage({
203
+ apiUrl,
204
+ authCookieHeader: member.project ? authCookieHeader : void 0,
205
+ draftId: readDraftId,
206
+ locale,
137
207
  pathname,
138
- projectSlug,
208
+ projectUuid,
139
209
  queryClient
210
+ }));
211
+ return {
212
+ ...read,
213
+ data: buildCamoxPageLoaderData(apiUrl, page, origin),
214
+ project: member.project,
215
+ shouldClearAuthCookie: member.clearAuthCookie
140
216
  };
141
- if (!authCookieHeader) return {
142
- data: buildCamoxPageLoaderData(apiUrl, await loadLivePage(loadOptions), origin),
143
- shouldClearAuthCookie: false,
144
- source: "live"
145
- };
146
- try {
147
- return {
148
- data: buildCamoxPageLoaderData(apiUrl, await loadCamoxPage({
149
- ...loadOptions,
150
- authCookieHeader,
151
- source: "draft"
152
- }), origin),
153
- shouldClearAuthCookie: false,
154
- source: "draft"
155
- };
156
- } catch (error) {
157
- if (!isAuthSessionError(error)) throw error;
158
- console.warn("[camox] Ignoring stale camox_auth_cookie and retrying published page load.");
159
- return {
160
- data: buildCamoxPageLoaderData(apiUrl, await loadLivePage(loadOptions), origin),
161
- shouldClearAuthCookie: true,
162
- source: "live"
163
- };
164
- }
165
217
  }
166
- async function createMarkdownResponse({ apiUrl, environmentName, pathname, projectSlug, request }) {
167
- if (!prefersMarkdown(request.headers.get("Accept") ?? "")) return null;
168
- const api = createServerApiClient(apiUrl, environmentName);
218
+ async function createMarkdownResponse({ apiUrl, camoxApp, locale, pathname, projectUuid, request, url, onNotFound }) {
219
+ const api = createServerApiClient(apiUrl, { locale });
169
220
  const requestPathname = pathname ?? new URL(request.url).pathname;
170
221
  try {
171
222
  const page = await api.pages.getByPath({
172
223
  path: requestPathname,
173
- projectSlug,
174
- source: "live"
224
+ projectUuid
175
225
  });
176
226
  const { markdown } = await api.blocks.getPageMarkdown({ pageId: page.page.id });
177
227
  if (!markdown) return null;
178
- return new Response(markdown, { headers: { "Content-Type": "text/markdown; charset=utf-8" } });
179
- } catch {
228
+ const meta = buildPageMeta(curatedPageMetaInput(camoxApp, page, locale));
229
+ return new Response(withFrontMatter(markdown, {
230
+ ...meta,
231
+ url
232
+ }), { headers: { "Content-Type": "text/markdown; charset=utf-8" } });
233
+ } catch (error) {
234
+ if (onNotFound && isNotFoundError(error)) return onNotFound();
180
235
  return null;
181
236
  }
182
237
  }
183
- function buildCamoxPageHead(camoxApp, loaderData) {
184
- if (!loaderData) return {};
185
- const { page, origin, faviconUrl } = loaderData;
186
- const pageMetaTitle = page.page.metaTitle ?? page.page.pathSegment;
187
- const meta = [];
188
- let title = pageMetaTitle;
189
- if (page.layout) {
190
- const layout = camoxApp.getLayoutById(page.layout.layoutId);
191
- if (layout) title = layout._internal.buildMetaTitle({
192
- pageMetaTitle,
193
- projectName: page.projectName,
194
- pageFullPath: page.page.fullPath
195
- });
196
- }
197
- meta.push({ title });
198
- if (page.page.metaDescription) meta.push({
238
+ /** A page's title and description, built by its layout's callbacks. */
239
+ function buildPageMeta(input) {
240
+ const context = {
241
+ data: input.data,
242
+ ...input.item && { item: input.item },
243
+ params: input.params,
244
+ projectName: input.projectName,
245
+ pageFullPath: input.pageFullPath
246
+ };
247
+ const title = input.layout?.buildMetaTitle({
248
+ ...context,
249
+ pageMetaTitle: input.pageMetaTitle
250
+ }) ?? input.pageMetaTitle;
251
+ const description = input.layout?.buildMetaDescription ? input.layout.buildMetaDescription({
252
+ ...context,
253
+ pageMetaDescription: input.pageMetaDescription
254
+ }) : input.pageMetaDescription;
255
+ return {
256
+ title,
257
+ ...description && { description }
258
+ };
259
+ }
260
+ /** A curated page's meta input: its editor metadata and its layout. */
261
+ /** A curated page's meta input. Its path keeps the prefix of the page's `locale`. */
262
+ function curatedPageMetaInput(camoxApp, page, locale) {
263
+ return {
264
+ layout: page.layout ? camoxApp?.getLayoutById(page.layout.layoutId)?._internal : void 0,
265
+ pageMetaTitle: page.page.metaTitle ?? page.page.pathSegment,
266
+ pageMetaDescription: page.page.metaDescription ?? void 0,
267
+ data: void 0,
268
+ params: {},
269
+ projectName: page.projectName,
270
+ pageFullPath: locale ? localizedPath(page.page.fullPath, locale) : page.page.fullPath
271
+ };
272
+ }
273
+ /** A Markdown Representation, opened by YAML front matter stating the page's title, description and URL. */
274
+ function withFrontMatter(markdown, meta) {
275
+ return `---\n${Object.entries({
276
+ title: meta.title,
277
+ description: meta.description,
278
+ url: meta.url
279
+ }).filter((field) => !!field[1]).map(([key, value]) => `${key}: ${JSON.stringify(value)}`).join("\n")}\n---\n\n${markdown}`;
280
+ }
281
+ /** The head every page gets, whatever its layout kind. */
282
+ function buildPageHead(input) {
283
+ const { title, description } = buildPageMeta(input);
284
+ const meta = [{ title }];
285
+ if (description) meta.push({
199
286
  name: "description",
200
- content: page.page.metaDescription
287
+ content: description
201
288
  });
202
289
  const ogImageParams = new URLSearchParams({
203
- ...page.layout && { layoutId: page.layout.layoutId },
204
- title: pageMetaTitle,
205
- ...page.page.metaDescription && { description: page.page.metaDescription },
206
- ...page.projectName && { projectName: page.projectName }
290
+ ...input.layout && { layoutId: input.layout.id },
291
+ title: input.ogImageTitle ?? title,
292
+ ...description && { description },
293
+ ...input.projectName && { projectName: input.projectName }
207
294
  });
208
- const ogImageUrl = page.page.customOgImageUrl ?? `${origin}/og?${ogImageParams.toString()}`;
295
+ const ogImageUrl = input.customOgImageUrl ?? `${input.origin}/og?${ogImageParams.toString()}`;
209
296
  meta.push({
210
297
  property: "og:title",
211
298
  content: title
@@ -219,18 +306,38 @@ function buildCamoxPageHead(camoxApp, loaderData) {
219
306
  property: "og:image:height",
220
307
  content: "630"
221
308
  });
222
- if (page.page.metaDescription) meta.push({
309
+ if (description) meta.push({
223
310
  property: "og:description",
224
- content: page.page.metaDescription
311
+ content: description
312
+ });
313
+ const links = [{
314
+ rel: "icon",
315
+ href: input.faviconUrl
316
+ }];
317
+ if (input.hasMarkdown) links.push({
318
+ rel: "alternate",
319
+ type: "text/markdown",
320
+ href: `${input.origin}${getMarkdownPath(input.pageFullPath)}`
225
321
  });
226
322
  return {
227
323
  meta,
228
- links: [{
229
- rel: "icon",
230
- href: faviconUrl
231
- }]
324
+ links
232
325
  };
233
326
  }
327
+ /** A curated page's head. Its paths keep the prefix of the page's `locale`. */
328
+ function buildCamoxPageHead(camoxApp, loaderData, locale) {
329
+ if (!loaderData) return {};
330
+ const { page, origin, faviconUrl } = loaderData;
331
+ const metaInput = curatedPageMetaInput(camoxApp, page, locale);
332
+ return buildPageHead({
333
+ ...metaInput,
334
+ ogImageTitle: metaInput.pageMetaTitle,
335
+ customOgImageUrl: page.page.customOgImageUrl,
336
+ origin,
337
+ faviconUrl,
338
+ hasMarkdown: true
339
+ });
340
+ }
234
341
 
235
342
  //#endregion
236
- export { buildCamoxPageHead, createMarkdownResponse, createServerApiClient, isAuthSessionError, isNotFoundError, loadCamoxPageForRequest, seedBlockCaches };
343
+ export { buildCamoxPageHead, buildCamoxPageLoaderData, buildFaviconPlaceholderUrl, buildFaviconUrl, buildPageHead, buildPageMeta, createMarkdownResponse, createServerApiClient, createServerStudioCache, getMarkdownPath, isAuthSessionError, isNotFoundError, loadCamoxPage, loadCamoxPageForRequest, parseMarkdownPath, parseQuality, prefersMarkdown, readDraftOrLive, readScopeLocales, renderedHref, resolveMemberProject, withFrontMatter };