camox 0.43.0 → 0.44.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 (63) hide show
  1. package/bin/camox.mjs +9 -1
  2. package/dist/core/components/lexical/InlineStylesPlugin.js +22 -6
  3. package/dist/core/components/lexical/SelectionBroadcaster.js +4 -4
  4. package/dist/core/components/lexical/SidebarLexicalEditor.js +15 -15
  5. package/dist/core/createApp.d.ts +28 -2
  6. package/dist/core/createBlock.js +24 -10
  7. package/dist/core/editing/createEditableBlock.d.ts +135 -1
  8. package/dist/core/editing/createEditableBlock.js +209 -74
  9. package/dist/core/lib/contentType.d.ts +5 -0
  10. package/dist/core/lib/contentType.js +11 -0
  11. package/dist/core/lib/fieldTypes.js +1 -0
  12. package/dist/core/lib/iconTypes.d.ts +13 -0
  13. package/dist/core/lib/icons.d.ts +6 -0
  14. package/dist/core/lib/icons.js +130 -0
  15. package/dist/core/lib/lexicalState.js +6 -6
  16. package/dist/core/lib/modifierFormats.js +1 -1
  17. package/dist/core/lib/textStyles.d.ts +1 -1
  18. package/dist/core/lib/textStyles.js +3 -3
  19. package/dist/features/content/components/AssetCard.js +104 -68
  20. package/dist/features/preview/CamoxPreview.js +120 -95
  21. package/dist/features/preview/commentsEnabled.js +2 -2
  22. package/dist/features/preview/components/AssetLightbox.js +17 -6
  23. package/dist/features/preview/components/AttachedComments.js +224 -87
  24. package/dist/features/preview/components/CommentTargetQuote.js +22 -21
  25. package/dist/features/preview/components/DerivedLayoutDialog.js +36 -21
  26. package/dist/features/preview/components/FieldOverlayStyles.js +29 -9
  27. package/dist/features/preview/components/FieldToolbar.js +8 -8
  28. package/dist/features/preview/components/IconFieldEditor.js +231 -0
  29. package/dist/features/preview/components/ItemFieldsEditor.js +21 -14
  30. package/dist/features/preview/components/OverlayTracker.js +1 -1
  31. package/dist/features/preview/components/PagePicker.js +44 -44
  32. package/dist/features/preview/components/PreviewPanel.js +1 -1
  33. package/dist/features/preview/components/PreviewToolbar.js +224 -225
  34. package/dist/features/preview/components/SendFeedbackDialog.js +83 -0
  35. package/dist/features/preview/overlayHighlights.js +54 -0
  36. package/dist/features/preview/previewCommentsStore.js +54 -34
  37. package/dist/features/preview/previewSelection.js +28 -23
  38. package/dist/features/preview/usePageComments.js +39 -0
  39. package/dist/features/provider/CoreCamoxProvider.js +37 -5
  40. package/dist/features/provider/LocalhostPreviewProvider.js +81 -45
  41. package/dist/features/provider/components/CommandPalette.js +35 -84
  42. package/dist/features/runtime/pageApp.js +32 -28
  43. package/dist/features/runtime/pageServer.js +4 -1
  44. package/dist/features/runtime/runtime.d.ts +2 -0
  45. package/dist/features/runtime/runtime.js +25 -0
  46. package/dist/features/studio/components/EnvironmentMenu.js +75 -63
  47. package/dist/features/vite/auth.js +1 -50
  48. package/dist/features/vite/iconGeneration.js +16 -0
  49. package/dist/features/vite/vite.d.ts +4 -2
  50. package/dist/features/vite/vite.js +19 -2
  51. package/dist/lib/auth.js +39 -16
  52. package/dist/lib/preview-handoff.js +13 -0
  53. package/dist/lib/queries.js +12 -1
  54. package/dist/lib/use-project-room.js +5 -2
  55. package/dist/studio-overlays.css +19 -15
  56. package/dist/studio.css +1 -1
  57. package/package.json +5 -4
  58. package/skills/camox/SKILL.md +6 -0
  59. package/skills/camox/references/block-definitions.md +27 -0
  60. package/skills/camox/references/cli-common.md +14 -0
  61. package/skills/camox/references/cli-content.md +11 -0
  62. package/skills/camox/references/field-styling.md +4 -4
  63. package/skills/camoxify/SKILL.md +14 -0
@@ -5,15 +5,14 @@ import { c } from "react/compiler-runtime";
5
5
  import * as React from "react";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
7
  import { useSelector } from "@xstate/store-react";
