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,772 +0,0 @@
1
- import { DatabaseManager } from '@/core/database/manager.js';
2
- import { AppError } from '@/api/middleware/error.js';
3
- import { ERROR_CODES } from '@/types/error-constants.js';
4
- import {
5
- COLUMN_TYPES,
6
- ForeignKeyRow,
7
- ColumnInfo,
8
- PrimaryKeyInfo,
9
- ForeignKeyInfo,
10
- } from '@/types/database.js';
11
- import {
12
- ColumnSchema,
13
- ColumnType,
14
- CreateTableResponse,
15
- GetTableSchemaResponse,
16
- UpdateTableSchemaRequest,
17
- UpdateTableSchemaResponse,
18
- DeleteTableResponse,
19
- OnDeleteActionSchema,
20
- OnUpdateActionSchema,
21
- ForeignKeySchema,
22
- } from '@insforge/shared-schemas';
23
- import { validateIdentifier } from '@/utils/validations.js';
24
- import { convertSqlTypeToColumnType } from '@/utils/helpers';
25
-
26
- const reservedColumns = {
27
- id: ColumnType.UUID,
28
- created_at: ColumnType.DATETIME,
29
- updated_at: ColumnType.DATETIME,
30
- };
31
-
32
- const userTableFrozenColumns = ['nickname', 'avatar_url'];
33
-
34
- const SAFE_FUNCS = new Set(['now()', 'gen_random_uuid()']);
35
-
36
- function getSafeDollarQuotedLiteral(s: string) {
37
- let tag = 'val';
38
- while (s.includes(`$${tag}$`)) {
39
- tag += '_';
40
- }
41
- return `$${tag}$${s}$${tag}$`;
42
- }
43
-
44
- function getSystemDefault(columnType?: ColumnType, isNullable?: boolean): string | null {
45
- if (!columnType || isNullable) {
46
- return null;
47
- }
48
- const fieldType = COLUMN_TYPES[columnType];
49
- if (!fieldType?.defaultValue) {
50
- return null;
51
- }
52
-
53
- const def = fieldType.defaultValue.trim().toLowerCase();
54
- if (SAFE_FUNCS.has(def)) {
55
- return `DEFAULT ${def}`;
56
- }
57
- return `DEFAULT ${getSafeDollarQuotedLiteral(def)}`;
58
- }
59
-
60
- export function formatDefaultValue(
61
- input: string | null | undefined,
62
- columnType?: ColumnType,
63
- isNullable?: boolean
64
- ): string {
65
- if (!input) {
66
- return getSystemDefault(columnType, isNullable) ?? '';
67
- }
68
- const value = input.trim();
69
- const lowered = value.toLowerCase();
70
-
71
- if (SAFE_FUNCS.has(lowered)) {
72
- return `DEFAULT ${lowered}`;
73
- }
74
- return `DEFAULT ${getSafeDollarQuotedLiteral(value)}`;
75
- }
76
-
77
- export class DatabaseTableService {
78
- private dbManager: DatabaseManager;
79
-
80
- constructor() {
81
- this.dbManager = DatabaseManager.getInstance();
82
- }
83
-
84
- /**
85
- * List all tables
86
- */
87
- async listTables(): Promise<string[]> {
88
- const db = this.dbManager.getDb();
89
- const tables = await db
90
- .prepare(
91
- `
92
- SELECT table_name as name
93
- FROM information_schema.tables
94
- WHERE table_schema = 'public'
95
- AND table_type = 'BASE TABLE'
96
- AND table_name NOT LIKE '\\_%'
97
- AND table_name != 'jwks'
98
- `
99
- )
100
- .all();
101
-
102
- return tables.map((t: { name: string }) => t.name);
103
- }
104
-
105
- /**
106
- * Create a new table
107
- */
108
- async createTable(
109
- table_name: string,
110
- columns: ColumnSchema[],
111
- use_RLS = true
112
- ): Promise<CreateTableResponse> {
113
- // Validate table name
114
- validateIdentifier(table_name, 'table');
115
- // Prevent creation of system tables
116
- if (table_name.startsWith('_')) {
117
- throw new AppError(
118
- 'Cannot create system tables',
119
- 403,
120
- ERROR_CODES.FORBIDDEN,
121
- 'Table names starting with underscore are reserved for system tables'
122
- );
123
- }
124
-
125
- // Filter out reserved fields with matching types, throw error for mismatched types
126
- const validatedColumns = this.validateReservedFields(columns);
127
-
128
- // Validate remaining columns - only need to validate column names since Zod handles type validation
129
- validatedColumns.forEach((col: ColumnSchema, index: number) => {
130
- // Validate column name
131
- try {
132
- validateIdentifier(col.columnName, 'column');
133
- } catch (error) {
134
- if (error instanceof AppError) {
135
- throw new AppError(
136
- `Invalid column name at index ${index}: ${error.message}`,
137
- error.statusCode,
138
- error.code,
139
- error.nextActions
140
- );
141
- }
142
- throw error;
143
- }
144
- });
145
-
146
- const db = this.dbManager.getDb();
147
-
148
- // Check if table exists
149
- const tableExists = await db
150
- .prepare(
151
- `
152
- SELECT EXISTS (
153
- SELECT FROM information_schema.tables
154
- WHERE table_schema = 'public'
155
- AND table_name = ?
156
- ) as exists
157
- `
158
- )
159
- .get(table_name);
160
-
161
- if (tableExists?.exists) {
162
- throw new AppError(
163
- `table ${table_name} already exists`,
164
- 400,
165
- ERROR_CODES.DATABASE_DUPLICATE,
166
- `table ${table_name} already exists. Please check the table name, it must be a unique table name.`
167
- );
168
- }
169
-
170
- // Map columns to SQL with proper type conversion
171
- const columnDefs = validatedColumns
172
- .map((col: ColumnSchema) => {
173
- const fieldType = COLUMN_TYPES[col.type as ColumnType];
174
- const sqlType = fieldType.sqlType;
175
-
176
- // Handle default values
177
- const defaultClause = formatDefaultValue(
178
- col.defaultValue,
179
- col.type as ColumnType,
180
- col.isNullable
181
- );
182
-
183
- const nullable = col.isNullable ? '' : 'NOT NULL';
184
- const unique = col.isUnique ? 'UNIQUE' : '';
185
-
186
- return `${this.quoteIdentifier(col.columnName)} ${sqlType} ${nullable} ${unique} ${defaultClause}`.trim();
187
- })
188
- .join(', ');
189
-
190
- // Prepare foreign key constraints
191
- const foreignKeyConstraints = validatedColumns
192
- .filter((col) => col.foreignKey)
193
- .map((col) => this.generateFkeyConstraintStatement(col, true))
194
- .join(', ');
195
-
196
- // Create table with auto fields and foreign keys
197
- const tableDefinition = [
198
- 'id UUID PRIMARY KEY DEFAULT gen_random_uuid()',
199
- columnDefs,
200
- 'created_at TIMESTAMPTZ DEFAULT now()',
201
- 'updated_at TIMESTAMPTZ DEFAULT now()',
202
- foreignKeyConstraints,
203
- ]
204
- .filter(Boolean)
205
- .join(', ');
206
-
207
- await db
208
- .prepare(
209
- `
210
- CREATE TABLE ${this.quoteIdentifier(table_name)} (
211
- ${tableDefinition}
212
- );
213
- NOTIFY pgrst, 'reload schema';
214
- `
215
- )
216
- .exec();
217
-
218
- if (use_RLS) {
219
- // Enable RLS policies
220
- await db
221
- .prepare(
222
- `
223
- ALTER TABLE ${this.quoteIdentifier(table_name)} ENABLE ROW LEVEL SECURITY;
224
- `
225
- )
226
- .exec();
227
- }
228
-
229
- // Create trigger for updated_at
230
- await db
231
- .prepare(
232
- `
233
- CREATE TRIGGER ${this.quoteIdentifier(table_name + '_update_timestamp')}
234
- BEFORE UPDATE ON ${this.quoteIdentifier(table_name)}
235
- FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
236
- `
237
- )
238
- .exec();
239
-
240
- // Update metadata
241
- // Metadata is now updated on-demand
242
-
243
- return {
244
- message: 'table created successfully',
245
- tableName: table_name,
246
- columns: validatedColumns.map((col) => ({
247
- ...col,
248
- sqlType: COLUMN_TYPES[col.type as ColumnType].sqlType,
249
- })),
250
- autoFields: ['id', 'created_at', 'updated_at'],
251
- nextActions: 'you can now use the table with the POST /api/database/tables/{table} endpoint',
252
- };
253
- }
254
-
255
- /**
256
- * Get table schema
257
- */
258
- /**
259
- * Parse PostgreSQL default value format
260
- * Extracts the actual value from formats like 'abc'::text or 123::integer
261
- */
262
- private parseDefaultValue(defaultValue: string | null): string | undefined {
263
- if (!defaultValue) {
264
- return undefined;
265
- }
266
- // Handle string literals with type casting (e.g., 'abc'::text)
267
- const stringMatch = defaultValue.match(/^'([^']*)'::[\w\s]+$/);
268
- if (stringMatch) {
269
- return stringMatch[1];
270
- }
271
-
272
- // Handle numeric/boolean values with type casting (e.g., 123::integer, true::boolean)
273
- const typeCastMatch = defaultValue.match(/^(.+?)::[\w\s]+$/);
274
- if (typeCastMatch) {
275
- return typeCastMatch[1];
276
- }
277
-
278
- // Return as-is if no type casting pattern found
279
- return defaultValue;
280
- }
281
-
282
- async getTableSchema(table: string): Promise<GetTableSchemaResponse> {
283
- const db = this.dbManager.getDb();
284
-
285
- // Get column information from information_schema
286
- const columns = await db
287
- .prepare(
288
- `
289
- SELECT
290
- column_name,
291
- data_type,
292
- is_nullable,
293
- column_default,
294
- character_maximum_length
295
- FROM information_schema.columns
296
- WHERE table_schema = 'public'
297
- AND table_name = ?
298
- ORDER BY ordinal_position
299
- `
300
- )
301
- .all(table);
302
-
303
- if (columns.length === 0) {
304
- throw new AppError(
305
- 'table not found',
306
- 404,
307
- ERROR_CODES.DATABASE_NOT_FOUND,
308
- 'table not found. Please check the table name, it must be a valid table name, or you can create a new table with the POST /api/database/tables endpoint'
309
- );
310
- }
311
-
312
- // Get foreign key information
313
- const foreignKeyMap = await this.getFkeyConstraints(table);
314
-
315
- // Get primary key information
316
- const primaryKeys = await db
317
- .prepare(
318
- `
319
- SELECT column_name
320
- FROM information_schema.key_column_usage
321
- WHERE table_schema = 'public'
322
- AND table_name = ?
323
- AND constraint_name = (
324
- SELECT constraint_name
325
- FROM information_schema.table_constraints
326
- WHERE table_schema = 'public'
327
- AND table_name = ?
328
- AND constraint_type = 'PRIMARY KEY'
329
- )
330
- `
331
- )
332
- .all(table, table);
333
-
334
- const pkSet = new Set(primaryKeys.map((pk: PrimaryKeyInfo) => pk.column_name));
335
-
336
- // Get unique columns
337
- const uniqueColumns = await db
338
- .prepare(
339
- `
340
- SELECT DISTINCT kcu.column_name
341
- FROM information_schema.table_constraints tc
342
- JOIN information_schema.key_column_usage kcu
343
- ON tc.constraint_name = kcu.constraint_name
344
- AND tc.table_schema = kcu.table_schema
345
- WHERE tc.table_schema = 'public'
346
- AND tc.table_name = ?
347
- AND tc.constraint_type = 'UNIQUE'
348
- `
349
- )
350
- .all(table);
351
-
352
- const uniqueSet = new Set(uniqueColumns.map((u: { column_name: string }) => u.column_name));
353
-
354
- // Get row count
355
- const { row_count } = await db.prepare(`SELECT COUNT(*) as row_count FROM "${table}"`).get();
356
-
357
- return {
358
- tableName: table,
359
- columns: columns.map((col: ColumnInfo) => ({
360
- columnName: col.column_name,
361
- type: convertSqlTypeToColumnType(col.data_type),
362
- isNullable: col.is_nullable === 'YES',
363
- isPrimaryKey: pkSet.has(col.column_name),
364
- isUnique: pkSet.has(col.column_name) || uniqueSet.has(col.column_name),
365
- defaultValue: this.parseDefaultValue(col.column_default),
366
- ...(foreignKeyMap.has(col.column_name) && {
367
- foreignKey: foreignKeyMap.get(col.column_name),
368
- }),
369
- })),
370
- recordCount: row_count,
371
- };
372
- }
373
-
374
- /**
375
- * Update table schema
376
- */
377
- async updateTableSchema(
378
- tableName: string,
379
- operations: UpdateTableSchemaRequest
380
- ): Promise<UpdateTableSchemaResponse> {
381
- const { addColumns, dropColumns, updateColumns, addForeignKeys, dropForeignKeys, renameTable } =
382
- operations;
383
-
384
- // Prevent modification of system tables
385
- if (tableName.startsWith('_')) {
386
- throw new AppError(
387
- 'System tables cannot be modified',
388
- 403,
389
- ERROR_CODES.DATABASE_FORBIDDEN,
390
- 'System tables cannot be modified. System tables are prefixed with underscore.'
391
- );
392
- }
393
-
394
- const db = this.dbManager.getDb();
395
-
396
- // Check if table exists
397
- const tableExists = await db
398
- .prepare(
399
- `
400
- SELECT EXISTS (
401
- SELECT FROM information_schema.tables
402
- WHERE table_schema = 'public'
403
- AND table_name = ?
404
- ) as exists
405
- `
406
- )
407
- .get(tableName);
408
-
409
- if (!tableExists?.exists) {
410
- throw new AppError(
411
- 'table not found',
412
- 404,
413
- ERROR_CODES.DATABASE_NOT_FOUND,
414
- 'Please check the table name, it must be a valid table name, or you can create a new table with the POST /api/database/tables endpoint'
415
- );
416
- }
417
-
418
- const safeTableName = this.quoteIdentifier(tableName);
419
- const foreignKeyMap = await this.getFkeyConstraints(tableName);
420
- const completedOperations: string[] = [];
421
-
422
- // Execute operations
423
-
424
- // Drop foreign key constraints
425
- if (dropForeignKeys && Array.isArray(dropForeignKeys)) {
426
- for (const col of dropForeignKeys) {
427
- const constraintName = foreignKeyMap.get(col)?.constraint_name;
428
- if (constraintName) {
429
- await db
430
- .prepare(
431
- `
432
- ALTER TABLE ${safeTableName}
433
- DROP CONSTRAINT ${this.quoteIdentifier(constraintName)}
434
- `
435
- )
436
- .exec();
437
-
438
- completedOperations.push(`Dropped foreign key constraint on column: ${col}`);
439
- }
440
- }
441
- }
442
-
443
- // Drop columns first (to avoid conflicts with renames)
444
- if (dropColumns && Array.isArray(dropColumns)) {
445
- for (const col of dropColumns) {
446
- if (Object.keys(reservedColumns).includes(col)) {
447
- throw new AppError(
448
- 'cannot drop system columns',
449
- 404,
450
- ERROR_CODES.DATABASE_FORBIDDEN,
451
- `You cannot drop the system column '${col}'`
452
- );
453
- }
454
- if (tableName === 'users' && userTableFrozenColumns.includes(col)) {
455
- throw new AppError(
456
- 'cannot drop frozen users columns',
457
- 403,
458
- ERROR_CODES.FORBIDDEN,
459
- `You cannot drop the frozen users column '${col}'`
460
- );
461
- }
462
- await db
463
- .prepare(
464
- `
465
- ALTER TABLE ${safeTableName}
466
- DROP COLUMN ${this.quoteIdentifier(col)}
467
- `
468
- )
469
- .exec();
470
-
471
- completedOperations.push(`Dropped column: ${col}`);
472
- }
473
- }
474
-
475
- // Update columns
476
- if (updateColumns && Array.isArray(updateColumns)) {
477
- for (const column of updateColumns) {
478
- if (Object.keys(reservedColumns).includes(column.columnName)) {
479
- throw new AppError(
480
- 'cannot update system columns',
481
- 404,
482
- ERROR_CODES.DATABASE_FORBIDDEN,
483
- `You cannot update the system column '${column.columnName}'`
484
- );
485
- }
486
- if (tableName === 'users' && userTableFrozenColumns.includes(column.columnName)) {
487
- throw new AppError(
488
- 'cannot update frozen user columns',
489
- 403,
490
- ERROR_CODES.FORBIDDEN,
491
- `You cannot update the frozen users column '${column.columnName}'`
492
- );
493
- }
494
-
495
- // Handle default value changes
496
- if (column.defaultValue !== undefined) {
497
- if (column.defaultValue === '') {
498
- // Drop default
499
- await db
500
- .prepare(
501
- `
502
- ALTER TABLE ${safeTableName}
503
- ALTER COLUMN ${this.quoteIdentifier(column.columnName)} DROP DEFAULT
504
- `
505
- )
506
- .exec();
507
- } else {
508
- // Set default
509
- await db
510
- .prepare(
511
- `
512
- ALTER TABLE ${safeTableName}
513
- ALTER COLUMN ${this.quoteIdentifier(column.columnName)} SET ${formatDefaultValue(column.defaultValue)}
514
- `
515
- )
516
- .exec();
517
- }
518
- }
519
-
520
- // Handle column rename - do this last to avoid issues with other operations
521
- if (column.newColumnName) {
522
- await db
523
- .prepare(
524
- `
525
- ALTER TABLE ${safeTableName}
526
- RENAME COLUMN ${this.quoteIdentifier(column.columnName)} TO ${this.quoteIdentifier(column.newColumnName as string)}
527
- `
528
- )
529
- .exec();
530
- }
531
- completedOperations.push(`Updated column: ${column.columnName}`);
532
- }
533
- }
534
-
535
- // Add new columns
536
- if (addColumns && Array.isArray(addColumns)) {
537
- // Validate and filter reserved fields
538
- const columnsToAdd = this.validateReservedFields(addColumns);
539
-
540
- for (const col of columnsToAdd) {
541
- const fieldType = COLUMN_TYPES[col.type as ColumnType];
542
- let sqlType = fieldType.sqlType;
543
- if (col.type === ColumnType.UUID) {
544
- sqlType = 'UUID';
545
- }
546
-
547
- const nullable = col.isNullable !== false ? '' : 'NOT NULL';
548
- const unique = col.isUnique ? 'UNIQUE' : '';
549
- const defaultClause = formatDefaultValue(
550
- col.defaultValue,
551
- col.type as ColumnType,
552
- col.isNullable
553
- );
554
-
555
- await db
556
- .prepare(
557
- `
558
- ALTER TABLE ${safeTableName}
559
- ADD COLUMN ${this.quoteIdentifier(col.columnName)} ${sqlType} ${nullable} ${unique} ${defaultClause}
560
- `
561
- )
562
- .exec();
563
-
564
- completedOperations.push(`Added column: ${col.columnName}`);
565
- }
566
- }
567
-
568
- // Add foreign key constraints
569
- if (addForeignKeys && Array.isArray(addForeignKeys)) {
570
- for (const col of addForeignKeys) {
571
- if (Object.keys(reservedColumns).includes(col.columnName)) {
572
- throw new AppError(
573
- 'cannot add foreign key on system columns',
574
- 404,
575
- ERROR_CODES.DATABASE_FORBIDDEN,
576
- `You cannot add foreign key on the system column '${col.columnName}'`
577
- );
578
- }
579
- const fkeyConstraint = this.generateFkeyConstraintStatement(col, true);
580
- await db
581
- .prepare(
582
- `
583
- ALTER TABLE ${safeTableName}
584
- ADD ${fkeyConstraint}
585
- `
586
- )
587
- .exec();
588
-
589
- completedOperations.push(`Added foreign key constraint on column: ${col.columnName}`);
590
- }
591
- }
592
-
593
- if (renameTable && renameTable.newTableName) {
594
- if (tableName === 'users') {
595
- throw new AppError('Cannot rename users table', 403, ERROR_CODES.FORBIDDEN);
596
- }
597
- // Prevent renaming to system tables
598
- if (renameTable.newTableName.startsWith('_')) {
599
- throw new AppError(
600
- 'Cannot rename to system table',
601
- 403,
602
- ERROR_CODES.FORBIDDEN,
603
- 'Table names starting with underscore are reserved for system tables'
604
- );
605
- }
606
-
607
- const safeNewTableName = this.quoteIdentifier(renameTable.newTableName);
608
- // Rename the table
609
- await db
610
- .prepare(
611
- `
612
- ALTER TABLE ${safeTableName}
613
- RENAME TO ${safeNewTableName}
614
- `
615
- )
616
- .exec();
617
-
618
- completedOperations.push(`Renamed table from ${tableName} to ${renameTable.newTableName}`);
619
- }
620
-
621
- // Update metadata after schema changes
622
- // Metadata is now updated on-demand
623
-
624
- // enable postgrest to query this table
625
- await db
626
- .prepare(
627
- `
628
- NOTIFY pgrst, 'reload schema';
629
- `
630
- )
631
- .exec();
632
-
633
- return {
634
- message: 'table schema updated successfully',
635
- tableName,
636
- operations: completedOperations,
637
- };
638
- }
639
-
640
- /**
641
- * Delete a table
642
- */
643
- async deleteTable(table: string): Promise<DeleteTableResponse> {
644
- // Prevent deletion of system tables
645
- if (table.startsWith('_')) {
646
- throw new AppError(
647
- 'System tables cannot be deleted',
648
- 403,
649
- ERROR_CODES.DATABASE_FORBIDDEN,
650
- 'System tables cannot be deleted. System tables are prefixed with underscore.'
651
- );
652
- }
653
- if (table === 'users') {
654
- throw new AppError('Cannot delete users table', 403, ERROR_CODES.DATABASE_FORBIDDEN);
655
- }
656
-
657
- const db = this.dbManager.getDb();
658
- await db.prepare(`DROP TABLE IF EXISTS ${this.quoteIdentifier(table)} CASCADE`).run();
659
-
660
- // Update metadata
661
- // Metadata is now updated on-demand
662
-
663
- // enable postgrest to query this table
664
- await db
665
- .prepare(
666
- `
667
- NOTIFY pgrst, 'reload schema';
668
- `
669
- )
670
- .exec();
671
-
672
- return {
673
- message: 'table deleted successfully',
674
- tableName: table,
675
- nextActions:
676
- 'table deleted successfully, you can create a new table with the POST /api/database/tables endpoint',
677
- };
678
- }
679
-
680
- // Helper methods
681
- private quoteIdentifier(identifier: string): string {
682
- return `"${identifier.replace(/"/g, '""')}"`;
683
- }
684
-
685
- private validateReservedFields(columns: ColumnSchema[]): ColumnSchema[] {
686
- return columns.filter((col: ColumnSchema) => {
687
- const reservedType = reservedColumns[col.columnName as keyof typeof reservedColumns];
688
- if (reservedType) {
689
- // If it's a reserved field name
690
- if (col.type === reservedType) {
691
- // Type matches - silently ignore this column
692
- return false;
693
- } else {
694
- // Type doesn't match - throw error
695
- throw new AppError(
696
- `Column '${col.columnName}' is a reserved field that requires type '${reservedType}', but got '${col.type}'`,
697
- 400,
698
- ERROR_CODES.DATABASE_VALIDATION_ERROR,
699
- 'Please check the column name and type, id/created_at/updated_at are reserved fields and cannot be used as column names'
700
- );
701
- }
702
- }
703
- return true;
704
- });
705
- }
706
-
707
- private generateFkeyConstraintStatement(
708
- col: { columnName: string; foreignKey?: ForeignKeySchema },
709
- include_source_column: boolean = true
710
- ) {
711
- if (!col.foreignKey) {
712
- return '';
713
- }
714
- // Store foreign_key in a const to avoid repeated non-null assertions
715
- const fk = col.foreignKey;
716
- const constraintName = `fk_${col.columnName}_${fk.referenceTable}_${fk.referenceColumn}`;
717
- const onDelete = fk.onDelete || 'RESTRICT';
718
- const onUpdate = fk.onUpdate || 'RESTRICT';
719
-
720
- if (include_source_column) {
721
- return `CONSTRAINT ${this.quoteIdentifier(constraintName)} FOREIGN KEY (${this.quoteIdentifier(col.columnName)}) REFERENCES ${this.quoteIdentifier(fk.referenceTable)}(${this.quoteIdentifier(fk.referenceColumn)}) ON DELETE ${onDelete} ON UPDATE ${onUpdate}`;
722
- } else {
723
- return `CONSTRAINT ${this.quoteIdentifier(constraintName)} REFERENCES ${this.quoteIdentifier(fk.referenceTable)}(${this.quoteIdentifier(fk.referenceColumn)}) ON DELETE ${onDelete} ON UPDATE ${onUpdate}`;
724
- }
725
- }
726
-
727
- private async getFkeyConstraints(table: string): Promise<Map<string, ForeignKeyInfo>> {
728
- const db = this.dbManager.getDb();
729
- const foreignKeys = await db
730
- .prepare(
731
- `
732
- SELECT
733
- tc.constraint_name,
734
- kcu.column_name as from_column,
735
- ccu.table_name AS foreign_table,
736
- ccu.column_name AS foreign_column,
737
- rc.delete_rule as on_delete,
738
- rc.update_rule as on_update
739
- FROM information_schema.table_constraints AS tc
740
- JOIN information_schema.key_column_usage AS kcu
741
- ON tc.constraint_name = kcu.constraint_name
742
- AND tc.table_schema = kcu.table_schema
743
- JOIN information_schema.constraint_column_usage AS ccu
744
- ON ccu.constraint_name = tc.constraint_name
745
- AND ccu.table_schema = tc.table_schema
746
- JOIN information_schema.referential_constraints AS rc
747
- ON rc.constraint_name = tc.constraint_name
748
- AND rc.constraint_schema = tc.table_schema
749
- WHERE tc.constraint_type = 'FOREIGN KEY'
750
- AND tc.table_name = ?
751
- `
752
- )
753
- .all(table);
754
-
755
- // Create a map of column names to their foreign key info
756
- const foreignKeyMap = new Map<string, ForeignKeyInfo>();
757
- foreignKeys.forEach((fk: ForeignKeyRow) => {
758
- if (fk.foreign_table.startsWith('_')) {
759
- // hiden internal table.
760
- return;
761
- }
762
- foreignKeyMap.set(fk.from_column, {
763
- constraint_name: fk.constraint_name,
764
- referenceTable: fk.foreign_table,
765
- referenceColumn: fk.foreign_column,
766
- onDelete: fk.on_delete as OnDeleteActionSchema,
767
- onUpdate: fk.on_update as OnUpdateActionSchema,
768
- });
769
- });
770
- return foreignKeyMap;
771
- }
772
- }