insforge 1.3.0 → 1.4.8

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 (269) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/auth/package.json +5 -3
  3. package/auth/src/lib/broadcastService.ts +115 -117
  4. package/auth/src/lib/insforge.ts +8 -0
  5. package/auth/src/main.tsx +2 -4
  6. package/auth/src/pages/SignInPage.tsx +60 -60
  7. package/auth/src/pages/SignUpPage.tsx +60 -60
  8. package/auth/src/pages/VerifyEmailPage.tsx +18 -0
  9. package/auth/tsconfig.json +2 -1
  10. package/backend/package.json +10 -6
  11. package/backend/src/api/middlewares/rate-limiters.ts +127 -127
  12. package/backend/src/api/routes/ai/index.routes.ts +475 -468
  13. package/backend/src/api/routes/auth/index.routes.ts +85 -32
  14. package/backend/src/api/routes/auth/oauth.routes.ts +11 -6
  15. package/backend/src/api/routes/database/index.routes.ts +2 -0
  16. package/backend/src/api/routes/database/records.routes.ts +39 -175
  17. package/backend/src/api/routes/database/rpc.routes.ts +69 -0
  18. package/backend/src/api/routes/deployments/index.routes.ts +192 -0
  19. package/backend/src/api/routes/docs/index.routes.ts +3 -2
  20. package/backend/src/api/routes/email/index.routes.ts +35 -35
  21. package/backend/src/api/routes/functions/index.routes.ts +3 -3
  22. package/backend/src/api/routes/metadata/index.routes.ts +26 -0
  23. package/backend/src/api/routes/webhooks/index.routes.ts +109 -0
  24. package/backend/src/infra/database/database.manager.ts +0 -10
  25. package/backend/src/infra/database/migrations/018_schema-rework.sql +441 -0
  26. package/backend/src/infra/database/migrations/019_create-deployments-table.sql +36 -0
  27. package/backend/src/infra/database/migrations/020_add-audio-modality.sql +11 -0
  28. package/backend/src/infra/database/migrations/bootstrap/bootstrap-migrations.js +103 -0
  29. package/backend/src/infra/security/token.manager.ts +1 -4
  30. package/backend/src/providers/ai/openrouter.provider.ts +12 -3
  31. package/backend/src/providers/database/base.provider.ts +39 -0
  32. package/backend/src/providers/database/cloud.provider.ts +159 -0
  33. package/backend/src/providers/deployments/vercel.provider.ts +516 -0
  34. package/backend/src/server.ts +19 -7
  35. package/backend/src/services/ai/ai-config.service.ts +6 -6
  36. package/backend/src/services/ai/ai-model.service.ts +60 -60
  37. package/backend/src/services/ai/ai-usage.service.ts +7 -7
  38. package/backend/src/services/ai/chat-completion.service.ts +415 -220
  39. package/backend/src/services/ai/helpers.ts +64 -64
  40. package/backend/src/services/ai/index.ts +13 -13
  41. package/backend/src/services/auth/auth-config.service.ts +4 -4
  42. package/backend/src/services/auth/auth-otp.service.ts +6 -6
  43. package/backend/src/services/auth/auth.service.ts +134 -74
  44. package/backend/src/services/auth/index.ts +4 -4
  45. package/backend/src/services/auth/oauth-config.service.ts +12 -12
  46. package/backend/src/services/database/database-advance.service.ts +19 -55
  47. package/backend/src/services/database/database-table.service.ts +38 -85
  48. package/backend/src/services/database/postgrest-proxy.service.ts +165 -0
  49. package/backend/src/services/deployments/deployment.service.ts +693 -0
  50. package/backend/src/services/functions/function.service.ts +61 -41
  51. package/backend/src/services/logs/audit.service.ts +10 -10
  52. package/backend/src/services/secrets/secret.service.ts +101 -27
  53. package/backend/src/services/storage/storage.service.ts +30 -30
  54. package/backend/src/services/usage/usage.service.ts +6 -6
  55. package/backend/src/types/ai.ts +8 -0
  56. package/backend/src/types/auth.ts +5 -1
  57. package/backend/src/types/database.ts +2 -0
  58. package/backend/src/types/deployments.ts +33 -0
  59. package/backend/src/types/storage.ts +1 -1
  60. package/backend/src/types/webhooks.ts +45 -0
  61. package/backend/src/utils/cookies.ts +34 -35
  62. package/backend/src/utils/environment.ts +0 -14
  63. package/backend/src/utils/s3-config-loader.ts +64 -64
  64. package/backend/src/utils/seed.ts +334 -301
  65. package/backend/src/utils/sql-parser.ts +126 -0
  66. package/backend/src/utils/utils.ts +114 -114
  67. package/backend/src/utils/validations.ts +10 -10
  68. package/backend/tests/local/test-rpc.sh +141 -0
  69. package/backend/tests/local/test-secrets.sh +1 -1
  70. package/backend/tests/manual/test-ai-model-plugins.sh +258 -0
  71. package/backend/tests/manual/test-rawsql-modes.sh +24 -24
  72. package/backend/tests/unit/database-advance.test.ts +326 -0
  73. package/backend/tests/unit/helpers.test.ts +2 -2
  74. package/claude-plugin/skills/insforge-schema-patterns/SKILL.md +13 -10
  75. package/docker-compose.prod.yml +1 -1
  76. package/docker-compose.yml +1 -1
  77. package/docs/agent-docs/deployment.md +79 -0
  78. package/docs/changelog.mdx +165 -72
  79. package/docs/core-concepts/ai/architecture.mdx +1 -23
  80. package/docs/core-concepts/ai/sdk.mdx +26 -1
  81. package/docs/core-concepts/authentication/architecture.mdx +6 -8
  82. package/docs/core-concepts/authentication/sdk.mdx +387 -91
  83. package/docs/core-concepts/authentication/ui-components/customization.mdx +460 -256
  84. package/docs/core-concepts/authentication/ui-components/nextjs.mdx +50 -24
  85. package/docs/core-concepts/authentication/ui-components/react-router.mdx +18 -19
  86. package/docs/core-concepts/authentication/ui-components/react.mdx +26 -19
  87. package/docs/core-concepts/database/architecture.mdx +58 -21
  88. package/docs/core-concepts/database/pgvector.mdx +138 -0
  89. package/docs/core-concepts/database/sdk.mdx +17 -17
  90. package/docs/core-concepts/deployments/architecture.mdx +152 -0
  91. package/docs/core-concepts/email/architecture.mdx +4 -2
  92. package/docs/core-concepts/functions/architecture.mdx +1 -1
  93. package/docs/core-concepts/functions/sdk.mdx +0 -1
  94. package/docs/core-concepts/realtime/architecture.mdx +1 -1
  95. package/docs/core-concepts/storage/architecture.mdx +1 -1
  96. package/docs/core-concepts/storage/sdk.mdx +25 -25
  97. package/docs/docs.json +14 -6
  98. package/docs/favicon.png +0 -0
  99. package/docs/favicon.svg +3 -18
  100. package/docs/images/changelog/dec-2025/apple-oauth.mp4 +0 -0
  101. package/docs/images/changelog/dec-2025/moreModels.png +0 -0
  102. package/docs/images/changelog/dec-2025/multi-region.webp +0 -0
  103. package/docs/images/changelog/dec-2025/postgres-connection.webp +0 -0
  104. package/docs/images/changelog/dec-2025/realtime2.png +0 -0
  105. package/docs/images/mcp-setup/CC-MCP-1.mp4 +0 -0
  106. package/docs/images/mcp-setup/CC-MCP-2.mp4 +0 -0
  107. package/docs/images/mcp-setup/Cursor-MCP-1.mp4 +0 -0
  108. package/docs/images/mcp-setup/Cursor-MCP-2.mp4 +0 -0
  109. package/docs/images/mcp-setup/Cursor-MCP-3.mp4 +0 -0
  110. package/docs/images/mcp-setup/claude-code-connect.png +0 -0
  111. package/docs/images/mcp-setup/cline-1.png +0 -0
  112. package/docs/images/mcp-setup/cline-2.png +0 -0
  113. package/docs/images/mcp-setup/cline-3.png +0 -0
  114. package/docs/images/mcp-setup/connect-project.png +0 -0
  115. package/docs/images/mcp-setup/copilot-1.png +0 -0
  116. package/docs/images/mcp-setup/copilot-2.png +0 -0
  117. package/docs/images/mcp-setup/copilot-3.png +0 -0
  118. package/docs/images/mcp-setup/mcp-json-1.png +0 -0
  119. package/docs/images/mcp-setup/mcp-json-2.png +0 -0
  120. package/docs/images/mcp-setup/qoder-1.png +0 -0
  121. package/docs/images/mcp-setup/qoder-2.png +0 -0
  122. package/docs/images/mcp-setup/roocode-1.png +0 -0
  123. package/docs/images/mcp-setup/roocode-2.png +0 -0
  124. package/docs/images/mcp-setup/trae-1.png +0 -0
  125. package/docs/images/mcp-setup/trae-2.png +0 -0
  126. package/docs/images/mcp-setup/trae-3.png +0 -0
  127. package/docs/images/mcp-setup/trae-4.png +0 -0
  128. package/docs/images/mcp-setup/trae-5.png +0 -0
  129. package/docs/images/mcp-setup/windsurf-1.png +0 -0
  130. package/docs/images/mcp-setup/windsurf-2.png +0 -0
  131. package/docs/insforge-instructions-sdk.md +7 -3
  132. package/docs/introduction.mdx +9 -8
  133. package/docs/mcp-setup.mdx +332 -0
  134. package/docs/oauth-server.mdx +563 -0
  135. package/docs/partnership.mdx +79 -10
  136. package/docs/quickstart.mdx +1 -1
  137. package/docs/vscode-extension.mdx +74 -0
  138. package/eslint.config.js +1 -0
  139. package/examples/response-examples.md +1 -1
  140. package/frontend/package.json +1 -1
  141. package/frontend/src/App.tsx +8 -3
  142. package/frontend/src/assets/logos/antigravity.svg +1 -0
  143. package/frontend/src/assets/logos/copilot.svg +10 -0
  144. package/frontend/src/assets/logos/deepseek.svg +139 -0
  145. package/frontend/src/assets/logos/kiro.svg +9 -0
  146. package/frontend/src/assets/logos/qoder.svg +4 -0
  147. package/frontend/src/assets/logos/qwen.svg +15 -0
  148. package/frontend/src/components/CodeBlock.tsx +2 -2
  149. package/frontend/src/components/ConnectCTA.tsx +3 -2
  150. package/frontend/src/components/datagrid/DataGrid.tsx +90 -62
  151. package/frontend/src/components/datagrid/datagridTypes.tsx +2 -1
  152. package/frontend/src/components/datagrid/index.ts +1 -1
  153. package/frontend/src/components/index.ts +0 -1
  154. package/frontend/src/components/layout/AppHeader.tsx +4 -27
  155. package/frontend/src/components/layout/AppSidebar.tsx +85 -100
  156. package/frontend/src/components/layout/Layout.tsx +34 -32
  157. package/frontend/src/components/layout/PrimaryMenu.tsx +12 -4
  158. package/frontend/src/components/radix/Select.tsx +151 -151
  159. package/frontend/src/features/ai/components/AIConfigCard.tsx +200 -200
  160. package/frontend/src/features/ai/components/AIEmptyState.tsx +23 -23
  161. package/frontend/src/features/ai/components/ModalityFilterSidebar.tsx +102 -101
  162. package/frontend/src/features/ai/components/ModelSelectionDialog.tsx +135 -135
  163. package/frontend/src/features/ai/components/ModelSelectionGrid.tsx +51 -51
  164. package/frontend/src/features/ai/components/SystemPromptDialog.tsx +118 -118
  165. package/frontend/src/features/ai/components/index.ts +6 -6
  166. package/frontend/src/features/ai/helpers.ts +147 -141
  167. package/frontend/src/features/ai/pages/AIPage.tsx +166 -166
  168. package/frontend/src/features/auth/components/AuthPreview.tsx +96 -96
  169. package/frontend/src/features/auth/components/UsersDataGrid.tsx +55 -31
  170. package/frontend/src/features/auth/components/index.ts +5 -5
  171. package/frontend/src/features/auth/pages/AuthMethodsPage.tsx +275 -275
  172. package/frontend/src/features/dashboard/pages/DashboardPage.tsx +1 -1
  173. package/frontend/src/features/database/components/DatabaseDataGrid.tsx +0 -2
  174. package/frontend/src/features/database/components/ForeignKeyCell.tsx +38 -11
  175. package/frontend/src/features/database/components/ForeignKeyPopover.tsx +18 -8
  176. package/frontend/src/features/database/components/LinkRecordModal.tsx +61 -13
  177. package/frontend/src/features/database/components/RecordFormField.tsx +1 -1
  178. package/frontend/src/features/database/components/TableSidebar.tsx +0 -3
  179. package/frontend/src/features/database/components/TablesEmptyState.tsx +1 -1
  180. package/frontend/src/features/database/components/TemplatePreview.tsx +1 -2
  181. package/frontend/src/features/database/constants.ts +16 -28
  182. package/frontend/src/features/database/hooks/useCSVImport.ts +3 -2
  183. package/frontend/src/features/database/hooks/useRawSQL.ts +3 -2
  184. package/frontend/src/features/database/hooks/useTables.ts +5 -7
  185. package/frontend/src/features/database/pages/FunctionsPage.tsx +0 -5
  186. package/frontend/src/features/database/pages/IndexesPage.tsx +0 -5
  187. package/frontend/src/features/database/pages/PoliciesPage.tsx +0 -5
  188. package/frontend/src/features/database/pages/SQLEditorPage.tsx +2 -2
  189. package/frontend/src/features/database/pages/TriggersPage.tsx +0 -5
  190. package/frontend/src/features/database/services/advance.service.ts +1 -15
  191. package/frontend/src/features/database/services/record.service.ts +4 -20
  192. package/frontend/src/features/database/services/table.service.ts +1 -4
  193. package/frontend/src/features/database/templates/ai-chatbot.ts +6 -6
  194. package/frontend/src/features/database/templates/ecommerce-platform.ts +2 -2
  195. package/frontend/src/features/database/templates/instagram-clone.ts +10 -10
  196. package/frontend/src/features/database/templates/notion-clone.ts +8 -8
  197. package/frontend/src/features/database/templates/reddit-clone.ts +10 -10
  198. package/frontend/src/features/deployments/components/DeploymentRow.tsx +93 -0
  199. package/frontend/src/features/deployments/components/DeploymentsEmptyState.tsx +15 -0
  200. package/frontend/src/features/deployments/hooks/useDeployments.ts +157 -0
  201. package/frontend/src/features/deployments/pages/DeploymentsPage.tsx +318 -0
  202. package/frontend/src/features/deployments/services/deployments.service.ts +63 -0
  203. package/frontend/src/features/functions/components/FunctionRow.tsx +72 -72
  204. package/frontend/src/features/functions/components/FunctionsSidebar.tsx +56 -56
  205. package/frontend/src/features/functions/components/SecretRow.tsx +3 -3
  206. package/frontend/src/features/functions/components/index.ts +5 -5
  207. package/frontend/src/features/functions/hooks/useFunctions.ts +5 -4
  208. package/frontend/src/features/functions/hooks/useSecrets.ts +6 -9
  209. package/frontend/src/features/functions/pages/SecretsPage.tsx +118 -118
  210. package/frontend/src/features/functions/services/function.service.ts +8 -25
  211. package/frontend/src/features/functions/services/secret.service.ts +23 -41
  212. package/frontend/src/features/login/pages/CloudLoginPage.tsx +125 -118
  213. package/frontend/src/features/logs/components/LogDetailPanel.tsx +41 -0
  214. package/frontend/src/features/logs/components/LogsDataGrid.tsx +32 -1
  215. package/frontend/src/features/logs/components/index.ts +1 -0
  216. package/frontend/src/features/logs/pages/LogsPage.tsx +36 -6
  217. package/frontend/src/features/onboard/components/ApiCredentialsSection.tsx +59 -0
  218. package/frontend/src/features/onboard/components/ConnectionStringSection.tsx +180 -0
  219. package/frontend/src/features/onboard/components/McpConnectionSection.tsx +159 -0
  220. package/frontend/src/features/onboard/components/OnboardingController.tsx +68 -0
  221. package/frontend/src/features/onboard/components/OnboardingModal.tsx +121 -267
  222. package/frontend/src/features/onboard/components/ShowPasswordButton.tsx +21 -0
  223. package/frontend/src/features/onboard/components/index.ts +9 -4
  224. package/frontend/src/features/onboard/components/mcp/CursorDeeplinkGenerator.tsx +1 -1
  225. package/frontend/src/features/onboard/components/mcp/QoderDeeplinkGenerator.tsx +36 -0
  226. package/frontend/src/features/onboard/components/mcp/helpers.tsx +123 -98
  227. package/frontend/src/features/onboard/components/mcp/index.ts +4 -3
  228. package/frontend/src/features/onboard/index.ts +17 -13
  229. package/frontend/src/features/settings/pages/SettingsPage.tsx +349 -0
  230. package/frontend/src/features/visualizer/components/AuthNode.tsx +4 -4
  231. package/frontend/src/features/visualizer/components/SchemaVisualizer.tsx +21 -8
  232. package/frontend/src/features/visualizer/pages/VisualizerPage.tsx +10 -1
  233. package/frontend/src/index.css +249 -249
  234. package/frontend/src/lib/contexts/ModalContext.tsx +35 -0
  235. package/frontend/src/lib/hooks/useMetadata.ts +45 -1
  236. package/frontend/src/lib/hooks/useModal.tsx +2 -0
  237. package/frontend/src/lib/routing/AppRoutes.tsx +103 -99
  238. package/frontend/src/lib/services/metadata.service.ts +20 -3
  239. package/frontend/src/lib/utils/menuItems.ts +223 -207
  240. package/frontend/src/lib/utils/utils.ts +196 -196
  241. package/functions/server.ts +315 -315
  242. package/functions/worker-template.js +1 -1
  243. package/openapi/ai.yaml +115 -5
  244. package/openapi/auth.yaml +97 -17
  245. package/openapi/logs.yaml +0 -2
  246. package/openapi/metadata.yaml +0 -2
  247. package/openapi/records.yaml +21 -21
  248. package/openapi/tables.yaml +1 -2
  249. package/package.json +1 -1
  250. package/shared-schemas/package.json +1 -1
  251. package/shared-schemas/src/ai-api.schema.ts +251 -143
  252. package/shared-schemas/src/ai.schema.ts +63 -63
  253. package/shared-schemas/src/auth-api.schema.ts +34 -6
  254. package/shared-schemas/src/auth.schema.ts +17 -10
  255. package/shared-schemas/src/cloud-events.schema.ts +26 -0
  256. package/shared-schemas/src/deployments-api.schema.ts +55 -0
  257. package/shared-schemas/src/deployments.schema.ts +30 -0
  258. package/shared-schemas/src/docs.schema.ts +8 -2
  259. package/shared-schemas/src/email-api.schema.ts +30 -30
  260. package/shared-schemas/src/functions-api.schema.ts +13 -4
  261. package/shared-schemas/src/functions.schema.ts +1 -1
  262. package/shared-schemas/src/index.ts +22 -18
  263. package/shared-schemas/src/metadata.schema.ts +30 -4
  264. package/shared-schemas/src/secrets-api.schema.ts +44 -0
  265. package/shared-schemas/src/secrets.schema.ts +15 -0
  266. package/zeabur/README.md +13 -0
  267. package/zeabur/template.yml +20 -51
  268. package/backend/src/types/profile.ts +0 -55
  269. package/frontend/src/components/ProjectInfoModal.tsx +0 -128
