insforge 0.3.2 → 1.2.10

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 (507) hide show
  1. package/.claude-plugin/marketplace.json +20 -0
  2. package/.cursor/rules/cursor-rules.mdc +94 -0
  3. package/.dockerignore +3 -0
  4. package/.env.example +33 -4
  5. package/.github/ISSUE_TEMPLATE/bug_report.yml +13 -60
  6. package/.github/ISSUE_TEMPLATE/config.yml +2 -2
  7. package/.github/ISSUE_TEMPLATE/feature_request.yml +10 -63
  8. package/.github/PULL_REQUEST_TEMPLATE.md +7 -0
  9. package/.github/workflows/build-image.yml +2 -1
  10. package/.github/workflows/e2e.yml +63 -0
  11. package/CHANGELOG.md +41 -0
  12. package/CLAUDE_PLUGIN.md +104 -0
  13. package/CODE_OF_CONDUCT.md +128 -0
  14. package/CONTRIBUTING.md +1 -1
  15. package/Dockerfile +4 -1
  16. package/README.md +66 -18
  17. package/assets/mcpInstallv2.png +0 -0
  18. package/assets/sampleResponse.png +0 -0
  19. package/auth/index.html +13 -0
  20. package/auth/package.json +28 -0
  21. package/auth/public/favicon.ico +0 -0
  22. package/auth/src/App.tsx +33 -0
  23. package/auth/src/components/ErrorCard.tsx +37 -0
  24. package/auth/src/components/Layout.tsx +13 -0
  25. package/auth/src/index.css +19 -0
  26. package/auth/src/lib/broadcastService.ts +115 -0
  27. package/auth/src/lib/utils.ts +11 -0
  28. package/auth/src/main.tsx +22 -0
  29. package/auth/src/pages/ForgotPasswordPage.tsx +11 -0
  30. package/auth/src/pages/ResetPasswordPage.tsx +11 -0
  31. package/auth/src/pages/SignInPage.tsx +57 -0
  32. package/auth/src/pages/SignUpPage.tsx +57 -0
  33. package/auth/src/pages/VerifyEmailPage.tsx +20 -0
  34. package/auth/src/vite-env.d.ts +10 -0
  35. package/auth/tsconfig.json +32 -0
  36. package/auth/tsconfig.node.json +11 -0
  37. package/auth/vite.config.ts +25 -0
  38. package/backend/package.json +9 -9
  39. package/backend/src/api/{middleware → middlewares}/auth.ts +8 -9
  40. package/backend/src/api/middlewares/rate-limiters.ts +127 -0
  41. package/backend/src/api/routes/{ai.ts → ai/index.routes.ts} +20 -24
  42. package/backend/src/api/routes/auth/index.routes.ts +570 -0
  43. package/backend/src/api/routes/auth/oauth.routes.ts +448 -0
  44. package/backend/src/api/routes/{database.advance.ts → database/advance.routes.ts} +107 -65
  45. package/backend/src/api/routes/database/index.routes.ts +13 -0
  46. package/backend/src/api/routes/{database.records.ts → database/records.routes.ts} +22 -8
  47. package/backend/src/api/routes/{database.tables.ts → database/tables.routes.ts} +20 -23
  48. package/backend/src/api/routes/docs/index.routes.ts +76 -0
  49. package/backend/src/api/routes/functions/index.routes.ts +188 -0
  50. package/backend/src/api/routes/{logs.ts → logs/index.routes.ts} +25 -30
  51. package/backend/src/api/routes/{metadata.ts → metadata/index.routes.ts} +21 -31
  52. package/backend/src/api/routes/{secrets.ts → secrets/index.routes.ts} +27 -22
  53. package/backend/src/api/routes/{storage.ts → storage/index.routes.ts} +34 -53
  54. package/backend/src/api/routes/usage/index.routes.ts +89 -0
  55. package/backend/src/infra/config/app.config.ts +51 -0
  56. package/backend/src/{core/database/manager.ts → infra/database/database.manager.ts} +76 -85
  57. package/backend/src/infra/database/migrations/013_create-auth-schema-functions.sql +44 -0
  58. package/backend/src/infra/database/migrations/014_add-updated-at-trigger-user-table.sql +8 -0
  59. package/backend/src/infra/database/migrations/015_create-auth-config-and-email-otp-tables.sql +60 -0
  60. package/backend/src/infra/database/migrations/016_update-auth-config-and-email-otp.sql +24 -0
  61. package/backend/src/{core/secrets/encryption.ts → infra/security/encryption.manager.ts} +3 -2
  62. package/backend/src/infra/security/token.manager.ts +125 -0
  63. package/backend/src/{core/socket/socket.ts → infra/socket/socket.manager.ts} +15 -15
  64. package/backend/src/providers/ai/openrouter.provider.ts +377 -0
  65. package/backend/src/providers/email/base.provider.ts +41 -0
  66. package/backend/src/providers/email/cloud.provider.ts +187 -0
  67. package/backend/src/{core/logs/providers → providers/logs}/base.provider.ts +11 -11
  68. package/backend/src/{core/logs/providers → providers/logs}/cloudwatch.provider.ts +61 -38
  69. package/backend/src/providers/logs/local.provider.ts +185 -0
  70. package/backend/src/providers/oauth/base.provider.ts +29 -0
  71. package/backend/src/providers/oauth/discord.provider.ts +195 -0
  72. package/backend/src/providers/oauth/facebook.provider.ts +194 -0
  73. package/backend/src/providers/oauth/github.provider.ts +208 -0
  74. package/backend/src/providers/oauth/google.provider.ts +249 -0
  75. package/backend/src/providers/oauth/index.ts +7 -0
  76. package/backend/src/providers/oauth/linkedin.provider.ts +240 -0
  77. package/backend/src/providers/oauth/microsoft.provider.ts +169 -0
  78. package/backend/src/providers/oauth/x.provider.ts +202 -0
  79. package/backend/src/providers/storage/base.provider.ts +29 -0
  80. package/backend/src/providers/storage/local.provider.ts +103 -0
  81. package/backend/src/providers/storage/s3.provider.ts +313 -0
  82. package/backend/src/server.ts +70 -74
  83. package/backend/src/{core/ai/config.ts → services/ai/ai-config.service.ts} +19 -24
  84. package/backend/src/services/ai/ai-model.service.ts +60 -0
  85. package/backend/src/{core/ai/usage.ts → services/ai/ai-usage.service.ts} +28 -35
  86. package/backend/src/{core/ai/chat.ts → services/ai/chat-completion.service.ts} +37 -24
  87. package/backend/src/services/ai/helpers.ts +64 -0
  88. package/backend/src/{core/ai/image.ts → services/ai/image-generation.service.ts} +17 -19
  89. package/backend/src/services/ai/index.ts +13 -0
  90. package/backend/src/services/auth/auth-config.service.ts +250 -0
  91. package/backend/src/services/auth/auth-otp.service.ts +424 -0
  92. package/backend/src/services/auth/auth.service.ts +1136 -0
  93. package/backend/src/services/auth/index.ts +4 -0
  94. package/backend/src/{core/auth/oauth.ts → services/auth/oauth-config.service.ts} +106 -52
  95. package/backend/src/{core/database/advance.ts → services/database/database-advance.service.ts} +97 -131
  96. package/backend/src/services/database/database-table.service.ts +811 -0
  97. package/backend/src/services/email/email.service.ts +75 -0
  98. package/backend/src/{core/functions/functions.ts → services/functions/function.service.ts} +95 -88
  99. package/backend/src/{core/logs/audit.ts → services/logs/audit.service.ts} +92 -75
  100. package/backend/src/services/logs/log.service.ts +73 -0
  101. package/backend/src/{core/secrets/secrets.ts → services/secrets/secret.service.ts} +48 -66
  102. package/backend/src/services/storage/storage.service.ts +617 -0
  103. package/backend/src/services/usage/usage.service.ts +149 -0
  104. package/backend/src/types/auth.ts +66 -2
  105. package/backend/src/types/email.ts +8 -0
  106. package/backend/src/types/error-constants.ts +4 -0
  107. package/backend/src/types/logs.ts +0 -29
  108. package/backend/src/{core/socket/types.ts → types/socket.ts} +5 -6
  109. package/backend/src/utils/environment.ts +9 -3
  110. package/backend/src/utils/logger.ts +20 -2
  111. package/backend/src/utils/seed.ts +150 -57
  112. package/backend/src/utils/sql-parser.ts +1 -1
  113. package/backend/src/utils/utils.ts +114 -0
  114. package/backend/src/utils/validations.ts +40 -4
  115. package/backend/tests/local/test-ai-config.sh +129 -0
  116. package/backend/tests/local/test-ai-usage.sh +80 -0
  117. package/backend/tests/local/test-auth-router.sh +1 -1
  118. package/backend/tests/local/test-e2e.sh +1 -1
  119. package/backend/tests/local/test-functions.sh +123 -0
  120. package/backend/tests/local/test-logs.sh +132 -0
  121. package/backend/tests/local/test-public-bucket.sh +3 -3
  122. package/backend/tests/local/test-secrets.sh +14 -12
  123. package/backend/tests/local/test-traditional-rest.sh +2 -2
  124. package/backend/tests/manual/test-rawsql-modes.sh +244 -0
  125. package/backend/tests/test-config.sh +37 -1
  126. package/backend/tests/unit/cloud-token.test.ts +48 -0
  127. package/backend/tests/unit/constant.test.ts +8 -0
  128. package/backend/tests/unit/email.test.ts +372 -0
  129. package/backend/tests/unit/environment.test.ts +59 -0
  130. package/backend/tests/unit/helpers.test.ts +63 -0
  131. package/backend/tests/unit/logger.test.ts +22 -0
  132. package/backend/tests/unit/rate-limit.test.ts +154 -0
  133. package/backend/tests/unit/response.test.ts +58 -0
  134. package/backend/tests/unit/sql-parser.test.ts +74 -0
  135. package/backend/tests/unit/uuid.test.ts +21 -0
  136. package/backend/tests/unit/validations.test.ts +80 -0
  137. package/backend/tsconfig.json +1 -1
  138. package/backend/vitest.config.ts +11 -0
  139. package/claude-plugin/.claude-plugin/plugin.json +24 -0
  140. package/claude-plugin/README.md +133 -0
  141. package/claude-plugin/skills/insforge-schema-patterns/SKILL.md +270 -0
  142. package/docker-compose.prod.yml +60 -4
  143. package/docker-compose.yml +65 -4
  144. package/docker-init/db/db-init.sql +6 -34
  145. package/docker-init/logs/vector.yml +236 -0
  146. package/docs/README.md +44 -0
  147. package/docs/changelog.mdx +67 -0
  148. package/docs/core-concepts/ai/architecture.mdx +373 -0
  149. package/docs/core-concepts/ai/sdk.mdx +213 -0
  150. package/docs/core-concepts/authentication/architecture.mdx +278 -0
  151. package/docs/core-concepts/authentication/sdk.mdx +414 -0
  152. package/docs/core-concepts/authentication/ui-components/customization.mdx +529 -0
  153. package/docs/core-concepts/authentication/ui-components/nextjs.mdx +221 -0
  154. package/docs/core-concepts/authentication/ui-components/react-router.mdx +184 -0
  155. package/docs/core-concepts/authentication/ui-components/react.mdx +129 -0
  156. package/docs/core-concepts/database/architecture.mdx +256 -0
  157. package/docs/core-concepts/database/sdk.mdx +382 -0
  158. package/docs/core-concepts/functions/architecture.mdx +105 -0
  159. package/docs/core-concepts/functions/sdk.mdx +184 -0
  160. package/docs/core-concepts/storage/architecture.mdx +243 -0
  161. package/docs/core-concepts/storage/sdk.mdx +253 -0
  162. package/docs/deployment/README.md +94 -0
  163. package/docs/deployment/deploy-to-aws-ec2.md +565 -0
  164. package/docs/deployment/deploy-to-azure-virtual-machines.md +313 -0
  165. package/docs/deployment/deploy-to-google-cloud-compute-engine.md +613 -0
  166. package/docs/deployment/deploy-to-render.md +441 -0
  167. package/docs/docs.json +210 -0
  168. package/docs/examples/framework-guides/nextjs.mdx +131 -0
  169. package/docs/examples/framework-guides/nuxt.mdx +165 -0
  170. package/docs/examples/framework-guides/react.mdx +165 -0
  171. package/docs/examples/framework-guides/svelte.mdx +153 -0
  172. package/docs/examples/framework-guides/vue.mdx +159 -0
  173. package/docs/examples/overview.mdx +67 -0
  174. package/docs/favicon.svg +19 -0
  175. package/docs/images/changelog/nov-2025/auth-components.webp +0 -0
  176. package/docs/images/changelog/nov-2025/database-metadata.webp +0 -0
  177. package/docs/images/changelog/nov-2025/quickstart-prompts.webp +0 -0
  178. package/docs/images/changelog/nov-2025/sql-editor.webp +0 -0
  179. package/docs/images/changelog/nov-2025/usage-page.webp +0 -0
  180. package/docs/images/changelog/october-2025/csv-upload.webp +0 -0
  181. package/docs/images/changelog/october-2025/logs-feature.webp +0 -0
  182. package/docs/images/changelog/october-2025/oauth-providers.webp +0 -0
  183. package/docs/images/checks-passed.png +0 -0
  184. package/docs/images/dashboard-connect-expanded.png +0 -0
  185. package/docs/images/dashboard-connect.png +0 -0
  186. package/docs/images/hero-dark.png +0 -0
  187. package/docs/images/hero-light.png +0 -0
  188. package/docs/images/icons/ai.svg +4 -0
  189. package/docs/images/icons/auth.svg +1 -0
  190. package/docs/images/icons/database.svg +1 -0
  191. package/docs/images/icons/function.svg +1 -0
  192. package/docs/images/icons/storage.svg +1 -0
  193. package/docs/images/logos/nextjs.svg +4 -0
  194. package/docs/images/logos/nuxt.svg +4 -0
  195. package/docs/images/logos/react.svg +5 -0
  196. package/docs/images/logos/svelte.svg +4 -0
  197. package/docs/images/logos/vue.svg +5 -0
  198. package/docs/images/mcp-install.png +0 -0
  199. package/docs/images/onboarding-mcp.png +0 -0
  200. package/docs/insforge-instructions-sdk.md +55 -374
  201. package/docs/introduction.mdx +45 -0
  202. package/docs/logo/dark.svg +22 -0
  203. package/docs/logo/light.svg +20 -0
  204. package/docs/partnership.mdx +647 -0
  205. package/docs/quickstart.mdx +83 -0
  206. package/docs/showcase/2048-arena.png +0 -0
  207. package/docs/showcase/framegen-cloud.png +0 -0
  208. package/docs/showcase/line-connect-race.png +0 -0
  209. package/docs/showcase/moment-vibe.png +0 -0
  210. package/docs/showcase/national-flags.png +0 -0
  211. package/docs/showcase/pokemon-vibe.png +0 -0
  212. package/docs/showcase/pure-browse-buy.png +0 -0
  213. package/docs/showcase.mdx +52 -0
  214. package/docs/snippets/sdk-installation.mdx +22 -0
  215. package/docs/snippets/service-icons.mdx +27 -0
  216. package/eslint.config.js +10 -3
  217. package/frontend/package.json +10 -4
  218. package/frontend/src/App.tsx +13 -82
  219. package/frontend/src/assets/icons/connected.svg +3 -0
  220. package/frontend/src/assets/icons/loader.svg +9 -0
  221. package/frontend/src/assets/logos/apple.svg +4 -0
  222. package/frontend/src/assets/logos/discord.svg +1 -1
  223. package/frontend/src/assets/logos/facebook.svg +3 -0
  224. package/frontend/src/assets/logos/instagram.svg +2 -0
  225. package/frontend/src/assets/logos/linkedin.svg +3 -0
  226. package/frontend/src/assets/logos/microsoft.svg +1 -0
  227. package/frontend/src/assets/logos/spotify.svg +17 -0
  228. package/frontend/src/assets/logos/tiktok.svg +6 -0
  229. package/frontend/src/assets/logos/x.svg +3 -0
  230. package/frontend/src/components/Checkbox.tsx +27 -29
  231. package/frontend/src/components/CodeBlock.tsx +55 -2
  232. package/frontend/src/components/CodeEditor.tsx +92 -0
  233. package/frontend/src/components/ConfirmDialog.tsx +1 -1
  234. package/frontend/src/components/ConnectCTA.tsx +38 -0
  235. package/frontend/src/components/CopyButton.tsx +52 -15
  236. package/frontend/src/components/ErrorState.tsx +1 -2
  237. package/frontend/src/components/FeatureSidebar.tsx +6 -6
  238. package/frontend/src/components/FeatureSidebarItem.tsx +2 -2
  239. package/frontend/src/components/JsonHighlight.tsx +21 -9
  240. package/frontend/src/components/ProjectInfoModal.tsx +128 -0
  241. package/frontend/src/components/PromptDialog.tsx +1 -4
  242. package/frontend/src/components/SearchInput.tsx +1 -2
  243. package/frontend/src/components/Stepper.tsx +53 -0
  244. package/frontend/src/components/ThemeToggle.tsx +3 -3
  245. package/frontend/src/components/datagrid/DataGrid.tsx +25 -32
  246. package/frontend/src/components/datagrid/cell-editors/DateCellEditor.tsx +1 -2
  247. package/frontend/src/components/datagrid/cell-editors/JsonCellEditor.tsx +2 -4
  248. package/frontend/src/components/datagrid/index.ts +23 -0
  249. package/frontend/src/components/index.ts +23 -30
  250. package/frontend/src/components/layout/AppHeader.tsx +133 -92
  251. package/frontend/src/components/layout/AppSidebar.tsx +80 -170
  252. package/frontend/src/components/layout/Layout.tsx +12 -23
  253. package/frontend/src/components/layout/PrimaryMenu.tsx +187 -0
  254. package/frontend/src/components/layout/SecondaryMenu.tsx +70 -0
  255. package/frontend/src/components/layout/index.ts +5 -0
  256. package/frontend/src/components/radix/Tooltip.tsx +24 -13
  257. package/frontend/src/components/radix/index.ts +22 -0
  258. package/frontend/src/features/ai/components/AIConfigCard.tsx +129 -83
  259. package/frontend/src/features/ai/components/AIEmptyState.tsx +12 -7
  260. package/frontend/src/features/ai/components/ModalityFilterSidebar.tsx +101 -0
  261. package/frontend/src/features/ai/components/ModelSelectionDialog.tsx +135 -0
  262. package/frontend/src/features/ai/components/ModelSelectionGrid.tsx +51 -0
  263. package/frontend/src/features/ai/components/SystemPromptDialog.tsx +118 -0
  264. package/frontend/src/features/ai/components/index.ts +6 -0
  265. package/frontend/src/features/ai/helpers.ts +57 -71
  266. package/frontend/src/features/ai/hooks/useAIConfigs.ts +39 -113
  267. package/frontend/src/features/ai/hooks/useAIUsage.ts +0 -2
  268. package/frontend/src/features/ai/page/AIPage.tsx +67 -79
  269. package/frontend/src/features/ai/services/ai.service.ts +5 -5
  270. package/frontend/src/features/auth/components/AuthPreview.tsx +96 -0
  271. package/frontend/src/features/auth/components/OAuthConfigDialog.tsx +53 -30
  272. package/frontend/src/features/auth/components/UserFormDialog.tsx +13 -6
  273. package/frontend/src/features/auth/components/UsersDataGrid.tsx +44 -14
  274. package/frontend/src/features/auth/components/index.ts +5 -0
  275. package/frontend/src/features/auth/helpers.tsx +200 -0
  276. package/frontend/src/features/auth/hooks/useAnonToken.ts +30 -0
  277. package/frontend/src/features/auth/hooks/useAuthConfig.ts +48 -0
  278. package/frontend/src/features/auth/hooks/useOAuthConfig.ts +14 -10
  279. package/frontend/src/features/auth/hooks/useUsers.ts +43 -5
  280. package/frontend/src/features/auth/index.ts +3 -2
  281. package/frontend/src/features/auth/page/AuthMethodsPage.tsx +275 -0
  282. package/frontend/src/features/auth/page/ConfigurationPage.tsx +395 -0
  283. package/frontend/src/features/auth/page/UsersPage.tsx +285 -0
  284. package/frontend/src/features/auth/services/anonToken.service.ts +11 -0
  285. package/frontend/src/features/auth/services/config.service.ts +19 -0
  286. package/frontend/src/features/auth/services/{oauth.service.ts → oauth-config.service.ts} +4 -4
  287. package/frontend/src/features/auth/services/{auth.service.ts → user.service.ts} +7 -53
  288. package/frontend/src/features/dashboard/components/ConnectionSuccessBanner.tsx +35 -0
  289. package/frontend/src/features/dashboard/components/PromptCard.tsx +21 -0
  290. package/frontend/src/features/dashboard/components/PromptDialog.tsx +103 -0
  291. package/frontend/src/features/dashboard/components/StatsCard.tsx +50 -0
  292. package/frontend/src/features/dashboard/components/index.ts +4 -0
  293. package/frontend/src/features/dashboard/page/DashboardPage.tsx +187 -169
  294. package/frontend/src/features/dashboard/prompts/ai-chatbot.ts +13 -0
  295. package/frontend/src/features/dashboard/prompts/crm-system.ts +13 -0
  296. package/frontend/src/features/dashboard/prompts/ecommerce-platform.ts +12 -0
  297. package/frontend/src/features/dashboard/prompts/index.ts +31 -0
  298. package/frontend/src/features/dashboard/prompts/instagram-clone.ts +11 -0
  299. package/frontend/src/features/dashboard/prompts/notion-clone.ts +14 -0
  300. package/frontend/src/features/dashboard/prompts/reddit-clone.ts +12 -0
  301. package/frontend/src/features/database/components/DatabaseDataGrid.tsx +48 -17
  302. package/frontend/src/features/database/components/ForeignKeyCell.tsx +15 -34
  303. package/frontend/src/features/database/components/ForeignKeyPopover.tsx +19 -20
  304. package/frontend/src/features/database/components/LinkRecordModal.tsx +120 -125
  305. package/frontend/src/features/database/components/RecordFormDialog.tsx +22 -33
  306. package/frontend/src/features/database/components/RecordFormField.tsx +45 -47
  307. package/frontend/src/features/database/components/TableEmptyState.tsx +6 -5
  308. package/frontend/src/features/database/components/TableForm.tsx +28 -15
  309. package/frontend/src/features/database/components/TableFormColumn.tsx +2 -3
  310. package/frontend/src/features/database/components/TableSidebar.tsx +1 -1
  311. package/frontend/src/features/database/components/TablesEmptyState.tsx +48 -0
  312. package/frontend/src/features/database/components/TemplateCard.tsx +37 -0
  313. package/frontend/src/features/database/components/TemplatePreview.tsx +92 -0
  314. package/frontend/src/features/database/components/index.ts +19 -0
  315. package/frontend/src/features/database/constants.ts +28 -2
  316. package/frontend/src/features/database/contexts/SQLEditorContext.tsx +188 -0
  317. package/frontend/src/features/database/helpers.ts +2 -2
  318. package/frontend/src/features/database/hooks/useCSVImport.ts +29 -0
  319. package/frontend/src/features/database/hooks/useFullMetadata.ts +18 -0
  320. package/frontend/src/features/database/hooks/useRawSQL.ts +55 -0
  321. package/frontend/src/features/database/hooks/useRecords.ts +139 -0
  322. package/frontend/src/features/database/hooks/useTables.ts +131 -0
  323. package/frontend/src/features/database/index.ts +6 -1
  324. package/frontend/src/features/database/page/FunctionsPage.tsx +211 -0
  325. package/frontend/src/features/database/page/IndexesPage.tsx +240 -0
  326. package/frontend/src/features/database/page/PoliciesPage.tsx +248 -0
  327. package/frontend/src/features/database/page/SQLEditorPage.tsx +382 -0
  328. package/frontend/src/features/database/page/{DatabasePage.tsx → TablesPage.tsx} +186 -185
  329. package/frontend/src/features/database/page/TemplatesPage.tsx +39 -0
  330. package/frontend/src/features/database/page/TriggersPage.tsx +242 -0
  331. package/frontend/src/features/database/services/advance.service.ts +66 -0
  332. package/frontend/src/features/database/services/{database.service.ts → record.service.ts} +67 -64
  333. package/frontend/src/features/database/services/table.service.ts +64 -0
  334. package/frontend/src/features/database/templates/ai-chatbot.ts +402 -0
  335. package/frontend/src/features/database/templates/crm-system.ts +528 -0
  336. package/frontend/src/features/database/templates/ecommerce-platform.ts +553 -0
  337. package/frontend/src/features/database/templates/index.ts +34 -0
  338. package/frontend/src/features/database/templates/instagram-clone.ts +222 -0
  339. package/frontend/src/features/database/templates/notion-clone.ts +483 -0
  340. package/frontend/src/features/database/templates/reddit-clone.ts +526 -0
  341. package/frontend/src/features/functions/components/FunctionRow.tsx +2 -1
  342. package/frontend/src/features/functions/components/FunctionsSidebar.tsx +1 -1
  343. package/frontend/src/features/functions/components/SecretRow.tsx +1 -1
  344. package/frontend/src/features/functions/components/index.ts +5 -0
  345. package/frontend/src/features/functions/hooks/useFunctions.ts +4 -4
  346. package/frontend/src/features/{secrets → functions}/hooks/useSecrets.ts +5 -5
  347. package/frontend/src/features/functions/page/FunctionsPage.tsx +160 -17
  348. package/frontend/src/features/functions/{components/SecretsContent.tsx → page/SecretsPage.tsx} +8 -12
  349. package/frontend/src/features/functions/services/{functions.service.ts → function.service.ts} +2 -2
  350. package/frontend/src/features/{secrets/services/secrets.service.ts → functions/services/secret.service.ts} +2 -2
  351. package/frontend/src/features/login/hooks/usePartnerOrigin.ts +27 -0
  352. package/frontend/src/features/login/page/CloudLoginPage.tsx +79 -54
  353. package/frontend/src/features/login/page/LoginPage.tsx +16 -23
  354. package/frontend/src/features/login/services/partnership.service.ts +65 -0
  355. package/frontend/src/features/logs/components/LogsDataGrid.tsx +89 -0
  356. package/frontend/src/features/logs/components/SeverityBadge.tsx +18 -0
  357. package/frontend/src/features/logs/components/index.ts +2 -0
  358. package/frontend/src/features/logs/helpers.ts +24 -0
  359. package/frontend/src/features/logs/hooks/useAuditLogs.ts +4 -4
  360. package/frontend/src/features/logs/hooks/useLogSources.ts +137 -0
  361. package/frontend/src/features/logs/hooks/useLogs.ts +163 -0
  362. package/frontend/src/features/logs/hooks/useMcpUsage.ts +181 -0
  363. package/frontend/src/features/logs/index.ts +8 -2
  364. package/frontend/src/features/logs/page/AuditsPage.tsx +91 -38
  365. package/frontend/src/features/logs/page/LogsPage.tsx +152 -0
  366. package/frontend/src/features/logs/page/MCPLogsPage.tsx +84 -0
  367. package/frontend/src/features/logs/services/audit.service.ts +63 -0
  368. package/frontend/src/features/logs/services/log.service.ts +15 -110
  369. package/frontend/src/features/logs/services/usage.service.ts +31 -0
  370. package/frontend/src/features/onboard/components/McpConnectionStatus.tsx +68 -0
  371. package/frontend/src/features/onboard/components/OnboardingModal.tsx +267 -0
  372. package/frontend/src/features/onboard/components/VideoDemoModal.tsx +38 -0
  373. package/frontend/src/features/onboard/components/index.ts +4 -0
  374. package/frontend/src/features/onboard/components/mcp/CursorDeeplinkGenerator.tsx +2 -2
  375. package/frontend/src/features/onboard/components/mcp/{mcp-helper.tsx → helpers.tsx} +8 -8
  376. package/frontend/src/features/onboard/components/mcp/index.ts +2 -3
  377. package/frontend/src/features/onboard/index.ts +13 -3
  378. package/frontend/src/features/storage/components/BucketEmptyState.tsx +9 -6
  379. package/frontend/src/features/storage/components/BucketFormDialog.tsx +25 -41
  380. package/frontend/src/features/storage/components/FilePreviewDialog.tsx +20 -8
  381. package/frontend/src/features/storage/components/StorageDataGrid.tsx +4 -3
  382. package/frontend/src/features/storage/components/StorageManager.tsx +23 -34
  383. package/frontend/src/features/storage/components/index.ts +12 -0
  384. package/frontend/src/features/storage/hooks/useStorage.ts +208 -0
  385. package/frontend/src/features/storage/page/StoragePage.tsx +41 -115
  386. package/frontend/src/features/storage/services/storage.service.ts +22 -1
  387. package/frontend/src/features/visualizer/components/AuthNode.tsx +72 -56
  388. package/frontend/src/features/visualizer/components/BucketNode.tsx +4 -4
  389. package/frontend/src/features/visualizer/components/SchemaVisualizer.tsx +108 -80
  390. package/frontend/src/features/visualizer/components/TableNode.tsx +34 -41
  391. package/frontend/src/features/visualizer/components/VisualizerSkeleton.tsx +12 -4
  392. package/frontend/src/features/visualizer/page/VisualizerPage.tsx +33 -29
  393. package/frontend/src/index.css +1 -0
  394. package/frontend/src/lib/analytics/posthog.tsx +27 -0
  395. package/frontend/src/lib/contexts/AuthContext.tsx +38 -31
  396. package/frontend/src/lib/contexts/SocketContext.tsx +5 -6
  397. package/frontend/src/{features/metadata → lib}/hooks/useMetadata.ts +1 -1
  398. package/frontend/src/lib/hooks/useToast.tsx +6 -2
  399. package/frontend/src/lib/routing/AppRoutes.tsx +84 -0
  400. package/frontend/src/lib/routing/RequireAuth.tsx +27 -0
  401. package/frontend/src/lib/utils/cloudMessaging.ts +20 -0
  402. package/frontend/src/lib/utils/menuItems.ts +183 -0
  403. package/frontend/src/lib/utils/{validation-schemas.ts → schemaValidations.ts} +10 -5
  404. package/frontend/src/lib/utils/utils.ts +19 -1
  405. package/frontend/src/vite-env.d.ts +1 -0
  406. package/frontend/vite.config.ts +5 -3
  407. package/functions/server.ts +28 -3
  408. package/functions/worker-template.js +15 -4
  409. package/i18n/README.ar.md +130 -0
  410. package/i18n/README.de.md +130 -0
  411. package/i18n/README.es.md +154 -0
  412. package/i18n/README.fr.md +134 -0
  413. package/i18n/README.hi.md +129 -0
  414. package/i18n/README.ja.md +174 -0
  415. package/i18n/README.ko.md +137 -0
  416. package/i18n/README.pt-BR.md +131 -0
  417. package/i18n/README.ru.md +129 -0
  418. package/i18n/README.zh-CN.md +133 -0
  419. package/openapi/ai.yaml +31 -4
  420. package/openapi/auth.yaml +827 -146
  421. package/package.json +16 -7
  422. package/shared-schemas/package.json +1 -1
  423. package/shared-schemas/src/ai-api.schema.ts +34 -58
  424. package/shared-schemas/src/ai.schema.ts +5 -0
  425. package/shared-schemas/src/auth-api.schema.ts +154 -8
  426. package/shared-schemas/src/auth.schema.ts +42 -6
  427. package/shared-schemas/src/cloud-events.schema.ts +57 -0
  428. package/shared-schemas/src/database-api.schema.ts +3 -3
  429. package/shared-schemas/src/database.schema.ts +1 -1
  430. package/shared-schemas/src/index.ts +1 -0
  431. package/shared-schemas/src/logs-api.schema.ts +7 -1
  432. package/shared-schemas/src/logs.schema.ts +26 -0
  433. package/shared-schemas/src/metadata.schema.ts +9 -4
  434. package/test-gemini.sh +35 -0
  435. package/test-usage-admin.sh +57 -0
  436. package/test-usage.sh +50 -0
  437. package/zeabur/README.md +13 -0
  438. package/zeabur/template.yml +1032 -0
  439. package/.github/workflows/deploy-aws.yml +0 -130
  440. package/backend/src/api/routes/agent.ts +0 -29
  441. package/backend/src/api/routes/auth.oauth.ts +0 -482
  442. package/backend/src/api/routes/auth.ts +0 -386
  443. package/backend/src/api/routes/docs.ts +0 -66
  444. package/backend/src/api/routes/functions.ts +0 -183
  445. package/backend/src/api/routes/openapi.ts +0 -82
  446. package/backend/src/api/routes/usage.ts +0 -96
  447. package/backend/src/core/ai/client.ts +0 -242
  448. package/backend/src/core/ai/model.ts +0 -117
  449. package/backend/src/core/auth/auth.ts +0 -781
  450. package/backend/src/core/database/table.ts +0 -772
  451. package/backend/src/core/documentation/agent.ts +0 -689
  452. package/backend/src/core/documentation/openapi.ts +0 -856
  453. package/backend/src/core/logs/analytics.ts +0 -76
  454. package/backend/src/core/logs/providers/localdb.provider.ts +0 -246
  455. package/backend/src/core/storage/storage.ts +0 -923
  456. package/backend/src/utils/cloud-token.ts +0 -39
  457. package/backend/src/utils/helpers.ts +0 -49
  458. package/backend/src/utils/uuid.ts +0 -9
  459. package/backend/tests/manual/test-better-auth.sh +0 -303
  460. package/docker-init/db/logs.sql +0 -9
  461. package/frontend/README.md +0 -112
  462. package/frontend/src/components/datagrid/index.tsx +0 -20
  463. package/frontend/src/components/layout/CloudLayout.tsx +0 -95
  464. package/frontend/src/features/ai/components/AIConfigDialog.tsx +0 -76
  465. package/frontend/src/features/ai/components/AIConfigForm.tsx +0 -222
  466. package/frontend/src/features/ai/components/fields/ModalityField.tsx +0 -87
  467. package/frontend/src/features/ai/components/fields/ModelSelectionField.tsx +0 -134
  468. package/frontend/src/features/ai/components/fields/SystemPromptField.tsx +0 -33
  469. package/frontend/src/features/auth/components/AddOAuthDialog.tsx +0 -106
  470. package/frontend/src/features/auth/components/AuthMethodTab.tsx +0 -238
  471. package/frontend/src/features/auth/components/UsersTab.tsx +0 -114
  472. package/frontend/src/features/auth/page/AuthenticationPage.tsx +0 -169
  473. package/frontend/src/features/database/hooks/UseLinkModal.tsx +0 -78
  474. package/frontend/src/features/functions/components/FunctionViewer.tsx +0 -46
  475. package/frontend/src/features/functions/components/FunctionsContent.tsx +0 -88
  476. package/frontend/src/features/login/components/AuthErrorBoundary.tsx +0 -87
  477. package/frontend/src/features/login/components/PrivateRoute.tsx +0 -24
  478. package/frontend/src/features/logs/components/AnalyticsLogsTable.tsx +0 -313
  479. package/frontend/src/features/logs/components/LogsTable.tsx +0 -199
  480. package/frontend/src/features/logs/page/AnalyticsLogsPage.tsx +0 -530
  481. package/frontend/src/features/metadata/index.ts +0 -0
  482. package/frontend/src/features/metadata/page/MetadataPage.tsx +0 -136
  483. package/frontend/src/features/onboard/components/CompletionCard.tsx +0 -41
  484. package/frontend/src/features/onboard/components/OnboardButton.tsx +0 -84
  485. package/frontend/src/features/onboard/components/StepContent.tsx +0 -91
  486. package/frontend/src/features/onboard/components/TestConnectionStep.tsx +0 -53
  487. package/frontend/src/features/onboard/components/mcp/McpInstallation.tsx +0 -144
  488. package/frontend/src/features/onboard/page/OnBoardPage.tsx +0 -104
  489. package/frontend/src/features/onboard/types.ts +0 -8
  490. package/frontend/src/lib/contexts/OnboardStepContext.tsx +0 -68
  491. package/frontend/src/lib/hooks/useOnboardingCompletion.ts +0 -29
  492. /package/backend/src/api/{middleware → middlewares}/error.ts +0 -0
  493. /package/backend/src/api/{middleware → middlewares}/upload.ts +0 -0
  494. /package/backend/{migrations → src/infra/database/migrations}/000_create-base-tables.sql +0 -0
  495. /package/backend/{migrations → src/infra/database/migrations}/001_create-helper-functions.sql +0 -0
  496. /package/backend/{migrations → src/infra/database/migrations}/002_rename-auth-tables.sql +0 -0
  497. /package/backend/{migrations → src/infra/database/migrations}/003_create-users-table.sql +0 -0
  498. /package/backend/{migrations → src/infra/database/migrations}/004_add-reload-postgrest-func.sql +0 -0
  499. /package/backend/{migrations → src/infra/database/migrations}/005_enable-project-admin-modify-users.sql +0 -0
  500. /package/backend/{migrations → src/infra/database/migrations}/006_modify-ai-usage-table.sql +0 -0
  501. /package/backend/{migrations → src/infra/database/migrations}/007_drop-metadata-table.sql +0 -0
  502. /package/backend/{migrations → src/infra/database/migrations}/008_add-system-tables.sql +0 -0
  503. /package/backend/{migrations → src/infra/database/migrations}/009_add-function-secrets.sql +0 -0
  504. /package/backend/{migrations → src/infra/database/migrations}/010_modify-ai-config-modalities.sql +0 -0
  505. /package/backend/{migrations → src/infra/database/migrations}/011_refactor-secrets-table.sql +0 -0
  506. /package/backend/{migrations → src/infra/database/migrations}/012_add-storage-uploaded-by.sql +0 -0
  507. /package/frontend/src/{features/metadata → lib}/services/metadata.service.ts +0 -0
