camox 0.52.2 → 0.53.1

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 (43) hide show
  1. package/dist/core/editing/createEditableBlock.js +1 -1
  2. package/dist/features/canvas/CamoxCanvas.js +103 -83
  3. package/dist/features/canvas/CanvasPageFrame.js +1 -1
  4. package/dist/features/canvas/CanvasPreviewPageSlot.js +1 -1
  5. package/dist/features/canvas/canvasCamera.js +3 -3
  6. package/dist/features/canvas/sidebar/CanvasInspector.js +4 -159
  7. package/dist/features/canvas/sidebar/CanvasNavigator.js +41 -85
  8. package/dist/features/canvas/sidebar/CanvasSidebar.js +54 -32
  9. package/dist/features/canvas/sidebar/CanvasSidebarFrame.js +4 -3
  10. package/dist/features/canvas/sidebar/CanvasSidebarSkeleton.js +14 -6
  11. package/dist/features/canvas/sidebar/CanvasViewHeader.js +50 -0
  12. package/dist/features/canvas/sidebar/DerivedPageInspector.js +30 -18
  13. package/dist/features/canvas/sidebar/LayoutPageOverview.js +28 -11
  14. package/dist/features/canvas/sidebar/LayoutPageSeo.js +356 -0
  15. package/dist/features/canvas/sidebar/PageInspector.js +118 -80
  16. package/dist/features/canvas/sidebar/PageOverview.js +6 -1
  17. package/dist/features/canvas/sidebar/SingletonPageInspector.js +22 -14
  18. package/dist/features/canvas/useCanvasCamera.js +36 -39
  19. package/dist/features/preview/CamoxPreview.js +1 -1
  20. package/dist/features/preview/components/BlockActionsPopover.js +1 -1
  21. package/dist/features/preview/components/BlockThumbnail.js +1 -1
  22. package/dist/features/preview/components/CanvasPreview.js +1 -1
  23. package/dist/features/preview/components/CreatePageModal.js +1 -1
  24. package/dist/features/preview/components/ItemFieldsEditor.js +1 -1
  25. package/dist/features/preview/components/OverlayTracker.js +1 -1
  26. package/dist/features/preview/components/PageInfo.js +345 -228
  27. package/dist/features/preview/components/PageTree.js +1 -1
  28. package/dist/features/preview/components/PreviewPanel.js +1 -1
  29. package/dist/features/preview/components/PreviewToolbar.js +2 -2
  30. package/dist/features/preview/components/RepeatableItemsList.js +1 -1
  31. package/dist/features/preview/components/SelectionEditor.js +645 -655
  32. package/dist/features/preview/components/SidebarStack.js +553 -0
  33. package/dist/features/preview/components/StudioEditingFallback.js +2 -2
  34. package/dist/features/renderer/RendererFrames.js +34 -27
  35. package/dist/features/runtime/RuntimeChrome.js +1 -1
  36. package/dist/features/runtime/runtime.js +84 -26
  37. package/dist/features/studio/components/ChatSidebar.js +27 -19
  38. package/dist/features/studio/components/Navbar.js +1 -1
  39. package/dist/features/studio/components/UserButton.js +1 -1
  40. package/dist/lib/studio-reads.js +18 -0
  41. package/dist/package.js +1 -1
  42. package/dist/studio.css +1 -1
  43. package/package.json +4 -4
@@ -933,17 +933,41 @@ async function loadLayoutResult(app, match, context, locale) {
933
933
  }
934
934
  /**
935
935
  * The Markdown of a singleton or derived page: front matter, its before blocks, the layout's
936
- * toMarkdown output, then its after blocks. Without toMarkdown, the page is HTML only.
936
+ * toMarkdown output, then its after blocks. Null without toMarkdown: the page is then HTML only.
937
+ * The layout's blocks settle which draft it reads, as they do for the page's HTML.
937
938
  */
