camox 0.51.0 → 0.52.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/createApp.d.ts +1 -0
- package/dist/core/createApp.js +1 -0
- package/dist/core/editing/contentEdits.js +78 -0
- package/dist/core/editing/createEditableBlock.js +277 -311
- package/dist/core/lib/contentType.js +2 -2
- package/dist/core/recordItem.js +3 -3
- package/dist/features/canvas/CamoxCanvas.js +15 -15
- package/dist/features/canvas/CanvasLoadingScreen.js +15 -11
- package/dist/features/canvas/CanvasPageFrame.js +81 -87
- package/dist/features/canvas/CanvasPreviewPageSlot.js +1 -1
- package/dist/features/canvas/DerivedPagePathInput.js +12 -12
- package/dist/features/canvas/canvasOverlayGeometry.js +1 -1
- package/dist/features/canvas/canvasStore.js +2 -2
- package/dist/features/canvas/sidebar/CuratedPageInspector.js +1 -1
- package/dist/features/canvas/sidebar/LayoutPageBlocks.js +23 -31
- package/dist/features/canvas/useCanvasCamera.js +1 -1
- package/dist/features/canvas/useDiscoveredPreviewPaths.js +16 -9
- package/dist/features/page/CuratedPageContent.js +1 -1
- package/dist/features/preview/CamoxPreview.d.ts +8 -4
- package/dist/features/preview/CamoxPreview.js +257 -442
- package/dist/features/preview/EditablePageContent.js +244 -2
- package/dist/features/preview/EditablePageExperience.js +2 -4
- package/dist/features/preview/components/AddBlockSheet.js +55 -15
- package/dist/features/preview/components/BlockActionsPopover.js +12 -16
- package/dist/features/preview/components/BlockPeek.js +66 -0
- package/dist/features/preview/components/BlockThumbnail.js +134 -119
- package/dist/features/preview/components/CanvasPreview.js +1 -1
- package/dist/features/preview/components/CreatePageModal.js +150 -156
- package/dist/features/preview/components/Frame.js +27 -4
- package/dist/features/preview/components/MobilePreviewDrawer.js +1 -1
- package/dist/features/preview/components/PageInfo.js +161 -126
- package/dist/features/preview/components/PagePicker.js +2 -2
- package/dist/features/preview/components/PageTree.js +174 -190
- package/dist/features/preview/components/PreviewPanel.js +3 -3
- package/dist/features/preview/components/ReferenceFieldEditor.js +4 -4
- package/dist/features/preview/components/ReferenceListFieldEditor.js +4 -4
- package/dist/features/preview/components/RemovedBlockPlaceholder.js +37 -70
- package/dist/features/preview/components/RepeatableItemsList.js +1 -1
- package/dist/features/preview/components/SelectionEditor.js +248 -256
- package/dist/features/preview/components/StudioEditingFallback.js +22 -26
- package/dist/features/preview/components/useFieldWriter.js +19 -19
- package/dist/features/preview/components/useRecordView.js +105 -147
- package/dist/features/preview/components/useRepeatableItemActions.js +0 -2
- package/dist/features/preview/pageRecord.js +30 -24
- package/dist/features/preview/previewStore.js +2 -0
- package/dist/features/preview/studioNotice.js +20 -0
- package/dist/features/provider/AuthenticatedCamoxProvider.js +46 -30
- package/dist/features/renderer/RendererApp.js +542 -0
- package/dist/features/renderer/RendererFrames.js +450 -0
- package/dist/features/renderer/definitionAnswers.js +26 -0
- package/dist/features/renderer/protocol.js +35 -0
- package/dist/features/renderer/rendererHost.js +249 -0
- package/dist/features/renderer/studioConnection.js +186 -0
- package/dist/features/routes/pageRuntime.js +7 -2
- package/dist/features/runtime/RuntimeChrome.js +2 -5
- package/dist/features/runtime/assetPrefix.js +14 -0
- package/dist/features/runtime/breadcrumbs.js +1 -1
- package/dist/features/runtime/editingFallback.js +4 -8
- package/dist/features/runtime/livePages.js +1 -1
- package/dist/features/runtime/pageApp.js +57 -83
- package/dist/features/runtime/pageClient.js +1 -1
- package/dist/features/runtime/pageNavigation.js +3 -2
- package/dist/features/runtime/publicCache.js +15 -3
- package/dist/features/runtime/publishingDraft.js +23 -0
- package/dist/features/runtime/rendererClient.d.ts +8 -0
- package/dist/features/runtime/rendererClient.js +77 -0
- package/dist/features/runtime/runtime.d.ts +9 -0
- package/dist/features/runtime/runtime.js +36 -17
- package/dist/features/runtime/runtimeRoutes.d.ts +2 -0
- package/dist/features/runtime/runtimeRoutes.js +2 -0
- package/dist/features/runtime/worker.d.ts +10 -1
- package/dist/features/runtime/worker.js +20 -7
- package/dist/features/studio/FollowAgentProvider.js +10 -10
- package/dist/features/studio/components/ProjectMenu.js +1 -1
- package/dist/features/studio/components/ReviewDraftSheet.js +242 -138
- package/dist/features/studio/components/ThreadMessages.js +100 -65
- package/dist/features/studio/components/UserButton.js +1 -1
- package/dist/features/vite/definitionsSync.js +1 -1
- package/dist/features/vite/hostedChecks.js +127 -0
- package/dist/features/vite/runtimeDev.js +26 -0
- package/dist/features/vite/vite.js +33 -5
- package/dist/hooks/use-page-destinations.js +10 -10
- package/dist/lib/revisions.js +20 -0
- package/dist/lib/studio-definitions.js +160 -0
- package/dist/lib/studio-reads.js +65 -21
- package/dist/lib/use-project-room.js +16 -10
- package/dist/package.js +1 -1
- package/dist/studio.css +1 -1
- package/package.json +8 -4
- package/skills/camox/SKILL.md +4 -0
- package/skills/camox/references/artifacts.md +1 -1
|
@@ -9,12 +9,13 @@ import { MessageScroller, MessageScrollerButton, MessageScrollerContent, Message
|
|
|
9
9
|
//#region src/features/studio/components/ThreadMessages.tsx
|
|
10
10
|
/**
|
|
11
11
|
* A thread's messages, and "Working…" while a run is going or a message is still `sending`: on
|
|
12
|
-
* its way to the thread, which hasn't accepted it yet.
|
|
12
|
+
* its way to the thread, which hasn't accepted it yet. While the end of a turn builds the
|
|
13
|
+
* agent's code, or the agent fixes a build error, it says so instead. A draft's thread is shared, so it shows
|
|
13
14
|
* senders' names too (`showSenders`). A fresh Live thread links to the draft the editor's
|
|
14
15
|
* previous one continued in (`continuedIn`).
|
|
15
16
|
*/
|
|
16
17
|
function ThreadMessages(t0) {
|
|
17
|
-
const $ = c(
|
|
18
|
+
const $ = c(28);
|
|
18
19
|
const { view, sending: t1, showSenders: t2, continuedIn } = t0;
|
|
19
20
|
const sending = t1 === void 0 ? false : t1;
|
|
20
21
|
const showSenders = t2 === void 0 ? false : t2;
|
|
@@ -53,9 +54,9 @@ function ThreadMessages(t0) {
|
|
|
53
54
|
$[6] = t3;
|
|
54
55
|
} else t3 = $[6];
|
|
55
56
|
let t4;
|
|
56
|
-
if ($[7] !== showSenders || $[8] !== view.messages || $[9] !== working) {
|
|
57
|
+
if ($[7] !== showSenders || $[8] !== view.messages || $[9] !== view.status || $[10] !== working) {
|
|
57
58
|
let t5;
|
|
58
|
-
if ($[
|
|
59
|
+
if ($[12] !== showSenders || $[13] !== view.messages.length || $[14] !== view.status || $[15] !== working) {
|
|
59
60
|
t5 = (message, index) => /* @__PURE__ */ jsxs(MessageScrollerItem, {
|
|
60
61
|
messageId: message.id,
|
|
61
62
|
scrollAnchor: message.from === "editor",
|
|
@@ -63,28 +64,31 @@ function ThreadMessages(t0) {
|
|
|
63
64
|
children: [/* @__PURE__ */ jsx(ThreadMessageRow, {
|
|
64
65
|
message,
|
|
65
66
|
showSender: showSenders
|
|
66
|
-
}), working && index === view.messages.length - 1 && /* @__PURE__ */ jsx(Working, {})]
|
|
67
|
+
}), working && index === view.messages.length - 1 && /* @__PURE__ */ jsx(Working, { status: view.status })]
|
|
67
68
|
}, message.id);
|
|
68
|
-
$[
|
|
69
|
-
$[
|
|
70
|
-
$[
|
|
71
|
-
$[
|
|
72
|
-
|
|
69
|
+
$[12] = showSenders;
|
|
70
|
+
$[13] = view.messages.length;
|
|
71
|
+
$[14] = view.status;
|
|
72
|
+
$[15] = working;
|
|
73
|
+
$[16] = t5;
|
|
74
|
+
} else t5 = $[16];
|
|
73
75
|
t4 = view.messages.map(t5);
|
|
74
76
|
$[7] = showSenders;
|
|
75
77
|
$[8] = view.messages;
|
|
76
|
-
$[9] =
|
|
77
|
-
$[10] =
|
|
78
|
-
|
|
78
|
+
$[9] = view.status;
|
|
79
|
+
$[10] = working;
|
|
80
|
+
$[11] = t4;
|
|
81
|
+
} else t4 = $[11];
|
|
79
82
|
let t5;
|
|
80
|
-
if ($[
|
|
81
|
-
t5 = working && view.messages.length === 0 && /* @__PURE__ */ jsx(Working, {});
|
|
82
|
-
$[
|
|
83
|
-
$[
|
|
84
|
-
$[
|
|
85
|
-
|
|
83
|
+
if ($[17] !== view.messages.length || $[18] !== view.status || $[19] !== working) {
|
|
84
|
+
t5 = working && view.messages.length === 0 && /* @__PURE__ */ jsx(Working, { status: view.status });
|
|
85
|
+
$[17] = view.messages.length;
|
|
86
|
+
$[18] = view.status;
|
|
87
|
+
$[19] = working;
|
|
88
|
+
$[20] = t5;
|
|
89
|
+
} else t5 = $[20];
|
|
86
90
|
let t6;
|
|
87
|
-
if ($[
|
|
91
|
+
if ($[21] !== t3 || $[22] !== t4 || $[23] !== t5) {
|
|
88
92
|
t6 = /* @__PURE__ */ jsx(MessageScrollerViewport, { children: /* @__PURE__ */ jsxs(MessageScrollerContent, {
|
|
89
93
|
className: "flex flex-col gap-4 px-2 py-3",
|
|
90
94
|
children: [
|
|
@@ -93,46 +97,53 @@ function ThreadMessages(t0) {
|
|
|
93
97
|
t5
|
|
94
98
|
]
|
|
95
99
|
}) });
|
|
96
|
-
$[
|
|
97
|
-
$[
|
|
98
|
-
$[
|
|
99
|
-
$[
|
|
100
|
-
} else t6 = $[
|
|
100
|
+
$[21] = t3;
|
|
101
|
+
$[22] = t4;
|
|
102
|
+
$[23] = t5;
|
|
103
|
+
$[24] = t6;
|
|
104
|
+
} else t6 = $[24];
|
|
101
105
|
let t7;
|
|
102
|
-
if ($[
|
|
106
|
+
if ($[25] === Symbol.for("react.memo_cache_sentinel")) {
|
|
103
107
|
t7 = /* @__PURE__ */ jsx(MessageScrollerButton, {});
|
|
104
|
-
$[
|
|
105
|
-
} else t7 = $[
|
|
108
|
+
$[25] = t7;
|
|
109
|
+
} else t7 = $[25];
|
|
106
110
|
let t8;
|
|
107
|
-
if ($[
|
|
111
|
+
if ($[26] !== t6) {
|
|
108
112
|
t8 = /* @__PURE__ */ jsx(MessageScrollerProvider, { children: /* @__PURE__ */ jsxs(MessageScroller, {
|
|
109
113
|
className: "min-h-0 flex-1",
|
|
110
114
|
children: [t6, t7]
|
|
111
115
|
}) });
|
|
112
|
-
$[
|
|
113
|
-
$[
|
|
114
|
-
} else t8 = $[
|
|
116
|
+
$[26] = t6;
|
|
117
|
+
$[27] = t8;
|
|
118
|
+
} else t8 = $[27];
|
|
115
119
|
return t8;
|
|
116
120
|
}
|
|
117
121
|
/**
|
|
118
122
|
* Shown in the last message, not after it: the scroller only brings a message the editor just
|
|
119
123
|
* sent into view when it's appended last, and it arrives while the agent is already working.
|
|
120
124
|
*/
|
|
121
|
-
function Working() {
|
|
122
|
-
const $ = c(
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
125
|
+
function Working(t0) {
|
|
126
|
+
const $ = c(2);
|
|
127
|
+
const { status } = t0;
|
|
128
|
+
const t1 = status ? STATUS_LINES[status] : "Working…";
|
|
129
|
+
let t2;
|
|
130
|
+
if ($[0] !== t1) {
|
|
131
|
+
t2 = /* @__PURE__ */ jsx("p", {
|
|
126
132
|
role: "status",
|
|
127
133
|
className: "shimmer text-muted-foreground text-sm",
|
|
128
|
-
children:
|
|
134
|
+
children: t1
|
|
129
135
|
});
|
|
130
|
-
$[0] =
|
|
131
|
-
|
|
132
|
-
|
|
136
|
+
$[0] = t1;
|
|
137
|
+
$[1] = t2;
|
|
138
|
+
} else t2 = $[1];
|
|
139
|
+
return t2;
|
|
133
140
|
}
|
|
141
|
+
const STATUS_LINES = {
|
|
142
|
+
building: "Building…",
|
|
143
|
+
fixing: "Fixing a build error…"
|
|
144
|
+
};
|
|
134
145
|
function ThreadMessageRow(t0) {
|
|
135
|
-
const $ = c(
|
|
146
|
+
const $ = c(20);
|
|
136
147
|
const { message, showSender } = t0;
|
|
137
148
|
if (message.from === "stopped" || message.from === "failed") {
|
|
138
149
|
const t1 = message.from === "stopped" ? `Stopped by ${message.sender.name}` : "Camox couldn’t finish this. Send your message again to retry.";
|
|
@@ -156,24 +167,48 @@ function ThreadMessageRow(t0) {
|
|
|
156
167
|
} else t1 = $[3];
|
|
157
168
|
return t1;
|
|
158
169
|
}
|
|
170
|
+
if (message.from === "camox") {
|
|
171
|
+
let t1;
|
|
172
|
+
if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
|
|
173
|
+
t1 = /* @__PURE__ */ jsx(MessageHeader, {
|
|
174
|
+
className: "text-muted-foreground text-xs",
|
|
175
|
+
children: "Camox"
|
|
176
|
+
});
|
|
177
|
+
$[4] = t1;
|
|
178
|
+
} else t1 = $[4];
|
|
179
|
+
let t2;
|
|
180
|
+
if ($[5] !== message.text) {
|
|
181
|
+
t2 = /* @__PURE__ */ jsx(Message, { children: /* @__PURE__ */ jsxs(MessageContent, { children: [t1, /* @__PURE__ */ jsx(Bubble, {
|
|
182
|
+
variant: "muted",
|
|
183
|
+
className: "max-w-full",
|
|
184
|
+
children: /* @__PURE__ */ jsx(BubbleContent, {
|
|
185
|
+
className: "whitespace-pre-wrap",
|
|
186
|
+
children: message.text
|
|
187
|
+
})
|
|
188
|
+
})] }) });
|
|
189
|
+
$[5] = message.text;
|
|
190
|
+
$[6] = t2;
|
|
191
|
+
} else t2 = $[6];
|
|
192
|
+
return t2;
|
|
193
|
+
}
|
|
159
194
|
let t1;
|
|
160
|
-
if ($[
|
|
195
|
+
if ($[7] !== message.sender) {
|
|
161
196
|
t1 = /* @__PURE__ */ jsx(MessageAvatar, { children: /* @__PURE__ */ jsx(SenderAvatar, { sender: message.sender }) });
|
|
162
|
-
$[
|
|
163
|
-
$[
|
|
164
|
-
} else t1 = $[
|
|
197
|
+
$[7] = message.sender;
|
|
198
|
+
$[8] = t1;
|
|
199
|
+
} else t1 = $[8];
|
|
165
200
|
let t2;
|
|
166
|
-
if ($[
|
|
201
|
+
if ($[9] !== message.sender || $[10] !== showSender) {
|
|
167
202
|
t2 = showSender && /* @__PURE__ */ jsx(MessageHeader, {
|
|
168
203
|
className: "text-muted-foreground text-xs",
|
|
169
204
|
children: message.sender.name
|
|
170
205
|
});
|
|
171
|
-
$[
|
|
172
|
-
$[
|
|
173
|
-
$[
|
|
174
|
-
} else t2 = $[
|
|
206
|
+
$[9] = message.sender;
|
|
207
|
+
$[10] = showSender;
|
|
208
|
+
$[11] = t2;
|
|
209
|
+
} else t2 = $[11];
|
|
175
210
|
let t3;
|
|
176
|
-
if ($[
|
|
211
|
+
if ($[12] !== message.text) {
|
|
177
212
|
t3 = /* @__PURE__ */ jsx(Bubble, {
|
|
178
213
|
align: "end",
|
|
179
214
|
variant: "muted",
|
|
@@ -183,26 +218,26 @@ function ThreadMessageRow(t0) {
|
|
|
183
218
|
children: message.text
|
|
184
219
|
})
|
|
185
220
|
});
|
|
186
|
-
$[
|
|
187
|
-
$[
|
|
188
|
-
} else t3 = $[
|
|
221
|
+
$[12] = message.text;
|
|
222
|
+
$[13] = t3;
|
|
223
|
+
} else t3 = $[13];
|
|
189
224
|
let t4;
|
|
190
|
-
if ($[
|
|
225
|
+
if ($[14] !== t2 || $[15] !== t3) {
|
|
191
226
|
t4 = /* @__PURE__ */ jsxs(MessageContent, { children: [t2, t3] });
|
|
192
|
-
$[
|
|
193
|
-
$[
|
|
194
|
-
$[
|
|
195
|
-
} else t4 = $[
|
|
227
|
+
$[14] = t2;
|
|
228
|
+
$[15] = t3;
|
|
229
|
+
$[16] = t4;
|
|
230
|
+
} else t4 = $[16];
|
|
196
231
|
let t5;
|
|
197
|
-
if ($[
|
|
232
|
+
if ($[17] !== t1 || $[18] !== t4) {
|
|
198
233
|
t5 = /* @__PURE__ */ jsxs(Message, {
|
|
199
234
|
align: "end",
|
|
200
235
|
children: [t1, t4]
|
|
201
236
|
});
|
|
202
|
-
$[
|
|
203
|
-
$[
|
|
204
|
-
$[
|
|
205
|
-
} else t5 = $[
|
|
237
|
+
$[17] = t1;
|
|
238
|
+
$[18] = t4;
|
|
239
|
+
$[19] = t5;
|
|
240
|
+
} else t5 = $[19];
|
|
206
241
|
return t5;
|
|
207
242
|
}
|
|
208
243
|
function ContinuedIn(t0) {
|
|
@@ -2,9 +2,9 @@ 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
4
|
import { PlatformLabel } from "../../../components/PlatformLabel.js";
|
|
5
|
+
import { previewStore, selectIsCanvasShown } from "../../preview/previewStore.js";
|
|
5
6
|
import { STUDIO_BASE_PATH } from "../routes.js";
|
|
6
7
|
import { studioStore } from "../studioStore.js";
|
|
7
|
-
import { previewStore, selectIsCanvasShown } from "../../preview/previewStore.js";
|
|
8
8
|
import { useApplyTheme } from "../useTheme.js";
|
|
9
9
|
import { c } from "react/compiler-runtime";
|
|
10
10
|
import { useSelector } from "@xstate/store-react";
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { Visitor, parseSync } from "vite-plus";
|
|
5
|
+
|
|
6
|
+
//#region src/features/vite/hostedChecks.ts
|
|
7
|
+
/**
|
|
8
|
+
* Set by Camox's revision and release sandboxes: a hosted project's build checks the code an
|
|
9
|
+
* agent may have written (ADR 0021). `apps/landing` and dev mode never set it.
|
|
10
|
+
*/
|
|
11
|
+
const HOSTED_BUILD_ENV = "CAMOX_INTERNAL_HOSTED";
|
|
12
|
+
const sdkRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../../..");
|
|
13
|
+
/** `camox`'s public entry points, as `camox/<path>`: its exports, less its internal ones. */
|
|
14
|
+
function camoxEntryPoints() {
|
|
15
|
+
const { exports } = JSON.parse(readFileSync(join(sdkRoot, "package.json"), "utf8"));
|
|
16
|
+
return new Set(Object.keys(exports).filter((path) => !path.startsWith("./_internal/")).map((path) => `camox${path.slice(1)}`));
|
|
17
|
+
}
|
|
18
|
+
function readHostedProject(root) {
|
|
19
|
+
const { dependencies = {} } = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
|
|
20
|
+
return {
|
|
21
|
+
root,
|
|
22
|
+
src: join(root, "src"),
|
|
23
|
+
dependencies: new Set(Object.keys(dependencies)),
|
|
24
|
+
camoxEntryPoints: camoxEntryPoints()
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const withoutQuery = (path) => path.replace(/[?#].*$/, "");
|
|
28
|
+
const isInside = (dir, path) => path.startsWith(dir + sep);
|
|
29
|
+
const displayPath = (project, file) => relative(project.root, file).split(sep).join("/");
|
|
30
|
+
/** The project's own file an importer names, when it is one of `src/`'s: the code it checks. */
|
|
31
|
+
function sourceFile(project, importer) {
|
|
32
|
+
if (!importer || importer.startsWith("\0")) return;
|
|
33
|
+
const file = withoutQuery(importer);
|
|
34
|
+
return isAbsolute(file) && isInside(project.src, file) ? file : void 0;
|
|
35
|
+
}
|
|
36
|
+
function isAllowedImport(project, specifier, importer) {
|
|
37
|
+
if (specifier.startsWith("\0")) return true;
|
|
38
|
+
const path = withoutQuery(specifier);
|
|
39
|
+
let file;
|
|
40
|
+
if (path.startsWith("./") || path.startsWith("../")) file = resolve(dirname(importer), path);
|
|
41
|
+
else if (path.startsWith("@/")) file = resolve(project.src, path.slice(2));
|
|
42
|
+
else if (path.startsWith("/")) file = isInside(project.root, path) ? resolve(path) : resolve(project.root, `.${path}`);
|
|
43
|
+
if (file !== void 0) return isInside(project.src, file);
|
|
44
|
+
if (path === "camox" || path.startsWith("camox/")) return project.camoxEntryPoints.has(path);
|
|
45
|
+
const [scopeOrName, name] = path.split("/");
|
|
46
|
+
const packageName = scopeOrName.startsWith("@") ? `${scopeOrName}/${name}` : scopeOrName;
|
|
47
|
+
return project.dependencies.has(packageName);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Why a file of `src/` can't import `specifier`, or nothing when it may: files of `src/`,
|
|
51
|
+
* `camox`'s public entry points and `package.json`'s `dependencies`.
|
|
52
|
+
*/
|
|
53
|
+
function forbiddenImport(project, specifier, importer) {
|
|
54
|
+
const file = sourceFile(project, importer);
|
|
55
|
+
if (!file || isAllowedImport(project, specifier, file)) return;
|
|
56
|
+
return `${displayPath(project, file)} imports "${specifier}", which a hosted project can't import. It can import files in src/, camox's public entry points and the packages package.json lists in dependencies.`;
|
|
57
|
+
}
|
|
58
|
+
/** The modules the registry loads blocks from, as its globs name them. */
|
|
59
|
+
const BLOCK_MODULE = /^src\/(?:camox\/)?blocks\/([^/]+)\.tsx?$/;
|
|
60
|
+
/** A string an expression spells out, without running it. */
|
|
61
|
+
function literalString(node) {
|
|
62
|
+
if (node?.type === "Literal" && typeof node.value === "string") return node.value;
|
|
63
|
+
if (node?.type === "TemplateLiteral" && node.expressions.length === 0) return node.quasis[0]?.value.cooked ?? void 0;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Whether `callee` calls `createBlock`: by its name, the names a module imports it as
|
|
67
|
+
* (`import { createBlock as defineBlock }`), or as a namespace's member.
|
|
68
|
+
*/
|
|
69
|
+
function isCreateBlock(callee, names) {
|
|
70
|
+
if (callee.type === "Identifier") return names.has(callee.name);
|
|
71
|
+
return callee.type === "MemberExpression" && callee.property.type === "Identifier" && callee.property.name === "createBlock";
|
|
72
|
+
}
|
|
73
|
+
/** The local names a module calls `createBlock` by: its own name, and its imports' aliases. */
|
|
74
|
+
function createBlockNames(program) {
|
|
75
|
+
const names = /* @__PURE__ */ new Set(["createBlock"]);
|
|
76
|
+
for (const statement of program.body) {
|
|
77
|
+
if (statement.type !== "ImportDeclaration") continue;
|
|
78
|
+
for (const specifier of statement.specifiers) {
|
|
79
|
+
if (specifier.type !== "ImportSpecifier") continue;
|
|
80
|
+
const imported = specifier.imported;
|
|
81
|
+
if ((imported.type === "Identifier" ? imported.name : imported.value) === "createBlock") names.add(specifier.local.name);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return names;
|
|
85
|
+
}
|
|
86
|
+
/** The `id` a block definition's object literal spells out. */
|
|
87
|
+
function definitionId(definition) {
|
|
88
|
+
if (definition?.type !== "ObjectExpression") return;
|
|
89
|
+
for (const property of definition.properties) {
|
|
90
|
+
if (property.type !== "Property" || property.computed) continue;
|
|
91
|
+
const key = property.key;
|
|
92
|
+
if (key.type === "Identifier" && key.name === "id" || key.type === "Literal" && key.value === "id") return property.value;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Why a block's module breaks the registry, or nothing when it doesn't. The browser finds a block
|
|
97
|
+
* by its file name, so a block's file must be named after its id: the build reads the id from the
|
|
98
|
+
* `createBlock()` call, and needs it written as a string.
|
|
99
|
+
*/
|
|
100
|
+
function misnamedBlock(project, moduleId, code) {
|
|
101
|
+
const file = sourceFile(project, moduleId);
|
|
102
|
+
if (!file) return;
|
|
103
|
+
const path = displayPath(project, file);
|
|
104
|
+
const fileName = BLOCK_MODULE.exec(path)?.[1];
|
|
105
|
+
if (!fileName) return;
|
|
106
|
+
const { program, errors } = parseSync(file, code);
|
|
107
|
+
if (errors.length > 0) return;
|
|
108
|
+
let problem;
|
|
109
|
+
const names = createBlockNames(program);
|
|
110
|
+
new Visitor({ CallExpression(call) {
|
|
111
|
+
if (problem || !isCreateBlock(call.callee, names)) return;
|
|
112
|
+
const id = literalString(definitionId(call.arguments[0]));
|
|
113
|
+
const at = definitionId(call.arguments[0])?.start ?? call.start;
|
|
114
|
+
if (id === void 0) problem = {
|
|
115
|
+
message: `${path} calls createBlock() without its id as a string literal, which the build needs to check that the file is named after it: write \`id: "${fileName}"\`.`,
|
|
116
|
+
at
|
|
117
|
+
};
|
|
118
|
+
else if (id !== fileName) problem = {
|
|
119
|
+
message: `${path} defines the block "${id}", but its file is named "${fileName}": a block's file is named after its id. Rename the file to ${id}${file.slice(file.lastIndexOf("."))} or the id to "${fileName}".`,
|
|
120
|
+
at
|
|
121
|
+
};
|
|
122
|
+
} }).visit(program);
|
|
123
|
+
return problem;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
//#endregion
|
|
127
|
+
export { HOSTED_BUILD_ENV, forbiddenImport, misnamedBlock, readHostedProject };
|
|
@@ -22,6 +22,10 @@ const VIRTUAL_STUDIO_CLIENT = "virtual:camox/studio-client";
|
|
|
22
22
|
const RESOLVED_VIRTUAL_STUDIO_CLIENT = "\0" + VIRTUAL_STUDIO_CLIENT;
|
|
23
23
|
const VIRTUAL_STUDIO_CLIENT_URL = "virtual:camox/studio-client-url";
|
|
24
24
|
const RESOLVED_VIRTUAL_STUDIO_CLIENT_URL = "\0" + VIRTUAL_STUDIO_CLIENT_URL;
|
|
25
|
+
const VIRTUAL_RENDERER_CLIENT = "virtual:camox/renderer-client";
|
|
26
|
+
const RESOLVED_VIRTUAL_RENDERER_CLIENT = "\0" + VIRTUAL_RENDERER_CLIENT;
|
|
27
|
+
const VIRTUAL_RENDERER_CLIENT_URL = "virtual:camox/renderer-client-url";
|
|
28
|
+
const RESOLVED_VIRTUAL_RENDERER_CLIENT_URL = "\0" + VIRTUAL_RENDERER_CLIENT_URL;
|
|
25
29
|
const VIRTUAL_BLOCK_CHUNKS = "virtual:camox/block-chunks";
|
|
26
30
|
const RESOLVED_VIRTUAL_BLOCK_CHUNKS = "\0" + VIRTUAL_BLOCK_CHUNKS;
|
|
27
31
|
const VIRTUAL_APP_STYLESHEET_URL = "virtual:camox/app-stylesheet-url";
|
|
@@ -64,6 +68,7 @@ function resolveCamoxSourceImport(id) {
|
|
|
64
68
|
"camox/_internal/pageServer": resolve(sdkRoot, "src/features/runtime/pageServer.tsx"),
|
|
65
69
|
"camox/_internal/pageClient": resolve(sdkRoot, "src/features/runtime/pageClient.tsx"),
|
|
66
70
|
"camox/_internal/studioClient": resolve(sdkRoot, "src/features/runtime/studioClient.tsx"),
|
|
71
|
+
"camox/_internal/rendererClient": resolve(sdkRoot, "src/features/runtime/rendererClient.tsx"),
|
|
67
72
|
"camox/_internal/studioServer": resolve(sdkRoot, "src/features/runtime/studioServer.tsx"),
|
|
68
73
|
"camox/_internal/runtime": resolve(sdkRoot, "src/features/runtime/runtime.ts"),
|
|
69
74
|
"camox/worker": resolve(sdkRoot, "src/features/runtime/worker.ts")
|
|
@@ -167,6 +172,13 @@ import { camoxApp } from "virtual:camox/app";
|
|
|
167
172
|
hydrateStudioWithApp(camoxApp);
|
|
168
173
|
`;
|
|
169
174
|
}
|
|
175
|
+
function generateVirtualRendererClient() {
|
|
176
|
+
return `import { startRendererWithApp } from "camox/_internal/rendererClient";
|
|
177
|
+
import { camoxApp } from "virtual:camox/app";
|
|
178
|
+
|
|
179
|
+
startRendererWithApp(camoxApp);
|
|
180
|
+
`;
|
|
181
|
+
}
|
|
170
182
|
function wrapViteDevId(id) {
|
|
171
183
|
return `/@id/${id.replace("\0", "__x00__")}`;
|
|
172
184
|
}
|
|
@@ -176,6 +188,9 @@ function generateVirtualPageClientUrl() {
|
|
|
176
188
|
function generateVirtualStudioClientUrl() {
|
|
177
189
|
return `export default ${JSON.stringify(wrapViteDevId(RESOLVED_VIRTUAL_STUDIO_CLIENT))};`;
|
|
178
190
|
}
|
|
191
|
+
function generateVirtualRendererClientUrl() {
|
|
192
|
+
return `export default ${JSON.stringify(wrapViteDevId(RESOLVED_VIRTUAL_RENDERER_CLIENT))};`;
|
|
193
|
+
}
|
|
179
194
|
function generateVirtualAppStylesheetUrl() {
|
|
180
195
|
return `import stylesheetUrl from "/src/styles.css?url";
|
|
181
196
|
|
|
@@ -194,6 +209,7 @@ import appStylesheetUrl from "virtual:camox/app-stylesheet-url";
|
|
|
194
209
|
import studioStylesheetUrl from "virtual:camox-studio-css";
|
|
195
210
|
import pageClientEntryUrl from "virtual:camox/page-client-url";
|
|
196
211
|
import studioClientEntryUrl from "virtual:camox/studio-client-url";
|
|
212
|
+
import rendererClientEntryUrl from "virtual:camox/renderer-client-url";
|
|
197
213
|
import { renderPage } from "virtual:camox/page-server";
|
|
198
214
|
import { renderStudio } from "virtual:camox/studio-server";
|
|
199
215
|
import devHtml from "virtual:camox/dev-html";
|
|
@@ -207,6 +223,7 @@ const options = {
|
|
|
207
223
|
blockPreloads: { modulePaths: blockModulePaths, chunks: blockChunks },
|
|
208
224
|
pageClientEntryUrl,
|
|
209
225
|
studioClientEntryUrl,
|
|
226
|
+
rendererClientEntryUrl,
|
|
210
227
|
developmentDraft: __CAMOX_DEVELOPMENT_DRAFT__,
|
|
211
228
|
getCamoxApp: async () => camoxApp,
|
|
212
229
|
getDocument: async () => camoxDocument,
|
|
@@ -231,6 +248,11 @@ export async function handleCamoxRequest(request) {
|
|
|
231
248
|
export function isPublicRequest(request) {
|
|
232
249
|
return isPublicRuntimeRequest(request, options);
|
|
233
250
|
}
|
|
251
|
+
|
|
252
|
+
// JSON, as \`definitions.sync\` receives it: what isn't JSON never reaches the API.
|
|
253
|
+
export async function readDefinitionSet() {
|
|
254
|
+
return JSON.parse(JSON.stringify(await camoxApp.getDefinitionSet()));
|
|
255
|
+
}
|
|
234
256
|
`;
|
|
235
257
|
}
|
|
236
258
|
function resolveRuntimeDevId(id, importer) {
|
|
@@ -247,6 +269,8 @@ function resolveRuntimeDevId(id, importer) {
|
|
|
247
269
|
if (id === VIRTUAL_PAGE_CLIENT_URL) return RESOLVED_VIRTUAL_PAGE_CLIENT_URL;
|
|
248
270
|
if (id === VIRTUAL_STUDIO_CLIENT) return RESOLVED_VIRTUAL_STUDIO_CLIENT;
|
|
249
271
|
if (id === VIRTUAL_STUDIO_CLIENT_URL) return RESOLVED_VIRTUAL_STUDIO_CLIENT_URL;
|
|
272
|
+
if (id === VIRTUAL_RENDERER_CLIENT) return RESOLVED_VIRTUAL_RENDERER_CLIENT;
|
|
273
|
+
if (id === VIRTUAL_RENDERER_CLIENT_URL) return RESOLVED_VIRTUAL_RENDERER_CLIENT_URL;
|
|
250
274
|
if (id === VIRTUAL_APP_STYLESHEET_URL) return RESOLVED_VIRTUAL_APP_STYLESHEET_URL;
|
|
251
275
|
if (id === VIRTUAL_BLOCK_CHUNKS) return RESOLVED_VIRTUAL_BLOCK_CHUNKS;
|
|
252
276
|
if (id === VIRTUAL_STUDIO_CSS) return RESOLVED_VIRTUAL_STUDIO_CSS;
|
|
@@ -264,6 +288,8 @@ function loadRuntimeDevModule(id, options = {}) {
|
|
|
264
288
|
if (id === RESOLVED_VIRTUAL_PAGE_CLIENT_URL) return generateVirtualPageClientUrl();
|
|
265
289
|
if (id === RESOLVED_VIRTUAL_STUDIO_CLIENT) return generateVirtualStudioClient();
|
|
266
290
|
if (id === RESOLVED_VIRTUAL_STUDIO_CLIENT_URL) return generateVirtualStudioClientUrl();
|
|
291
|
+
if (id === RESOLVED_VIRTUAL_RENDERER_CLIENT) return generateVirtualRendererClient();
|
|
292
|
+
if (id === RESOLVED_VIRTUAL_RENDERER_CLIENT_URL) return generateVirtualRendererClientUrl();
|
|
267
293
|
if (id === RESOLVED_VIRTUAL_APP_STYLESHEET_URL) return generateVirtualAppStylesheetUrl();
|
|
268
294
|
if (id === RESOLVED_VIRTUAL_STUDIO_CSS) {
|
|
269
295
|
const cssUrl = `/@fs/${resolve(sdkRoot, "dist/studio.css").replaceAll("\\", "/").replace(/^\/+/, "")}`;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createServerApiClient } from "../../lib/api-client-server.js";
|
|
2
|
+
import { ASSET_PREFIX_GLOBAL } from "../runtime/assetPrefix.js";
|
|
2
3
|
import { transformArtifactRuntime } from "./artifactRuntimeMinification.js";
|
|
3
4
|
import { readAuthTokenForUrl } from "./auth.js";
|
|
4
5
|
import { watchNewBlockFiles } from "./blockBoilerplate.js";
|
|
@@ -6,6 +7,7 @@ import { collectBlockChunks } from "./blockChunks.js";
|
|
|
6
7
|
import { withoutExpectedCamoxLogs } from "./bundlerLogs.js";
|
|
7
8
|
import { installDevAuthenticationMiddleware } from "./devAuthentication.js";
|
|
8
9
|
import { installDevSignInLink } from "./devSignIn.js";
|
|
10
|
+
import { HOSTED_BUILD_ENV, forbiddenImport, misnamedBlock, readHostedProject } from "./hostedChecks.js";
|
|
9
11
|
import { generateIconTypes } from "./iconGeneration.js";
|
|
10
12
|
import { generateLayoutFiles, watchLayoutFiles } from "./layoutGeneration.js";
|
|
11
13
|
import { publicFilesInHashedDirs, readOwnHeaders, staticAssetHeaders, unhashedEntries } from "./staticAssetHeaders.js";
|
|
@@ -18,7 +20,7 @@ import { projectIdSchema } from "@camox/api-contract/ids";
|
|
|
18
20
|
import { DEVELOPMENT_DRAFT } from "@camox/api-contract/drafts";
|
|
19
21
|
import { createHash, randomUUID } from "node:crypto";
|
|
20
22
|
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
21
|
-
import { dirname, join, resolve } from "node:path";
|
|
23
|
+
import { dirname, join, posix, resolve } from "node:path";
|
|
22
24
|
import { fileURLToPath } from "node:url";
|
|
23
25
|
import { createServer } from "vite-plus";
|
|
24
26
|
|
|
@@ -34,7 +36,11 @@ const VIRTUAL_PAGE_CLIENT = "virtual:camox/page-client";
|
|
|
34
36
|
const RESOLVED_VIRTUAL_PAGE_CLIENT_URL = "\0virtual:camox/page-client-url";
|
|
35
37
|
const VIRTUAL_STUDIO_CLIENT = "virtual:camox/studio-client";
|
|
36
38
|
const RESOLVED_VIRTUAL_STUDIO_CLIENT_URL = "\0virtual:camox/studio-client-url";
|
|
39
|
+
const VIRTUAL_RENDERER_CLIENT = "virtual:camox/renderer-client";
|
|
40
|
+
const RESOLVED_VIRTUAL_RENDERER_CLIENT_URL = "\0virtual:camox/renderer-client-url";
|
|
37
41
|
const RESOLVED_VIRTUAL_BLOCK_CHUNKS = "\0virtual:camox/block-chunks";
|
|
42
|
+
/** A built file's URL in the server bundle: under the asset prefix, read when the bundle loads. */
|
|
43
|
+
const serverAssetUrl = (file) => `(globalThis.${ASSET_PREFIX_GLOBAL} ?? "/") + ${JSON.stringify(file)}`;
|
|
38
44
|
const PRODUCTION_API_URL = "https://api.camox.ai";
|
|
39
45
|
/** Authentication URL to use for Camox authentication (production Camox Dashboard) */
|
|
40
46
|
const DEFAULT_AUTHENTICATION_URL = "https://app.camox.ai";
|
|
@@ -174,6 +180,8 @@ function camox(options) {
|
|
|
174
180
|
let isRelease = false;
|
|
175
181
|
/** A release's build, without syncing to Live: what the upgrade job checks a project with. */
|
|
176
182
|
let isDryRun = false;
|
|
183
|
+
/** Set when the build checks a hosted project's code. */
|
|
184
|
+
let hostedProject;
|
|
177
185
|
let resolvedConfig;
|
|
178
186
|
let localAuth = null;
|
|
179
187
|
let blockChunks = {};
|
|
@@ -182,6 +190,10 @@ function camox(options) {
|
|
|
182
190
|
name: "camox",
|
|
183
191
|
enforce: "pre",
|
|
184
192
|
resolveId(id, importer) {
|
|
193
|
+
if (hostedProject) {
|
|
194
|
+
const forbidden = forbiddenImport(hostedProject, id, importer);
|
|
195
|
+
if (forbidden) this.error(forbidden);
|
|
196
|
+
}
|
|
185
197
|
const runtimeId = resolveRuntimeDevId(id, importer);
|
|
186
198
|
if (runtimeId) return runtimeId;
|
|
187
199
|
if (id === VIRTUAL_STUDIO_CSS) return RESOLVED_VIRTUAL_STUDIO_CSS;
|
|
@@ -199,7 +211,8 @@ function camox(options) {
|
|
|
199
211
|
fileName,
|
|
200
212
|
source: css
|
|
201
213
|
});
|
|
202
|
-
return `export default ${JSON.stringify(
|
|
214
|
+
if (this.environment.config.consumer === "client") return `export default new URL(/* @vite-ignore */ ${JSON.stringify(`../${fileName}`)}, import.meta.url).href;`;
|
|
215
|
+
return `export default ${serverAssetUrl(fileName)};`;
|
|
203
216
|
}
|
|
204
217
|
const cssUrl = `/@fs/${cssPath.replaceAll("\\", "/").replace(/^\/+/, "")}`;
|
|
205
218
|
return `export default ${JSON.stringify(cssUrl)};`;
|
|
@@ -209,8 +222,9 @@ function camox(options) {
|
|
|
209
222
|
const css = readFileSync(cssPath, "utf-8");
|
|
210
223
|
return `export default ${JSON.stringify(css)};`;
|
|
211
224
|
}
|
|
212
|
-
if (id === RESOLVED_VIRTUAL_PAGE_CLIENT_URL && isBuild) return
|
|
213
|
-
if (id === RESOLVED_VIRTUAL_STUDIO_CLIENT_URL && isBuild) return
|
|
225
|
+
if (id === RESOLVED_VIRTUAL_PAGE_CLIENT_URL && isBuild) return `export default ${serverAssetUrl("_chunks/camox-page-client.mjs")};`;
|
|
226
|
+
if (id === RESOLVED_VIRTUAL_STUDIO_CLIENT_URL && isBuild) return `export default ${serverAssetUrl("_chunks/camox-studio-client.mjs")};`;
|
|
227
|
+
if (id === RESOLVED_VIRTUAL_RENDERER_CLIENT_URL && isBuild) return `export default ${serverAssetUrl("_chunks/camox-renderer-client.mjs")};`;
|
|
214
228
|
if (id === RESOLVED_VIRTUAL_BLOCK_CHUNKS && isBuild) return `export default ${JSON.stringify(blockChunks)};`;
|
|
215
229
|
if (id === "\0virtual:camox/dev-html") {
|
|
216
230
|
if (!devServer) return "export default null;";
|
|
@@ -222,6 +236,10 @@ function camox(options) {
|
|
|
222
236
|
});
|
|
223
237
|
},
|
|
224
238
|
transform(code, id) {
|
|
239
|
+
if (hostedProject) {
|
|
240
|
+
const misnamed = misnamedBlock(hostedProject, id, code);
|
|
241
|
+
if (misnamed) this.error(misnamed.message, misnamed.at);
|
|
242
|
+
}
|
|
225
243
|
return transformArtifactRuntime(code, id);
|
|
226
244
|
},
|
|
227
245
|
generateBundle(_outputOptions, bundle) {
|
|
@@ -249,6 +267,14 @@ function camox(options) {
|
|
|
249
267
|
if (isBuild && !localAuth) throw new Error("Camox: not authenticated. Run `npx camox login` before building the site.");
|
|
250
268
|
}
|
|
251
269
|
return {
|
|
270
|
+
...isBuild && {
|
|
271
|
+
base: "./",
|
|
272
|
+
experimental: { renderBuiltUrl(filename, { ssr, hostType }) {
|
|
273
|
+
if (hostType === "css") return posix.relative("assets", filename);
|
|
274
|
+
if (!ssr) return { relative: true };
|
|
275
|
+
return { runtime: serverAssetUrl(filename) };
|
|
276
|
+
} }
|
|
277
|
+
},
|
|
252
278
|
build: { emitAssets: true },
|
|
253
279
|
..._config.builder?.buildApp ? {} : { builder: { buildApp: buildClientThenWorker } },
|
|
254
280
|
define: {
|
|
@@ -266,7 +292,8 @@ function camox(options) {
|
|
|
266
292
|
onLog: withoutExpectedCamoxLogs(findClientOnLog(_config)),
|
|
267
293
|
input: {
|
|
268
294
|
"camox-page-client": VIRTUAL_PAGE_CLIENT,
|
|
269
|
-
"camox-studio-client": VIRTUAL_STUDIO_CLIENT
|
|
295
|
+
"camox-studio-client": VIRTUAL_STUDIO_CLIENT,
|
|
296
|
+
"camox-renderer-client": VIRTUAL_RENDERER_CLIENT
|
|
270
297
|
},
|
|
271
298
|
output: {
|
|
272
299
|
assetFileNames: "assets/[name]-[hash][extname]",
|
|
@@ -298,6 +325,7 @@ function camox(options) {
|
|
|
298
325
|
},
|
|
299
326
|
configResolved(config) {
|
|
300
327
|
resolvedConfig = config;
|
|
328
|
+
if (process.env["CAMOX_INTERNAL_HOSTED"] === "1") hostedProject = readHostedProject(config.root);
|
|
301
329
|
if (!config.plugins.some((plugin) => plugin.name.startsWith("vite-plugin-cloudflare"))) throw new Error("Camox: Camox apps run on Cloudflare Workers. Add `cloudflare()` from `@cloudflare/vite-plugin` to your Vite plugins, and point `main` in `wrangler.jsonc` at `camox/worker`.");
|
|
302
330
|
const routesDir = resolve(config.root, "src/routes");
|
|
303
331
|
writeRuntimeSidecar(config.root, {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useProjectUuid } from "../lib/auth.js";
|
|
2
|
-
import { useCamoxApp } from "../features/provider/components/CamoxAppContext.js";
|
|
3
2
|
import { reads, useReadQuery } from "../lib/studio-reads.js";
|
|
4
3
|
import { linkablePages, useLinkablePages } from "../lib/link-pages.js";
|
|
4
|
+
import { useRoutableLayouts } from "../lib/studio-definitions.js";
|
|
5
5
|
import { getPageDestinations } from "../core/pageDestinations.js";
|
|
6
6
|
import { c } from "react/compiler-runtime";
|
|
7
7
|
|
|
@@ -9,7 +9,7 @@ import { c } from "react/compiler-runtime";
|
|
|
9
9
|
/** The pages of the locale viewed, which the studio navigates to. */
|
|
10
10
|
function usePageDestinations() {
|
|
11
11
|
const $ = c(11);
|
|
12
|
-
const
|
|
12
|
+
const layouts = useRoutableLayouts();
|
|
13
13
|
const projectUuid = useProjectUuid();
|
|
14
14
|
let t0;
|
|
15
15
|
if ($[0] !== projectUuid) {
|
|
@@ -39,9 +39,9 @@ function usePageDestinations() {
|
|
|
39
39
|
$[7] = t4;
|
|
40
40
|
} else t4 = $[7];
|
|
41
41
|
let t5;
|
|
42
|
-
if ($[8] !==
|
|
43
|
-
t5 = getPageDestinations(t4,
|
|
44
|
-
$[8] =
|
|
42
|
+
if ($[8] !== layouts || $[9] !== t4) {
|
|
43
|
+
t5 = getPageDestinations(t4, layouts);
|
|
44
|
+
$[8] = layouts;
|
|
45
45
|
$[9] = t4;
|
|
46
46
|
$[10] = t5;
|
|
47
47
|
} else t5 = $[10];
|
|
@@ -53,7 +53,7 @@ function usePageDestinations() {
|
|
|
53
53
|
*/
|
|
54
54
|
function useLinkDestinations() {
|
|
55
55
|
const $ = c(7);
|
|
56
|
-
const
|
|
56
|
+
const layouts = useRoutableLayouts();
|
|
57
57
|
let t0;
|
|
58
58
|
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
|
59
59
|
t0 = { fetchProject: true };
|
|
@@ -61,16 +61,16 @@ function useLinkDestinations() {
|
|
|
61
61
|
} else t0 = $[0];
|
|
62
62
|
const { pages, fallbackPages } = useLinkablePages(useProjectUuid(), t0);
|
|
63
63
|
let t1;
|
|
64
|
-
if ($[1] !==
|
|
64
|
+
if ($[1] !== fallbackPages || $[2] !== layouts || $[3] !== pages) {
|
|
65
65
|
let t2;
|
|
66
66
|
if ($[5] !== pages) {
|
|
67
67
|
t2 = pages ?? [];
|
|
68
68
|
$[5] = pages;
|
|
69
69
|
$[6] = t2;
|
|
70
70
|
} else t2 = $[6];
|
|
71
|
-
t1 = getPageDestinations(linkablePages(t2, fallbackPages).map(_temp),
|
|
72
|
-
$[1] =
|
|
73
|
-
$[2] =
|
|
71
|
+
t1 = getPageDestinations(linkablePages(t2, fallbackPages).map(_temp), layouts);
|
|
72
|
+
$[1] = fallbackPages;
|
|
73
|
+
$[2] = layouts;
|
|
74
74
|
$[3] = pages;
|
|
75
75
|
$[4] = t1;
|
|
76
76
|
} else t1 = $[4];
|