@@ -1,27 +1,170 @@
1
- import { useState, useEffect } from 'react';
2
- import { FunctionsSidebar } from '@/features/functions/components/FunctionsSidebar';
3
- import { FunctionsContent } from '@/features/functions/components/FunctionsContent';
4
- import { SecretsContent } from '@/features/functions/components/SecretsContent';
1
+ import { ChevronRight } from 'lucide-react';
2
+ import { FunctionRow } from '../components/FunctionRow';
3
+ import FunctionEmptyState from '../components/FunctionEmptyState';
4
+ import { useFunctions } from '../hooks/useFunctions';
5
+ import { useToast } from '@/lib/hooks/useToast';
6
+ import { useEffect, useRef, useState } from 'react';
7
+ import RefreshIcon from '@/assets/icons/refresh.svg?react';
8
+ import {
9
+ CodeEditor,
10
+ Button,
11
+ Skeleton,
12
+ Tooltip,
13
+ TooltipContent,
14
+ TooltipProvider,
15
+ TooltipTrigger,
16
+ } from '@/components';
17
+ import {
18
+ DataUpdatePayload,
19
+ DataUpdateResourceType,
20
+ ServerEvents,
21
+ SocketMessage,
22
+ useSocket,
23
+ } from '@/lib/contexts/SocketContext';
5
24
 
