@adminide-stack/yantra-mobile 12.0.142 → 12.0.145-alpha.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 (118) hide show
  1. package/lib/features/attachments/displayUserMessageText.js +2 -2
  2. package/lib/features/attachments/displayUserMessageText.js.map +1 -1
  3. package/lib/features/devices/readings.js.map +1 -1
  4. package/lib/features/devices/session.js +2 -22
  5. package/lib/features/devices/session.js.map +1 -1
  6. package/lib/features/notion/NotionAgentPanel.js +987 -0
  7. package/lib/features/notion/NotionAgentPanel.js.map +1 -0
  8. package/lib/features/notion/NotionAskAiSheet.js +362 -0
  9. package/lib/features/notion/NotionAskAiSheet.js.map +1 -0
  10. package/lib/features/notion/NotionBlockView.js +4 -3
  11. package/lib/features/notion/NotionBlockView.js.map +1 -1
  12. package/lib/features/notion/NotionConnectionsSheet.js +47 -13
  13. package/lib/features/notion/NotionConnectionsSheet.js.map +1 -1
  14. package/lib/features/notion/NotionPageView.js +68 -8
  15. package/lib/features/notion/NotionPageView.js.map +1 -1
  16. package/lib/features/notion/NotionSidebarSections.js +1 -1
  17. package/lib/features/notion/NotionSidebarSections.js.map +1 -1
  18. package/lib/features/notion/NotionWorkspaceView.js +14 -9
  19. package/lib/features/notion/NotionWorkspaceView.js.map +1 -1
  20. package/lib/features/notion/database/DatabaseCells.js +3 -1
  21. package/lib/features/notion/database/DatabaseCells.js.map +1 -1
  22. package/lib/features/notion/database/DatabaseDateLayouts.js +1 -1
  23. package/lib/features/notion/database/DatabaseDateLayouts.js.map +1 -1
  24. package/lib/features/notion/database/NotionDatabaseView.js +1 -1
  25. package/lib/features/notion/database/NotionDatabaseView.js.map +1 -1
  26. package/lib/features/notion/notionAgentRunStatus.js +2 -2
  27. package/lib/features/notion/notionAgentRunStatus.js.map +1 -1
  28. package/lib/features/notion/notionAgentRuns.js +57 -0
  29. package/lib/features/notion/notionAgentRuns.js.map +1 -0
  30. package/lib/features/notion/notionAiContext.js +91 -0
  31. package/lib/features/notion/notionAiContext.js.map +1 -0
  32. package/lib/features/notion/notionConnections.js +42 -4
  33. package/lib/features/notion/notionConnections.js.map +1 -1
  34. package/lib/features/notion/notionDocuments.js +61 -1
  35. package/lib/features/notion/notionDocuments.js.map +1 -1
  36. package/lib/features/notion/notionNotesAgent.js +173 -3
  37. package/lib/features/notion/notionNotesAgent.js.map +1 -1
  38. package/lib/features/notion/notionPageKinds.js +1 -1
  39. package/lib/features/webbuilder/WebBuilderExperience.js +229 -97
  40. package/lib/features/webbuilder/WebBuilderExperience.js.map +1 -1
  41. package/lib/features/webbuilder/buildFragments.js +33 -7
  42. package/lib/features/webbuilder/buildFragments.js.map +1 -1
  43. package/lib/features/webbuilder/buildJob.js +2 -2
  44. package/lib/features/webbuilder/buildJob.js.map +1 -1
  45. package/lib/features/webbuilder/codeFiles.js +18 -1
  46. package/lib/features/webbuilder/codeFiles.js.map +1 -1
  47. package/lib/features/webbuilder/components/BottomTabs.js.map +1 -1
  48. package/lib/features/webbuilder/components/CodeView.js +134 -56
  49. package/lib/features/webbuilder/components/CodeView.js.map +1 -1
  50. package/lib/features/webbuilder/components/Composer.js +2 -2
  51. package/lib/features/webbuilder/components/Composer.js.map +1 -1
  52. package/lib/features/webbuilder/components/PreviewFrame.js +19 -3
  53. package/lib/features/webbuilder/components/PreviewFrame.js.map +1 -1
  54. package/lib/features/webbuilder/components/PreviewScreen.js +310 -46
  55. package/lib/features/webbuilder/components/PreviewScreen.js.map +1 -1
  56. package/lib/features/webbuilder/components/ProjectChat.js +141 -12
  57. package/lib/features/webbuilder/components/ProjectChat.js.map +1 -1
  58. package/lib/features/webbuilder/components/ProjectSheets.js +792 -0
  59. package/lib/features/webbuilder/components/ProjectSheets.js.map +1 -0
  60. package/lib/features/webbuilder/components/ProjectsScreen.js +14 -2
  61. package/lib/features/webbuilder/components/ProjectsScreen.js.map +1 -1
  62. package/lib/features/webbuilder/components/PublishSheet.js +914 -58
  63. package/lib/features/webbuilder/components/PublishSheet.js.map +1 -1
  64. package/lib/features/webbuilder/components/TemplateCard.js +9 -6
  65. package/lib/features/webbuilder/components/TemplateCard.js.map +1 -1
  66. package/lib/features/webbuilder/components/TemplatesSheet.js +5 -17
  67. package/lib/features/webbuilder/components/TemplatesSheet.js.map +1 -1
  68. package/lib/features/webbuilder/connectorTemplates.js +171 -0
  69. package/lib/features/webbuilder/connectorTemplates.js.map +1 -0
  70. package/lib/features/webbuilder/fileTree.js +163 -0
  71. package/lib/features/webbuilder/fileTree.js.map +1 -0
  72. package/lib/features/webbuilder/followUps.js +67 -0
  73. package/lib/features/webbuilder/followUps.js.map +1 -0
  74. package/lib/features/webbuilder/previewProbe.js +49 -0
  75. package/lib/features/webbuilder/previewProbe.js.map +1 -0
  76. package/lib/features/webbuilder/previewRoutes.js +156 -0
  77. package/lib/features/webbuilder/previewRoutes.js.map +1 -0
  78. package/lib/features/webbuilder/projectTools.js +341 -0
  79. package/lib/features/webbuilder/projectTools.js.map +1 -0
  80. package/lib/features/webbuilder/publishTools.js +475 -0
  81. package/lib/features/webbuilder/publishTools.js.map +1 -0
  82. package/lib/features/webbuilder/sleepNotice.js +13 -0
  83. package/lib/features/webbuilder/sleepNotice.js.map +1 -0
  84. package/lib/features/webbuilder/stepLabels.js +37 -7
  85. package/lib/features/webbuilder/stepLabels.js.map +1 -1
  86. package/lib/features/webbuilder/studioCatalog.js +5 -1
  87. package/lib/features/webbuilder/studioCatalog.js.map +1 -1
  88. package/lib/features/webbuilder/templateCatalog.js +140 -0
  89. package/lib/features/webbuilder/templateCatalog.js.map +1 -0
  90. package/lib/features/webbuilder/webbuilderPrompts.js +31 -5
  91. package/lib/features/webbuilder/webbuilderPrompts.js.map +1 -1
  92. package/lib/features/webbuilder/workflow.js +8 -4
  93. package/lib/features/webbuilder/workflow.js.map +1 -1
  94. package/lib/screens/Devices/index.js +3 -205
  95. package/lib/screens/Devices/index.js.map +1 -1
  96. package/lib/screens/WebBuilderNative/codeWorkspaceApi.js +9 -6
  97. package/lib/screens/WebBuilderNative/codeWorkspaceApi.js.map +1 -1
  98. package/lib/screens/WebBuilderNative/index.js +1 -1
  99. package/lib/screens/WebBuilderNative/index.js.map +1 -1
  100. package/lib/screens/WebBuilderNative/keepAlive.js +53 -3
  101. package/lib/screens/WebBuilderNative/keepAlive.js.map +1 -1
  102. package/lib/screens/WebBuilderNative/unreachableRetry.js +23 -0
  103. package/lib/screens/WebBuilderNative/unreachableRetry.js.map +1 -0
  104. package/lib/screens/WebBuilderNative/useConnectorTemplates.js +37 -0
  105. package/lib/screens/WebBuilderNative/useConnectorTemplates.js.map +1 -0
  106. package/lib/screens/WebBuilderNative/useSandboxKeepAlive.js +6 -0
  107. package/lib/screens/WebBuilderNative/useSandboxKeepAlive.js.map +1 -1
  108. package/lib/screens/WebBuilderNative/useWebBuilderHost.js +302 -40
  109. package/lib/screens/WebBuilderNative/useWebBuilderHost.js.map +1 -1
  110. package/lib/screens/WebBuilderNative/useWebBuilderJobs.js +2 -2
  111. package/lib/screens/WebBuilderNative/useWebBuilderJobs.js.map +1 -1
  112. package/lib/screens/WebBuilderNative/versionUndo.js +1 -1
  113. package/lib/screens/WebBuilderNative/versionUndo.js.map +1 -1
  114. package/lib/screens/WebBuilderNative/webbuilderTransport.js +147 -77
  115. package/lib/screens/WebBuilderNative/webbuilderTransport.js.map +1 -1
  116. package/package.json +4 -4
  117. package/lib/features/devices/bodyComposition.js +0 -116
  118. package/lib/features/devices/bodyComposition.js.map +0 -1
