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
@@ -0,0 +1,448 @@
1
+ import { Router, Request, Response, NextFunction } from 'express';
2
+ import { AuthService } from '@/services/auth/auth.service.js';
3
+ import { OAuthConfigService } from '@/services/auth/oauth-config.service.js';
4
+ import { AuditService } from '@/services/logs/audit.service.js';
5
+ import { AppError } from '@/api/middlewares/error.js';
6
+ import { ERROR_CODES } from '@/types/error-constants.js';
7
+ import { successResponse } from '@/utils/response.js';
8
+ import { AuthRequest, verifyAdmin } from '@/api/middlewares/auth.js';
9
+ import logger from '@/utils/logger.js';
10
+ import jwt from 'jsonwebtoken';
11
+ import {
12
+ createOAuthConfigRequestSchema,
13
+ updateOAuthConfigRequestSchema,
14
+ type ListOAuthConfigsResponse,
15
+ oAuthProvidersSchema,
16
+ } from '@insforge/shared-schemas';
17
+ import { isOAuthSharedKeysAvailable } from '@/utils/environment.js';
18
+
19
+ const router = Router();
20
+ const authService = AuthService.getInstance();
21
+ const oAuthConfigService = OAuthConfigService.getInstance();
22
+ const auditService = AuditService.getInstance();
23
+
24
+ // Helper function to validate JWT_SECRET
25
+ const validateJwtSecret = (): string => {
26
+ const jwtSecret = process.env.JWT_SECRET;
27
+ if (!jwtSecret || jwtSecret.trim() === '') {
28
+ throw new AppError(
29
+ 'JWT_SECRET environment variable is not configured.',
30
+ 500,
31
+ ERROR_CODES.INTERNAL_ERROR
32
+ );
33
+ }
34
+ return jwtSecret;
35
+ };
36
+
37
+ // OAuth Configuration Management Routes (must come before wildcard routes)
38
+ // GET /api/auth/oauth/configs - List all OAuth configurations (admin only)
39
+ router.get('/configs', verifyAdmin, async (req: AuthRequest, res: Response, next: NextFunction) => {
40
+ try {
41
+ const configs = await oAuthConfigService.getAllConfigs();
42
+ const response: ListOAuthConfigsResponse = {
43
+ data: configs,
44
+ count: configs.length,
45
+ };
46
+ successResponse(res, response);
47
+ } catch (error) {
48
+ logger.error('Failed to list OAuth configurations', { error });
49
+ next(error);
50
+ }
51
+ });
52
+
53
+ // GET /api/auth/oauth/:provider/config - Get specific OAuth configuration (admin only)
54
+ router.get(
55
+ '/:provider/config',
56
+ verifyAdmin,
57
+ async (req: AuthRequest, res: Response, next: NextFunction) => {
58
+ try {
59
+ const { provider } = req.params;
60
+ const config = await oAuthConfigService.getConfigByProvider(provider);
61
+ const clientSecret = await oAuthConfigService.getClientSecretByProvider(provider);
62
+
63
+ if (!config) {
64
+ throw new AppError(
65
+ `OAuth configuration for ${provider} not found`,
66
+ 404,
67
+ ERROR_CODES.NOT_FOUND
68
+ );
69
+ }
70
+
71
+ successResponse(res, {
72
+ ...config,
73
+ clientSecret: clientSecret || undefined,
74
+ });
75
+ } catch (error) {
76
+ logger.error('Failed to get OAuth config by provider', {
77
+ provider: req.params.provider,
78
+ error,
79
+ });
80
+ next(error);
81
+ }
82
+ }
83
+ );
84
+
85
+ // POST /api/auth/oauth/configs - Create new OAuth configuration (admin only)
86
+ router.post(
87
+ '/configs',
88
+ verifyAdmin,
89
+ async (req: AuthRequest, res: Response, next: NextFunction) => {
90
+ try {
91
+ const validationResult = createOAuthConfigRequestSchema.safeParse(req.body);
92
+ if (!validationResult.success) {
93
+ throw new AppError(
94
+ validationResult.error.issues.map((e) => `${e.path.join('.')}: ${e.message}`).join(', '),
95
+ 400,
96
+ ERROR_CODES.INVALID_INPUT
97
+ );
98
+ }
99
+
100
+ const input = validationResult.data;
101
+
102
+ // Check if using shared keys when not allowed
103
+ if (input.useSharedKey && !isOAuthSharedKeysAvailable()) {
104
+ throw new AppError(
105
+ 'Shared OAuth keys are not enabled in this environment',
106
+ 400,
107
+ ERROR_CODES.AUTH_OAUTH_CONFIG_ERROR
108
+ );
109
+ }
110
+
111
+ const config = await oAuthConfigService.createConfig(input);
112
+
113
+ await auditService.log({
114
+ actor: req.user?.email || 'api-key',
115
+ action: 'CREATE_OAUTH_CONFIG',
116
+ module: 'AUTH',
117
+ details: {
118
+ provider: input.provider,
119
+ useSharedKey: input.useSharedKey || false,
120
+ },
121
+ ip_address: req.ip,
122
+ });
123
+
124
+ successResponse(res, config);
125
+ } catch (error) {
126
+ logger.error('Failed to create OAuth configuration', { error });
127
+ next(error);
128
+ }
129
+ }
130
+ );
131
+
132
+ // PUT /api/auth/oauth/:provider/config - Update OAuth configuration (admin only)
133
+ router.put(
134
+ '/:provider/config',
135
+ verifyAdmin,
136
+ async (req: AuthRequest, res: Response, next: NextFunction) => {
137
+ try {
138
+ const provider = req.params.provider;
139
+ if (!provider || provider.length === 0 || provider.length > 50) {
140
+ throw new AppError('Invalid provider name', 400, ERROR_CODES.INVALID_INPUT);
141
+ }
142
+
143
+ const validationResult = updateOAuthConfigRequestSchema.safeParse(req.body);
144
+ if (!validationResult.success) {
145
+ throw new AppError(
146
+ validationResult.error.issues.map((e) => `${e.path.join('.')}: ${e.message}`).join(', '),
147
+ 400,
148
+ ERROR_CODES.INVALID_INPUT
149
+ );
150
+ }
151
+
152
+ const input = validationResult.data;
153
+
154
+ // Check if using shared keys when not allowed
155
+ if (input.useSharedKey && !isOAuthSharedKeysAvailable()) {
156
+ throw new AppError(
157
+ 'Shared OAuth keys are not enabled in this environment',
158
+ 400,
159
+ ERROR_CODES.AUTH_OAUTH_CONFIG_ERROR
160
+ );
161
+ }
162
+
163
+ const config = await oAuthConfigService.updateConfig(provider, input);
164
+
165
+ await auditService.log({
166
+ actor: req.user?.email || 'api-key',
167
+ action: 'UPDATE_OAUTH_CONFIG',
168
+ module: 'AUTH',
169
+ details: {
170
+ provider,
171
+ updatedFields: Object.keys(input),
172
+ },
173
+ ip_address: req.ip,
174
+ });
175
+
176
+ successResponse(res, config);
177
+ } catch (error) {
178
+ logger.error('Failed to update OAuth configuration', {
179
+ error,
180
+ provider: req.params.provider,
181
+ });
182
+ next(error);
183
+ }
184
+ }
185
+ );
186
+
187
+ // DELETE /api/auth/oauth/:provider/config - Delete OAuth configuration (admin only)
188
+ router.delete(
189
+ '/:provider/config',
190
+ verifyAdmin,
191
+ async (req: AuthRequest, res: Response, next: NextFunction) => {
192
+ try {
193
+ const provider = req.params.provider;
194
+ if (!provider || provider.length === 0 || provider.length > 50) {
195
+ throw new AppError('Invalid provider name', 400, ERROR_CODES.INVALID_INPUT);
196
+ }
197
+ const deleted = await oAuthConfigService.deleteConfig(provider);
198
+
199
+ if (!deleted) {
200
+ throw new AppError(
201
+ `OAuth configuration for ${provider} not found`,
202
+ 404,
203
+ ERROR_CODES.NOT_FOUND
204
+ );
205
+ }
206
+
207
+ await auditService.log({
208
+ actor: req.user?.email || 'api-key',
209
+ action: 'DELETE_OAUTH_CONFIG',
210
+ module: 'AUTH',
211
+ details: { provider },
212
+ ip_address: req.ip,
213
+ });
214
+
215
+ successResponse(res, {
216
+ success: true,
217
+ message: `OAuth configuration for ${provider} deleted successfully`,
218
+ });
219
+ } catch (error) {
220
+ logger.error('Failed to delete OAuth configuration', {
221
+ error,
222
+ provider: req.params.provider,
223
+ });
224
+ next(error);
225
+ }
226
+ }
227
+ );
228
+
229
+ // OAuth Flow Routes
230
+ // GET /api/auth/oauth/:provider - Initialize OAuth flow for any supported provider
231
+ router.get('/:provider', async (req: Request, res: Response, next: NextFunction) => {
232
+ try {
233
+ const { provider } = req.params;
234
+ const { redirect_uri } = req.query;
235
+
236
+ // Validate provider using OAuthProvidersSchema
237
+ const providerValidation = oAuthProvidersSchema.safeParse(provider);
238
+ if (!providerValidation.success) {
239
+ throw new AppError(
240
+ `Unsupported OAuth provider: ${provider}. Supported providers: ${oAuthProvidersSchema.options.join(', ')}`,
241
+ 400,
242
+ ERROR_CODES.INVALID_INPUT
243
+ );
244
+ }
245
+
246
+ const validatedProvider = providerValidation.data;
247
+
248
+ if (!redirect_uri) {
249
+ throw new AppError('Redirect URI is required', 400, ERROR_CODES.INVALID_INPUT);
250
+ }
251
+
252
+ const jwtPayload = {
253
+ provider: validatedProvider,
254
+ redirectUri: redirect_uri ? (redirect_uri as string) : undefined,
255
+ createdAt: Date.now(),
256
+ };
257
+ const jwtSecret = validateJwtSecret();
258
+ const state = jwt.sign(jwtPayload, jwtSecret, {
259
+ algorithm: 'HS256',
260
+ expiresIn: '1h', // Set expiration time for the state token
261
+ });
262
+
263
+ const authUrl = await authService.generateOAuthUrl(validatedProvider, state);
264
+
265
+ successResponse(res, { authUrl });
266
+ } catch (error) {
267
+ logger.error(`${req.params.provider} OAuth error`, { error });
268
+
269
+ // If it's already an AppError, pass it through
270
+ if (error instanceof AppError) {
271
+ next(error);
272
+ return;
273
+ }
274
+
275
+ // For other errors, return the generic OAuth configuration error
276
+ next(
277
+ new AppError(
278
+ `${req.params.provider} OAuth is not properly configured. Please check your oauth configurations.`,
279
+ 500,
280
+ ERROR_CODES.AUTH_OAUTH_CONFIG_ERROR
281
+ )
282
+ );
283
+ }
284
+ });
285
+
286
+ // GET /api/auth/oauth/shared/callback/:state - Shared callback for OAuth providers
287
+ router.get('/shared/callback/:state', async (req: Request, res: Response, next: NextFunction) => {
288
+ try {
289
+ const { state } = req.params;
290
+ const { success, error, payload } = req.query;
291
+
292
+ if (!state) {
293
+ logger.warn('Shared OAuth callback called without state parameter');
294
+ throw new AppError('State parameter is required', 400, ERROR_CODES.INVALID_INPUT);
295
+ }
296
+
297
+ let redirectUri: string;
298
+ let provider: string;
299
+ try {
300
+ const jwtSecret = validateJwtSecret();
301
+ const decodedState = jwt.verify(state, jwtSecret) as {
302
+ provider: string;
303
+ redirectUri: string;
304
+ };
305
+ redirectUri = decodedState.redirectUri || '';
306
+ provider = decodedState.provider || '';
307
+ } catch {
308
+ logger.warn('Invalid state parameter', { state });
309
+ throw new AppError('Invalid state parameter', 400, ERROR_CODES.INVALID_INPUT);
310
+ }
311
+
312
+ // Validate provider using OAuthProvidersSchema
313
+ const providerValidation = oAuthProvidersSchema.safeParse(provider);
314
+ if (!providerValidation.success) {
315
+ logger.warn('Invalid provider in state', { provider });
316
+ throw new AppError(
317
+ `Invalid provider in state: ${provider}. Supported providers: ${oAuthProvidersSchema.options.join(', ')}`,
318
+ 400,
319
+ ERROR_CODES.INVALID_INPUT
320
+ );
321
+ }
322
+ const validatedProvider = providerValidation.data;
323
+ if (!redirectUri) {
324
+ throw new AppError('redirectUri is required', 400, ERROR_CODES.INVALID_INPUT);
325
+ }
326
+
327
+ if (success !== 'true') {
328
+ const errorMessage = error || 'OAuth Authentication Failed';
329
+ logger.warn('Shared OAuth callback failed', { error: errorMessage, provider });
330
+ return res.redirect(`${redirectUri}/?error=${encodeURIComponent(String(errorMessage))}`);
331
+ }
332
+
333
+ if (!payload) {
334
+ throw new AppError('No payload provided in callback', 400, ERROR_CODES.INVALID_INPUT);
335
+ }
336
+
337
+ const payloadData = JSON.parse(
338
+ Buffer.from(payload as string, 'base64').toString('utf8')
339
+ ) as Record<string, unknown>;
340
+
341
+ // Handle shared callback - transforms payload and creates/finds user
342
+ const result = await authService.handleSharedCallback(validatedProvider, payloadData);
343
+
344
+ const params = new URLSearchParams();
345
+ params.set('access_token', result?.accessToken ?? '');
346
+ params.set('user_id', result?.user?.id ?? '');
347
+ params.set('email', result?.user?.email ?? '');
348
+ params.set('name', result?.user?.name ?? '');
349
+
350
+ res.redirect(`${redirectUri}?${params.toString()}`);
351
+ } catch (error) {
352
+ logger.error('Shared OAuth callback error', { error });
353
+ next(error);
354
+ }
355
+ });
356
+
357
+ // GET /api/auth/oauth/:provider/callback - OAuth provider callback
358
+ router.get('/:provider/callback', async (req: Request, res: Response, next: NextFunction) => {
359
+ try {
360
+ const { provider } = req.params;
361
+ const { code, state, token } = req.query;
362
+
363
+ if (!state) {
364
+ logger.warn('OAuth callback called without state parameter');
365
+ throw new AppError('State parameter is required', 400, ERROR_CODES.INVALID_INPUT);
366
+ }
367
+
368
+ // Decode redirectUri from state (needed for both success and error paths)
369
+ let redirectUri: string;
370
+
371
+ try {
372
+ const jwtSecret = validateJwtSecret();
373
+ const stateData = jwt.verify(state as string, jwtSecret) as {
374
+ provider: string;
375
+ redirectUri: string;
376
+ };
377
+ redirectUri = stateData.redirectUri || '';
378
+ } catch {
379
+ // Invalid state
380
+ logger.warn('Invalid state in provider callback', { state });
381
+ throw new AppError('Invalid state parameter', 400, ERROR_CODES.INVALID_INPUT);
382
+ }
383
+
384
+ if (!redirectUri) {
385
+ throw new AppError('redirectUri is required', 400, ERROR_CODES.INVALID_INPUT);
386
+ }
387
+
388
+ try {
389
+ // Validate provider using OAuthProvidersSchema
390
+ const providerValidation = oAuthProvidersSchema.safeParse(provider);
391
+ if (!providerValidation.success) {
392
+ throw new AppError(
393
+ `Unsupported OAuth provider: ${provider}. Supported providers: ${oAuthProvidersSchema.options.join(', ')}`,
394
+ 400,
395
+ ERROR_CODES.INVALID_INPUT
396
+ );
397
+ }
398
+
399
+ const validatedProvider = providerValidation.data;
400
+
401
+ const result = await authService.handleOAuthCallback(validatedProvider, {
402
+ code: code as string | undefined,
403
+ token: token as string | undefined,
404
+ state: state as string | undefined,
405
+ });
406
+
407
+ // Construct redirect URL with query parameters
408
+ const params = new URLSearchParams();
409
+ params.set('access_token', result?.accessToken ?? '');
410
+ params.set('user_id', result?.user?.id ?? '');
411
+ params.set('email', result?.user?.email ?? '');
412
+ params.set('name', result?.user?.name ?? '');
413
+
414
+ const finalRedirectUri = `${redirectUri}?${params.toString()}`;
415
+
416
+ logger.info('OAuth callback successful, redirecting with token', {
417
+ redirectUri: finalRedirectUri,
418
+ hasAccessToken: !!result?.accessToken,
419
+ hasUserId: !!result?.user?.id,
420
+ provider: validatedProvider,
421
+ });
422
+
423
+ return res.redirect(finalRedirectUri);
424
+ } catch (error) {
425
+ logger.error('OAuth callback error', {
426
+ error: error instanceof Error ? error.message : error,
427
+ stack: error instanceof Error ? error.stack : undefined,
428
+ provider: req.params.provider,
429
+ hasCode: !!req.query.code,
430
+ hasState: !!req.query.state,
431
+ hasToken: !!req.query.token,
432
+ });
433
+
434
+ const errorMessage = error instanceof Error ? error.message : 'OAuth Authentication Failed';
435
+
436
+ // Redirect with error in URL parameters
437
+ const params = new URLSearchParams();
438
+ params.set('error', errorMessage);
439
+
440
+ return res.redirect(`${redirectUri}?${params.toString()}`);
441
+ }
442
+ } catch (error) {
443
+ logger.error('OAuth callback error', { error });
444
+ next(error);
445
+ }
446
+ });
447
+
448
+ export default router;
@@ -1,27 +1,87 @@
1
- import { Router, Response } from 'express';
2
- import { DatabaseAdvanceService } from '@/core/database/advance.js';
3
- import { AuditService } from '@/core/logs/audit.js';
4
- import { verifyAdmin, AuthRequest } from '@/api/middleware/auth.js';
5
- import { AppError } from '@/api/middleware/error.js';
1
+ import { Router, Response, NextFunction } from 'express';
2
+ import { DatabaseAdvanceService } from '@/services/database/database-advance.service.js';
3
+ import { AuditService } from '@/services/logs/audit.service.js';
4
+ import { verifyAdmin, AuthRequest } from '@/api/middlewares/auth.js';
5
+ import { AppError } from '@/api/middlewares/error.js';
6
6
  import { ERROR_CODES } from '@/types/error-constants.js';