6
25
  export default function FunctionsPage() {
7
- // Load selected section from localStorage on mount
8
- const [selectedSection, setSelectedSection] = useState<'functions' | 'secrets'>(() => {
9
- return (
10
- (localStorage.getItem('selectedFunctionSection') as 'functions' | 'secrets') || 'functions'
11
- );
12
- });
26
+ const toastShownRef = useRef(false);
27
+ const [isRefreshing, setIsRefreshing] = useState(false);
28
+ const { showToast } = useToast();
29
+ const {
30
+ functions,
31
+ isRuntimeAvailable,
32
+ selectedFunction,
33
+ isLoading: loading,
34
+ selectFunction,
35
+ clearSelection,
36
+ refetch,
37
+ } = useFunctions();
38
+
39
+ const { socket, isConnected } = useSocket();
40
+
41
+ const handleRefresh = async () => {
42
+ setIsRefreshing(true);
43
+ try {
44
+ await refetch();
45
+ } finally {
46
+ setIsRefreshing(false);
47
+ }
48
+ };
13
49
 
14
- // Save selected section to localStorage when it changes
15
50
  useEffect(() => {
16
- localStorage.setItem('selectedFunctionSection', selectedSection);
17
- }, [selectedSection]);
51
+ if (!isRuntimeAvailable && !toastShownRef.current) {
52
+ toastShownRef.current = true;
53
+ showToast('Function container is unhealthy.', 'error');
54
+ }
55
+ }, [isRuntimeAvailable, showToast]);
56
+
57
+ useEffect(() => {
58
+ if (!socket || !isConnected) {
59
+ return;
60
+ }
61
+
62
+ const handleDataUpdate = (message: SocketMessage<DataUpdatePayload>) => {
63
+ if (message.payload?.resource === DataUpdateResourceType.FUNCTIONS) {
64
+ void refetch();
65
+ }
66
+ };
67
+
68
+ socket.on(ServerEvents.DATA_UPDATE, handleDataUpdate);
18
69
 
70
+ return () => {
71
+ socket.off(ServerEvents.DATA_UPDATE, handleDataUpdate);
72
+ };
73
+ }, [socket, isConnected, refetch]);
74
+
75
+ // If a function is selected, show the detail view
76
+ if (selectedFunction) {
77
+ return (
78
+ <div className="h-full flex flex-col overflow-hidden">
79
+ <div className="flex items-center gap-2.5 p-4 border-b border-border-gray dark:border-neutral-600">
80
+ <button
81
+ onClick={clearSelection}
82
+ className="text-xl text-zinc-500 dark:text-neutral-400 hover:text-zinc-950 dark:hover:text-white transition-colors"
83
+ >
84
+ Functions
85
+ </button>
86
+ <ChevronRight className="w-5 h-5 text-muted-foreground dark:text-neutral-400" />
87
+ <p className="text-xl text-zinc-950 dark:text-white">{selectedFunction.name}</p>
88
+ </div>
89
+
90
+ <div className="flex-1 min-h-0">
91
+ <CodeEditor code={selectedFunction.code || '// No code available'} />
92
+ </div>
93
+ </div>
94
+ );
95
+ }
96
+
97
+ // Default list view
19
98
  return (
20
- <div className="h-full flex">
21
- <FunctionsSidebar selectedSection={selectedSection} onSectionSelect={setSelectedSection} />
99
+ <div className="h-full flex flex-col overflow-hidden">
100
+ <div className="flex flex-col gap-6 p-4">
101
+ <div className="flex items-center gap-3">
102
+ <h1 className="text-xl font-normal text-zinc-950 dark:text-white">Functions</h1>
103
+
104
+ {/* Separator */}
105
+ <div className="h-6 w-px bg-gray-200 dark:bg-neutral-700" />
106
+
107
+ {/* Refresh button */}
108
+ <TooltipProvider>
109
+ <Tooltip>
110
+ <TooltipTrigger asChild>
111
+ <Button
112
+ variant="ghost"
113
+ size="icon"
114
+ className="p-1 h-9 w-9"
115
+ onClick={() => void handleRefresh()}
116
+ disabled={isRefreshing}
117
+ >
118
+ <RefreshIcon className="h-5 w-5 text-zinc-400 dark:text-neutral-400" />
119
+ </Button>
120
+ </TooltipTrigger>
121
+ <TooltipContent side="bottom" align="center">
122
+ <p>{isRefreshing ? 'Refreshing...' : 'Refresh'}</p>
123
+ </TooltipContent>
124
+ </Tooltip>
125
+ </TooltipProvider>
126
+ </div>
127
+ <div className="flex flex-col gap-2 relative">
128
+ {/* Table Header */}
129
+ <div className="grid grid-cols-12 px-3 text-sm text-muted-foreground dark:text-neutral-400">
130
+ <div className="col-span-2 py-1 px-3">Name</div>
131
+ <div className="col-span-6 py-1 px-3">URL</div>
132
+ <div className="col-span-2 py-1 px-3">Created</div>
133
+ <div className="col-span-2 py-1 px-3">Last Update</div>
134
+ </div>
135
+ {loading ? (
136
+ <>
137
+ {[...Array(4)].map((_, i) => (
138
+ <Skeleton key={i} className="h-14 rounded-[8px] cols-span-full" />
139
+ ))}
140
+ </>
141
+ ) : functions.length >= 1 ? (
142
+ <>
143
+ {functions.map((func) => (
144
+ <FunctionRow
145
+ key={func.id}
146
+ function={func}
147
+ onClick={() => void selectFunction(func)}
148
+ className="cols-span-full"
149
+ />
150
+ ))}
151
+ </>
152
+ ) : (
153
+ <div className="cols-span-full">
154
+ <FunctionEmptyState />
155
+ </div>
156
+ )}
22
157
 
23
- <div className="flex-1 flex flex-col overflow-hidden">
24
- {selectedSection === 'functions' ? <FunctionsContent /> : <SecretsContent />}
158
+ {/* Loading mask overlay */}
159
+ {isRefreshing && (
160
+ <div className="absolute inset-0 bg-white dark:bg-neutral-800 flex items-center justify-center z-50">
161
+ <div className="flex items-center gap-1">
162
+ <div className="w-5 h-5 border-2 border-zinc-500 dark:border-neutral-700 border-t-transparent rounded-full animate-spin" />
163
+ <span className="text-sm text-zinc-500 dark:text-zinc-400">Loading</span>
164
+ </div>
165
+ </div>
166
+ )}
167
+ </div>
25
168
  </div>
26
169
  </div>
27
170
  );
