camox 0.33.1 → 0.34.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 (94) hide show
  1. package/dist/core/createBlock.js +19 -19
  2. package/dist/core/defineDocument.d.ts +7 -0
  3. package/dist/core/defineDocument.js +7 -0
  4. package/dist/features/agent-chat/components/AgentChatSidebar.js +3 -3
  5. package/dist/features/agent-chat/components/AgentChatThread.js +5 -5
  6. package/dist/features/navigation/navigation.d.ts +39 -0
  7. package/dist/features/navigation/navigation.js +231 -0
  8. package/dist/features/preview/CamoxPreview.d.ts +3 -0
  9. package/dist/features/preview/CamoxPreview.js +12 -12
  10. package/dist/features/preview/components/AddBlockSidebar.js +4 -4
  11. package/dist/features/preview/components/CreatePageModal.js +3 -3
  12. package/dist/features/preview/components/FieldToolbar.js +1 -1
  13. package/dist/features/preview/components/PageInfoSidebar.js +23 -23
  14. package/dist/features/preview/components/PageNavigatorSidebar.js +6 -6
  15. package/dist/features/preview/components/PagePicker.js +1 -1
  16. package/dist/features/preview/components/useUpdateBlockPosition.js +3 -3
  17. package/dist/features/provider/CamoxProvider.js +10 -8
  18. package/dist/features/routes/pageRuntime.js +6 -0
  19. package/dist/features/runtime/pageApp.js +75 -0
  20. package/dist/features/runtime/pageClient.d.ts +7 -0
  21. package/dist/features/runtime/pageClient.js +37 -0
  22. package/dist/features/runtime/pageNavigation.js +170 -0
  23. package/dist/features/runtime/pageServer.d.ts +9 -0
  24. package/dist/features/runtime/pageServer.js +18 -0
  25. package/dist/features/runtime/runtime.d.ts +24 -0
  26. package/dist/features/runtime/runtime.js +44 -0
  27. package/dist/features/runtime/studioApp.d.ts +15 -0
  28. package/dist/features/runtime/studioApp.js +117 -0
  29. package/dist/features/runtime/studioNavigation.js +115 -0
  30. package/dist/features/runtime/studioServer.d.ts +9 -0
  31. package/dist/features/runtime/studioServer.js +18 -0
  32. package/dist/features/studio/CamoxStudio.js +3 -3
  33. package/dist/features/studio/components/Navbar.js +7 -7
  34. package/dist/features/studio/components/ProjectMenu.js +9 -9
  35. package/dist/features/studio/components/UserButton.js +3 -3
  36. package/dist/features/vite/appGeneration.js +16 -5
  37. package/dist/features/vite/blockBoilerplate.js +1 -1
  38. package/dist/features/vite/definitionsSync.js +4 -4
  39. package/dist/features/vite/routeGeneration.js +9 -156
  40. package/dist/features/vite/runtimeDev.js +270 -0
  41. package/dist/features/vite/utils.js +3 -1
  42. package/dist/features/vite/vite.d.ts +22 -3
  43. package/dist/features/vite/vite.js +36 -19
  44. package/dist/lib/auth.js +42 -68
  45. package/dist/lib/telemetry.js +1 -24
  46. package/dist/lib/utils.js +1 -1
  47. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/Matches.d.ts +114 -0
  48. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/RouterProvider.d.ts +25 -0
  49. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/config.d.ts +1 -0
  50. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/defer.d.ts +1 -0
  51. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/fileRoute.d.ts +20 -0
  52. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/global.d.ts +8 -0
  53. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/hash-scroll.d.ts +1 -0
  54. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/index.d.ts +18 -0
  55. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/link.d.ts +161 -0
  56. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/load-matches.d.ts +6 -0
  57. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/location.d.ts +54 -0
  58. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/lru-cache.d.ts +8 -0
  59. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/manifest.d.ts +32 -0
  60. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/new-process-route-tree.d.ts +115 -0
  61. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/not-found.d.ts +1 -0
  62. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/redirect.d.ts +49 -0
  63. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/rewrite.d.ts +1 -0
  64. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/root.d.ts +6 -0
  65. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/route.d.ts +343 -0
  66. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/routeInfo.d.ts +48 -0
  67. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/router.d.ts +695 -0
  68. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/scroll-restoration.d.ts +1 -0
  69. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/searchMiddleware.d.ts +1 -0
  70. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/searchParams.d.ts +5 -0
  71. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/ssr/serializer/RawStream.d.ts +38 -0
  72. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/ssr/serializer/seroval-plugins.d.ts +1 -0
  73. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/ssr/serializer/transformer.d.ts +65 -0
  74. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/stores.d.ts +69 -0
  75. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/structuralSharing.d.ts +1 -0
  76. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/typePrimitives.d.ts +1 -0
  77. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/useLoaderData.d.ts +1 -0
  78. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/useLoaderDeps.d.ts +1 -0
  79. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/useNavigate.d.ts +10 -0
  80. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/useParams.d.ts +1 -0
  81. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/useRouteContext.d.ts +1 -0
  82. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/useSearch.d.ts +1 -0
  83. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/utils.d.ts +28 -0
  84. package/dist/node_modules/.pnpm/@tanstack_router-core@1.168.14/node_modules/@tanstack/router-core/dist/esm/validators.d.ts +49 -0
  85. package/package.json +34 -12
  86. package/skills/camox-block/SKILL.md +4 -4
  87. package/skills/camox-cli/SKILL.md +3 -3
  88. package/skills/camox-layout/SKILL.md +2 -2
  89. package/dist/features/routes/ogRoute.d.ts +0 -12
  90. package/dist/features/routes/ogRoute.js +0 -20
  91. package/dist/features/routes/pageRoute.d.ts +0 -48
  92. package/dist/features/routes/pageRoute.js +0 -254
  93. package/dist/lib/api-client.d.ts +0 -7
  94. package/dist/lib/queries.d.ts +0 -12