@@ -0,0 +1,180 @@
1
+ import { useState, useCallback, useRef, useEffect, useMemo } from 'react';
2
+ import { CopyButton, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components';
3
+ import { ShowPasswordButton } from './ShowPasswordButton';
4
+ import { useDatabaseConnectionString, useDatabasePassword } from '@/lib/hooks/useMetadata';
5
+ import { cn } from '@/lib/utils/utils';
6
+
7
+ interface ParameterRowProps {
8
+ label: string;
9
+ value: string | number | undefined;
10
+ copyValue?: string;
11
+ }
12
+
13
+ const RESET_TIMEOUT_MS = 2000;
14
+
15
+ function ParameterRow({ label, value, copyValue }: ParameterRowProps) {
16
+ const [copied, setCopied] = useState(false);
17
+ const timeoutRef = useRef<NodeJS.Timeout | null>(null);
18
+
19
+ const textToCopy = copyValue ?? String(value ?? '');
20
+ const displayValue = value ?? '-';
21
+ const hasCopyableValue = value !== undefined && value !== null && value !== '';
22
+
23
+ useEffect(() => {
24
+ return () => {
25
+ if (timeoutRef.current) {
26
+ clearTimeout(timeoutRef.current);
27
+ }
28
+ };
29
+ }, []);
30
+
31
+ const handleCopy = useCallback(() => {
32
+ if (!hasCopyableValue) {
33
+ return;
34
+ }
35
+
36
+ if (timeoutRef.current) {
37
+ clearTimeout(timeoutRef.current);
38
+ }
39
+
40
+ navigator.clipboard
41
+ .writeText(textToCopy)
42
+ .then(() => {
43
+ setCopied(true);
44
+ timeoutRef.current = setTimeout(() => {
45
+ setCopied(false);
46
+ timeoutRef.current = null;
47
+ }, RESET_TIMEOUT_MS);
48
+ })
49
+ .catch((error) => {
50
+ console.error('Failed to copy to clipboard:', error);
51
+ });
52
+ }, [hasCopyableValue, textToCopy]);
53
+
54
+ return (
55
+ <div className="group flex items-center gap-2">
56
+ <span className="text-gray-400 dark:text-neutral-500 text-sm">{label}:</span>
57
+ <TooltipProvider>
58
+ <Tooltip open={copied}>
59
+ <TooltipTrigger asChild>
60
+ <button
61
+ type="button"
62
+ className={cn(
63
+ 'text-gray-700 dark:text-neutral-300 text-sm',
64
+ hasCopyableValue &&
65
+ 'cursor-pointer hover:text-gray-900 dark:hover:text-neutral-100 transition-colors'
66
+ )}
67
+ disabled={!hasCopyableValue}
68
+ aria-label={`Copy ${label}`}
69
+ onClick={handleCopy}
70
+ >
71
+ {displayValue}
72
+ </button>
73
+ </TooltipTrigger>
74
+ <TooltipContent side="top" sideOffset={4}>
75
+ <p className="font-medium text-xs leading-5">Copied</p>
76
+ </TooltipContent>
77
+ </Tooltip>
78
+ </TooltipProvider>
79
+ {hasCopyableValue && (
80
+ <CopyButton
81
+ text={textToCopy}
82
+ showText={false}
83
+ className="h-6 w-6 p-1 min-w-0 shrink-0 text-black dark:text-white bg-white dark:bg-neutral-700 hover:bg-neutral-100 dark:hover:bg-neutral-600 border-none opacity-0 group-hover:opacity-100 transition-opacity"
84
+ />
85
+ )}
86
+ </div>
87
+ );
88
+ }
89
+
90
+ interface ConnectionStringSectionProps {
91
+ className?: string;
92
+ }
93
+
94
+ export function ConnectionStringSection({ className }: ConnectionStringSectionProps) {
95
+ const [showConnectionPassword, setShowConnectionPassword] = useState(false);
96
+ const [showParamsPassword, setShowParamsPassword] = useState(false);
97
+
98
+ const { connectionData, isLoading: isConnectionLoading } = useDatabaseConnectionString();
99
+ const { passwordData } = useDatabasePassword();
100
+
101
+ const dbParams = connectionData?.parameters;
102
+ const dbPassword = passwordData?.databasePassword || '';
103
+ const maskedPassword = dbParams?.password || '********';
104
+
105
+ const connectionStringDisplay = useMemo(() => {
106
+ if (!connectionData?.connectionURL) {
107
+ return '';
108
+ }
109
+ if (showConnectionPassword && dbPassword) {
110
+ return connectionData.connectionURL.replace('********', dbPassword);
111
+ }
112
+ return connectionData.connectionURL;
113
+ }, [connectionData?.connectionURL, showConnectionPassword, dbPassword]);
114
+
115
+ const connectionStringClipboard = useMemo(() => {
116
+ if (!connectionData?.connectionURL || !dbPassword) {
117
+ return connectionData?.connectionURL || '';
118
+ }
119
+ return connectionData.connectionURL.replace('********', dbPassword);
120
+ }, [connectionData?.connectionURL, dbPassword]);
121
+
122
+ return (
123
+ <div className={cn('flex flex-col gap-6', isConnectionLoading && 'animate-pulse', className)}>
124
+ <p className="text-gray-500 dark:text-neutral-400 text-base leading-7">
125
+ Ideal for applications with persistent and long-lived connections, such as those running on
126
+ virtual machines or long-standing containers.
127
+ </p>
128
+
129
+ {/* Connection String */}
130
+ <div className="bg-gray-100 dark:bg-neutral-900 rounded p-3">
131
+ <div className="flex items-center justify-between mb-2">
132
+ <div className="bg-gray-200 dark:bg-neutral-700 rounded px-2 h-5 flex items-center justify-center">
133
+ <span className="text-gray-700 dark:text-neutral-50 text-xs">connection string</span>
134
+ </div>
135
+ <div className="flex items-center gap-2">
136
+ <ShowPasswordButton
137
+ show={showConnectionPassword}
138
+ onToggle={() => setShowConnectionPassword(!showConnectionPassword)}
139
+ />
140
+ <CopyButton
141
+ text={connectionStringClipboard}
142
+ showText={false}
143
+ className="h-6 w-6 p-1 min-w-0 shrink-0 text-black dark:text-white bg-white dark:bg-neutral-700 hover:bg-neutral-100 dark:hover:bg-neutral-600 border-none"
144
+ />
145
+ </div>
146
+ </div>
147
+ <p className="text-gray-700 dark:text-neutral-300 text-sm leading-6 break-words">
148
+ {connectionStringDisplay || 'Loading...'}
149
+ </p>
150
+ </div>
151
+
152
+ <div className="h-px bg-gray-200 dark:bg-neutral-700" />
153
+
154
+ {/* Parameters */}
155
+ <div className="bg-gray-100 dark:bg-neutral-900 rounded p-3">
156
+ <div className="flex items-center justify-between mb-4">
157
+ <div className="bg-gray-200 dark:bg-neutral-700 rounded px-2 h-5 flex items-center justify-center">
158
+ <span className="text-gray-700 dark:text-neutral-50 text-xs">parameters</span>
159
+ </div>
160
+ <ShowPasswordButton
161
+ show={showParamsPassword}
162
+ onToggle={() => setShowParamsPassword(!showParamsPassword)}
163
+ />
164
+ </div>
165
+ <div className="flex flex-col gap-3">
166
+ <ParameterRow label="HOST" value={dbParams?.host} />
167
+ <ParameterRow label="DATABASE" value={dbParams?.database} />
168
+ <ParameterRow label="USER" value={dbParams?.user} />
169
+ <ParameterRow label="PORT" value={dbParams?.port} />
170
+ <ParameterRow
171
+ label="PASSWORD"
172
+ value={showParamsPassword ? dbPassword || maskedPassword : maskedPassword}
173
+ copyValue={dbPassword || maskedPassword}
174
+ />
175
+ <ParameterRow label="SSL" value={dbParams?.sslmode} />
176
+ </div>
177
+ </div>
178
+ </div>
179
+ );
180
+ }
@@ -0,0 +1,159 @@
1
+ import { useState, useMemo } from 'react';
2
+ import { ChevronDown } from 'lucide-react';
3
+ import {
4
+ CodeBlock,
5
+ CopyButton,
6
+ DropdownMenu,
7
+ DropdownMenuContent,
8
+ DropdownMenuItem,
9
+ DropdownMenuTrigger,
10
+ } from '@/components';
11
+ import { CursorDeeplinkGenerator } from './mcp/CursorDeeplinkGenerator';
12
+ import { QoderDeeplinkGenerator } from './mcp/QoderDeeplinkGenerator';
13
+ import { MCP_AGENTS, GenerateInstallCommand, createMCPConfig, type MCPAgent } from './mcp/helpers';
14
+ import { cn } from '@/lib/utils/utils';
15
+
16
+ interface McpConnectionSectionProps {
17
+ apiKey: string;
18
+ appUrl: string;
19
+ isLoading?: boolean;
20
+ className?: string;
21
+ }
22
+
23
+ export function McpConnectionSection({
24
+ apiKey,
25
+ appUrl,
26
+ isLoading = false,
27
+ className,
28
+ }: McpConnectionSectionProps) {
29
+ const [selectedAgent, setSelectedAgent] = useState<MCPAgent>(MCP_AGENTS[0]);
30
+
31
+ const installCommand = useMemo(() => {
32
+ return GenerateInstallCommand(selectedAgent, apiKey);
33
+ }, [selectedAgent, apiKey]);
34
+
35
+ const mcpJsonConfig = useMemo(() => {
36
+ const config = createMCPConfig(apiKey, 'macos-linux', appUrl);
37
+ return JSON.stringify(config, null, 2);
38
+ }, [apiKey, appUrl]);
39
+
40
+ const testPrompt =
41
+ "I'm using InsForge as my backend platform, call InsForge MCP's fetch-docs tool to learn about InsForge instructions.";
42
+
43
+ return (
44
+ <div className={cn('flex flex-col gap-6', className)}>
45
+ <p className="text-gray-500 dark:text-neutral-400 text-base leading-7">
46
+ Install the MCP server so your coding agent can access and build the backend.
47
+ </p>
48
+
49
+ {/* Agent Selector Dropdown */}
50
+ <DropdownMenu>
51
+ <DropdownMenuTrigger asChild>
52
+ <button className="w-40 bg-gray-100 dark:bg-[rgba(0,0,0,0.12)] border border-gray-300 dark:border-[rgba(255,255,255,0.24)] rounded flex items-center justify-between px-2 py-1 cursor-pointer">
53
+ <div className="flex items-center gap-2">
54
+ {selectedAgent.logo && (
55
+ <div className="w-6 h-6 flex items-center justify-center">{selectedAgent.logo}</div>
56
+ )}
57
+ <span className="text-gray-900 dark:text-white text-sm font-medium">
58
+ {selectedAgent.displayName}
59
+ </span>
60
+ </div>
61
+ <ChevronDown className="w-5 h-5 text-gray-400 dark:text-neutral-400" />
62
+ </button>
63
+ </DropdownMenuTrigger>
64
+ <DropdownMenuContent
65
+ align="start"
66
+ className="w-40 bg-white dark:bg-neutral-800 border border-gray-200 dark:border-neutral-700 rounded shadow-lg p-0"
67
+ >
68
+ {MCP_AGENTS.map((agent) => (
69
+ <DropdownMenuItem
70
+ key={agent.id}
71
+ onSelect={() => setSelectedAgent(agent)}
72
+ className="flex items-center gap-2 px-2 py-2 text-gray-900 dark:text-white text-sm hover:bg-gray-100 dark:hover:bg-neutral-700 cursor-pointer"
73
+ >
74
+ {agent.logo && (
75
+ <div className="w-6 h-6 flex items-center justify-center">{agent.logo}</div>
76
+ )}
77
+ <span className="font-medium">{agent.displayName}</span>
78
+ </DropdownMenuItem>
79
+ ))}
80
+ </DropdownMenuContent>
81
+ </DropdownMenu>
82
+
83
+ {/* Step 1 - Conditional based on agent */}
84
+ {selectedAgent.id === 'cursor' ? (
85
+ <div className="flex flex-col gap-3">
86
+ <p className="text-gray-900 dark:text-white text-sm">
87
+ <span className="font-semibold leading-5">1.</span>
88
+ <span className="leading-6"> Install in one click</span>
89
+ </p>
90
+ <div className="w-fit">
91
+ <CursorDeeplinkGenerator apiKey={apiKey} os="macos-linux" />
92
+ </div>
93
+ </div>
94
+ ) : selectedAgent.id === 'qoder' ? (
95
+ <div className="flex flex-col gap-3">
96
+ <p className="text-gray-900 dark:text-white text-sm">
97
+ <span className="font-semibold leading-5">1.</span>
98
+ <span className="leading-6"> Install in one click</span>
99
+ </p>
100
+ <div className="w-fit">
101
+ <QoderDeeplinkGenerator apiKey={apiKey} os="macos-linux" />
102
+ </div>
103
+ </div>
104
+ ) : selectedAgent.id === 'mcp' ? (
105
+ <div className="flex flex-col gap-3">
106
+ <p className="text-gray-900 dark:text-white text-sm">
107
+ <span className="font-semibold leading-5">1.</span>
108
+ <span className="leading-6">
109
+ {' '}
110
+ Copy the configuration below and add it to your AI assistant.
111
+ </span>
112
+ </p>
113
+ <div className="bg-gray-100 dark:bg-neutral-900 rounded overflow-hidden flex flex-col h-[320px] w-full">
114
+ {/* Header - fixed at top */}
115
+ <div className="bg-gray-100 dark:bg-neutral-900 flex items-center justify-between p-3">
116
+ <div className="bg-gray-200 dark:bg-neutral-700 rounded px-2">
117
+ <span className="text-gray-700 dark:text-neutral-50 text-xs">
118
+ MCP Configuration
119
+ </span>
120
+ </div>
121
+ <CopyButton
122
+ text={mcpJsonConfig}
123
+ showText={false}
124
+ className="h-6 w-6 p-1 bg-white dark:bg-neutral-700 hover:bg-neutral-100 dark:hover:bg-neutral-600 border-none rounded-md shadow-sm min-w-0 text-black dark:text-white"
125
+ />
126
+ </div>
127
+ {/* Scrollable content */}
128
+ <div className="flex-1 overflow-auto p-3">
129
+ <pre className="text-gray-700 dark:text-neutral-300 text-sm leading-6 m-0 whitespace-pre-wrap break-all">
130
+ <code>{mcpJsonConfig}</code>
131
+ </pre>
132
+ </div>
133
+ </div>
134
+ </div>
135
+ ) : (
136
+ <div className="flex flex-col gap-3">
137
+ <p className="text-gray-900 dark:text-white text-sm">
138
+ <span className="font-semibold leading-5">1.</span>
139
+ <span className="leading-6"> Install in one click</span>
140
+ </p>
141
+ <CodeBlock
142
+ code={installCommand}
143
+ label="Terminal Command"
144
+ className={cn(isLoading && 'animate-pulse')}
145
+ />
146
+ </div>
147
+ )}
148
+
149
+ {/* Step 2 */}
150
+ <div className="flex flex-col gap-3">
151
+ <p className="text-gray-900 dark:text-white text-sm">
152
+ <span className="font-semibold leading-5">2.</span>
153
+ <span className="leading-6"> Check for connection using this prompt</span>
154
+ </p>
155
+ <CodeBlock code={testPrompt} label="prompt" className="bg-gray-100 dark:bg-neutral-900" />
156
+ </div>
157
+ </div>
158
+ );
159
+ }
@@ -0,0 +1,68 @@
1
+ import { useEffect, useCallback } from 'react';
2
+ import { useModal } from '@/lib/hooks/useModal';
3
+ import { parseCloudEvent } from '@/lib/utils/cloudMessaging';
4
+ import { isIframe } from '@/lib/utils/utils';
5
+ import { useMcpUsage } from '@/features/logs/hooks/useMcpUsage';
6
+ import { getOnboardingSkipped, setOnboardingSkipped } from './OnboardingModal';
7
+
8
+ /**
9
+ * OnboardingController manages onboarding modal state:
10
+ * - Handles Cloud parent messages in iframe mode
11
+ * - Auto-opens onboarding for new users (non-iframe mode)
12
+ * - Auto-closes onboarding when MCP connection is established (all modes)
13
+ */
14
+ export function OnboardingController() {
15
+ const { setOnboardingModalOpen } = useModal();
16
+ const { hasCompletedOnboarding, isLoading: isMcpLoading } = useMcpUsage();
17
+
18
+ // Handle messages from Cloud parent window (iframe mode only)
19
+ const handleMessage = useCallback(
20
+ (event: MessageEvent) => {
21
+ if (!isIframe()) {
22
+ return;
23
+ }
24
+
25
+ const result = parseCloudEvent(event.data);
26
+ if (!result.ok) {
27
+ return;
28
+ }
29
+
30
+ const cloudEvent = result.data;
31
+
32
+ switch (cloudEvent.type) {
33
+ case 'SHOW_ONBOARDING_OVERLAY':
34
+ setOnboardingModalOpen(true);
35
+ break;
36
+ }
37
+ },
38
+ [setOnboardingModalOpen]
39
+ );
40
+
41
+ useEffect(() => {
42
+ window.addEventListener('message', handleMessage);
43
+ return () => {
44
+ window.removeEventListener('message', handleMessage);
45
+ };
46
+ }, [handleMessage]);
47
+
48
+ // Auto-open onboarding modal for new users (non-iframe mode only)
49
+ // In iframe mode, Cloud controls when to show the modal via messages
50
+ useEffect(() => {
51
+ if (isIframe()) {
52
+ return;
53
+ }
54
+ if (!isMcpLoading && !hasCompletedOnboarding && !getOnboardingSkipped()) {
55
+ setOnboardingModalOpen(true);
56
+ }
57
+ }, [isMcpLoading, hasCompletedOnboarding, setOnboardingModalOpen]);
58
+
59
+ // Auto-close onboarding modal when MCP connection is established (all modes)
60
+ useEffect(() => {
61
+ if (!isMcpLoading && hasCompletedOnboarding) {
62
+ setOnboardingModalOpen(false);
63
+ setOnboardingSkipped(false);
64
+ }
65
+ }, [hasCompletedOnboarding, isMcpLoading, setOnboardingModalOpen]);
66
+
67
+ return null;
68
+ }