938
- async function createLayoutMarkdownResponse(options, match, locale, page) {
939
+ async function buildLayoutMarkdown(options, match, locale, page, reader = { member: false }) {
939
940
  const { toMarkdown, id } = match.layout._internal;
940
941
  const { apiUrl, projectUuid } = options;
941
942
  if (!toMarkdown || !apiUrl || !projectUuid) return null;
942
- const api = createServerApiClient(apiUrl, { locale });
943
+ const authCookieHeader = reader.member ? reader.authCookieHeader : void 0;
944
+ const api = (draftId) => createServerApiClient(apiUrl, {
945
+ authCookieHeader,
946
+ draftId,
947
+ locale
948
+ });
949
+ const { value: slots, draftId } = await readDraftOrLive(reader.requestedDraft, reader.member, (draftId) => api(draftId).blocks.getLayoutMarkdown({
950
+ projectUuid,
951
+ layoutId: id
952
+ })).catch((error) => {
953
+ if (!isNotFoundError(error)) throw error;
954
+ return {
955
+ value: {
956
+ before: "",
957
+ after: "",
958
+ projectName: ""
959
+ },
960
+ draftId: reader.member ? reader.requestedDraft : void 0
961
+ };
962
+ });
943
963
  const app = await options.getCamoxApp?.();
944
964
  /** The layout's own Markdown, between its before and after blocks, and what built it. */
945
965
  const layoutMarkdown = async () => {
946
- const result = await loadLayoutResult(app, match, createLayoutRequestContext(options, "live", { locale }), locale);
966
+ const result = await loadLayoutResult(app, match, createLayoutRequestContext(options, reader.member ? "draft" : "live", {
967
+ authCookieHeader,
968
+ draftId,
969
+ locale
970
+ }), locale);
947
971
  const record = asCollectionItem(result);
948
972
  const collection = record && app?.getCollectionById(record.collectionId);
949
973
  if (!record || !collection) return {
@@ -960,7 +984,7 @@ async function createLayoutMarkdownResponse(options, match, locale, page) {
960
984
  item
961
985
  }));
962
986
  return {
963
- body: [await api.collectionDefinitions.recordMarkdown({
987
+ body: [await api(draftId).collectionDefinitions.recordMarkdown({
964
988
  projectUuid,
965
989
  collectionId: record.collectionId,
966
990
  id: data.id,
@@ -970,24 +994,7 @@ async function createLayoutMarkdownResponse(options, match, locale, page) {
970
994
  record: recordPageValues(collection, record)
971
995
  };
972
996
  };
973
- let rendered;
974
- try {
975
- rendered = await layoutMarkdown();
976
- } catch (error) {
977
- if (isNotFoundError(error)) return new Response("Page not found", { status: 404 });
978
- throw error;
979
- }
980
- const slots = await api.blocks.getLayoutMarkdown({
981
- projectUuid,
982
- layoutId: id
983
- }).catch((error) => {
984
- if (isNotFoundError(error)) return {
985
- before: "",
986
- after: "",
987
- projectName: ""
988
- };
989
- throw error;
990
- });
997
+ const rendered = await layoutMarkdown();
991
998
  const meta = buildPageMeta({
992
999
  layout: match.layout._internal,
993
1000
  context: buildLayoutContext(match.layout._internal, {
@@ -1004,10 +1011,59 @@ async function createLayoutMarkdownResponse(options, match, locale, page) {
1004
1011
  ...rendered.body,
1005
1012
  slots.after
1006
1013
  ].filter(Boolean).join("\n\n");
1007
- return new Response(withFrontMatter(markdown, {
1014
+ return withFrontMatter(markdown, {
1008
1015
  ...meta,
1009
1016
  url: page.url
1010
- }), { headers: { "Content-Type": "text/markdown; charset=utf-8" } });
1017
+ });
1018
+ }
1019
+ /**
1020
+ * A singleton or derived page's public Markdown Representation. Markdown is a public output: it
1021
+ * reads published records and blocks whoever asks.
1022
+ */
1023
+ async function createLayoutMarkdownResponse(options, match, locale, page) {
1024
+ let markdown;
1025
+ try {
1026
+ markdown = await buildLayoutMarkdown(options, match, locale, page);
1027
+ } catch (error) {
1028
+ if (isNotFoundError(error)) return new Response("Page not found", { status: 404 });
1029
+ throw error;
1030
+ }
1031
+ if (markdown === null) return null;
1032
+ return new Response(markdown, { headers: { "Content-Type": "text/markdown; charset=utf-8" } });
1033
+ }
1034
+ /**
1035
+ * A singleton or derived page's Markdown Representation as JSON (`/_camox/data?markdown`), read
1036
+ * like the page's data: in the draft the URL names, for a member. The studio shows it, while the
1037
+ * page's `.md` URL always reads Live. `markdown` is null when the layout declares none.
1038
+ */
1039
+ async function createLayoutMarkdownDataResponse(options, request, pathname) {
1040
+ const located = await locateRequest(request, options, pathname);
1041
+ const app = await options.getCamoxApp?.();
1042
+ const match = app && matchDerivedLayout(app.getLayouts(), located.path);
1043
+ if (!match || matchLocalizedRoute(located.path)?.kind !== "page") return new Response("Not found", { status: 404 });
1044
+ const { project, clearAuthCookie } = await resolveRequestMember(request, options);
1045
+ const headers = {
1046
+ ...isPrivateRender(request, options) ? { "Cache-Control": "private, no-store" } : {},
1047
+ Vary: "Cookie",
1048
+ ...clearAuthCookie ? { "Set-Cookie": buildClearServerAuthCookieHeader() } : {}
1049
+ };
1050
+ try {
1051
+ const markdown = await buildLayoutMarkdown(options, match, located.locale, {
1052
+ pathname,
1053
+ url: absoluteUrl(request, options)(pathname)
1054
+ }, {
1055
+ member: project !== void 0,
1056
+ authCookieHeader: getServerAuthCookieHeader(request.headers),
1057
+ requestedDraft: getRequestDraftId(request, options)
1058
+ });
1059
+ return Response.json({ markdown }, { headers });
1060
+ } catch (error) {
1061
+ if (isNotFoundError(error)) return new Response("Not found", {
1062
+ status: 404,
1063
+ headers
1064
+ });
1065
+ throw error;
1066
+ }
1011
1067
  }
1012
1068
  async function createDerivedResponse(options, pathname, located, request, { dataOnly = false, singletonOnly = false } = {}) {
1013
1069
  const app = await options.getCamoxApp?.();
@@ -1337,8 +1393,10 @@ async function handleCamoxRequest(request, options = {}) {
1337
1393
  if (match.kind === "llms-txt") return createLlmsTxtResponse(request, options);
1338
1394
  if (match.kind === "routes") return createRoutesResponse(request, options);
1339
1395
  if (match.kind === "data") {
1340
- const targetPathname = normalizePagePath(new URL(request.url).searchParams.get("path"));
1396
+ const { searchParams } = new URL(request.url);
1397
+ const targetPathname = normalizePagePath(searchParams.get("path"));
1341
1398
  if (matchRuntimeOwnedRoute(targetPathname)) return new Response("Not found", { status: 404 });
1399
+ if (searchParams.has("markdown")) return createLayoutMarkdownDataResponse(options, request, targetPathname);
1342
1400
  return respondInLocale(options, request, targetPathname, { dataOnly: true });
1343
1401
  }
1344
1402
  if (isPreviewHandoff(request, options) && match.kind === "page") return createPreviewHandoffResponse({
@@ -2,6 +2,8 @@ import { AuthContext } from "../../../lib/auth.js";
2
2
  import { useCurrentDraftId, useDraftScope } from "../../../lib/draft-scope.js";
3
3
  import { useNavigate } from "../../navigation/navigation.js";
4
4
  import { reads, useReadQuery } from "../../../lib/studio-reads.js";
5
+ import { cn } from "../../../lib/utils.js";
6
+ import { BOTTOM_CARD_EDGES, CARD_BODY_EDGES, SIDEBAR_GUTTER } from "../../preview/components/SidebarStack.js";
5
7
  import { draftLabel } from "../draftLabel.js";
6
8
  import { FollowAgentContext } from "../followAgentContext.js";
7
9
  import { useThread } from "../../../lib/use-thread.js";
@@ -20,45 +22,51 @@ import { EMPTY_THREAD_VIEW } from "@camox/api-contract/threads";
20
22
  * When the Live thread starts a draft, the studio enters it with the thread.
21
23
  */
22
24
  function ChatSidebar(t0) {
23
- const $ = c(5);
25
+ const $ = c(6);
24
26
  const { hidden: t1 } = t0;
25
27
  const hidden = t1 === void 0 ? false : t1;
26
28
  let t2;
27
- if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
28
- t2 = { width: 265 };
29
- $[0] = t2;
30
- } else t2 = $[0];
31
29
  let t3;
32
30
  let t4;
33
- if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
34
- t3 = /* @__PURE__ */ jsxs("header", {
35
- className: "border-border box-content flex h-8 min-w-0 items-center gap-2 border-b px-2 py-2",
31
+ let t5;
32
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
33
+ t2 = cn("absolute inset-y-0 right-0 z-10 flex flex-col py-2 max-md:hidden", SIDEBAR_GUTTER);
34
+ t3 = { width: 265 };
35
+ t4 = /* @__PURE__ */ jsxs("header", {
36
+ className: cn("bg-background flex h-11 min-w-0 shrink-0 items-center justify-center gap-2 px-3", BOTTOM_CARD_EDGES),
36
37
  children: [/* @__PURE__ */ jsx(CamoxMark, {}), /* @__PURE__ */ jsx("h2", {
37
38
  className: "truncate text-sm font-medium",
38
39
  children: "Chat"
39
40
  })]
40
41
  });
41
- t4 = /* @__PURE__ */ jsx(CurrentThread, {});
42
+ t5 = /* @__PURE__ */ jsx("div", {
43
+ className: cn("bg-background flex min-h-0 flex-1 flex-col", CARD_BODY_EDGES),
44
+ children: /* @__PURE__ */ jsx(CurrentThread, {})
45
+ });
46
+ $[0] = t2;
42
47
  $[1] = t3;
43
48
  $[2] = t4;
49
+ $[3] = t5;
44
50
  } else {
51
+ t2 = $[0];
45
52
  t3 = $[1];
46
53
  t4 = $[2];
54
+ t5 = $[3];
47
55
  }
48
- let t5;
49
- if ($[3] !== hidden) {
50
- t5 = /* @__PURE__ */ jsxs("aside", {
56
+ let t6;
57
+ if ($[4] !== hidden) {
58
+ t6 = /* @__PURE__ */ jsxs("aside", {
51
59
  "aria-label": "Chat",
52
60
  "data-chat-sidebar": true,
53
61
  hidden,
54
- className: "bg-background flex shrink-0 flex-col border-l-2 max-md:hidden",
55
- style: t2,
56
- children: [t3, t4]
62
+ className: t2,
63
+ style: t3,
64
+ children: [t4, t5]
57
65
  });
58
- $[3] = hidden;
59
- $[4] = t5;
60
- } else t5 = $[4];
61
- return t5;
66
+ $[4] = hidden;
67
+ $[5] = t6;
68
+ } else t6 = $[5];
69
+ return t6;
62
70
  }
63
71
  /** Camox's logo, beside the heading: the agent is Camox. */
64
72
  function CamoxMark() {
@@ -151,7 +151,7 @@ const Navbar = (t0) => {
151
151
  let t11;
152
152
  if ($[24] !== t9) {
153
153
  t11 = /* @__PURE__ */ jsxs("nav", {
154
- className: "bg-background relative flex items-center justify-between gap-4 border-b-2 px-2 py-2",
154
+ className: "bg-background relative flex items-center justify-between gap-4 border-b px-2 py-2",
155
155
  children: [t9, t10]
156
156
  });
157
157
  $[24] = t9;
@@ -1,8 +1,8 @@
1
1
  import { useAuthContext, useAuthState } from "../../../lib/auth.js";
2
2
  import { useNavigate } from "../../navigation/navigation.js";
3
3
  import { useLocalePath, useLocalizedPath } from "../../../lib/view-locale.js";
4
- import { PlatformLabel } from "../../../components/PlatformLabel.js";
5
4
  import { previewStore, selectIsCanvasShown } from "../../preview/previewStore.js";
5
+ import { PlatformLabel } from "../../../components/PlatformLabel.js";
6
6
  import { STUDIO_BASE_PATH } from "../routes.js";
7
7
  import { studioStore } from "../studioStore.js";
8
8
  import { useApplyTheme } from "../useTheme.js";
@@ -251,6 +251,24 @@ const reads = {
251
251
  fetch: async (context, { runtimeBasePath, pathname }) => (await readRender(context, runtimeBasePath, pathname))?.derived?.result ?? null,
252
252
  staleTime: Infinity
253
253
  }),
254
+ layoutPageMarkdown: entry({
255
+ key: ({ projectUuid, runtimeBasePath, pathname }) => [
256
+ ...queryKeys.layouts.all,
257
+ "markdown",
258
+ projectUuid,
259
+ runtimeBasePath,
260
+ pathname
261
+ ],
262
+ fetch: async ({ runtimeJson, draft, signal }, { runtimeBasePath, pathname }) => {
263
+ const response = await runtimeJson("/_camox/data", runtimeBasePath, {
264
+ path: pathname,
265
+ markdown: ""
266
+ }, draft, signal);
267
+ if (!response.ok) throw new Error(`Could not load the Markdown of ${pathname}.`);
268
+ return (await response.json()).markdown;
269
+ },
270
+ retry: false
271
+ }),
254
272
  discoveredPath: entry({
255
273
  key: ({ projectUuid, runtimeBasePath, layoutId, recordId }) => [
256
274
  ...queryKeys.layouts.all,
package/dist/package.js CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "0.52.2";
2
+ var version = "0.53.1";
3
3
 
4
4
  //#endregion
5
5
  export { version };