@@ -1,5 +1,4 @@
1
1
  import { STUDIO_ROUTE_SEGMENT } from "../studio/routes.js";
2
- import { writeIfChanged } from "./utils.js";
3
2
  import { mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
4
3
  import { relative, resolve } from "node:path";
5
4
 
@@ -16,132 +15,6 @@ const HEADER = `/* =============================================================
16
15
  // @ts-nocheck
17
16
 
18
17
  `;
19
- function generatePageRoute(authenticationUrl) {
20
- return HEADER + `import { createFileRoute } from "@tanstack/react-router";
21
- import {
22
- createMarkdownMiddleware,
23
- createPageLoader,
24
- createPageHead,
25
- PageRouteComponent,
26
- } from "camox/_internal/pageRoute";
27
- import { CamoxProvider } from "camox/CamoxProvider";
28
- import { camoxApp } from "@/camox/app";
29
-
30
- const markdownMiddleware = createMarkdownMiddleware(__CAMOX_API_URL__, __CAMOX_PROJECT_SLUG__, __CAMOX_ENVIRONMENT_NAME__);
31
- const loader = createPageLoader(__CAMOX_API_URL__, __CAMOX_PROJECT_SLUG__, __CAMOX_ENVIRONMENT_NAME__);
32
- const head = createPageHead(camoxApp);
33
-
34
- export const Route = createFileRoute("/(camox)/(_preview)/$")({
35
- server: {
36
- middleware: [markdownMiddleware],
37
- },
38
- component: RouteComponent,
39
- notFoundComponent: () => <div>No Camox page on this path</div>,
40
- loader,
41
- head,
42
- });
43
-
44
- function RouteComponent() {
45
- return (
46
- <CamoxProvider camoxApp={camoxApp} authenticationUrl="${authenticationUrl}" apiUrl={__CAMOX_API_URL__} projectSlug={__CAMOX_PROJECT_SLUG__} environmentName={__CAMOX_ENVIRONMENT_NAME__}>
47
- <PageRouteComponent />
48
- </CamoxProvider>
49
- );
50
- }
51
- `;
52
- }
53
- function generateOgRoute() {
54
- return HEADER + `import { createFileRoute } from "@tanstack/react-router";
55
- import { createOgHandler } from "camox/_internal/ogRoute";
56
- import { camoxApp } from "@/camox/app";
57
-
58
- export const Route = createFileRoute("/(camox)/(_preview)/og")({
59
- server: {
60
- handlers: createOgHandler(camoxApp),
61
- },
62
- });
63
- `;
64
- }
65
- function generateCamoxStudio(authenticationUrl) {
66
- return HEADER + `import { Outlet, createFileRoute } from "@tanstack/react-router";
67
- import { CamoxProvider } from "camox/CamoxProvider";
68
- import { CamoxStudio } from "camox/CamoxStudio";
69
- import { camoxApp } from "@/camox/app";
70
-
71
- export const Route = createFileRoute("/(camox)/(_studio)/${STUDIO_ROUTE_SEGMENT}")({
72
- component: RouteComponent,
73
- notFoundComponent: () => <div>Studio page not found</div>,
74
- });
75
-
76
- function RouteComponent() {
77
- return (
78
- <CamoxProvider camoxApp={camoxApp} authenticationUrl="${authenticationUrl}" apiUrl={__CAMOX_API_URL__} projectSlug={__CAMOX_PROJECT_SLUG__} environmentName={__CAMOX_ENVIRONMENT_NAME__}>
79
- <CamoxStudio>
80
- <Outlet />
81
- </CamoxStudio>
82
- </CamoxProvider>
83
- );
84
- }
85
- `;
86
- }
87
- function generateCamoxStudioCatchAll() {
88
- return HEADER + `import { Outlet, createFileRoute } from "@tanstack/react-router";
89
- import { CamoxStudio } from "camox/CamoxStudio";
90
-
91
- export const Route = createFileRoute("/(camox)/(_studio)/${STUDIO_ROUTE_SEGMENT}/$")({
92
- component: RouteComponent,
93
- notFoundComponent: () => <div>Studio page not found</div>,
94
- });
95
-
96
- function RouteComponent() {
97
- return (
98
- <CamoxStudio>
99
- <Outlet />
100
- </CamoxStudio>
101
- );
102
- }
103
- `;
104
- }
105
- function generateCamoxStudioContent() {
106
- return HEADER + `import { createFileRoute } from "@tanstack/react-router";
107
- import { CamoxContent } from "camox/CamoxContent";
108
-
109
- export const Route = createFileRoute("/(camox)/(_studio)/${STUDIO_ROUTE_SEGMENT}/content")({
110
- component: RouteComponent,
111
- });
112
-
113
- function RouteComponent() {
114
- return <CamoxContent />;
115
- }
116
- `;
117
- }
118
- function getRouteFileEntries({ routesDir, authenticationUrl }) {
119
- const groupDir = resolve(routesDir, "(camox)");
120
- const previewDir = resolve(groupDir, "(_preview)");
121
- const studioDir = resolve(groupDir, "(_studio)");
122
- return [
123
- {
124
- path: resolve(previewDir, "$.tsx"),
125
- content: generatePageRoute(authenticationUrl)
126
- },
127
- {
128
- path: resolve(previewDir, "og.tsx"),
129
- content: generateOgRoute()
130
- },
131
- {
132
- path: resolve(studioDir, `${STUDIO_ROUTE_SEGMENT}.tsx`),
133
- content: generateCamoxStudio(authenticationUrl)
134
- },
135
- {
136
- path: resolve(studioDir, `${STUDIO_ROUTE_SEGMENT}.$.tsx`),
137
- content: generateCamoxStudioCatchAll()
138
- },
139
- {
140
- path: resolve(studioDir, `${STUDIO_ROUTE_SEGMENT}.content.tsx`),
141
- content: generateCamoxStudioContent()
142
- }
143
- ];
144
- }
145
18
  function removeObsoleteRouteFiles(routesDir) {
146
19
  const camoxDir = resolve(routesDir, "_camox");
147
20
  const studioDir = resolve(routesDir, "(camox)", "(_studio)");
@@ -156,7 +29,12 @@ function removeObsoleteRouteFiles(routesDir) {
156
29
  resolve(studioDir, "cmx.tsx"),
157
30
  resolve(studioDir, "cmx-studio.tsx"),
158
31
  resolve(studioDir, "cmx-studio.$.tsx"),
159
- resolve(studioDir, "cmx-studio.content.tsx")
32
+ resolve(studioDir, "cmx-studio.content.tsx"),
33
+ resolve(routesDir, "(camox)", "(_preview)", "$.tsx"),
34
+ resolve(routesDir, "(camox)", "(_preview)", "og.tsx"),
35
+ resolve(studioDir, `${STUDIO_ROUTE_SEGMENT}.tsx`),
36
+ resolve(studioDir, `${STUDIO_ROUTE_SEGMENT}.$.tsx`),
37
+ resolve(studioDir, `${STUDIO_ROUTE_SEGMENT}.content.tsx`)
160
38
  ];
161
39
  for (const filePath of obsoletePaths) try {
162
40
  if (!readFileSync(filePath, "utf-8").startsWith(HEADER)) continue;
@@ -166,34 +44,9 @@ function removeObsoleteRouteFiles(routesDir) {
166
44
  throw error;
167
45
  }
168
46
  }
169
- function generateRouteFiles(options) {
170
- const groupDir = resolve(options.routesDir, "(camox)");
171
- mkdirSync(resolve(groupDir, "(_preview)"), { recursive: true });
172
- mkdirSync(resolve(groupDir, "(_studio)"), { recursive: true });
173
- removeObsoleteRouteFiles(options.routesDir);
174
- for (const entry of getRouteFileEntries(options)) writeIfChanged(entry.path, entry.content);
175
- }
176
- function watchRouteFiles(options) {
177
- const { server, ...routeFilesOptions } = options;
178
- const entries = getRouteFileEntries(routeFilesOptions);
179
- const expectedByPath = new Map(entries.map((e) => [e.path, e.content]));
180
- server.watcher.on("change", (changedPath) => {
181
- const expected = expectedByPath.get(changedPath);
182
- if (!expected) return;
183
- if (readFileSync(changedPath, "utf-8") !== expected) {
184
- const rel = relative(server.config.root, changedPath);
185
- server.config.logger.warn(`Camox route file "${rel}" was modified — reverting to generated version.`, { timestamp: true });
186
- writeFileSync(changedPath, expected, "utf-8");
187
- }
188
- });
189
- server.watcher.on("unlink", (deletedPath) => {
190
- const expected = expectedByPath.get(deletedPath);
191
- if (!expected) return;
192
- const rel = relative(server.config.root, deletedPath);
193
- server.config.logger.warn(`Camox route file "${rel}" was deleted — recreating.`, { timestamp: true });
194
- writeFileSync(deletedPath, expected, "utf-8");
195
- });
47
+ function cleanupGeneratedRouteFiles(routesDir) {
48
+ removeObsoleteRouteFiles(routesDir);
196
49
  }
197
50
 
198
51
  //#endregion
199
- export { generateRouteFiles, watchRouteFiles };
52
+ export { cleanupGeneratedRouteFiles };
@@ -0,0 +1,270 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { dirname, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ //#region src/features/vite/runtimeDev.ts
6
+ const sdkRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../../..");
7
+ const VIRTUAL_CAMOX_APP = "virtual:camox/app";
8
+ const RESOLVED_VIRTUAL_CAMOX_APP = "\0" + VIRTUAL_CAMOX_APP;
9
+ const VIRTUAL_CAMOX_DOCUMENT = "virtual:camox/document";
10
+ const RESOLVED_VIRTUAL_CAMOX_DOCUMENT = "\0" + VIRTUAL_CAMOX_DOCUMENT;
11
+ const VIRTUAL_CAMOX_SERVER = "virtual:camox/server";
12
+ const RESOLVED_VIRTUAL_CAMOX_SERVER = "\0" + VIRTUAL_CAMOX_SERVER;
13
+ const VIRTUAL_CAMOX_NITRO_HANDLER = "#camox/nitro-handler";
14
+ const VIRTUAL_PAGE_SERVER = "virtual:camox/page-server";
15
+ const RESOLVED_VIRTUAL_PAGE_SERVER = "\0" + VIRTUAL_PAGE_SERVER;
16
+ const VIRTUAL_STUDIO_SERVER = "virtual:camox/studio-server";
17
+ const RESOLVED_VIRTUAL_STUDIO_SERVER = "\0" + VIRTUAL_STUDIO_SERVER;
18
+ const VIRTUAL_PAGE_CLIENT = "virtual:camox/page-client";
19
+ const RESOLVED_VIRTUAL_PAGE_CLIENT = "\0" + VIRTUAL_PAGE_CLIENT;
20
+ const VIRTUAL_PAGE_CLIENT_URL = "virtual:camox/page-client-url";
21
+ const RESOLVED_VIRTUAL_PAGE_CLIENT_URL = "\0" + VIRTUAL_PAGE_CLIENT_URL;
22
+ const VIRTUAL_APP_STYLESHEET_URL = "virtual:camox/app-stylesheet-url";
23
+ const RESOLVED_VIRTUAL_APP_STYLESHEET_URL = "\0" + VIRTUAL_APP_STYLESHEET_URL;
24
+ const VIRTUAL_STUDIO_CSS = "virtual:camox-studio-css";
25
+ const RESOLVED_VIRTUAL_STUDIO_CSS = "\0" + VIRTUAL_STUDIO_CSS;
26
+ const VIRTUAL_OVERLAY_CSS = "virtual:camox-overlay-css";
27
+ const RESOLVED_VIRTUAL_OVERLAY_CSS = "\0" + VIRTUAL_OVERLAY_CSS;
28
+ function normalizeImporterPath(importer) {
29
+ if (!importer) return "";
30
+ const [path] = importer.split("?");
31
+ if (path.startsWith("file://")) return fileURLToPath(path);
32
+ if (path.startsWith("/@fs/")) return path.slice(4);
33
+ return path;
34
+ }
35
+ function resolveSdkAlias(id, importer) {
36
+ if (!id.startsWith("@/")) return;
37
+ const normalizedImporter = normalizeImporterPath(importer).replaceAll("\\", "/");
38
+ const normalizedSdkSrc = resolve(sdkRoot, "src").replaceAll("\\", "/");
39
+ if (!normalizedImporter.includes(`${normalizedSdkSrc}/`)) return;
40
+ const basePath = resolve(sdkRoot, "src", id.slice(2));
41
+ return [
42
+ basePath,
43
+ `${basePath}.ts`,
44
+ `${basePath}.tsx`,
45
+ resolve(basePath, "index.ts")
46
+ ].find((candidate) => existsSync(candidate));
47
+ }
48
+ function resolveCamoxSourceImport(id) {
49
+ return {
50
+ "camox/createApp": resolve(sdkRoot, "src/core/createApp.ts"),
51
+ "camox/createBlock": resolve(sdkRoot, "src/core/createBlock.tsx"),
52
+ "camox/createLayout": resolve(sdkRoot, "src/core/createLayout.tsx"),
53
+ "camox/document": resolve(sdkRoot, "src/core/defineDocument.ts"),
54
+ "camox/CamoxProvider": resolve(sdkRoot, "src/features/provider/CamoxProvider.tsx"),
55
+ "camox/CamoxPreview": resolve(sdkRoot, "src/features/preview/CamoxPreview.tsx"),
56
+ "camox/navigation": resolve(sdkRoot, "src/features/navigation/navigation.tsx"),
57
+ "camox/_internal/pageServer": resolve(sdkRoot, "src/features/runtime/pageServer.tsx"),
58
+ "camox/_internal/pageClient": resolve(sdkRoot, "src/features/runtime/pageClient.tsx"),
59
+ "camox/_internal/studioServer": resolve(sdkRoot, "src/features/runtime/studioServer.tsx"),
60
+ "camox/_internal/runtime": resolve(sdkRoot, "src/features/runtime/runtime.ts")
61
+ }[id];
62
+ }
63
+ function generateVirtualCamoxApp() {
64
+ return `import { createApp } from "camox/createApp";
65
+
66
+ const rootBlockModules = import.meta.glob("/src/blocks/*.{ts,tsx}", { eager: true });
67
+ const legacyBlockModules = import.meta.glob("/src/camox/blocks/*.{ts,tsx}", { eager: true });
68
+ const rootLayoutModules = import.meta.glob("/src/layouts/*.{ts,tsx}", { eager: true });
69
+ const legacyLayoutModules = import.meta.glob("/src/camox/layouts/*.{ts,tsx}", { eager: true });
70
+
71
+ const blocks = [...Object.values(rootBlockModules), ...Object.values(legacyBlockModules)]
72
+ .map((mod) => mod.block)
73
+ .filter(Boolean);
74
+ const layouts = [...Object.values(rootLayoutModules), ...Object.values(legacyLayoutModules)]
75
+ .map((mod) => mod.layout)
76
+ .filter(Boolean);
77
+
78
+ export const camoxApp = createApp({ blocks, layouts });
79
+ `;
80
+ }
81
+ function generateVirtualCamoxDocument() {
82
+ return `const documentModules = import.meta.glob("/src/document.{ts,tsx}", { eager: true });
83
+ const documents = Object.values(documentModules)
84
+ .map((mod) => mod.default)
85
+ .filter(Boolean);
86
+
87
+ export const camoxDocument = documents[0] ?? {};
88
+ `;
89
+ }
90
+ function generateVirtualPageServer() {
91
+ return `import { renderPageWithApp } from "camox/_internal/pageServer";
92
+ import { camoxApp } from "virtual:camox/app";
93
+
94
+ export async function renderPage(input) {
95
+ return renderPageWithApp({ ...input, camoxApp });
96
+ }
97
+ `;
98
+ }
99
+ function generateVirtualStudioServer() {
100
+ return `import { renderStudioWithApp } from "camox/_internal/studioServer";
101
+ import { camoxApp } from "virtual:camox/app";
102
+
103
+ export async function renderStudio(input) {
104
+ return renderStudioWithApp({ ...input, camoxApp });
105
+ }
106
+ `;
107
+ }
108
+ function generateVirtualPageClient() {
109
+ return `import { hydrateRuntimeWithApp } from "camox/_internal/pageClient";
110
+ import { camoxApp } from "virtual:camox/app";
111
+
112
+ hydrateRuntimeWithApp(camoxApp);
113
+ `;
114
+ }
115
+ function wrapViteDevId(id) {
116
+ return `/@id/${id.replace("\0", "__x00__")}`;
117
+ }
118
+ function generateVirtualPageClientUrl() {
119
+ return `export default ${JSON.stringify(wrapViteDevId(RESOLVED_VIRTUAL_PAGE_CLIENT))};`;
120
+ }
121
+ function generateVirtualAppStylesheetUrl() {
122
+ return `import stylesheetUrl from "/src/styles.css?url";
123
+
124
+ export default stylesheetUrl;
125
+ `;
126
+ }
127
+ function generateVirtualCamoxServer(runtimeBasePath) {
128
+ return `import { handleCamoxRequest as handleRuntimeRequest } from "camox/_internal/runtime";
129
+ import { camoxApp } from "virtual:camox/app";
130
+ import { camoxDocument } from "virtual:camox/document";
131
+ import appStylesheetUrl from "virtual:camox/app-stylesheet-url";
132
+ import pageClientEntryUrl from "virtual:camox/page-client-url";
133
+ import { renderPage } from "virtual:camox/page-server";
134
+ import { renderStudio } from "virtual:camox/studio-server";
135
+
136
+ export async function handleCamoxRequest(request) {
137
+ return handleRuntimeRequest(request, {
138
+ apiUrl: __CAMOX_API_URL__,
139
+ authenticationUrl: __CAMOX_AUTHENTICATION_URL__,
140
+ clientEntryUrl: pageClientEntryUrl,
141
+ environmentName: __CAMOX_ENVIRONMENT_NAME__,
142
+ getCamoxApp: async () => camoxApp,
143
+ getDocument: async () => camoxDocument,
144
+ projectSlug: __CAMOX_PROJECT_SLUG__,
145
+ renderPage,
146
+ renderStudio,
147
+ runtimeBasePath: ${JSON.stringify(runtimeBasePath)},
148
+ stylesheetUrl: appStylesheetUrl,
149
+ });
150
+ }
151
+ `;
152
+ }
153
+ function generateVirtualCamoxNitroHandler(runtimeBasePath) {
154
+ return `import { defineHandler } from "nitro";
155
+ import { handleCamoxRequest } from "virtual:camox/server";
156
+
157
+ const runtimeBasePath = ${JSON.stringify(normalizeRuntimeBasePath(runtimeBasePath))};
158
+
159
+ function isDocumentRequest(request) {
160
+ const accept = request.headers.get("Accept") ?? request.headers.get("accept") ?? "";
161
+ return accept.includes("text/html") || accept.includes("*/*");
162
+ }
163
+
164
+ function getRuntimePathname(pathname) {
165
+ if (!runtimeBasePath) return pathname;
166
+ if (pathname === runtimeBasePath) return "/";
167
+ if (!pathname.startsWith(runtimeBasePath + "/")) return null;
168
+ return pathname.slice(runtimeBasePath.length) || "/";
169
+ }
170
+
171
+ function shouldHandleRequest(request) {
172
+ const url = new URL(request.url);
173
+ const pathname = getRuntimePathname(url.pathname);
174
+ if (!pathname) return false;
175
+ if (request.method !== "GET" && request.method !== "HEAD") return false;
176
+ if (
177
+ pathname === "/_camox/data" ||
178
+ pathname === "/_camox/health" ||
179
+ pathname === "/_camox/registry"
180
+ ) {
181
+ return true;
182
+ }
183
+ if (pathname === "/og" || pathname === "/sitemap.xml") return true;
184
+ if (pathname === "/camox" || pathname.startsWith("/camox/")) return true;
185
+ if (/\\.[a-z0-9]+$/i.test(pathname)) return false;
186
+ if (pathname.startsWith("/@") || pathname.startsWith("/src/")) return false;
187
+ if (pathname.startsWith("/__vite")) return false;
188
+ if (pathname.startsWith("/node_modules/")) return false;
189
+ return isDocumentRequest(request);
190
+ }
191
+
192
+ async function transformHtmlResponse(response) {
193
+ const contentType = response.headers.get("Content-Type") ?? response.headers.get("content-type") ?? "";
194
+ if (!contentType.includes("text/html")) return response;
195
+ if (!globalThis.__transform_html__) return response;
196
+
197
+ const headers = new Headers(response.headers);
198
+ headers.delete("Content-Length");
199
+ headers.delete("content-length");
200
+
201
+ return new Response(await globalThis.__transform_html__(await response.text()), {
202
+ headers,
203
+ status: response.status,
204
+ statusText: response.statusText,
205
+ });
206
+ }
207
+
208
+ export default defineHandler(async (event) => {
209
+ if (!shouldHandleRequest(event.req)) {
210
+ return new Response("Not found", { status: 404 });
211
+ }
212
+
213
+ const response = await handleCamoxRequest(event.req);
214
+ if (response) return transformHtmlResponse(response);
215
+ return new Response("Not found", { status: 404 });
216
+ });
217
+ `;
218
+ }
219
+ function resolveRuntimeDevId(id, importer) {
220
+ const camoxSourceImport = resolveCamoxSourceImport(id);
221
+ if (camoxSourceImport) return camoxSourceImport;
222
+ const sdkAlias = resolveSdkAlias(id, importer);
223
+ if (sdkAlias) return sdkAlias;
224
+ if (id === VIRTUAL_CAMOX_APP) return RESOLVED_VIRTUAL_CAMOX_APP;
225
+ if (id === VIRTUAL_CAMOX_DOCUMENT) return RESOLVED_VIRTUAL_CAMOX_DOCUMENT;
226
+ if (id === VIRTUAL_CAMOX_SERVER) return RESOLVED_VIRTUAL_CAMOX_SERVER;
227
+ if (id === VIRTUAL_PAGE_SERVER) return RESOLVED_VIRTUAL_PAGE_SERVER;
228
+ if (id === VIRTUAL_STUDIO_SERVER) return RESOLVED_VIRTUAL_STUDIO_SERVER;
229
+ if (id === VIRTUAL_PAGE_CLIENT) return RESOLVED_VIRTUAL_PAGE_CLIENT;
230
+ if (id === VIRTUAL_PAGE_CLIENT_URL) return RESOLVED_VIRTUAL_PAGE_CLIENT_URL;
231
+ if (id === VIRTUAL_APP_STYLESHEET_URL) return RESOLVED_VIRTUAL_APP_STYLESHEET_URL;
232
+ if (id === VIRTUAL_STUDIO_CSS) return RESOLVED_VIRTUAL_STUDIO_CSS;
233
+ if (id === VIRTUAL_OVERLAY_CSS) return RESOLVED_VIRTUAL_OVERLAY_CSS;
234
+ }
235
+ function loadRuntimeDevModule(id, options = {}) {
236
+ if (id === RESOLVED_VIRTUAL_CAMOX_APP) return generateVirtualCamoxApp();
237
+ if (id === RESOLVED_VIRTUAL_CAMOX_DOCUMENT) return generateVirtualCamoxDocument();
238
+ if (id === RESOLVED_VIRTUAL_CAMOX_SERVER) return generateVirtualCamoxServer(options.runtimeBasePath);
239
+ if (id === VIRTUAL_CAMOX_NITRO_HANDLER) return generateVirtualCamoxNitroHandler(options.runtimeBasePath);
240
+ if (id === RESOLVED_VIRTUAL_PAGE_SERVER) return generateVirtualPageServer();
241
+ if (id === RESOLVED_VIRTUAL_STUDIO_SERVER) return generateVirtualStudioServer();
242
+ if (id === RESOLVED_VIRTUAL_PAGE_CLIENT) return generateVirtualPageClient();
243
+ if (id === RESOLVED_VIRTUAL_PAGE_CLIENT_URL) return generateVirtualPageClientUrl();
244
+ if (id === RESOLVED_VIRTUAL_APP_STYLESHEET_URL) return generateVirtualAppStylesheetUrl();
245
+ if (id === RESOLVED_VIRTUAL_STUDIO_CSS) return `export default "/@fs/${resolve(sdkRoot, "dist/studio.css")}";`;
246
+ if (id === RESOLVED_VIRTUAL_OVERLAY_CSS) return `export default ${JSON.stringify(readFileSync(resolve(sdkRoot, "dist/studio-overlays.css"), "utf-8"))};`;
247
+ }
248
+ function normalizeRuntimeBasePath(basePath) {
249
+ if (basePath === void 0) return "";
250
+ if (!basePath || basePath === "/") return "";
251
+ return basePath.startsWith("/") ? basePath.replace(/\/+$/, "") : `/${basePath.replace(/\/+$/, "")}`;
252
+ }
253
+ function installRuntimeNitroRoutes(nitro, options) {
254
+ const routes = options.runtimeBasePath && options.runtimeBasePath !== "/" ? [options.runtimeBasePath, `${options.runtimeBasePath}/**`] : [
255
+ "/",
256
+ "/_camox/data",
257
+ "/_camox/health",
258
+ "/_camox/registry",
259
+ "/og",
260
+ "/sitemap.xml",
261
+ "/camox",
262
+ "/camox/**",
263
+ "/**"
264
+ ];
265
+ for (const route of routes) nitro.options.routes[route] = VIRTUAL_CAMOX_NITRO_HANDLER;
266
+ nitro.options.virtual[VIRTUAL_CAMOX_NITRO_HANDLER] = generateVirtualCamoxNitroHandler(options.runtimeBasePath);
267
+ }
268
+
269
+ //#endregion
270
+ export { installRuntimeNitroRoutes, loadRuntimeDevModule, resolveRuntimeDevId };
@@ -1,10 +1,12 @@
1
- import { existsSync, readFileSync, writeFileSync } from "node:fs";
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { dirname } from "node:path";
2
3
 
3
4
  //#region src/features/vite/utils.ts
4
5
  function writeIfChanged(filePath, content) {
5
6
  if (existsSync(filePath)) {
6
7
  if (readFileSync(filePath, "utf-8") === content) return;
7
8
  }
9
+ mkdirSync(dirname(filePath), { recursive: true });
8
10
  writeFileSync(filePath, content, "utf-8");
9
11
  }
10
12
 
@@ -1,6 +1,24 @@
1
1
  import { Plugin } from "vite-plus";
2
2
 
3
3
  //#region src/features/vite/vite.d.ts
4
+ interface CamoxNitro {
5
+ hooks: {
6
+ hook: (name: "compiled", callback: (nitro: CamoxNitro) => void) => void;
7
+ };
8
+ options: {
9
+ output: {
10
+ publicDir: string;
11
+ serverDir: string;
12
+ };
13
+ routes: Record<string, string>;
14
+ virtual: Record<string, string>;
15
+ };
16
+ }
17
+ type CamoxVitePlugin = Plugin & {
18
+ nitro?: {
19
+ setup: (nitro: CamoxNitro) => void;
20
+ };
21
+ };
4
22
  interface CamoxPluginOptions {
5
23
  /** Stable, human-readable slug identifying this project (e.g. "prestigious-impala-84") */
6
24
  projectSlug: string;
@@ -10,12 +28,13 @@ interface CamoxPluginOptions {
10
28
  disableTelemetry?: boolean;
11
29
  /** Internal options (intended for Camox contributors in development, not for public use) */
12
30
  _internal?: {
13
- /** URL of the Camox API backend, used for data fetching */apiUrl?: string; /** URL of the Camox authentication backend (default: https://camox.ai) */
31
+ /** URL of the Camox API backend, used for data fetching */apiUrl?: string; /** URL of the Camox authentication backend (default: https://app.camox.ai) */
14
32
  authenticationUrl?: string; /** Show Tanstack query devtools (default: false) */
15
33
  enableTanstackDevtools?: boolean; /** Disable automatic code generation (route files, app file, skill files) (default: false) */
16
- disableCodeGen?: boolean;
34
+ disableCodeGen?: boolean; /** Mount the Camox-owned dev runtime at this base path. Use "/" for root mode. */
35
+ runtimeBasePath?: string;
17
36
  };
18
37
  }
19
- declare function camox(options: CamoxPluginOptions): Plugin;
38
+ declare function camox(options: CamoxPluginOptions): CamoxVitePlugin;
20
39
  //#endregion
21
40
  export { CamoxPluginOptions, camox };
@@ -1,9 +1,10 @@
1
1
  import { generateAppFile, watchAppFile } from "./appGeneration.js";
2
2
  import { watchNewBlockFiles } from "./blockBoilerplate.js";
3
3
  import { syncDefinitions, syncDefinitionsToApi } from "./definitionsSync.js";
4
- import { generateRouteFiles, watchRouteFiles } from "./routeGeneration.js";
4
+ import { cleanupGeneratedRouteFiles } from "./routeGeneration.js";
5
+ import { installRuntimeNitroRoutes, loadRuntimeDevModule, resolveRuntimeDevId } from "./runtimeDev.js";
5
6
  import { generateSkillFiles, watchSkillFiles } from "./skillGeneration.js";
6
- import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
7
+ import { cpSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
7
8
  import { homedir } from "node:os";
8
9
  import { dirname, join, resolve } from "node:path";
9
10
  import { fileURLToPath } from "node:url";
@@ -16,9 +17,11 @@ const VIRTUAL_STUDIO_CSS = "virtual:camox-studio-css";
16
17
  const RESOLVED_VIRTUAL_STUDIO_CSS = "\0" + VIRTUAL_STUDIO_CSS;
17
18
  const VIRTUAL_OVERLAY_CSS = "virtual:camox-overlay-css";
18
19
  const RESOLVED_VIRTUAL_OVERLAY_CSS = "\0" + VIRTUAL_OVERLAY_CSS;
20
+ const VIRTUAL_PAGE_CLIENT = "virtual:camox/page-client";
21
+ const RESOLVED_VIRTUAL_PAGE_CLIENT_URL = "\0virtual:camox/page-client-url";
19
22
  const PRODUCTION_API_URL = "https://api.camox.ai";
20
- /** Authentication URL to use for Camox authentication (production Camox web app) */
21
- const DEFAULT_AUTHENTICATION_URL = "https://camox.ai";
23
+ /** Authentication URL to use for Camox authentication (production Camox Dashboard) */
24
+ const DEFAULT_AUTHENTICATION_URL = "https://app.camox.ai";
22
25
  const authTokenSchema = z.object({
23
26
  token: z.string(),
24
27
  name: z.string(),
@@ -66,12 +69,16 @@ function camox(options) {
66
69
  const authenticationUrl = options._internal?.authenticationUrl ?? DEFAULT_AUTHENTICATION_URL;
67
70
  const enableTanstackDevtools = options._internal?.enableTanstackDevtools ?? false;
68
71
  const disableCodeGen = options._internal?.disableCodeGen ?? false;
72
+ const runtimeBasePath = options._internal?.runtimeBasePath;
69
73
  let isBuild = false;
70
74
  let resolvedConfig;
71
75
  let environmentName;
72
76
  return {
73
77
  name: "camox",
74
- resolveId(id) {
78
+ enforce: "pre",
79
+ resolveId(id, importer) {
80
+ const runtimeId = resolveRuntimeDevId(id, importer);
81
+ if (runtimeId) return runtimeId;
75
82
  if (id === VIRTUAL_STUDIO_CSS) return RESOLVED_VIRTUAL_STUDIO_CSS;
76
83
  if (id === VIRTUAL_OVERLAY_CSS) return RESOLVED_VIRTUAL_OVERLAY_CSS;
77
84
  },
@@ -80,11 +87,8 @@ function camox(options) {
80
87
  const cssPath = resolve(sdkRoot, "dist/studio.css");
81
88
  if (isBuild) {
82
89
  const css = readFileSync(cssPath, "utf-8");
83
- return `export default import.meta.ROLLUP_FILE_URL_${this.emitFile({
84
- type: "asset",
85
- name: "studio.css",
86
- source: css
87
- })};`;
90
+ const dataUrl = `data:text/css;base64,${Buffer.from(css).toString("base64")}`;
91
+ return `export default ${JSON.stringify(dataUrl)};`;
88
92
  }
89
93
  return `export default "/@fs/${cssPath}";`;
90
94
  }
@@ -92,18 +96,38 @@ function camox(options) {
92
96
  const css = readFileSync(resolve(sdkRoot, "dist/studio-overlays.css"), "utf-8");
93
97
  return `export default ${JSON.stringify(css)};`;
94
98
  }
99
+ if (id === RESOLVED_VIRTUAL_PAGE_CLIENT_URL && isBuild) return "export default \"/_chunks/camox-page-client.mjs\";";
100
+ return loadRuntimeDevModule(id, { runtimeBasePath });
95
101
  },
102
+ nitro: { setup(nitro) {
103
+ installRuntimeNitroRoutes(nitro, { runtimeBasePath });
104
+ nitro.hooks.hook("compiled", ({ options }) => {
105
+ const serverAssets = join(options.output.serverDir, "assets");
106
+ if (!existsSync(serverAssets)) return;
107
+ cpSync(serverAssets, join(options.output.publicDir, "assets"), { recursive: true });
108
+ });
109
+ } },
96
110
  config(_config, env) {
97
111
  isBuild = env.command === "build";
98
112
  environmentName = resolveEnvironmentName(env.command, authenticationUrl);
99
113
  return {
114
+ build: { emitAssets: true },
100
115
  define: {
101
116
  __CAMOX_TELEMETRY_DISABLED__: JSON.stringify(!!options.disableTelemetry),
102
117
  __ENABLE_TANSTACK_DEVTOOLS__: JSON.stringify(enableTanstackDevtools),
103
118
  __CAMOX_ENVIRONMENT_NAME__: JSON.stringify(environmentName),
104
119
  __CAMOX_API_URL__: JSON.stringify(apiUrl),
120
+ __CAMOX_AUTHENTICATION_URL__: JSON.stringify(authenticationUrl),
105
121
  __CAMOX_PROJECT_SLUG__: JSON.stringify(options.projectSlug)
106
122
  },
123
+ environments: { client: { build: { rollupOptions: {
124
+ input: { "camox-page-client": VIRTUAL_PAGE_CLIENT },
125
+ output: {
126
+ assetFileNames: "assets/[name]-[hash][extname]",
127
+ chunkFileNames: "_chunks/[name]-[hash].mjs",
128
+ entryFileNames: "_chunks/[name].mjs"
129
+ }
130
+ } } } },
107
131
  resolve: { alias: [{
108
132
  find: /^tslib$/,
109
133
  replacement: "tslib/tslib.es6.mjs"
@@ -189,10 +213,7 @@ function camox(options) {
189
213
  });
190
214
  if (!disableCodeGen) {
191
215
  generateAppFile(config.root);
192
- generateRouteFiles({
193
- routesDir,
194
- authenticationUrl
195
- });
216
+ cleanupGeneratedRouteFiles(routesDir);
196
217
  generateSkillFiles(config.root);
197
218
  }
198
219
  if (disableCodeGen) config.logger.warn("⚠️ Code generation is disabled (_internal.disableCodeGen). This option is only meant for momentary debugging — do not deploy or commit your app with it enabled.", { timestamp: true });
@@ -203,11 +224,7 @@ function camox(options) {
203
224
  const routesDir = resolve(server.config.root, "src/routes");
204
225
  if (!disableCodeGen) {
205
226
  watchAppFile(server, server.config.root);
206
- watchRouteFiles({
207
- server,
208
- routesDir,
209
- authenticationUrl
210
- });
227
+ cleanupGeneratedRouteFiles(routesDir);
211
228
  watchSkillFiles(server, server.config.root);
212
229
  watchNewBlockFiles(server);
213
230
  }