7
- import { upload, handleUploadError } from '@/api/middleware/upload.js';
7
+ import { upload, handleUploadError } from '@/api/middlewares/upload.js';
8
8
  import {
9
9
  rawSQLRequestSchema,
10
10
  exportRequestSchema,
11
11
  importRequestSchema,
12
12
  bulkUpsertRequestSchema,
13
13
  } from '@insforge/shared-schemas';
14
- import logger from '@/utils/logger';
14
+ import logger from '@/utils/logger.js';
15
+ import { SocketManager } from '@/infra/socket/socket.manager.js';
16
+ import { DataUpdateResourceType, ServerEvents } from '@/types/socket.js';
17
+ import { successResponse } from '@/utils/response.js';
15
18
 
16
19
  const router = Router();
17
- const dbAdvanceService = new DatabaseAdvanceService();
20
+ const dbAdvanceService = DatabaseAdvanceService.getInstance();
18
21
  const auditService = AuditService.getInstance();
19
22
 
20
23
  /**
21
- * Execute raw SQL query
24
+ * Execute raw SQL query with relaxed sanitization (Power User Mode)
25
+ * POST /api/database/advance/rawsql/unrestricted
26
+ *
27
+ * ⚠️ This endpoint has relaxed restrictions compared to /rawsql
28
+ * - Allows SELECT and INSERT into system tables and users table
29
+ */
30
+ router.post(
31
+ '/rawsql/unrestricted',
32
+ verifyAdmin,
33
+ async (req: AuthRequest, res: Response, next: NextFunction) => {
34
+ try {
35
+ // Validate request body
36
+ const validation = rawSQLRequestSchema.safeParse(req.body);
37
+ if (!validation.success) {
38
+ throw new AppError(
39
+ validation.error.issues.map((e) => `${e.path.join('.')}: ${e.message}`).join(', '),
40
+ 400,
41
+ ERROR_CODES.INVALID_INPUT
42
+ );
43
+ }
44
+
45
+ const { query, params = [] } = validation.data;
46
+
47
+ // Sanitize query with relaxed mode
48
+ const sanitizedQuery = dbAdvanceService.sanitizeQuery(query, 'relaxed');
49
+
50
+ // Execute SQL
51
+ const response = await dbAdvanceService.executeRawSQL(sanitizedQuery, params);
52
+
53
+ // Log audit for relaxed raw SQL execution
54
+ await auditService.log({
55
+ actor: req.user?.email || 'api-key',
56
+ action: 'EXECUTE_RAW_SQL_RELAXED',
57
+ module: 'DATABASE',
58
+ details: {
59
+ query: query.substring(0, 300), // Limit query length in audit log
60
+ paramCount: params.length,
61
+ rowsAffected: response.rowCount,
62
+ mode: 'relaxed',
63
+ },
64
+ ip_address: req.ip,
65
+ });
66
+
67
+ const socket = SocketManager.getInstance();
68
+ socket.broadcastToRoom('role:project_admin', ServerEvents.DATA_UPDATE, {
69
+ resource: DataUpdateResourceType.DATABASE,
70
+ });
71
+
72
+ successResponse(res, response);
73
+ } catch (error: unknown) {
74
+ logger.warn('Relaxed raw SQL execution error:', error);
75
+ next(error);
76
+ }
77
+ }
78
+ );
79
+
80
+ /**
81
+ * Execute raw SQL query with strict sanitization
22
82
  * POST /api/database/advance/rawsql
23
83
  */