@@ -0,0 +1,156 @@
1
+ const pathToLabel = (path) => {
2
+ var _a;
3
+ if (path === "/") return "Homepage";
4
+ const segment = (_a = path.replace(/^\//, "").split("/")[0]) != null ? _a : path;
5
+ const clean = segment.replace(/^:/, "").replace(/^\*/, "");
6
+ return clean.charAt(0).toUpperCase() + clean.slice(1).replace(/-/g, " ");
7
+ };
8
+ const normalizeFilePath = (filePath) => filePath.replace(/\\/g, "/").replace(/^\.\//, "");
9
+ const ensureLeadingSlash = (path) => {
10
+ const trimmed = path.trim();
11
+ if (!trimmed || trimmed === "*") return "";
12
+ return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
13
+ };
14
+ const fileSegmentToUrl = (segment) => {
15
+ if (/^\(.*\)$/.test(segment)) return null;
16
+ if (segment.startsWith("@") || /^\(\.+\).+$/.test(segment)) return null;
17
+ if (segment.startsWith("_") && segment !== "_index") return null;
18
+ const optionalCatch = segment.match(/^\[\[\.\.\.(.+)\]\]$/);
19
+ if (optionalCatch) return `:${optionalCatch[1]}?`;
20
+ const catchAll = segment.match(/^\[\.\.\.(.+)\]$/);
21
+ if (catchAll) return `:${catchAll[1]}*`;
22
+ const dynamic = segment.match(/^\[(.+)\]$/);
23
+ if (dynamic) return `:${dynamic[1]}`;
24
+ if (segment.startsWith("$")) {
25
+ return `:${segment.slice(1)}`;
26
+ }
27
+ return segment;
28
+ };
29
+ const segmentsToPath = (segments) => {
30
+ const parts = segments.filter((raw) => raw && raw !== "index" && raw !== "_index" && raw !== "page").map(fileSegmentToUrl).filter((mapped) => mapped !== null);
31
+ if (parts.length === 0) return "/";
32
+ return `/${parts.join("/")}`;
33
+ };
34
+ const routeFromPageFile = (filePath) => {
35
+ const normalized = normalizeFilePath(filePath);
36
+ const appMatch = normalized.match(/(?:^|\/)(?:src\/)?app\/(.*)\/page\.(?:tsx|jsx|ts|js)$/);
37
+ if (appMatch) {
38
+ const segs = appMatch[1].split("/").filter(Boolean);
39
+ return segmentsToPath(segs);
40
+ }
41
+ if (/(?:^|\/)(?:src\/)?app\/page\.(?:tsx|jsx|ts|js)$/.test(normalized)) return "/";
42
+ const pagesMatch = normalized.match(/(?:^|\/)(?:src\/)?pages\/(.+)\.(?:tsx|jsx|ts|js)$/);
43
+ if (pagesMatch) {
44
+ const name = pagesMatch[1];
45
+ if (name === "_app" || name === "_document" || name === "_error" || name.startsWith("api/")) {
46
+ return null;
47
+ }
48
+ const segs = name.split("/").filter(Boolean);
49
+ return segmentsToPath(segs);
50
+ }
51
+ return null;
52
+ };
53
+ const routeFromReactRouterFile = (filePath) => {
54
+ const normalized = normalizeFilePath(filePath);
55
+ const match = normalized.match(/(?:^|\/)(?:src\/)?(?:app\/)?routes\/(.+?)\.(?:tsx|jsx|ts|js)$/);
56
+ if (!match) return null;
57
+ const name = match[1];
58
+ if (/_layout$/.test(name) || name === "route" || name.startsWith("+")) return null;
59
+ if (name === "home" || name === "_index" || name === "index") return "/";
60
+ const segments = name.split(/[./]/).filter((part) => part && part !== "_index" && part !== "index" && !part.endsWith("_layout"));
61
+ return segmentsToPath(segments);
62
+ };
63
+ const isRouterSourceFile = (filePath) => {
64
+ const normalized = normalizeFilePath(filePath);
65
+ if (!/\.(?:tsx|jsx|ts|js)$/.test(normalized)) return false;
66
+ return /(?:^|\/)(?:src\/)?App\.(?:tsx|jsx)$/.test(normalized) || /(?:^|\/)(?:src\/)?main\.(?:tsx|jsx|ts|js)$/.test(normalized) || /(?:^|\/)(?:src\/)?index\.(?:tsx|jsx)$/.test(normalized) || /(?:^|\/)(?:src\/)?(?:router|routes|Router|Routes|routing)\.(?:tsx|jsx|ts|js)$/.test(normalized) || /(?:^|\/)app\/routes\.(?:tsx|ts|js)$/.test(normalized) || /(?:^|\/)(?:src\/)?pages\/.*\.(?:tsx|jsx)$/.test(normalized);
67
+ };
68
+ const isScannableSourceFile = (filePath) => {
69
+ const normalized = normalizeFilePath(filePath);
70
+ if (!/\.(?:tsx|jsx|ts|js)$/.test(normalized)) return false;
71
+ if (/\.(?:test|spec|d)\.(?:tsx|jsx|ts|js)$/.test(normalized)) return false;
72
+ if (/(?:^|\/)node_modules\//.test(normalized)) return false;
73
+ return true;
74
+ };
75
+ const addPath = (paths, raw) => {
76
+ const path = ensureLeadingSlash(raw);
77
+ if (!path) return;
78
+ paths.add(path);
79
+ };
80
+ const extractRoutesFromSource = (source) => {
81
+ const paths = /* @__PURE__ */ new Set();
82
+ for (const match of source.matchAll(/<Route\b[^>]*\bpath=["']([^"']+)["']/g)) addPath(paths, match[1]);
83
+ for (const match of source.matchAll(/\bpath\s*:\s*['"]([^'"]+)['"]/g)) addPath(paths, match[1]);
84
+ for (const match of source.matchAll(/\b(?:to|href)=["'](\/[^"']*)["']/g)) {
85
+ const href = match[1];
86
+ if (!href.startsWith("/#") && !/\.(?:css|js|png|jpg|svg|ico)(?:\?|$)/i.test(href)) {
87
+ addPath(paths, href.split(/[?#]/)[0] || "/");
88
+ }
89
+ }
90
+ return Array.from(paths);
91
+ };
92
+ const sortPreviewRoutes = (paths) => Array.from(paths).sort((a, b) => {
93
+ if (a === "/") return -1;
94
+ if (b === "/") return 1;
95
+ return a.localeCompare(b);
96
+ }).map((path) => ({
97
+ path,
98
+ label: pathToLabel(path)
99
+ }));
100
+ const extractPreviewRoutes = (files) => {
101
+ if (!files || Object.keys(files).length === 0) {
102
+ return [{
103
+ path: "/",
104
+ label: "Homepage"
105
+ }];
106
+ }
107
+ const paths = /* @__PURE__ */ new Set();
108
+ for (const filePath of Object.keys(files)) {
109
+ const fromPage = routeFromPageFile(filePath);
110
+ if (fromPage) paths.add(fromPage);
111
+ const fromReactRouter = routeFromReactRouterFile(filePath);
112
+ if (fromReactRouter) paths.add(fromReactRouter);
113
+ }
114
+ for (const [filePath, source] of Object.entries(files)) {
115
+ if (isRouterSourceFile(filePath) && typeof source === "string") {
116
+ for (const routePath of extractRoutesFromSource(source)) paths.add(routePath);
117
+ }
118
+ }
119
+ if (paths.size <= 1) {
120
+ for (const [filePath, source] of Object.entries(files)) {
121
+ if (isScannableSourceFile(filePath) && !isRouterSourceFile(filePath) && typeof source === "string") {
122
+ for (const routePath of extractRoutesFromSource(source)) paths.add(routePath);
123
+ }
124
+ }
125
+ }
126
+ paths.add("/");
127
+ return sortPreviewRoutes(paths);
128
+ };
129
+ const buildPreviewUrl = (baseUrl, route) => {
130
+ if (!baseUrl) return void 0;
131
+ const safeRoute = route.includes(":") || route.includes("*") ? "/" : route;
132
+ try {
133
+ const url = new URL(baseUrl);
134
+ if (safeRoute === "/") {
135
+ return url.toString();
136
+ }
137
+ url.pathname = safeRoute;
138
+ return url.toString();
139
+ } catch (e) {
140
+ const trimmed = baseUrl.replace(/\/$/, "");
141
+ return safeRoute === "/" ? trimmed : `${trimmed}${safeRoute}`;
142
+ }
143
+ };
144
+ function matchPreviewRoutes(routes, query) {
145
+ const q = query.trim().toLowerCase();
146
+ if (!q || q === "/") return routes;
147
+ const exactPath = q.startsWith("/") ? q : `/${q}`;
148
+ const matched = routes.filter((r) => r.path.toLowerCase().includes(q) || r.label.toLowerCase().includes(q));
149
+ if (!matched.some((r) => r.path === exactPath) && exactPath.length > 1 && !exactPath.includes(" ")) {
150
+ return [...matched, {
151
+ path: exactPath,
152
+ label: exactPath
153
+ }];
154
+ }
155
+ return matched;
156
+ }export{buildPreviewUrl,extractPreviewRoutes,matchPreviewRoutes};//# sourceMappingURL=previewRoutes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"previewRoutes.js","sources":["../../../src/features/webbuilder/previewRoutes.ts"],"sourcesContent":["/**\n * The pages a preview can open (web `utils/previewRoutes.ts`): discovered from the\n * build's files for Vite / React Router, Next.js (app + pages) and Remix flat routes.\n */\n\nexport type PreviewRoute = {\n path: string;\n label: string;\n};\n\nconst pathToLabel = (path: string): string => {\n if (path === '/') return 'Homepage';\n const segment = path.replace(/^\\//, '').split('/')[0] ?? path;\n // Drop param markers for the pill label: /blog/:id → Blog\n const clean = segment.replace(/^:/, '').replace(/^\\*/, '');\n return clean.charAt(0).toUpperCase() + clean.slice(1).replace(/-/g, ' ');\n};\n\nconst normalizeFilePath = (filePath: string): string => filePath.replace(/\\\\/g, '/').replace(/^\\.\\//, '');\n\nconst ensureLeadingSlash = (path: string): string => {\n const trimmed = path.trim();\n if (!trimmed || trimmed === '*') return '';\n return trimmed.startsWith('/') ? trimmed : `/${trimmed}`;\n};\n\n/** Convert Next/Remix file segments into URL path segments. */\nconst fileSegmentToUrl = (segment: string): string | null => {\n // Next.js route groups: (marketing)\n if (/^\\(.*\\)$/.test(segment)) return null;\n // Next.js parallel/intercept: @slot, (.)foo\n if (segment.startsWith('@') || /^\\(\\.+\\).+$/.test(segment)) return null;\n // Remix / RR pathless layout: _layout, _index handled by caller\n if (segment.startsWith('_') && segment !== '_index') return null;\n // Next dynamic [id] / [...slug] / [[...slug]]\n const optionalCatch = segment.match(/^\\[\\[\\.\\.\\.(.+)\\]\\]$/);\n if (optionalCatch) return `:${optionalCatch[1]}?`;\n const catchAll = segment.match(/^\\[\\.\\.\\.(.+)\\]$/);\n if (catchAll) return `:${catchAll[1]}*`;\n const dynamic = segment.match(/^\\[(.+)\\]$/);\n if (dynamic) return `:${dynamic[1]}`;\n // Remix / RR7: $id\n if (segment.startsWith('$')) {\n return `:${segment.slice(1)}`;\n }\n return segment;\n};\n\nconst segmentsToPath = (segments: string[]): string | null => {\n const parts = segments\n .filter((raw) => raw && raw !== 'index' && raw !== '_index' && raw !== 'page')\n .map(fileSegmentToUrl)\n .filter((mapped): mapped is string => mapped !== null);\n if (parts.length === 0) return '/';\n return `/${parts.join('/')}`;\n};\n\n/** Next.js app router + pages router + src/pages */\nconst routeFromPageFile = (filePath: string): string | null => {\n const normalized = normalizeFilePath(filePath);\n\n // app/**/page.(tsx|jsx|ts|js) — also src/app\n const appMatch = normalized.match(/(?:^|\\/)(?:src\\/)?app\\/(.*)\\/page\\.(?:tsx|jsx|ts|js)$/);\n if (appMatch) {\n const segs = appMatch[1].split('/').filter(Boolean);\n return segmentsToPath(segs);\n }\n if (/(?:^|\\/)(?:src\\/)?app\\/page\\.(?:tsx|jsx|ts|js)$/.test(normalized)) return '/';\n\n // pages/** (Next pages router) and src/pages/**\n const pagesMatch = normalized.match(/(?:^|\\/)(?:src\\/)?pages\\/(.+)\\.(?:tsx|jsx|ts|js)$/);\n if (pagesMatch) {\n const name = pagesMatch[1];\n // skip api / _app / _document / _error\n if (name === '_app' || name === '_document' || name === '_error' || name.startsWith('api/')) {\n return null;\n }\n const segs = name.split('/').filter(Boolean);\n return segmentsToPath(segs);\n }\n\n return null;\n};\n\n/**\n * Remix / React Router v7 flat file routes:\n * app/routes/about.tsx → /about\n * app/routes/blog.$id.tsx → /blog/:id\n * app/routes/_index.tsx → /\n * Also src/routes/* and routes/*\n */\nconst routeFromReactRouterFile = (filePath: string): string | null => {\n const normalized = normalizeFilePath(filePath);\n const match = normalized.match(/(?:^|\\/)(?:src\\/)?(?:app\\/)?routes\\/(.+?)\\.(?:tsx|jsx|ts|js)$/);\n if (!match) return null;\n\n const name = match[1];\n // Skip layouts / resource routes markers\n if (/_layout$/.test(name) || name === 'route' || name.startsWith('+')) return null;\n if (name === 'home' || name === '_index' || name === 'index') return '/';\n\n // Flat dots: blog.$id → blog/:id ; nested folders already use /\n const segments = name\n .split(/[./]/)\n .filter((part) => part && part !== '_index' && part !== 'index' && !part.endsWith('_layout'));\n\n return segmentsToPath(segments);\n};\n\n/** Files that typically declare <Route> / createBrowserRouter trees. */\nconst isRouterSourceFile = (filePath: string): boolean => {\n const normalized = normalizeFilePath(filePath);\n if (!/\\.(?:tsx|jsx|ts|js)$/.test(normalized)) return false;\n // Prefer known router entrypoints, but also scan any App / main / router file\n return (\n /(?:^|\\/)(?:src\\/)?App\\.(?:tsx|jsx)$/.test(normalized) ||\n /(?:^|\\/)(?:src\\/)?main\\.(?:tsx|jsx|ts|js)$/.test(normalized) ||\n /(?:^|\\/)(?:src\\/)?index\\.(?:tsx|jsx)$/.test(normalized) ||\n /(?:^|\\/)(?:src\\/)?(?:router|routes|Router|Routes|routing)\\.(?:tsx|jsx|ts|js)$/.test(normalized) ||\n /(?:^|\\/)app\\/routes\\.(?:tsx|ts|js)$/.test(normalized) ||\n /(?:^|\\/)(?:src\\/)?pages\\/.*\\.(?:tsx|jsx)$/.test(normalized)\n );\n};\n\n/** Any TS/JS source — used as a secondary scan so Vite apps don't miss routes. */\nconst isScannableSourceFile = (filePath: string): boolean => {\n const normalized = normalizeFilePath(filePath);\n if (!/\\.(?:tsx|jsx|ts|js)$/.test(normalized)) return false;\n if (/\\.(?:test|spec|d)\\.(?:tsx|jsx|ts|js)$/.test(normalized)) return false;\n if (/(?:^|\\/)node_modules\\//.test(normalized)) return false;\n return true;\n};\n\nconst addPath = (paths: Set<string>, raw: string) => {\n const path = ensureLeadingSlash(raw);\n if (!path) return;\n paths.add(path);\n};\n\n/**\n * Pull routes from JSX/TS router source:\n * <Route path=\"...\">\n * path: '...'\n * { path: '...', element: ... }\n * Keeps dynamic segments (`:id`) so the list matches the sandbox router.\n */\nconst extractRoutesFromSource = (source: string): string[] => {\n const paths = new Set<string>();\n\n for (const match of source.matchAll(/<Route\\b[^>]*\\bpath=[\"']([^\"']+)[\"']/g)) addPath(paths, match[1]);\n\n // path={\\`/blog/${id}\\`} — skip template literals; only static strings\n for (const match of source.matchAll(/\\bpath\\s*:\\s*['\"]([^'\"]+)['\"]/g)) addPath(paths, match[1]);\n\n // Links (`to=\"/x\"`, `href=\"/x\"`): skip assets and hashes, strip query/hash for the route list.\n for (const match of source.matchAll(/\\b(?:to|href)=[\"'](\\/[^\"']*)[\"']/g)) {\n const href = match[1];\n if (!href.startsWith('/#') && !/\\.(?:css|js|png|jpg|svg|ico)(?:\\?|$)/i.test(href)) {\n addPath(paths, href.split(/[?#]/)[0] || '/');\n }\n }\n\n return Array.from(paths);\n};\n\nconst sortPreviewRoutes = (paths: Iterable<string>): PreviewRoute[] =>\n Array.from(paths)\n .sort((a, b) => {\n if (a === '/') return -1;\n if (b === '/') return 1;\n return a.localeCompare(b);\n })\n .map((path) => ({ path, label: pathToLabel(path) }));\n\nexport const extractPreviewRoutes = (files?: Record<string, string> | null): PreviewRoute[] => {\n if (!files || Object.keys(files).length === 0) {\n return [{ path: '/', label: 'Homepage' }];\n }\n\n const paths = new Set<string>();\n\n for (const filePath of Object.keys(files)) {\n const fromPage = routeFromPageFile(filePath);\n if (fromPage) paths.add(fromPage);\n\n const fromReactRouter = routeFromReactRouterFile(filePath);\n if (fromReactRouter) paths.add(fromReactRouter);\n }\n\n // First pass: known router entry files\n for (const [filePath, source] of Object.entries(files)) {\n if (isRouterSourceFile(filePath) && typeof source === 'string') {\n for (const routePath of extractRoutesFromSource(source)) paths.add(routePath);\n }\n }\n\n // Second pass: if still thin, scan all source files (Vite multi-file routers)\n if (paths.size <= 1) {\n for (const [filePath, source] of Object.entries(files)) {\n if (isScannableSourceFile(filePath) && !isRouterSourceFile(filePath) && typeof source === 'string') {\n for (const routePath of extractRoutesFromSource(source)) paths.add(routePath);\n }\n }\n }\n\n // Always expose Homepage so the pill label matches a selectable row\n paths.add('/');\n\n return sortPreviewRoutes(paths);\n};\n\nexport const buildPreviewUrl = (baseUrl: string | undefined, route: string): string | undefined => {\n if (!baseUrl) return undefined;\n // Dynamic segments aren't navigable as-is — keep the base for those\n const safeRoute = route.includes(':') || route.includes('*') ? '/' : route;\n try {\n const url = new URL(baseUrl);\n if (safeRoute === '/') {\n // Preserve sandbox base path (e.g. /) — don't wipe trailing structure\n return url.toString();\n }\n // Append route onto origin; sandbox preview hosts usually serve at /\n url.pathname = safeRoute;\n return url.toString();\n } catch {\n const trimmed = baseUrl.replace(/\\/$/, '');\n return safeRoute === '/' ? trimmed : `${trimmed}${safeRoute}`;\n }\n};\n\n/** The path a preview URL is on (`/` for the site root). */\nexport function previewPathOf(url: string | null | undefined): string {\n const match = String(url ?? '').match(/^https?:\\/\\/[^/?#]+(\\/[^?#]*)?/i);\n const path = match?.[1] || '/';\n return path.length > 1 ? path.replace(/\\/$/, '') : '/';\n}\n\n/** Typed into the path pill: the known routes matching it, plus the typed path itself (web `filtered`). */\nexport function matchPreviewRoutes(routes: PreviewRoute[], query: string): PreviewRoute[] {\n const q = query.trim().toLowerCase();\n if (!q || q === '/') return routes;\n const exactPath = q.startsWith('/') ? q : `/${q}`;\n const matched = routes.filter((r) => r.path.toLowerCase().includes(q) || r.label.toLowerCase().includes(q));\n if (!matched.some((r) => r.path === exactPath) && exactPath.length > 1 && !exactPath.includes(' ')) {\n return [...matched, { path: exactPath, label: exactPath }];\n }\n return matched;\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,341 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ const PROJECT_KNOWLEDGE_MAX = 4e3;
21
+ const PROJECT_TITLE_MAX = 80;
22
+ function normalizeProjectKnowledge(text) {
23
+ const t = String(text != null ? text : "").replace(/\r\n?/g, "\n").replace(/\u0000/g, "").trim();
24
+ return t.length > PROJECT_KNOWLEDGE_MAX ? t.slice(0, PROJECT_KNOWLEDGE_MAX) : t;
25
+ }
26
+ function normalizeProjectTitle(name) {
27
+ const t = String(name != null ? name : "").replace(/[\u0000-\u001f\u007f]+/g, " ").replace(/\s+/g, " ").trim();
28
+ if (!t) return null;
29
+ return t.length > PROJECT_TITLE_MAX ? t.slice(0, PROJECT_TITLE_MAX).trim() : t;
30
+ }
31
+ function projectInstructionsNote(knowledge) {
32
+ return `[Project instructions] The owner's standing instructions for this project - follow them in every change:
33
+ ${knowledge}`;
34
+ }
35
+ function normalizeGithubRepoUrl(raw) {
36
+ const m = /^https:\/\/github\.com\/([A-Za-z0-9-]{1,39})\/([A-Za-z0-9._-]{1,100}?)(?:\.git)?\/?$/.exec(String(raw != null ? raw : "").trim());
37
+ return m ? `https://github.com/${m[1]}/${m[2]}` : "";
38
+ }
39
+ function normalizeBranch(raw) {
40
+ const b = String(raw != null ? raw : "").trim();
41
+ return /^[A-Za-z0-9._/-]{1,100}$/.test(b) && !b.includes("..") && !b.startsWith("/") && !b.endsWith("/") ? b : "";
42
+ }
43
+ function rec(v) {
44
+ let value = v;
45
+ if (typeof value === "string") {
46
+ try {
47
+ value = JSON.parse(value);
48
+ } catch (e) {
49
+ return null;
50
+ }
51
+ }
52
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
53
+ }
54
+ function str(v) {
55
+ return typeof v === "string" ? v.trim() : "";
56
+ }
57
+ const MAX_INTEGRATIONS = 20;
58
+ function normalizeIntegrations(raw) {
59
+ if (!Array.isArray(raw)) return [];
60
+ const byId = /* @__PURE__ */ new Map();
61
+ for (const item of raw) {
62
+ const r = rec(item);
63
+ const connectorId = str(r == null ? void 0 : r.connectorId);
64
+ if (r && /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(connectorId)) {
65
+ byId.set(connectorId, __spreadValues(__spreadValues({
66
+ connectorId,
67
+ title: str(r.title).slice(0, 80) || connectorId
68
+ }, str(r.credentialId) ? {
69
+ credentialId: str(r.credentialId)
70
+ } : {}), str(r.purpose) ? {
71
+ purpose: str(r.purpose).slice(0, 300)
72
+ } : {}));
73
+ }
74
+ }
75
+ return [...byId.values()].slice(-20);
76
+ }
77
+ function parseProjectSettings(raw) {
78
+ var _a;
79
+ const top = rec(raw);
80
+ if (!top) return null;
81
+ const r = (_a = rec(top.settings)) != null ? _a : top;
82
+ const gh = rec(r.github);
83
+ return {
84
+ title: normalizeProjectTitle(typeof r.title === "string" ? r.title : ""),
85
+ instructions: normalizeProjectKnowledge(typeof r.instructions === "string" ? r.instructions : ""),
86
+ integrations: normalizeIntegrations(r.integrations),
87
+ github: gh ? __spreadProps(__spreadValues(__spreadValues({}, normalizeGithubRepoUrl(str(gh.repoUrl)) ? {
88
+ repoUrl: normalizeGithubRepoUrl(str(gh.repoUrl))
89
+ } : {}), normalizeBranch(str(gh.branch)) ? {
90
+ branch: normalizeBranch(str(gh.branch))
91
+ } : {}), {
92
+ sync: gh.sync === true
93
+ }) : null
94
+ };
95
+ }
96
+ const SETTINGS_NOT_SAVED = "Couldn't save the settings.";
97
+ function readSettingsUpdateReply(raw) {
98
+ const r = rec(raw);
99
+ if ((r == null ? void 0 : r.ok) === true) return {
100
+ ok: true,
101
+ settings: parseProjectSettings(r.settings)
102
+ };
103
+ if ((r == null ? void 0 : r.ok) === false) {
104
+ const errors = Array.isArray(r.errors) ? r.errors.map((e) => String(e != null ? e : "").trim()).filter(Boolean) : [];
105
+ return {
106
+ ok: false,
107
+ error: errors.join("; ") || SETTINGS_NOT_SAVED
108
+ };
109
+ }
110
+ return {
111
+ ok: false,
112
+ error: SETTINGS_NOT_SAVED
113
+ };
114
+ }
115
+ function readDeleteReply(raw) {
116
+ if (raw === true) return {
117
+ ok: true
118
+ };
119
+ const r = rec(raw);
120
+ if ((r == null ? void 0 : r.ok) === false || (r == null ? void 0 : r.deleted) === false) {
121
+ return {
122
+ ok: false,
123
+ error: str(r.error) || str(r.message) || "The project could not be deleted."
124
+ };
125
+ }
126
+ return {
127
+ ok: Boolean(r) || raw != null
128
+ };
129
+ }
130
+ const DEFAULT_SYNC_BRANCH = "main";
131
+ function repoSlug(title) {
132
+ return String(title != null ? title : "").toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 100) || "my-site";
133
+ }
134
+ function isValidRepoName(name) {
135
+ return /^[A-Za-z0-9._-]{1,100}$/.test(name) && name !== "." && name !== "..";
136
+ }
137
+ function githubSyncPatch(repoUrl, branch, sync) {
138
+ const b = normalizeBranch(String(branch != null ? branch : "").trim() || DEFAULT_SYNC_BRANCH);
139
+ if (!b) return null;
140
+ const url = normalizeGithubRepoUrl(repoUrl);
141
+ return __spreadProps(__spreadValues({}, url ? {
142
+ repoUrl: url
143
+ } : {}), {
144
+ branch: b,
145
+ sync
146
+ });
147
+ }
148
+ const FEATURED = [{
149
+ key: "stripe",
150
+ ids: ["stripe"]
151
+ }, {
152
+ key: "mailer",
153
+ ids: ["yantra-mailer", "mailer"]
154
+ }, {
155
+ key: "slack",
156
+ ids: ["slack"]
157
+ }, {
158
+ key: "sheets",
159
+ ids: ["google-sheets", "googlesheets", "google_sheets", "sheets"]
160
+ }];
161
+ const ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
162
+ function parseCatalog(raw) {
163
+ var _a;
164
+ if (!Array.isArray(raw)) return [];
165
+ const seen = /* @__PURE__ */ new Set();
166
+ const out = [];
167
+ for (const item of raw) {
168
+ const r = rec(item);
169
+ const id = str(r == null ? void 0 : r.id);
170
+ if (r && ID_RE.test(id) && !seen.has(id)) {
171
+ seen.add(id);
172
+ const meta = (_a = rec(r.meta)) != null ? _a : {};
173
+ const logo = str(r.logo);
174
+ out.push({
175
+ id,
176
+ title: str(r.title) || id,
177
+ description: str(r.description),
178
+ logo: /^https:\/\//.test(logo) ? logo : null,
179
+ categories: Array.isArray(meta.categories) ? meta.categories.map(str).filter(Boolean) : [],
180
+ authMethods: Array.isArray(r.authMethods) ? r.authMethods.map(str).filter(Boolean) : []
181
+ });
182
+ }
183
+ }
184
+ return out;
185
+ }
186
+ function categoryLabel(raw) {
187
+ const c = (raw || "").trim().replace(/[-_]+/g, " ");
188
+ if (!c) return "Other";
189
+ if (/^(crm|ai|sms|erp|hr|cms|seo|api)$/i.test(c)) return c.toUpperCase();
190
+ return c.charAt(0).toUpperCase() + c.slice(1).toLowerCase();
191
+ }
192
+ function featuredRank(id) {
193
+ const lower = id.toLowerCase();
194
+ return FEATURED.findIndex((f) => f.ids.includes(lower));
195
+ }
196
+ function matchesSearch(entry, search) {
197
+ const q = search.trim().toLowerCase();
198
+ if (!q) return true;
199
+ return [entry.id, entry.title, entry.description, ...entry.categories].some((s) => s.toLowerCase().includes(q));
200
+ }
201
+ function groupCatalog(entries, search = "") {
202
+ var _a;
203
+ const hits = entries.filter((e) => matchesSearch(e, search));
204
+ const featured = hits.filter((e) => featuredRank(e.id) >= 0).sort((a, b) => featuredRank(a.id) - featuredRank(b.id));
205
+ const byCat = /* @__PURE__ */ new Map();
206
+ for (const e of hits) {
207
+ if (featuredRank(e.id) < 0) {
208
+ const cat = categoryLabel(e.categories[0]);
209
+ byCat.set(cat, [...(_a = byCat.get(cat)) != null ? _a : [], e]);
210
+ }
211
+ }
212
+ const groups = [...byCat.entries()].map(([category, list]) => ({
213
+ category,
214
+ entries: list.sort((a, b) => a.title.localeCompare(b.title))
215
+ })).sort((a, b) => {
216
+ if (a.category === "Other") return 1;
217
+ if (b.category === "Other") return -1;
218
+ return a.category.localeCompare(b.category);
219
+ });
220
+ return {
221
+ featured,
222
+ groups
223
+ };
224
+ }
225
+ function purposeText(purpose) {
226
+ return String(purpose != null ? purpose : "").replace(/\s+/g, " ").trim().replace(/[.!]+$/, "").slice(0, 300);
227
+ }
228
+ function integrationRequest(entry, purpose) {
229
+ var _a;
230
+ const p = purposeText(purpose);
231
+ switch ((_a = FEATURED[featuredRank(entry.id)]) == null ? void 0 : _a.key) {
232
+ case "stripe":
233
+ return `Add Stripe checkout for ${p || "the products on my site"}.`;
234
+ case "mailer":
235
+ return `Send emails with the Yantra mailer for ${p || "messages from the contact form"}.`;
236
+ case "slack":
237
+ return `Post a Slack message ${p ? `for ${p}` : "when someone fills in a form on my site"}.`;
238
+ case "sheets":
239
+ return `Save ${p || "form submissions"} to a Google Sheet.`;
240
+ default:
241
+ return `Add the ${entry.title} integration to my site${p ? ` for ${p}` : ""}.`;
242
+ }
243
+ }
244
+ function aiRequest(purpose) {
245
+ const p = purposeText(purpose);
246
+ return `Add AI to my site: ${p || "an assistant that answers visitors' questions"}.`;
247
+ }
248
+ function withIntegration(list, entry, purpose) {
249
+ const current = normalizeIntegrations(list);
250
+ if (current.length >= MAX_INTEGRATIONS && !current.some((i) => i.connectorId === entry.id)) {
251
+ throw new Error(`This project already has ${MAX_INTEGRATIONS} integrations, the most it can keep. Remove one before adding another.`);
252
+ }
253
+ const p = purposeText(purpose);
254
+ return normalizeIntegrations([...current.filter((i) => i.connectorId !== entry.id), __spreadValues({
255
+ connectorId: entry.id,
256
+ title: entry.title
257
+ }, p ? {
258
+ purpose: p
259
+ } : {})]);
260
+ }
261
+ function parseRepoInput(raw) {
262
+ var _a, _b;
263
+ let s = String(raw != null ? raw : "").trim();
264
+ if (!s) return {
265
+ ok: false,
266
+ error: "Paste the address of a GitHub repository."
267
+ };
268
+ s = s.replace(/^git@github\.com:/i, "https://github.com/");
269
+ if (/^[A-Za-z0-9-]+\/[A-Za-z0-9._-]+$/.test(s)) s = `https://github.com/${s}`;
270
+ if (!/^[a-z]+:\/\//i.test(s)) s = `https://${s}`;
271
+ const m = /^https?:\/\/(?:([^@/]+)@)?(?:www\.)?([^/?#]+)(\/[^?#]*)?/i.exec(s);
272
+ if (!m) return {
273
+ ok: false,
274
+ error: "That doesn't look like a repository address."
275
+ };
276
+ if (m[1]) return {
277
+ ok: false,
278
+ error: "Leave passwords and tokens out of the address."
279
+ };
280
+ if (m[2].toLowerCase() !== "github.com") return {
281
+ ok: false,
282
+ error: "Only GitHub repositories can be imported for now."
283
+ };
284
+ const parts = (m[3] || "").split("/").filter(Boolean);
285
+ const owner = (_a = parts[0]) != null ? _a : "";
286
+ const repo = ((_b = parts[1]) != null ? _b : "").replace(/\.git$/i, "");
287
+ if (!/^[A-Za-z0-9](?:[A-Za-z0-9-]{0,38})$/.test(owner) || !/^[A-Za-z0-9._-]{1,100}$/.test(repo) || repo === "." || repo === "..") {
288
+ return {
289
+ ok: false,
290
+ error: "Use the address of a repository, like https://github.com/you/your-app."
291
+ };
292
+ }
293
+ let branch = null;
294
+ if (parts[2] === "tree" && parts.length > 3) {
295
+ const b = decodeURIComponent(parts.slice(3).join("/"));
296
+ if (normalizeBranch(b)) branch = b;
297
+ }
298
+ return {
299
+ ok: true,
300
+ ref: {
301
+ owner,
302
+ repo,
303
+ url: `https://github.com/${owner}/${repo}`,
304
+ branch
305
+ }
306
+ };
307
+ }
308
+ function readRepoCheck(ref, status, body) {
309
+ if (status === 404) {
310
+ return {
311
+ ok: false,
312
+ message: "That repository wasn't found. Check the address, or make the repository public."
313
+ };
314
+ }
315
+ if (status === 403 || status === 429) {
316
+ return {
317
+ ok: false,
318
+ message: "GitHub is limiting requests right now. Try again in a minute."
319
+ };
320
+ }
321
+ const r = rec(body);
322
+ if (status < 200 || status >= 300 || !r) return {
323
+ ok: false,
324
+ message: "Couldn't reach GitHub. Try again."
325
+ };
326
+ if (r.private === true) return {
327
+ ok: false,
328
+ message: "Make the repository public, then check again."
329
+ };
330
+ return {
331
+ ok: true,
332
+ ref: __spreadProps(__spreadValues({}, ref), {
333
+ branch: ref.branch || str(r.default_branch) || DEFAULT_SYNC_BRANCH
334
+ }),
335
+ name: str(r.name) || ref.repo,
336
+ description: str(r.description)
337
+ };
338
+ }
339
+ function importTurn(ref) {
340
+ return `Import my app from ${ref.url} (branch ${ref.branch}) with its code and history, then run its preview.`;
341
+ }export{DEFAULT_SYNC_BRANCH,MAX_INTEGRATIONS,PROJECT_KNOWLEDGE_MAX,PROJECT_TITLE_MAX,SETTINGS_NOT_SAVED,aiRequest,categoryLabel,githubSyncPatch,groupCatalog,importTurn,integrationRequest,isValidRepoName,matchesSearch,normalizeBranch,normalizeGithubRepoUrl,normalizeIntegrations,normalizeProjectKnowledge,normalizeProjectTitle,parseCatalog,parseProjectSettings,parseRepoInput,projectInstructionsNote,readDeleteReply,readRepoCheck,readSettingsUpdateReply,repoSlug,withIntegration};//# sourceMappingURL=projectTools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectTools.js","sources":["../../../src/features/webbuilder/projectTools.ts"],"sourcesContent":["/**\n * The project menu's logic (web `project/projectSettings`, `project/serverSettings`,\n * `github/githubSync`, `integrations/catalog`, `import/githubRepo`): the name and the\n * project instructions (saved with the project, sent with every turn), Push to my GitHub\n * with \"Keep in sync\", the integrations catalog and its edit requests, and the repository\n * address an import starts from. Pure.\n */\n\n// ── Name and instructions ────────────────────────────────────────────────\n\nexport const PROJECT_KNOWLEDGE_MAX = 4000;\nexport const PROJECT_TITLE_MAX = 80;\n\nexport function normalizeProjectKnowledge(text: string | null | undefined): string {\n const t = String(text ?? '')\n .replace(/\\r\\n?/g, '\\n')\n // eslint-disable-next-line no-control-regex\n .replace(/\\u0000/g, '')\n .trim();\n return t.length > PROJECT_KNOWLEDGE_MAX ? t.slice(0, PROJECT_KNOWLEDGE_MAX) : t;\n}\n\n/** One line, collapsed whitespace, max 80 characters. Null when empty. */\nexport function normalizeProjectTitle(name: string | null | undefined): string | null {\n const t = String(name ?? '')\n // eslint-disable-next-line no-control-regex\n .replace(/[\\u0000-\\u001f\\u007f]+/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n if (!t) return null;\n return t.length > PROJECT_TITLE_MAX ? t.slice(0, PROJECT_TITLE_MAX).trim() : t;\n}\n\n/** The note every agent turn carries when the project has instructions (web `projectInstructionsNote`). */\nexport function projectInstructionsNote(knowledge: string): string {\n return `[Project instructions] The owner's standing instructions for this project - follow them in every change:\\n${knowledge}`;\n}\n\nexport function normalizeGithubRepoUrl(raw: string | null | undefined): string {\n const m = /^https:\\/\\/github\\.com\\/([A-Za-z0-9-]{1,39})\\/([A-Za-z0-9._-]{1,100}?)(?:\\.git)?\\/?$/.exec(\n String(raw ?? '').trim(),\n );\n return m ? `https://github.com/${m[1]}/${m[2]}` : '';\n}\n\nexport function normalizeBranch(raw: string | null | undefined): string {\n const b = String(raw ?? '').trim();\n return /^[A-Za-z0-9._/-]{1,100}$/.test(b) && !b.includes('..') && !b.startsWith('/') && !b.endsWith('/') ? b : '';\n}\n\nexport interface ProjectIntegration {\n connectorId: string;\n title: string;\n credentialId?: string;\n purpose?: string;\n}\n\nexport interface ProjectGithubSettings {\n repoUrl?: string;\n branch?: string;\n sync?: boolean;\n}\n\n/** What `aiCodeProjectSettings` holds that the menu uses. */\nexport interface ProjectSettings {\n title: string | null;\n instructions: string;\n integrations: ProjectIntegration[];\n github: ProjectGithubSettings | null;\n}\n\nfunction rec(v: unknown): Record<string, unknown> | null {\n let value = v;\n if (typeof value === 'string') {\n try {\n value = JSON.parse(value);\n } catch {\n return null;\n }\n }\n return value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : null;\n}\n\nfunction str(v: unknown): string {\n return typeof v === 'string' ? v.trim() : '';\n}\n\nexport const MAX_INTEGRATIONS = 20;\n\nexport function normalizeIntegrations(raw: unknown): ProjectIntegration[] {\n if (!Array.isArray(raw)) return [];\n const byId = new Map<string, ProjectIntegration>();\n for (const item of raw) {\n const r = rec(item);\n const connectorId = str(r?.connectorId);\n if (r && /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/.test(connectorId)) {\n byId.set(connectorId, {\n connectorId,\n title: str(r.title).slice(0, 80) || connectorId,\n ...(str(r.credentialId) ? { credentialId: str(r.credentialId) } : {}),\n ...(str(r.purpose) ? { purpose: str(r.purpose).slice(0, 300) } : {}),\n });\n }\n }\n return [...byId.values()].slice(-MAX_INTEGRATIONS);\n}\n\n/** `aiCodeProjectSettings` -> the settings, or null when the reply isn't one. */\nexport function parseProjectSettings(raw: unknown): ProjectSettings | null {\n const top = rec(raw);\n if (!top) return null;\n const r = rec(top.settings) ?? top;\n const gh = rec(r.github);\n return {\n title: normalizeProjectTitle(typeof r.title === 'string' ? r.title : ''),\n instructions: normalizeProjectKnowledge(typeof r.instructions === 'string' ? r.instructions : ''),\n integrations: normalizeIntegrations(r.integrations),\n github: gh\n ? {\n ...(normalizeGithubRepoUrl(str(gh.repoUrl))\n ? { repoUrl: normalizeGithubRepoUrl(str(gh.repoUrl)) }\n : {}),\n ...(normalizeBranch(str(gh.branch)) ? { branch: normalizeBranch(str(gh.branch)) } : {}),\n sync: gh.sync === true,\n }\n : null,\n };\n}\n\nexport const SETTINGS_NOT_SAVED = \"Couldn't save the settings.\";\n\n/** `aiCodeUpdateProjectSettings`: `{ ok: true, settings }` or `{ ok: false, errors }`. */\nexport function readSettingsUpdateReply(raw: unknown): {\n ok: boolean;\n error?: string;\n settings?: ProjectSettings | null;\n} {\n const r = rec(raw);\n if (r?.ok === true) return { ok: true, settings: parseProjectSettings(r.settings) };\n if (r?.ok === false) {\n const errors = Array.isArray(r.errors) ? r.errors.map((e) => String(e ?? '').trim()).filter(Boolean) : [];\n return { ok: false, error: errors.join('; ') || SETTINGS_NOT_SAVED };\n }\n return { ok: false, error: SETTINGS_NOT_SAVED };\n}\n\n/** `aiCodeDeleteProject`: a refusal names why (owners only); anything truthy otherwise is done. */\nexport function readDeleteReply(raw: unknown): { ok: boolean; error?: string } {\n if (raw === true) return { ok: true };\n const r = rec(raw);\n if (r?.ok === false || r?.deleted === false) {\n return { ok: false, error: str(r.error) || str(r.message) || 'The project could not be deleted.' };\n }\n return { ok: Boolean(r) || raw != null };\n}\n\n// ── GitHub ───────────────────────────────────────────────────────────────\n\nexport const DEFAULT_SYNC_BRANCH = 'main';\n\n/** The repository name a push starts with: the project's name as a slug. */\nexport function repoSlug(title: string | null | undefined): string {\n return (\n String(title ?? '')\n .toLowerCase()\n .replace(/[^a-z0-9._-]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 100) || 'my-site'\n );\n}\n\nexport function isValidRepoName(name: string): boolean {\n return /^[A-Za-z0-9._-]{1,100}$/.test(name) && name !== '.' && name !== '..';\n}\n\n/** The `github` settings patch \"Keep in sync\" saves, or null when the branch isn't valid. */\nexport function githubSyncPatch(\n repoUrl: string | null | undefined,\n branch: string | null | undefined,\n sync: boolean,\n): ProjectGithubSettings | null {\n const b = normalizeBranch(String(branch ?? '').trim() || DEFAULT_SYNC_BRANCH);\n if (!b) return null;\n const url = normalizeGithubRepoUrl(repoUrl);\n return { ...(url ? { repoUrl: url } : {}), branch: b, sync };\n}\n\n// ── Integrations ─────────────────────────────────────────────────────────\n\nexport interface IntegrationCatalogEntry {\n id: string;\n title: string;\n description: string;\n logo: string | null;\n categories: string[];\n authMethods: string[];\n}\n\n/** The short list shown first, in this order (AI is its own card: \"Add AI to my site\"). */\nconst FEATURED: Array<{ key: string; ids: string[] }> = [\n { key: 'stripe', ids: ['stripe'] },\n { key: 'mailer', ids: ['yantra-mailer', 'mailer'] },\n { key: 'slack', ids: ['slack'] },\n { key: 'sheets', ids: ['google-sheets', 'googlesheets', 'google_sheets', 'sheets'] },\n];\n\nconst ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;\n\nexport function parseCatalog(raw: unknown): IntegrationCatalogEntry[] {\n if (!Array.isArray(raw)) return [];\n const seen = new Set<string>();\n const out: IntegrationCatalogEntry[] = [];\n for (const item of raw) {\n const r = rec(item);\n const id = str(r?.id);\n if (r && ID_RE.test(id) && !seen.has(id)) {\n seen.add(id);\n const meta = rec(r.meta) ?? {};\n const logo = str(r.logo);\n out.push({\n id,\n title: str(r.title) || id,\n description: str(r.description),\n logo: /^https:\\/\\//.test(logo) ? logo : null,\n categories: Array.isArray(meta.categories) ? meta.categories.map(str).filter(Boolean) : [],\n authMethods: Array.isArray(r.authMethods) ? r.authMethods.map(str).filter(Boolean) : [],\n });\n }\n }\n return out;\n}\n\n/** \"crm\" -> \"CRM\", \"project-management\" -> \"Project management\". */\nexport function categoryLabel(raw: string | undefined): string {\n const c = (raw || '').trim().replace(/[-_]+/g, ' ');\n if (!c) return 'Other';\n if (/^(crm|ai|sms|erp|hr|cms|seo|api)$/i.test(c)) return c.toUpperCase();\n return c.charAt(0).toUpperCase() + c.slice(1).toLowerCase();\n}\n\nfunction featuredRank(id: string): number {\n const lower = id.toLowerCase();\n return FEATURED.findIndex((f) => f.ids.includes(lower));\n}\n\nexport function matchesSearch(entry: IntegrationCatalogEntry, search: string): boolean {\n const q = search.trim().toLowerCase();\n if (!q) return true;\n return [entry.id, entry.title, entry.description, ...entry.categories].some((s) => s.toLowerCase().includes(q));\n}\n\n/** The featured short list first, then the rest grouped by first category (A-Z, \"Other\" last). */\nexport function groupCatalog(\n entries: IntegrationCatalogEntry[],\n search = '',\n): { featured: IntegrationCatalogEntry[]; groups: Array<{ category: string; entries: IntegrationCatalogEntry[] }> } {\n const hits = entries.filter((e) => matchesSearch(e, search));\n const featured = hits\n .filter((e) => featuredRank(e.id) >= 0)\n .sort((a, b) => featuredRank(a.id) - featuredRank(b.id));\n const byCat = new Map<string, IntegrationCatalogEntry[]>();\n for (const e of hits) {\n if (featuredRank(e.id) < 0) {\n const cat = categoryLabel(e.categories[0]);\n byCat.set(cat, [...(byCat.get(cat) ?? []), e]);\n }\n }\n const groups = [...byCat.entries()]\n .map(([category, list]) => ({ category, entries: list.sort((a, b) => a.title.localeCompare(b.title)) }))\n .sort((a, b) => {\n if (a.category === 'Other') return 1;\n if (b.category === 'Other') return -1;\n return a.category.localeCompare(b.category);\n });\n return { featured, groups };\n}\n\nfunction purposeText(purpose: string | null | undefined): string {\n return String(purpose ?? '')\n .replace(/\\s+/g, ' ')\n .trim()\n .replace(/[.!]+$/, '')\n .slice(0, 300);\n}\n\n/** The plain edit request for \"Add to my site\" (\"Add Stripe checkout for …\"). */\nexport function integrationRequest(\n entry: Pick<IntegrationCatalogEntry, 'id' | 'title'>,\n purpose?: string | null,\n): string {\n const p = purposeText(purpose);\n switch (FEATURED[featuredRank(entry.id)]?.key) {\n case 'stripe':\n return `Add Stripe checkout for ${p || 'the products on my site'}.`;\n case 'mailer':\n return `Send emails with the Yantra mailer for ${p || 'messages from the contact form'}.`;\n case 'slack':\n return `Post a Slack message ${p ? `for ${p}` : 'when someone fills in a form on my site'}.`;\n case 'sheets':\n return `Save ${p || 'form submissions'} to a Google Sheet.`;\n default:\n return `Add the ${entry.title} integration to my site${p ? ` for ${p}` : ''}.`;\n }\n}\n\n/** The plain edit request for \"Add AI to my site\". */\nexport function aiRequest(purpose?: string | null): string {\n const p = purposeText(purpose);\n return `Add AI to my site: ${p || \"an assistant that answers visitors' questions\"}.`;\n}\n\n/** The project's integrations after adding one (re-adding replaces it); throws when the list is full. */\nexport function withIntegration(\n list: ProjectIntegration[],\n entry: Pick<IntegrationCatalogEntry, 'id' | 'title'>,\n purpose?: string | null,\n): ProjectIntegration[] {\n const current = normalizeIntegrations(list);\n if (current.length >= MAX_INTEGRATIONS && !current.some((i) => i.connectorId === entry.id)) {\n throw new Error(\n `This project already has ${MAX_INTEGRATIONS} integrations, the most it can keep. Remove one before adding another.`,\n );\n }\n const p = purposeText(purpose);\n return normalizeIntegrations([\n ...current.filter((i) => i.connectorId !== entry.id),\n { connectorId: entry.id, title: entry.title, ...(p ? { purpose: p } : {}) },\n ]);\n}\n\n// ── Import a project ─────────────────────────────────────────────────────\n\nexport interface RepoRef {\n owner: string;\n repo: string;\n url: string;\n branch: string | null;\n}\n\n/** `https://github.com/o/r`, `github.com/o/r(.git)`, `git@github.com:o/r.git`, `o/r`, `…/tree/<branch>`. */\nexport interface RepoParse {\n ok: boolean;\n ref?: RepoRef;\n error?: string;\n}\n\nexport function parseRepoInput(raw: string): RepoParse {\n let s = String(raw ?? '').trim();\n if (!s) return { ok: false, error: 'Paste the address of a GitHub repository.' };\n s = s.replace(/^git@github\\.com:/i, 'https://github.com/');\n if (/^[A-Za-z0-9-]+\\/[A-Za-z0-9._-]+$/.test(s)) s = `https://github.com/${s}`;\n if (!/^[a-z]+:\\/\\//i.test(s)) s = `https://${s}`;\n const m = /^https?:\\/\\/(?:([^@/]+)@)?(?:www\\.)?([^/?#]+)(\\/[^?#]*)?/i.exec(s);\n if (!m) return { ok: false, error: \"That doesn't look like a repository address.\" };\n if (m[1]) return { ok: false, error: 'Leave passwords and tokens out of the address.' };\n if (m[2].toLowerCase() !== 'github.com')\n return { ok: false, error: 'Only GitHub repositories can be imported for now.' };\n const parts = (m[3] || '').split('/').filter(Boolean);\n const owner = parts[0] ?? '';\n const repo = (parts[1] ?? '').replace(/\\.git$/i, '');\n if (\n !/^[A-Za-z0-9](?:[A-Za-z0-9-]{0,38})$/.test(owner) ||\n !/^[A-Za-z0-9._-]{1,100}$/.test(repo) ||\n repo === '.' ||\n repo === '..'\n ) {\n return { ok: false, error: 'Use the address of a repository, like https://github.com/you/your-app.' };\n }\n let branch: string | null = null;\n if (parts[2] === 'tree' && parts.length > 3) {\n const b = decodeURIComponent(parts.slice(3).join('/'));\n if (normalizeBranch(b)) branch = b;\n }\n return { ok: true, ref: { owner, repo, url: `https://github.com/${owner}/${repo}`, branch } };\n}\n\nexport interface RepoCheck {\n ok: boolean;\n ref?: RepoRef & { branch: string };\n name?: string;\n description?: string;\n /** Why it can't be imported. */\n message?: string;\n}\n\n/** The public GitHub API's answer for a repository, as the check shows it. */\nexport function readRepoCheck(ref: RepoRef, status: number, body: unknown): RepoCheck {\n if (status === 404) {\n return {\n ok: false,\n message: \"That repository wasn't found. Check the address, or make the repository public.\",\n };\n }\n if (status === 403 || status === 429) {\n return { ok: false, message: 'GitHub is limiting requests right now. Try again in a minute.' };\n }\n const r = rec(body);\n if (status < 200 || status >= 300 || !r) return { ok: false, message: \"Couldn't reach GitHub. Try again.\" };\n if (r.private === true) return { ok: false, message: 'Make the repository public, then check again.' };\n return {\n ok: true,\n ref: { ...ref, branch: ref.branch || str(r.default_branch) || DEFAULT_SYNC_BRANCH },\n name: str(r.name) || ref.repo,\n description: str(r.description),\n };\n}\n\n/** The turn that starts the imported project in the agent chat. */\nexport function importTurn(ref: RepoRef & { branch: string }): string {\n return `Import my app from ${ref.url} (branch ${ref.branch}) with its code and history, then run its preview.`;\n}\n"],"names":[],"mappings":"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"}