@@ -1,14 +1,10 @@
1
1
  import { useState } from 'react';
2
- import { Button } from '@/components/radix/Button';
3
- import { Input } from '@/components/radix/Input';
4
- import { Skeleton } from '@/components/radix/Skeleton';
5
- import { SearchInput } from '@/components/SearchInput';
6
- import { ConfirmDialog } from '@/components/ConfirmDialog';
7
- import { SecretRow } from './SecretRow';
8
- import SecretEmptyState from './SecretEmptyState';
9
- import { useSecrets } from '@/features/secrets/hooks/useSecrets';
2
+ import { Button, Input, Skeleton, SearchInput, ConfirmDialog } from '@/components';
3
+ import { SecretRow } from '../components/SecretRow';
4
+ import SecretEmptyState from '../components/SecretEmptyState';
5
+ import { useSecrets } from '@/features/functions/hooks/useSecrets';
10
6
 
11
- export function SecretsContent() {
7
+ export default function SecretsPage() {
12
8
  const [newSecretKey, setNewSecretKey] = useState('');
13
9
  const [newSecretValue, setNewSecretValue] = useState('');
14
10
 
@@ -31,7 +27,7 @@ export function SecretsContent() {
31
27
  };
32
28
 
33
29
  return (
34
- <>
30
+ <div className="h-full flex flex-col overflow-hidden">
35
31
  <div className="flex flex-col gap-6 p-4">
36
32
  {/* Header */}
37
33
  <p className="h-7 text-xl text-zinc-950 dark:text-white">Secrets</p>
@@ -63,7 +59,7 @@ export function SecretsContent() {
63
59
  </div>
64
60
  <Button
65
61
  onClick={() => void handleSaveNewSecret()}
66
- className="bg-emerald-300 hover:bg-emerald-400 text-black px-3 py-2 w-20 h-9 rounded"
62
+ className="bg-black hover:bg-zinc-800 dark:bg-emerald-300 dark:hover:bg-emerald-400 dark:text-black text-white px-3 py-2 w-20 h-9 rounded"
67
63
  disabled={!newSecretKey.trim() || !newSecretValue.trim()}
68
64
  >
69
65
  Save
@@ -115,6 +111,6 @@ export function SecretsContent() {
115
111
  </div>
116
112
 
117
113
  <ConfirmDialog {...confirmDialogProps} />
118
- </>
114
+ </div>
119
115
  );
120
116
  }
@@ -19,7 +19,7 @@ export interface FunctionsResponse {
19
19
  };
20
20
  }
21
21
 
22
- export class FunctionsService {
22
+ export class FunctionService {
23
23
  async listFunctions(): Promise<FunctionsResponse> {
24
24
  const data = await apiClient.request('/functions', {
25
25
  headers: apiClient.withAccessToken(),
@@ -45,4 +45,4 @@ export class FunctionsService {
45
45
  }
46
46
  }
47
47
 
48
- export const functionsService = new FunctionsService();
48
+ export const functionService = new FunctionService();
@@ -25,7 +25,7 @@ export interface SecretValueResponse {
25
25
  value: string;
26
26
  }
27
27
 
28
- export class SecretsService {
28
+ export class SecretService {
29
29
  async listSecrets(): Promise<Secret[]> {
30
30
  const data = (await apiClient.request('/secrets', {
31
31
  headers: apiClient.withAccessToken(),
@@ -54,4 +54,4 @@ export class SecretsService {
54
54
  }
55
55
  }
56
56
 
57
- export const secretsService = new SecretsService();
57
+ export const secretService = new SecretService();
@@ -0,0 +1,27 @@
1
+ import { useCallback } from 'react';
2
+ import { partnershipService } from '../services/partnership.service';
3
+
4
+ /**
5
+ * Hook to check if origins are partner sites
6
+ * Delegates to the partnership service which handles caching and fetching
7
+ */
8
+ export function usePartnerOrigin() {
9
+ /**
10
+ * Checks if an origin is a partner origin
11
+ * The service handles caching, so first call fetches, subsequent calls return cached result
12
+ */
13
+ const isPartnerOrigin = useCallback(async (origin: string): Promise<boolean> => {
14
+ const config = await partnershipService.fetchConfig();
15
+
16
+ if (!config?.partner_sites || config.partner_sites.length === 0) {
17
+ return false;
18
+ }
19
+
20
+ // Exact match only
21
+ return config.partner_sites.includes(origin);
22
+ }, []);
23
+
24
+ return {
25
+ isPartnerOrigin,
26
+ };
27
+ }
@@ -1,69 +1,94 @@
1
- import { useEffect, useState } from 'react';
2
- import { useNavigate, useSearchParams } from 'react-router-dom';
1
+ import { useCallback, useEffect, useState } from 'react';
2
+ import { useNavigate } from 'react-router-dom';
3
3
  import { LockIcon } from 'lucide-react';
4
4
  import { useAuth } from '@/lib/contexts/AuthContext';
5
+ import { postMessageToParent } from '@/lib/utils/cloudMessaging';
6
+ import { useMcpUsage } from '@/features/logs/hooks/useMcpUsage';
7
+ import { usePartnerOrigin } from '../hooks/usePartnerOrigin';
5
8
 
6
9
  export default function CloudLoginPage() {
7
10
  const navigate = useNavigate();
8
- const [searchParams, setSearchParams] = useSearchParams();
9
11
  const { loginWithAuthorizationCode, isAuthenticated } = useAuth();
12
+ const { hasCompletedOnboarding, isLoading: isMcpUsageLoading } = useMcpUsage();
13
+ const { isPartnerOrigin } = usePartnerOrigin();
10
14
  const [authError, setAuthError] = useState<string | null>(null);
11
15
 
12
- useEffect(() => {
13
- if (isAuthenticated) {
14
- void navigate('/cloud/dashboard', { replace: true });
15
- }
16
- }, [isAuthenticated, navigate]);
17
-
18
- // Handle authorization token exchange
19
- useEffect(() => {
20
- const authorizationCode = searchParams.get('authorizationCode');
16
+ // Handle authorization code from postMessage
17
+ const onAuthorizationCodeReceived = useCallback(
18
+ async (event: MessageEvent) => {
19
+ try {
20
+ // Validate origin - allow insforge.dev, *.insforge.dev, and partner domains
21
+ const isInsforgeOrigin =
22
+ event.origin.endsWith('.insforge.dev') || event.origin === 'https://insforge.dev';
21
23
 
22
- if (authorizationCode) {
23
- setAuthError(null);
24
- // Exchange the authorization code for an access token
25
- loginWithAuthorizationCode(authorizationCode)
26
- .then((success) => {
27
- if (success) {
28
- // Notify parent of success
29
- if (window.parent !== window) {
30
- window.parent.postMessage(
31
- {
32
- type: 'AUTH_SUCCESS',
33
- },
34
- '*'
35
- );
36
- }
37
- } else {
38
- setAuthError('The authorization code may have expired or already been used.');
39
- if (window.parent !== window) {
40
- window.parent.postMessage(
41
- {
42
- type: 'AUTH_ERROR',
43
- message: 'Authorization code validation failed',
44
- },
45
- '*'
46
- );
47
- }
24
+ if (!isInsforgeOrigin) {
25
+ const isPartner = await isPartnerOrigin(event.origin);
26
+ if (!isPartner) {
27
+ console.warn('Received message from unauthorized origin:', event.origin);
28
+ return;
48
29
  }
49
- })
50
- .catch((error) => {
51
- console.error('Authorization code exchange failed:', error);
30
+ }
31
+
32
+ const authorizationCode = event.data.code;
33
+
34
+ setAuthError(null);
35
+ // Exchange the authorization code for an access token
36
+ const success = await loginWithAuthorizationCode(authorizationCode);
37
+ if (success) {
38
+ // Notify parent of success
39
+ postMessageToParent(
40
+ {
41
+ type: 'AUTH_SUCCESS',
42
+ },
43
+ event.origin
44
+ );
45
+ } else {
52
46
  setAuthError('The authorization code may have expired or already been used.');
53
- if (window.parent !== window) {
54
- window.parent.postMessage(
55
- {
56
- type: 'AUTH_ERROR',
57
- message: 'Authorization code validation failed',
58
- },
59
- '*'
60
- );
61
- }
62
- });
63
- } else {
64
- setAuthError('No authorization code provided.');
47
+ postMessageToParent(
48
+ {
49
+ type: 'AUTH_ERROR',
50
+ message: 'Authorization code validation failed',
51
+ },
52
+ event.origin
53
+ );
54
+ }
55
+ } catch (error) {
56
+ console.error('Authorization code exchange failed:', error);
57
+ setAuthError('The authorization code may have expired or already been used.');
58
+ postMessageToParent(
59
+ {
60
+ type: 'AUTH_ERROR',
61
+ message: 'Authorization code validation failed',
62
+ },
63
+ event.origin
64
+ );
65
+ }
66
+ },
67
+ [loginWithAuthorizationCode, isPartnerOrigin]
68
+ );
69
+
70
+ useEffect(() => {
71
+ const handleMessage = (event: MessageEvent) => {
72
+ if (event.data?.type === 'AUTHORIZATION_CODE' && event.data?.code) {
73
+ void onAuthorizationCodeReceived(event);
74
+ }
75
+ };
76
+
77
+ window.addEventListener('message', handleMessage);
78
+
79
+ return () => {
80
+ window.removeEventListener('message', handleMessage);
81
+ };
82
+ }, [onAuthorizationCodeReceived]);
83
+
84
+ useEffect(() => {
85
+ if (isAuthenticated && !isMcpUsageLoading) {
86
+ if (!hasCompletedOnboarding) {
87
+ postMessageToParent({ type: 'SHOW_ONBOARDING_OVERLAY' });
88
+ }
89
+ void navigate('/dashboard', { replace: true });
65
90
  }
66
- }, [searchParams, setSearchParams, loginWithAuthorizationCode, navigate]);
91
+ }, [hasCompletedOnboarding, isAuthenticated, isMcpUsageLoading, navigate]);
67
92
 
68
93
  // Show error state if authentication failed
69
94
  if (authError) {
@@ -1,44 +1,38 @@
1
- import { useEffect, useCallback, useState } from 'react';
1
+ import { useEffect, useState } from 'react';
2
2
  import { useNavigate } from 'react-router-dom';
3
3
  import { useForm } from 'react-hook-form';
4
4
  import { zodResolver } from '@hookform/resolvers/zod';
5
5
  import { Lock, Mail } from 'lucide-react';
6
6
  import {
7
+ Alert,
8
+ AlertDescription,
7
9
  Card,
8
10
  CardContent,
9
11
  CardDescription,
10
12
  CardFooter,
11
13
  CardHeader,
12
14
  CardTitle,
13
- } from '@/components/radix/Card';
14
- import {
15
15
  Form,
16
16
  FormControl,
17
17
  FormField,
18
18
  FormItem,
19
19
  FormLabel,
20
20
  FormMessage,
21
- } from '@/components/radix/Form';
22
- import { Input } from '@/components/radix/Input';
23
- import { ButtonWithLoading } from '@/components/ButtonWithLoading';
24
- import { Alert, AlertDescription } from '@/components/radix/Alert';
21
+ Input,
22
+ ButtonWithLoading,
23
+ } from '@/components';
25
24
  import { useAuth } from '@/lib/contexts/AuthContext';
26
- import { useOnboardingCompletion } from '@/lib/hooks/useOnboardingCompletion';
27
- import { loginFormSchema, LoginFormData } from '@/lib/utils/validation-schemas';
25
+ import { useMcpUsage } from '@/features/logs/hooks/useMcpUsage';
26
+ import { loginFormSchema, LoginForm } from '@/lib/utils/schemaValidations';
28
27
 
29
28
  export default function LoginPage() {
30
29
  const navigate = useNavigate();
31
30
  const { loginWithPassword, isAuthenticated } = useAuth();
32
- const { isCompleted } = useOnboardingCompletion();
31
+ const { hasCompletedOnboarding, isLoading: isMcpUsageLoading } = useMcpUsage();
33
32
  const [isSubmitting, setIsSubmitting] = useState(false);
34
33
  const [submitError, setSubmitError] = useState<string | null>(null);
35
34
 
36
- // Determine where to redirect based on onboarding completion status
37
- const getRedirectPath = useCallback(() => {
38
- return isCompleted ? '/dashboard' : '/dashboard/onboard';
39
- }, [isCompleted]);
40
-
41
- const form = useForm<LoginFormData>({
35
+ const form = useForm<LoginForm>({
42
36
  resolver: zodResolver(loginFormSchema),
43
37
  defaultValues: {
44
38
  email: 'admin@example.com',
@@ -46,16 +40,14 @@ export default function LoginPage() {
46
40
  },
47
41
  });
48
42
 
49
- const onSubmit = async (data: LoginFormData) => {
43
+ const onSubmit = async (data: LoginForm) => {
50
44
  setIsSubmitting(true);
51
45
  setSubmitError(null);
52
46
 
53
47
  try {
54
48
  const success = await loginWithPassword(data.email, data.password);
55
49
 
56
- if (success) {
57
- void navigate(getRedirectPath(), { replace: true });
58
- } else {
50
+ if (!success) {
59
51
  throw new Error('Invalid email or password');
60
52
  }
61
53
  } catch (error) {
@@ -67,10 +59,11 @@ export default function LoginPage() {
67
59
  };
68
60
 
69
61
  useEffect(() => {
70
- if (isAuthenticated) {
71
- void navigate(getRedirectPath(), { replace: true });
62
+ if (isAuthenticated && !isMcpUsageLoading) {
63
+ const redirectPath = hasCompletedOnboarding ? '/dashboard' : '/dashboard/onboard';
64
+ void navigate(redirectPath, { replace: true });
72
65
  }
73
- }, [isAuthenticated, navigate, getRedirectPath]);
66
+ }, [hasCompletedOnboarding, isAuthenticated, isMcpUsageLoading, navigate]);
74
67
 
75
68
  return (
76
69
  <div className="min-h-screen bg-gray-50 dark:bg-neutral-900 flex items-center justify-center px-4 sm:px-6 lg:px-8">
@@ -0,0 +1,65 @@
1
+ export interface PartnershipConfig {
2
+ partner_sites: string[];
3
+ }
4
+
5
+ export class PartnershipService {
6
+ private configCache: PartnershipConfig | null = null;
7
+ private fetchPromise: Promise<PartnershipConfig | null> | null = null;
8
+ private readonly CONFIG_URL = 'https://config.insforge.dev/partnership.json';
9
+
10
+ /**
11
+ * Fetches the partnership configuration from S3
12
+ * Uses caching to avoid repeated fetches
13
+ */
14
+ async fetchConfig(): Promise<PartnershipConfig | null> {
15
+ // Return cached config if available
16
+ if (this.configCache) {
17
+ return this.configCache;
18
+ }
19
+
20
+ // If a fetch is already in progress, wait for it
21
+ if (this.fetchPromise) {
22
+ return this.fetchPromise;
23
+ }
24
+
25
+ // Start a new fetch
26
+ this.fetchPromise = (async () => {
27
+ try {
28
+ const response = await fetch(this.CONFIG_URL);
29
+
30
+ if (response.ok) {
31
+ const data = await response.json();
32
+
33
+ // Basic validation - ensure partner_sites exists and is an array
34
+ if (data && Array.isArray(data.partner_sites)) {
35
+ this.configCache = data;
36
+ return this.configCache;
37
+ } else {
38
+ console.warn('Invalid partnership config structure:', data);
39
+ return null;
40
+ }
41
+ } else {
42
+ console.warn('Failed to fetch partnership config:', response.status);
43
+ return null;
44
+ }
45
+ } catch (error) {
46
+ console.warn('Error fetching partnership config:', error);
47
+ return null;
48
+ } finally {
49
+ this.fetchPromise = null;
50
+ }
51
+ })();
52
+
53
+ return this.fetchPromise;
54
+ }
55
+
56
+ /**
57
+ * Clears the cached configuration (useful for testing or forcing refresh)
58
+ */
59
+ clearCache(): void {
60
+ this.configCache = null;
61
+ this.fetchPromise = null;
62
+ }
63
+ }
64
+
65
+ export const partnershipService = new PartnershipService();