24
- router.post('/rawsql', verifyAdmin, async (req: AuthRequest, res: Response) => {
84
+ router.post('/rawsql', verifyAdmin, async (req: AuthRequest, res: Response, next: NextFunction) => {
25
85
  try {
26
86
  // Validate request body
27
87
  const validation = rawSQLRequestSchema.safeParse(req.body);
@@ -34,9 +94,14 @@ router.post('/rawsql', verifyAdmin, async (req: AuthRequest, res: Response) => {
34
94
  }
35
95
 
36
96
  const { query, params = [] } = validation.data;
37
- const response = await dbAdvanceService.executeRawSQL(query, params);
38
97
 
39
- // Log audit for raw SQL execution
98
+ // Sanitize query with strict mode
99
+ const sanitizedQuery = dbAdvanceService.sanitizeQuery(query, 'strict');
100
+
101
+ // Execute SQL
102
+ const response = await dbAdvanceService.executeRawSQL(sanitizedQuery, params);
103
+
104
+ // Log audit for strict raw SQL execution
40
105
  await auditService.log({
41
106
  actor: req.user?.email || 'api-key',
42
107
  action: 'EXECUTE_RAW_SQL',
@@ -45,27 +110,20 @@ router.post('/rawsql', verifyAdmin, async (req: AuthRequest, res: Response) => {
45
110
  query: query.substring(0, 300), // Limit query length in audit log
46
111
  paramCount: params.length,
47
112
  rowsAffected: response.rowCount,
113
+ mode: 'strict',
48
114
  },
49
115
  ip_address: req.ip,
50
116
  });
51
117
 
52
- res.json(response);
118
+ const socket = SocketManager.getInstance();
119
+ socket.broadcastToRoom('role:project_admin', ServerEvents.DATA_UPDATE, {
120
+ resource: DataUpdateResourceType.DATABASE,
121
+ });
122
+
123
+ successResponse(res, response);
53
124
  } catch (error: unknown) {
54
125
  logger.warn('Raw SQL execution error:', error);
55
-
56
- if (error instanceof AppError) {
57
- res.status(error.statusCode).json({
58
- error: 'SQL_EXECUTION_ERROR',
59
- message: error.message,
60
- statusCode: error.statusCode,
61
- });
62
- } else {
63
- res.status(400).json({
64
- error: 'SQL_EXECUTION_ERROR',
65
- message: error instanceof Error ? error.message : 'Failed to execute SQL query',
66
- statusCode: 400,
67
- });
68
- }
126
+ next(error);
69
127
  }
70
128
  });
71
129
 
@@ -73,7 +131,7 @@ router.post('/rawsql', verifyAdmin, async (req: AuthRequest, res: Response) => {
73
131
  * Export database data
74
132
  * POST /api/database/advance/export
75
133
  */
76
- router.post('/export', verifyAdmin, async (req: AuthRequest, res: Response) => {
134
+ router.post('/export', verifyAdmin, async (req: AuthRequest, res: Response, next: NextFunction) => {
77
135
  try {
78
136
  // Validate request body
79
137
  const validation = exportRequestSchema.safeParse(req.body);
@@ -115,14 +173,10 @@ router.post('/export', verifyAdmin, async (req: AuthRequest, res: Response) => {
115
173
  ip_address: req.ip,
116
174
  });
117
175
 
118
- res.json(response);
176
+ successResponse(res, response);
119
177
  } catch (error: unknown) {
120
178
  logger.warn('Database export error:', error);
121
- res.status(500).json({
122
- error: 'EXPORT_ERROR',
123
- message: error instanceof Error ? error.message : 'Failed to export database',
124
- statusCode: 500,
125
- });
179
+ next(error);
126
180
  }
127
181
  });
128
182
 
@@ -139,7 +193,7 @@ router.post(
139
193
  verifyAdmin,
140
194
  upload.single('file'),
141
195
  handleUploadError,
142
- async (req: AuthRequest, res: Response) => {
196
+ async (req: AuthRequest, res: Response, next: NextFunction) => {
143
197
  try {
144
198
  if (!req.file) {
145
199
  throw new AppError('File is required', 400, ERROR_CODES.INVALID_INPUT);
@@ -180,23 +234,19 @@ router.post(
180
234
  ip_address: req.ip,
181
235
  });
182
236
 
183
- res.json(response);
237
+ const socket = SocketManager.getInstance();
238
+ socket.broadcastToRoom('role:project_admin', ServerEvents.DATA_UPDATE, {
239
+ resource: DataUpdateResourceType.RECORDS,
240
+ data: {
241
+ tableName: table,
242
+ },
243
+ });
244
+
245
+ successResponse(res, response);
184
246
  } catch (error: unknown) {
185
247
  logger.warn('Bulk upsert error:', error);
186
248
 
187
- if (error instanceof AppError) {
188
- res.status(error.statusCode).json({
189
- error: 'BULK_UPSERT_ERROR',
190
- message: error.message,
191
- statusCode: error.statusCode,
192
- });
193
- } else {
194
- res.status(400).json({
195
- error: 'BULK_UPSERT_ERROR',
196
- message: error instanceof Error ? error.message : 'Failed to perform bulk upsert',
197
- statusCode: 400,
198
- });
199
- }
249
+ next(error);
200
250
  }
201
251
  }
202
252
  );
@@ -211,7 +261,7 @@ router.post(
211
261
  verifyAdmin,
212
262
  upload.single('file'),
213
263
  handleUploadError,
214
- async (req: AuthRequest, res: Response) => {
264
+ async (req: AuthRequest, res: Response, next: NextFunction) => {
215
265
  try {
216
266
  // Validate request body
217
267
  const validation = importRequestSchema.safeParse(req.body);
@@ -251,23 +301,15 @@ router.post(
251
301
  ip_address: req.ip,
252
302
  });
253
303
 
254
- res.json(response);
304
+ const socket = SocketManager.getInstance();
305
+ socket.broadcastToRoom('role:project_admin', ServerEvents.DATA_UPDATE, {
306
+ resource: DataUpdateResourceType.DATABASE,
307
+ });
308
+
309
+ successResponse(res, response);
255
310
  } catch (error: unknown) {
256
311
  logger.warn('Database import error:', error);
257
-
258
- if (error instanceof AppError) {
259
- res.status(error.statusCode).json({
260
- error: 'IMPORT_ERROR',
261
- message: error.message,
262
- statusCode: error.statusCode,
263
- });
264
- } else {
265
- res.status(500).json({
266
- error: 'IMPORT_ERROR',
267
- message: error instanceof Error ? error.message : 'Failed to import database',
268
- statusCode: 500,
269
- });
270
- }
312
+ next(error);
271
313
  }
272
314
  }
273
315
  );