8
- import { Kbd } from "@camox/ui/kbd";
9
8
  import { Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandShortcut } from "@camox/ui/command";
10
9
 
11
10
  //#region src/features/provider/components/CommandPalette.tsx
12
11
  function CommandPalette() {
13
- const $ = c(43);
14
- if ($[0] !== "911725dec1e42161265ff27436f9ae9c6c82392d2b8fce53f3eb80dfb29cb6f0") {
15
- for (let $i = 0; $i < 43; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
16
- $[0] = "911725dec1e42161265ff27436f9ae9c6c82392d2b8fce53f3eb80dfb29cb6f0";
12
+ const $ = c(37);
13
+ if ($[0] !== "9972e9f574379197af85e2183aa9808df309da92f446247a1c5412a1062393cb") {
14
+ for (let $i = 0; $i < 37; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
15
+ $[0] = "9972e9f574379197af85e2183aa9808df309da92f446247a1c5412a1062393cb";
17
16
  }
18
17
  const isOpen = useSelector(studioStore, _temp);
19
18
  const [search, setSearch] = React.useState("");
@@ -163,64 +162,18 @@ function CommandPalette() {
163
162
  } else t8 = $[25];
164
163
  let t9;
165
164
  if ($[26] === Symbol.for("react.memo_cache_sentinel")) {
166
- t9 = /* @__PURE__ */ jsxs("span", {
167
- className: "flex items-center gap-1.5",
168
- children: [
169
- /* @__PURE__ */ jsx(Kbd, { children: "↑" }),
170
- /* @__PURE__ */ jsx(Kbd, { children: "↓" }),
171
- " to navigate"
172
- ]
165
+ t9 = /* @__PURE__ */ jsx(CommandEmpty, {
166
+ className: "text-muted-foreground py-8",
167
+ children: "No results found."
173
168
  });
174
169
  $[26] = t9;
175
170
  } else t9 = $[26];
176
171
  let t10;
177
- if ($[27] === Symbol.for("react.memo_cache_sentinel")) {
178
- t10 = /* @__PURE__ */ jsxs("span", {
179
- className: "flex items-center gap-1.5",
180
- children: [/* @__PURE__ */ jsx(Kbd, { children: "↵" }), " to select"]
181
- });
182
- $[27] = t10;
183
- } else t10 = $[27];
184
- let t11;
185
- if ($[28] === Symbol.for("react.memo_cache_sentinel")) {
186
- t11 = /* @__PURE__ */ jsx(Kbd, { children: "Esc" });
187
- $[28] = t11;
188
- } else t11 = $[28];
189
- const t12 = page ? "to go back" : "to close";
190
- let t13;
191
- if ($[29] !== t12) {
192
- t13 = /* @__PURE__ */ jsxs("div", {
193
- className: "text-muted-foreground flex flex-wrap items-center gap-x-4 gap-y-2 border-b px-5 pb-3 text-xs",
194
- children: [
195
- t9,
196
- t10,
197
- /* @__PURE__ */ jsxs("span", {
198
- className: "flex items-center gap-1.5",
199
- children: [
200
- t11,
201
- " ",
202
- t12
203
- ]
204
- })
205
- ]
206
- });
207
- $[29] = t12;
208
- $[30] = t13;
209
- } else t13 = $[30];
210
- let t14;
211
- if ($[31] === Symbol.for("react.memo_cache_sentinel")) {
212
- t14 = /* @__PURE__ */ jsx(CommandEmpty, {
213
- className: "text-muted-foreground py-8",
214
- children: "No results found."
215
- });
216
- $[31] = t14;
217
- } else t14 = $[31];
218
- let t15;
219
- if ($[32] !== groupedActions || $[33] !== handleSelect) {
220
- t15 = /* @__PURE__ */ jsxs(CommandList, {
172
+ if ($[27] !== groupedActions || $[28] !== handleSelect) {
173
+ t10 = /* @__PURE__ */ jsxs(CommandList, {
221
174
  className: "max-h-[min(24rem,45dvh)] min-h-0 scroll-py-1 px-2 pt-1 pb-2",
222
- children: [t14, Array.from(groupedActions.entries()).map((t16) => {
223
- const [groupLabel_0, groupActions] = t16;
175
+ children: [t9, Array.from(groupedActions.entries()).map((t11) => {
176
+ const [groupLabel_0, groupActions] = t11;
224
177
  return /* @__PURE__ */ jsx(CommandGroup, {
225
178
  heading: groupLabel_0,
226
179
  className: "mb-2 p-0 last:mb-0 **:[[cmdk-group-heading]]:px-3 **:[[cmdk-group-heading]]:py-2 **:[[cmdk-group-heading]]:text-[11px] **:[[cmdk-group-heading]]:tracking-widest **:[[cmdk-group-heading]]:uppercase",
@@ -234,44 +187,42 @@ function CommandPalette() {
234
187
  }, groupLabel_0);
235
188
  })]
236
189
  });
237
- $[32] = groupedActions;
238
- $[33] = handleSelect;
239
- $[34] = t15;
240
- } else t15 = $[34];
241
- let t16;
242
- if ($[35] !== t13 || $[36] !== t15 || $[37] !== t8 || $[38] !== value) {
243
- t16 = /* @__PURE__ */ jsxs(Command, {
190
+ $[27] = groupedActions;
191
+ $[28] = handleSelect;
192
+ $[29] = t10;
193
+ } else t10 = $[29];
194
+ let t11;
195
+ if ($[30] !== t10 || $[31] !== t8 || $[32] !== value) {
196
+ t11 = /* @__PURE__ */ jsxs(Command, {
244
197
  value,
245
198
  onValueChange: setValue,
246
199
  className: "h-auto max-h-[80dvh] p-0",
247
200
  children: [
248
201
  t6,
249
202
  t8,
250
- t13,
251
- t15
203
+ t10
252
204
  ]
253
205
  });
254
- $[35] = t13;
255
- $[36] = t15;
256
- $[37] = t8;
257
- $[38] = value;
258
- $[39] = t16;
259
- } else t16 = $[39];
260
- let t17;
261
- if ($[40] !== isOpen || $[41] !== t16) {
262
- t17 = /* @__PURE__ */ jsx(CommandDialog, {
206
+ $[30] = t10;
207
+ $[31] = t8;
208
+ $[32] = value;
209
+ $[33] = t11;
210
+ } else t11 = $[33];
211
+ let t12;
212
+ if ($[34] !== isOpen || $[35] !== t11) {
213
+ t12 = /* @__PURE__ */ jsx(CommandDialog, {
263
214
  open: isOpen,
264
215
  onOpenChange: handleOpenChange,
265
216
  className: "top-[12vh] sm:max-w-xl",
266
217
  description: "Navigate your site and switch settings quickly.",
267
218
  showCloseButton: true,
268
- children: t16
219
+ children: t11
269
220
  });
270
- $[40] = isOpen;
271
- $[41] = t16;
272
- $[42] = t17;
273
- } else t17 = $[42];
274
- return t17;
221
+ $[34] = isOpen;
222
+ $[35] = t11;
223
+ $[36] = t12;
224
+ } else t12 = $[36];
225
+ return t12;
275
226
  }
276
227
  function _temp3(state_1) {
277
228
  return state_1.context.commandPalettePages;
@@ -284,9 +235,9 @@ function _temp(state) {
284
235
  }
285
236
  function useCommandPaletteActions() {
286
237
  const $ = c(2);
287
- if ($[0] !== "911725dec1e42161265ff27436f9ae9c6c82392d2b8fce53f3eb80dfb29cb6f0") {
238
+ if ($[0] !== "9972e9f574379197af85e2183aa9808df309da92f446247a1c5412a1062393cb") {
288
239
  for (let $i = 0; $i < 2; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
289
- $[0] = "911725dec1e42161265ff27436f9ae9c6c82392d2b8fce53f3eb80dfb29cb6f0";
240
+ $[0] = "9972e9f574379197af85e2183aa9808df309da92f446247a1c5412a1062393cb";
290
241
  }
291
242
  let t0;
292
243
  if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
@@ -14,15 +14,15 @@ import { jsx } from "react/jsx-runtime";
14
14
 
15
15
  //#region src/features/runtime/pageApp.tsx
16
16
  function PageApp(t0) {
17
- const $ = c(19);
18
- if ($[0] !== "9929b5234f34e8dc8642da9eb491a90e9a57f3ab875ddfc1a186f42f4452f2f5") {
19
- for (let $i = 0; $i < 19; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
20
- $[0] = "9929b5234f34e8dc8642da9eb491a90e9a57f3ab875ddfc1a186f42f4452f2f5";
17
+ const $ = c(20);
18
+ if ($[0] !== "cc0d298a8943efca3ffb5e7cf2f8f814ebecbf27dec68e2a3129c1bb95c18943") {
19
+ for (let $i = 0; $i < 20; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
20
+ $[0] = "cc0d298a8943efca3ffb5e7cf2f8f814ebecbf27dec68e2a3129c1bb95c18943";
21
21
  }
22
22
  const { camoxApp, input, queryClient } = t0;
23
23
  const t1 = input.dehydratedState;
24
24
  let t2;
25
- if ($[1] !== camoxApp || $[2] !== input.apiUrl || $[3] !== input.authenticationUrl || $[4] !== input.environmentName || $[5] !== input.presentation || $[6] !== input.projectSlug || $[7] !== queryClient) {
25
+ if ($[1] !== camoxApp || $[2] !== input.apiUrl || $[3] !== input.authenticationUrl || $[4] !== input.environmentName || $[5] !== input.presentation || $[6] !== input.previewHandoff || $[7] !== input.projectSlug || $[8] !== queryClient) {
26
26
  t2 = (currentInput) => /* @__PURE__ */ jsx(CoreCamoxProvider, {
27
27
  camoxApp,
28
28
  authenticationUrl: input.authenticationUrl,
@@ -33,7 +33,10 @@ function PageApp(t0) {
33
33
  initialProject: currentInput.project,
34
34
  children: /* @__PURE__ */ jsx(PreviewDocumentContext.Provider, {
35
35
  value: currentInput.previewDocument,
36
- children: /* @__PURE__ */ jsx(PageExperience, {
36
+ children: input.previewHandoff ? /* @__PURE__ */ jsx("div", {
37
+ role: "status",
38
+ children: "Signing in to draft preview…"
39
+ }) : /* @__PURE__ */ jsx(PageExperience, {
37
40
  camoxApp,
38
41
  input: currentInput,
39
42
  queryClient,
@@ -46,42 +49,43 @@ function PageApp(t0) {
46
49
  $[3] = input.authenticationUrl;
47
50
  $[4] = input.environmentName;
48
51
  $[5] = input.presentation;
49
- $[6] = input.projectSlug;
50
- $[7] = queryClient;
51
- $[8] = t2;
52
- } else t2 = $[8];
52
+ $[6] = input.previewHandoff;
53
+ $[7] = input.projectSlug;
54
+ $[8] = queryClient;
55
+ $[9] = t2;
56
+ } else t2 = $[9];
53
57
  let t3;
54
- if ($[9] !== input || $[10] !== queryClient || $[11] !== t2) {
58
+ if ($[10] !== input || $[11] !== queryClient || $[12] !== t2) {
55
59
  t3 = /* @__PURE__ */ jsx(PageNavigationProvider, {
56
60
  initialInput: input,
57
61
  queryClient,
58
62
  children: t2
59
63
  });
60
- $[9] = input;
61
- $[10] = queryClient;
62
- $[11] = t2;
63
- $[12] = t3;
64
- } else t3 = $[12];
64
+ $[10] = input;
65
+ $[11] = queryClient;
66
+ $[12] = t2;
67
+ $[13] = t3;
68
+ } else t3 = $[13];
65
69
  let t4;
66
- if ($[13] !== t1 || $[14] !== t3) {
70
+ if ($[14] !== t1 || $[15] !== t3) {
67
71
  t4 = /* @__PURE__ */ jsx(HydrationBoundary, {
68
72
  state: t1,
69
73
  children: t3
70
74
  });
71
- $[13] = t1;
72
- $[14] = t3;
73
- $[15] = t4;
74
- } else t4 = $[15];
75
+ $[14] = t1;
76
+ $[15] = t3;
77
+ $[16] = t4;
78
+ } else t4 = $[16];
75
79
  let t5;
76
- if ($[16] !== queryClient || $[17] !== t4) {
80
+ if ($[17] !== queryClient || $[18] !== t4) {
77
81
  t5 = /* @__PURE__ */ jsx(QueryClientProvider, {
78
82
  client: queryClient,
79
83
  children: t4
80
84
  });
81
- $[16] = queryClient;
82
- $[17] = t4;
83
- $[18] = t5;
84
- } else t5 = $[18];
85
+ $[17] = queryClient;
86
+ $[18] = t4;
87
+ $[19] = t5;
88
+ } else t5 = $[19];
85
89
  return t5;
86
90
  }
87
91
  const LazyEditablePageExperience = React.lazy(() => import("../preview/EditablePageExperience.js").then((module) => ({ default: module.EditablePageExperience })));
@@ -101,9 +105,9 @@ var EditingActivationBoundary = class extends React.Component {
101
105
  const subscribeToHydration = () => () => {};
102
106
  function PageExperience(t0) {
103
107
  const $ = c(39);
104
- if ($[0] !== "9929b5234f34e8dc8642da9eb491a90e9a57f3ab875ddfc1a186f42f4452f2f5") {
108
+ if ($[0] !== "cc0d298a8943efca3ffb5e7cf2f8f814ebecbf27dec68e2a3129c1bb95c18943") {
105
109
  for (let $i = 0; $i < 39; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
106
- $[0] = "9929b5234f34e8dc8642da9eb491a90e9a57f3ab875ddfc1a186f42f4452f2f5";
110
+ $[0] = "cc0d298a8943efca3ffb5e7cf2f8f814ebecbf27dec68e2a3129c1bb95c18943";
107
111
  }
108
112
  const { camoxApp, input, queryClient, studioDocument } = t0;
109
113
  const { isAuthenticated, isLoading } = useAuthState();
@@ -1,5 +1,6 @@
1
+ import { prefetchIcons } from "../../core/lib/icons.js";
1
2
  import { PageApp } from "./pageApp.js";
2
- import { QueryClient, hydrate } from "@tanstack/react-query";
3
+ import { QueryClient, dehydrate, hydrate } from "@tanstack/react-query";
3
4
  import { jsx } from "react/jsx-runtime";
4
5
  import { renderToString } from "react-dom/server";
5
6
 
@@ -7,6 +8,8 @@ import { renderToString } from "react-dom/server";
7
8
  async function renderPageWithApp(input) {
8
9
  const queryClient = new QueryClient();
9
10
  hydrate(queryClient, input.dehydratedState);
11
+ await prefetchIcons(queryClient, input.dehydratedState, input.camoxApp.getSerializableDefinitions());
12
+ Object.assign(input.dehydratedState, dehydrate(queryClient));
10
13
  return renderToString(/* @__PURE__ */ jsx(PageApp, {
11
14
  camoxApp: input.camoxApp,
12
15
  input,
@@ -17,6 +17,8 @@ interface LayoutIdentity {
17
17
  version: string;
18
18
  }
19
19
  interface PageRenderInput {
20
+ /** Authenticate before looking up a page that may exist only in draft. */
21
+ previewHandoff?: boolean;
20
22
  previewDocument?: string;
21
23
  routeKind?: "studio" | "studio-content" | "studio-nested";
22
24
  project?: Awaited<ReturnType<ReturnType<typeof createServerApiClient>["projects"]["getBySlug"]>>;
@@ -208,6 +208,31 @@ async function createPageHtmlResponse({ options, pathname, request }) {
208
208
  pathname,
209
209
  request
210
210
  });
211
+ const requestUrl = new URL(request.url);
212
+ if (requestUrl.searchParams.has("camox-preview") && requestUrl.searchParams.has("ott")) {
213
+ const input = {
214
+ previewHandoff: true,
215
+ presentation: "public",
216
+ source: "live",
217
+ apiUrl: options.apiUrl,
218
+ authenticationUrl: options.authenticationUrl,
219
+ environmentName: options.environmentName,
220
+ projectSlug: options.projectSlug,
221
+ href: requestUrl.href,
222
+ pathname,
223
+ runtimeBasePath: normalizeRuntimeBasePath(options.runtimeBasePath),
224
+ head: {},
225
+ loaderData: null,
226
+ layoutIdentity: null,
227
+ dehydratedState: dehydrate(new QueryClient())
228
+ };
229
+ const html = await options.renderPage(input);
230
+ return new Response(`<!doctype html><html><head><meta name="referrer" content="no-referrer"><title>Camox draft preview</title><script id="__CAMOX_DATA__" type="application/json">${serializeJsonForHtml(input)}<\/script></head><body><div id="root">${html}</div>${renderClientEntryScript(options.pageClientEntryUrl)}</body></html>`, { headers: {
231
+ "Content-Type": "text/html; charset=utf-8",
232
+ "Cache-Control": "private, no-store",
233
+ "Referrer-Policy": "no-referrer"
234
+ } });
235
+ }
211
236
  const singleton = await createDerivedResponse(options, pathname, request, false, true);
212
237
  if (singleton) return singleton;
213
238
  const queryClient = new QueryClient();
@@ -1,5 +1,6 @@
1
1
  import { AuthContext } from "../../../lib/auth.js";
2
2
  import { environmentMutations, environmentQueries, projectQueries } from "../../../lib/queries.js";
3
+ import { areCommentsEnabled } from "../../preview/commentsEnabled.js";
3
4
  import { c } from "react/compiler-runtime";
4
5
  import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
5
6
  import * as React from "react";
@@ -36,10 +37,10 @@ function formatReason(reason, direction) {
36
37
  }
37
38
  }
38
39
  const EnvironmentMenu = () => {
39
- const $ = c(84);
40
- if ($[0] !== "5eec2ee2385ce7d4417564ed3e8ad71e1d521ff3c557dea4a4ca42288fb12d99") {
41
- for (let $i = 0; $i < 84; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
42
- $[0] = "5eec2ee2385ce7d4417564ed3e8ad71e1d521ff3c557dea4a4ca42288fb12d99";
40
+ const $ = c(87);
41
+ if ($[0] !== "a19764fc2cadba3ca96828ce487913043214419dfe0474e5a0ab5e6e8d2d6177") {
42
+ for (let $i = 0; $i < 87; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
43
+ $[0] = "a19764fc2cadba3ca96828ce487913043214419dfe0474e5a0ab5e6e8d2d6177";
43
44
  }
44
45
  const [open, setOpen] = React.useState(false);
45
46
  const [pendingDirection, setPendingDirection] = React.useState(null);
@@ -302,7 +303,7 @@ const EnvironmentMenu = () => {
302
303
  } else t25 = $[55];
303
304
  let t26;
304
305
  if ($[56] !== environmentName || $[57] !== pendingDirection) {
305
- t26 = /* @__PURE__ */ jsx(AlertDialogDescription, { children: pendingDirection === "push" ? /* @__PURE__ */ jsxs(Fragment, { children: [
306
+ t26 = pendingDirection === "push" ? /* @__PURE__ */ jsxs(Fragment, { children: [
306
307
  "This will replace all content in",
307
308
  " ",
308
309
  /* @__PURE__ */ jsx("span", {
@@ -329,84 +330,95 @@ const EnvironmentMenu = () => {
329
330
  children: "production"
330
331
  }),
331
332
  ". This action cannot be undone."
332
- ] }) });
333
+ ] });
333
334
  $[56] = environmentName;
334
335
  $[57] = pendingDirection;
335
336
  $[58] = t26;
336
337
  } else t26 = $[58];
337
338
  let t27;
338
- if ($[59] !== t25 || $[60] !== t26) {
339
- t27 = /* @__PURE__ */ jsxs(AlertDialogHeader, { children: [t25, t26] });
340
- $[59] = t25;
341
- $[60] = t26;
342
- $[61] = t27;
343
- } else t27 = $[61];
339
+ if ($[59] === Symbol.for("react.memo_cache_sentinel")) {
340
+ t27 = areCommentsEnabled() && " Feedback comments in the destination will also be replaced.";
341
+ $[59] = t27;
342
+ } else t27 = $[59];
344
343
  let t28;
345
- if ($[62] !== replicate.isPending) {
346
- t28 = /* @__PURE__ */ jsx(AlertDialogCancel, {
344
+ if ($[60] !== t26) {
345
+ t28 = /* @__PURE__ */ jsxs(AlertDialogDescription, { children: [t26, t27] });
346
+ $[60] = t26;
347
+ $[61] = t28;
348
+ } else t28 = $[61];
349
+ let t29;
350
+ if ($[62] !== t25 || $[63] !== t28) {
351
+ t29 = /* @__PURE__ */ jsxs(AlertDialogHeader, { children: [t25, t28] });
352
+ $[62] = t25;
353
+ $[63] = t28;
354
+ $[64] = t29;
355
+ } else t29 = $[64];
356
+ let t30;
357
+ if ($[65] !== replicate.isPending) {
358
+ t30 = /* @__PURE__ */ jsx(AlertDialogCancel, {
347
359
  variant: "outline",
348
360
  size: "default",
349
361
  disabled: replicate.isPending,
350
362
  children: "Cancel"
351
363
  });
352
- $[62] = replicate.isPending;
353
- $[63] = t28;
354
- } else t28 = $[63];
355
- let t29;
356
- if ($[64] !== replicate.isPending) {
357
- t29 = replicate.isPending ? /* @__PURE__ */ jsx(Spinner, {}) : null;
358
- $[64] = replicate.isPending;
359
- $[65] = t29;
360
- } else t29 = $[65];
361
- const t30 = pendingDirection === "push" ? "Push" : "Pull";
364
+ $[65] = replicate.isPending;
365
+ $[66] = t30;
366
+ } else t30 = $[66];
362
367
  let t31;
363
- if ($[66] !== handleConfirm || $[67] !== replicate.isPending || $[68] !== t29 || $[69] !== t30) {
364
- t31 = /* @__PURE__ */ jsxs(AlertDialogAction, {
368
+ if ($[67] !== replicate.isPending) {
369
+ t31 = replicate.isPending ? /* @__PURE__ */ jsx(Spinner, {}) : null;
370
+ $[67] = replicate.isPending;
371
+ $[68] = t31;
372
+ } else t31 = $[68];
373
+ const t32 = pendingDirection === "push" ? "Push" : "Pull";
374
+ let t33;
375
+ if ($[69] !== handleConfirm || $[70] !== replicate.isPending || $[71] !== t31 || $[72] !== t32) {
376
+ t33 = /* @__PURE__ */ jsxs(AlertDialogAction, {
365
377
  variant: "destructive",
366
378
  onClick: handleConfirm,
367
379
  disabled: replicate.isPending,
368
- children: [t29, t30]
380
+ children: [t31, t32]
369
381
  });
370
- $[66] = handleConfirm;
371
- $[67] = replicate.isPending;
372
- $[68] = t29;
373
- $[69] = t30;
374
- $[70] = t31;
375
- } else t31 = $[70];
376
- let t32;
377
- if ($[71] !== t28 || $[72] !== t31) {
378
- t32 = /* @__PURE__ */ jsxs(AlertDialogFooter, { children: [t28, t31] });
379
- $[71] = t28;
380
- $[72] = t31;
381
- $[73] = t32;
382
- } else t32 = $[73];
383
- let t33;
384
- if ($[74] !== t27 || $[75] !== t32) {
385
- t33 = /* @__PURE__ */ jsxs(AlertDialogContent, { children: [t27, t32] });
386
- $[74] = t27;
387
- $[75] = t32;
388
- $[76] = t33;
389
- } else t33 = $[76];
382
+ $[69] = handleConfirm;
383
+ $[70] = replicate.isPending;
384
+ $[71] = t31;
385
+ $[72] = t32;
386
+ $[73] = t33;
387
+ } else t33 = $[73];
390
388
  let t34;
391
- if ($[77] !== t22 || $[78] !== t23 || $[79] !== t33) {
392
- t34 = /* @__PURE__ */ jsx(AlertDialog, {
389
+ if ($[74] !== t30 || $[75] !== t33) {
390
+ t34 = /* @__PURE__ */ jsxs(AlertDialogFooter, { children: [t30, t33] });
391
+ $[74] = t30;
392
+ $[75] = t33;
393
+ $[76] = t34;
394
+ } else t34 = $[76];
395
+ let t35;
396
+ if ($[77] !== t29 || $[78] !== t34) {
397
+ t35 = /* @__PURE__ */ jsxs(AlertDialogContent, { children: [t29, t34] });
398
+ $[77] = t29;
399
+ $[78] = t34;
400
+ $[79] = t35;
401
+ } else t35 = $[79];
402
+ let t36;
403
+ if ($[80] !== t22 || $[81] !== t23 || $[82] !== t35) {
404
+ t36 = /* @__PURE__ */ jsx(AlertDialog, {
393
405
  open: t22,
394
406
  onOpenChange: t23,
395
- children: t33
407
+ children: t35
396
408
  });
397
- $[77] = t22;
398
- $[78] = t23;
399
- $[79] = t33;
400
- $[80] = t34;
401
- } else t34 = $[80];
402
- let t35;
403
- if ($[81] !== t21 || $[82] !== t34) {
404
- t35 = /* @__PURE__ */ jsxs(Fragment, { children: [t21, t34] });
405
- $[81] = t21;
406
- $[82] = t34;
407
- $[83] = t35;
408
- } else t35 = $[83];
409
- return t35;
409
+ $[80] = t22;
410
+ $[81] = t23;
411
+ $[82] = t35;
412
+ $[83] = t36;
413
+ } else t36 = $[83];
414
+ let t37;
415
+ if ($[84] !== t21 || $[85] !== t36) {
416
+ t37 = /* @__PURE__ */ jsxs(Fragment, { children: [t21, t36] });
417
+ $[84] = t21;
418
+ $[85] = t36;
419
+ $[86] = t37;
420
+ } else t37 = $[86];
421
+ return t37;
410
422
  };
411
423
 
412
424
  //#endregion
@@ -1,52 +1,3 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
- import os from "node:os";
1
+ import { readAuthTokenForUrl, verifyOneTimeToken, writeAuthTokenForUrl } from "@camox/cli/auth";
4
2
 
5
- //#region src/features/vite/auth.ts
6
- const AUTH_DIR = path.join(os.homedir(), ".camox");
7
- const AUTH_FILE = path.join(AUTH_DIR, "auth.json");
8
- function normalizeUrl(url) {
9
- return url.replace(/\/+$/, "");
10
- }
11
- function readAllTokens() {
12
- try {
13
- return JSON.parse(fs.readFileSync(AUTH_FILE, "utf-8"));
14
- } catch {
15
- return {};
16
- }
17
- }
18
- function writeAllTokens(tokens) {
19
- fs.mkdirSync(AUTH_DIR, { recursive: true });
20
- fs.writeFileSync(AUTH_FILE, JSON.stringify(tokens, null, 2), { mode: 384 });
21
- }
22
- function readAuthTokenForUrl(authenticationUrl) {
23
- const entry = readAllTokens()[normalizeUrl(authenticationUrl)];
24
- if (entry?.token && entry?.name && typeof entry.email === "string") return entry;
25
- return null;
26
- }
27
- function writeAuthTokenForUrl(authenticationUrl, token) {
28
- const tokens = readAllTokens();
29
- tokens[normalizeUrl(authenticationUrl)] = token;
30
- writeAllTokens(tokens);
31
- }
32
- async function verifyOneTimeToken(apiUrl, token) {
33
- const response = await fetch(`${normalizeUrl(apiUrl)}/api/auth/one-time-token/verify`, {
34
- method: "POST",
35
- headers: { "Content-Type": "application/json" },
36
- body: JSON.stringify({ token })
37
- });
38
- if (!response.ok) throw new Error(`OTT verification failed: ${response.status}`);
39
- const data = await response.json();
40
- const user = data.user;
41
- if (!user?.name) throw new Error("No user info in verification response");
42
- const sessionToken = data.session?.token;
43
- if (!sessionToken) throw new Error("No session token in verification response");
44
- return {
45
- name: user.name,
46
- email: user.email ?? "",
47
- token: sessionToken
48
- };
49
- }
50
-
51
- //#endregion
52
3
  export { readAuthTokenForUrl, verifyOneTimeToken, writeAuthTokenForUrl };
@@ -0,0 +1,16 @@
1
+ import { iconCollectionIds, loadIconCollection } from "@camox/api-contract";
2
+ import { mkdirSync, writeFileSync } from "node:fs";
3
+ import { resolve } from "node:path";
4
+
5
+ //#region src/features/vite/iconGeneration.ts
6
+ async function generateIconTypes(root, prefix) {
7
+ const ids = prefix ? iconCollectionIds(await loadIconCollection(prefix)) : [];
8
+ mkdirSync(resolve(root, "src/camox"), { recursive: true });
9
+ const union = ids.map((id) => JSON.stringify(id));
10
+ const type = union.length > 1 ? `\n | ${union.join("\n | ")}` : union[0] ?? "never";
11
+ writeFileSync(resolve(root, "src/camox/icons.gen.d.ts"), `// Generated by Camox. Do not edit.\nexport {};\ndeclare global {\n interface CamoxIconRegistry {\n ids:${union.length > 1 ? "" : " "}${type};\n }\n}\n`);
12
+ return ids;
13
+ }
14
+
15
+ //#endregion
16
+ export { generateIconTypes };
@@ -23,14 +23,16 @@ type CamoxVitePlugin = Plugin & {
23
23
  interface CamoxPluginOptions {
24
24
  /** Stable, human-readable slug identifying this project (e.g. "prestigious-impala-84") */
25
25
  projectSlug: string;
26
+ /** Iconify collection available to all icon fields. */
27
+ icons?: string;
26
28
  /** Disable telemetry collection (default: false) */
27
29
  disableTelemetry?: boolean;
28
30
  /** Internal options (intended for Camox contributors in development, not for public use) */
29
31
  _internal?: {
30
32
  /** URL of the Camox API backend, used for data fetching */apiUrl?: string; /** URL of the Camox authentication backend (default: https://app.camox.dev) */
31
33
  authenticationUrl?: string; /** Show Tanstack query devtools (default: false) */
32
- enableTanstackDevtools?: boolean; /** Enable the frontend-only comments prototype (default: false). */
33
- enableComments?: boolean; /** Disable automatic code generation (route files and app file) (default: false) */
34
+ enableTanstackDevtools?: boolean; /** Enable experimental features, including feedback (default: false). */
35
+ enableExperimentalFeatures?: boolean; /** Disable automatic code generation (route files and app file) (default: false) */
34
36
  disableCodeGen?: boolean; /** Mount the Camox-owned dev runtime at this base path. Use "/" for root mode. */
35
37
  runtimeBasePath?: string;
36
38
  };