insforge 0.3.3 → 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 -780
  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,313 @@
1
+ import {
2
+ S3Client,
3
+ PutObjectCommand,
4
+ GetObjectCommand,
5
+ DeleteObjectCommand,
6
+ ListObjectsV2Command,
7
+ DeleteObjectsCommand,
8
+ HeadObjectCommand,
9
+ } from '@aws-sdk/client-s3';
10
+ import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
11
+ import { createPresignedPost } from '@aws-sdk/s3-presigned-post';
12
+ import { getSignedUrl as getCloudFrontSignedUrl } from '@aws-sdk/cloudfront-signer';
13
+ import { UploadStrategyResponse, DownloadStrategyResponse } from '@insforge/shared-schemas';
14
+ import { StorageProvider } from './base.provider.js';
15
+ import logger from '@/utils/logger.js';
16
+
17
+ const ONE_HOUR_IN_SECONDS = 3600;
18
+ const DEFAULT_MAX_UPLOAD_SIZE_BYTES = 10485760;
19
+ const SEVEN_DAYS_IN_SECONDS = 604800;
20
+
21
+ /**
22
+ * S3 storage implementation
23
+ */
24
+ export class S3StorageProvider implements StorageProvider {
25
+ private s3Client: S3Client | null = null;
26
+
27
+ constructor(
28
+ private s3Bucket: string,
29
+ private appKey: string,
30
+ private region: string = 'us-east-2'
31
+ ) {}
32
+
33
+ initialize(): void {
34
+ // Use explicit AWS credentials if provided (local dev or self hosting)
35
+ // Otherwise, use IAM role credentials (EC2 production)
36
+ const s3Config: {
37
+ region: string;
38
+ credentials?: { accessKeyId: string; secretAccessKey: string };
39
+ } = {
40
+ region: this.region,
41
+ };
42
+
43
+ if (process.env.AWS_ACCESS_KEY_ID && process.env.AWS_SECRET_ACCESS_KEY) {
44
+ s3Config.credentials = {
45
+ accessKeyId: process.env.AWS_ACCESS_KEY_ID,
46
+ secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
47
+ };
48
+ }
49
+
50
+ this.s3Client = new S3Client(s3Config);
51
+ }
52
+
53
+ private getS3Key(bucket: string, key: string): string {
54
+ return `${this.appKey}/${bucket}/${key}`;
55
+ }
56
+
57
+ async putObject(bucket: string, key: string, file: Express.Multer.File): Promise<void> {
58
+ if (!this.s3Client) {
59
+ throw new Error('S3 client not initialized');
60
+ }
61
+ const s3Key = this.getS3Key(bucket, key);
62
+
63
+ const command = new PutObjectCommand({
64
+ Bucket: this.s3Bucket,
65
+ Key: s3Key,
66
+ Body: file.buffer,
67
+ ContentType: file.mimetype || 'application/octet-stream',
68
+ });
69
+
70
+ try {
71
+ await this.s3Client.send(command);
72
+ } catch (error) {
73
+ logger.error('S3 Upload error', {
74
+ error: error instanceof Error ? error.message : String(error),
75
+ bucket,
76
+ key: s3Key,
77
+ });
78
+ throw error;
79
+ }
80
+ }
81
+
82
+ async getObject(bucket: string, key: string): Promise<Buffer | null> {
83
+ if (!this.s3Client) {
84
+ throw new Error('S3 client not initialized');
85
+ }
86
+ try {
87
+ const command = new GetObjectCommand({
88
+ Bucket: this.s3Bucket,
89
+ Key: this.getS3Key(bucket, key),
90
+ });
91
+ const response = await this.s3Client.send(command);
92
+ const chunks: Uint8Array[] = [];
93
+ // Type assertion for readable stream
94
+ const body = response.Body as AsyncIterable<Uint8Array>;
95
+ for await (const chunk of body) {
96
+ chunks.push(chunk);
97
+ }
98
+ return Buffer.concat(chunks);
99
+ } catch {
100
+ return null;
101
+ }
102
+ }
103
+
104
+ async deleteObject(bucket: string, key: string): Promise<void> {
105
+ if (!this.s3Client) {
106
+ throw new Error('S3 client not initialized');
107
+ }
108
+ const command = new DeleteObjectCommand({
109
+ Bucket: this.s3Bucket,
110
+ Key: this.getS3Key(bucket, key),
111
+ });
112
+ await this.s3Client.send(command);
113
+ }
114
+
115
+ async createBucket(_bucket: string): Promise<void> {
116
+ // In S3 with multi-tenant, we don't create actual buckets
117
+ // We just use folders under the app key
118
+ }
119
+
120
+ async deleteBucket(bucket: string): Promise<void> {
121
+ if (!this.s3Client) {
122
+ throw new Error('S3 client not initialized');
123
+ }
124
+ // List and delete all objects in the "bucket" (folder)
125
+ const prefix = `${this.appKey}/${bucket}/`;
126
+
127
+ let continuationToken: string | undefined;
128
+ do {
129
+ const listCommand = new ListObjectsV2Command({
130
+ Bucket: this.s3Bucket,
131
+ Prefix: prefix,
132
+ ContinuationToken: continuationToken,
133
+ });
134
+ const listResponse = await this.s3Client.send(listCommand);
135
+
136
+ if (listResponse.Contents && listResponse.Contents.length) {
137
+ const deleteCommand = new DeleteObjectsCommand({
138
+ Bucket: this.s3Bucket,
139
+ Delete: {
140
+ Objects: listResponse.Contents.filter((obj) => obj.Key !== undefined).map((obj) => ({
141
+ Key: obj.Key as string,
142
+ })),
143
+ },
144
+ });
145
+ await this.s3Client.send(deleteCommand);
146
+ }
147
+
148
+ continuationToken = listResponse.NextContinuationToken;
149
+ } while (continuationToken);
150
+ }
151
+
152
+ // S3 supports presigned URLs
153
+ supportsPresignedUrls(): boolean {
154
+ return true;
155
+ }
156
+
157
+ async getUploadStrategy(
158
+ bucket: string,
159
+ key: string,
160
+ metadata: { contentType?: string; size?: number }
161
+ ): Promise<UploadStrategyResponse> {
162
+ if (!this.s3Client) {
163
+ throw new Error('S3 client not initialized');
164
+ }
165
+
166
+ const s3Key = this.getS3Key(bucket, key);
167
+ const expiresIn = ONE_HOUR_IN_SECONDS; // 1 hour
168
+
169
+ try {
170
+ // Generate presigned POST URL for multipart form upload
171
+ const { url, fields } = await createPresignedPost(this.s3Client, {
172
+ Bucket: this.s3Bucket,
173
+ Key: s3Key,
174
+ Conditions: [
175
+ ['content-length-range', 0, metadata.size || DEFAULT_MAX_UPLOAD_SIZE_BYTES], // Max 10MB by default
176
+ ],
177
+ Expires: expiresIn,
178
+ });
179
+
180
+ return {
181
+ method: 'presigned',
182
+ uploadUrl: url,
183
+ fields,
184
+ key,
185
+ confirmRequired: true,
186
+ confirmUrl: `/api/storage/buckets/${bucket}/objects/${encodeURIComponent(key)}/confirm-upload`,
187
+ expiresAt: new Date(Date.now() + expiresIn * 1000),
188
+ };
189
+ } catch (error) {
190
+ logger.error('Failed to generate presigned upload URL', {
191
+ error: error instanceof Error ? error.message : String(error),
192
+ bucket,
193
+ key,
194
+ });
195
+ throw error;
196
+ }
197
+ }
198
+
199
+ async getDownloadStrategy(
200
+ bucket: string,
201
+ key: string,
202
+ expiresIn: number = ONE_HOUR_IN_SECONDS,
203
+ isPublic: boolean = false
204
+ ): Promise<DownloadStrategyResponse> {
205
+ if (!this.s3Client) {
206
+ throw new Error('S3 client not initialized');
207
+ }
208
+
209
+ const s3Key = this.getS3Key(bucket, key);
210
+ // Public files get longer expiration (7 days), private files get shorter (1 hour default)
211
+ const actualExpiresIn = isPublic ? SEVEN_DAYS_IN_SECONDS : expiresIn; // 604800 = 7 days
212
+ const cloudFrontUrl = process.env.AWS_CLOUDFRONT_URL;
213
+
214
+ try {
215
+ // If CloudFront URL is configured, use CloudFront for downloads
216
+ if (cloudFrontUrl) {
217
+ const cloudFrontKeyPairId = process.env.AWS_CLOUDFRONT_KEY_PAIR_ID;
218
+ const cloudFrontPrivateKey = process.env.AWS_CLOUDFRONT_PRIVATE_KEY;
219
+
220
+ if (!cloudFrontKeyPairId || !cloudFrontPrivateKey) {
221
+ logger.warn(
222
+ 'CloudFront URL configured but missing key pair ID or private key, falling back to S3'
223
+ );
224
+ } else {
225
+ try {
226
+ // Generate CloudFront signed URL
227
+ // IMPORTANT: URL-encode the S3 key to match what CloudFront receives
228
+ // This ensures the signature matches for files with spaces, parentheses, etc.
229
+ const encodedS3Key = s3Key
230
+ .split('/')
231
+ .map((segment) => encodeURIComponent(segment))
232
+ .join('/');
233
+ const cloudFrontObjectUrl = `${cloudFrontUrl.replace(/\/$/, '')}/${encodedS3Key}`;
234
+
235
+ // Convert escaped newlines to actual newlines in the private key
236
+ const formattedPrivateKey = cloudFrontPrivateKey.replace(/\\n/g, '\n');
237
+
238
+ // dateLessThan can be string | number | Date - using Date object directly
239
+ const dateLessThan = new Date(Date.now() + actualExpiresIn * 1000);
240
+
241
+ const signedUrl = getCloudFrontSignedUrl({
242
+ url: cloudFrontObjectUrl,
243
+ keyPairId: cloudFrontKeyPairId,
244
+ privateKey: formattedPrivateKey,
245
+ dateLessThan,
246
+ });
247
+
248
+ logger.info('CloudFront signed URL generated successfully.');
249
+
250
+ return {
251
+ method: 'presigned',
252
+ url: signedUrl,
253
+ expiresAt: dateLessThan,
254
+ };
255
+ } catch (cfError) {
256
+ logger.error('Failed to generate CloudFront signed URL, falling back to S3', {
257
+ error: cfError instanceof Error ? cfError.message : String(cfError),
258
+ bucket,
259
+ key,
260
+ });
261
+ // Fall through to S3 signed URL generation
262
+ }
263
+ }
264
+ }
265
+
266
+ // Note: isPublic here refers to the application-level setting,
267
+ // not the actual S3 bucket policy. In a multi-tenant setup,
268
+ // we're using a single S3 bucket with folder-based isolation,
269
+ // so we always use presigned URLs for security.
270
+ // The "public" setting only affects the URL expiration time.
271
+
272
+ // Always generate presigned URL for security in multi-tenant environment
273
+ const command = new GetObjectCommand({
274
+ Bucket: this.s3Bucket,
275
+ Key: s3Key,
276
+ });
277
+
278
+ const url = await getSignedUrl(this.s3Client, command, { expiresIn: actualExpiresIn });
279
+
280
+ return {
281
+ method: 'presigned',
282
+ url,
283
+ expiresAt: new Date(Date.now() + actualExpiresIn * 1000),
284
+ };
285
+ } catch (error) {
286
+ logger.error('Failed to generate download URL', {
287
+ error: error instanceof Error ? error.message : String(error),
288
+ bucket,
289
+ key,
290
+ });
291
+ throw error;
292
+ }
293
+ }
294
+
295
+ async verifyObjectExists(bucket: string, key: string): Promise<boolean> {
296
+ if (!this.s3Client) {
297
+ throw new Error('S3 client not initialized');
298
+ }
299
+
300
+ const s3Key = this.getS3Key(bucket, key);
301
+
302
+ try {
303
+ const command = new HeadObjectCommand({
304
+ Bucket: this.s3Bucket,
305
+ Key: s3Key,
306
+ });
307
+ await this.s3Client.send(command);
308
+ return true;
309
+ } catch {
310
+ return false;
311
+ }
312
+ }
313
+ }
@@ -5,29 +5,25 @@ import dotenv from 'dotenv';
5
5
  import path from 'path';
6
6
  import { fileURLToPath } from 'url';
7
7
  import fs from 'fs';
8
- import authRouter from '@/api/routes/auth.js';
9
- import { databaseTablesRouter } from '@/api/routes/database.tables.js';
10
- import { databaseRecordsRouter } from '@/api/routes/database.records.js';
11
- import databaseAdvanceRouter from '@/api/routes/database.advance.js';
12
- import { storageRouter } from '@/api/routes/storage.js';
13
- import { metadataRouter } from '@/api/routes/metadata.js';
14
- import { logsRouter } from '@/api/routes/logs.js';
15
- import { docsRouter } from '@/api/routes/docs.js';
16
- import functionsRouter from '@/api/routes/functions.js';
17
- import secretsRouter from '@/api/routes/secrets.js';
18
- import { usageRouter } from '@/api/routes/usage.js';
19
- import { openAPIRouter } from '@/api/routes/openapi.js';
20
- import { agentDocsRouter } from '@/api/routes/agent.js';
21
- import { aiRouter } from '@/api/routes/ai.js';
22
- import { errorMiddleware } from '@/api/middleware/error.js';
8
+ import authRouter from '@/api/routes/auth/index.routes.js';
9
+ import databaseRouter from '@/api/routes/database/index.routes.js';
10
+ import { storageRouter } from '@/api/routes/storage/index.routes.js';
11
+ import { metadataRouter } from '@/api/routes/metadata/index.routes.js';
12
+ import { logsRouter } from '@/api/routes/logs/index.routes.js';
13
+ import { docsRouter } from '@/api/routes/docs/index.routes.js';
14
+ import functionsRouter from '@/api/routes/functions/index.routes.js';
15
+ import secretsRouter from '@/api/routes/secrets/index.routes.js';
16
+ import { usageRouter } from '@/api/routes/usage/index.routes.js';
17
+ import { aiRouter } from '@/api/routes/ai/index.routes.js';
18
+ import { errorMiddleware } from '@/api/middlewares/error.js';
23
19
  import fetch, { HeadersInit } from 'node-fetch';
24
- import { DatabaseManager } from '@/core/database/manager.js';
25
- import { AnalyticsManager } from '@/core/logs/analytics.js';
26
- import { StorageService } from '@/core/storage/storage.js';
27
- import { SocketService } from '@/core/socket/socket.js';
20
+ import { DatabaseManager } from '@/infra/database/database.manager.js';
21
+ import { LogService } from '@/services/logs/log.service.js';
22
+ import { StorageService } from '@/services/storage/storage.service.js';
23
+ import { SocketManager } from '@/infra/socket/socket.manager.js';
28
24
  import { seedBackend } from '@/utils/seed.js';
29
25
  import logger from '@/utils/logger.js';
30
- import { isProduction } from './utils/environment';
26
+ import { isProduction } from './utils/environment.js';
31
27
  import packageJson from '../../package.json';
32
28
 
33
29
  const __filename = fileURLToPath(import.meta.url);
@@ -51,11 +47,9 @@ export async function createApp() {
51
47
  const storageService = StorageService.getInstance();
52
48
  await storageService.initialize(); // create data/storage
53
49
 
54
- // Metadata is now handled by individual modules on-demand
55
-
56
- // Initialize analytics service
57
- const analyticsManager = AnalyticsManager.getInstance();
58
- await analyticsManager.initialize(); // connect to _insforge database
50
+ // Initialize logs service
51
+ const logService = LogService.getInstance();
52
+ await logService.initialize(); // connect to CloudWatch
59
53
 
60
54
  const app = express();
61
55
 
@@ -87,25 +81,47 @@ export async function createApp() {
87
81
  let responseSize = 0;
88
82
 
89
83
  // Override send method
90
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
91
- res.send = function (data: any) {
92
- if (data) {
93
- responseSize = Buffer.byteLength(typeof data === 'string' ? data : JSON.stringify(data));
84
+ res.send = function (
85
+ data: string | Buffer | Record<string, unknown> | unknown[] | number | boolean
86
+ ) {
87
+ if (data !== undefined && data !== null) {
88
+ if (typeof data === 'string') {
89
+ responseSize = Buffer.byteLength(data);
90
+ } else if (Buffer.isBuffer(data)) {
91
+ responseSize = data.length;
92
+ } else if (typeof data === 'number' || typeof data === 'boolean') {
93
+ responseSize = Buffer.byteLength(String(data));
94
+ } else {
95
+ try {
96
+ responseSize = Buffer.byteLength(JSON.stringify(data));
97
+ } catch {
98
+ // Handle circular references or unstringifiable objects
99
+ responseSize = 0;
100
+ }
101
+ }
94
102
  }
95
103
  return originalSend.call(this, data);
96
104
  };
105
+
97
106
  // Override json method
98
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
99
- res.json = function (data: any) {
100
- if (data) {
101
- responseSize = Buffer.byteLength(JSON.stringify(data));
107
+ res.json = function (
108
+ data: Record<string, unknown> | unknown[] | string | number | boolean | null
109
+ ) {
110
+ if (data !== undefined) {
111
+ try {
112
+ responseSize = Buffer.byteLength(JSON.stringify(data));
113
+ } catch {
114
+ // Handle circular references or unstringifiable objects
115
+ responseSize = 0;
116
+ }
102
117
  }
103
118
  return originalJson.call(this, data);
104
119
  };
120
+
105
121
  // Log after response is finished
106
122
  res.on('finish', () => {
107
- // Skip logging for analytics endpoints to avoid infinite loops
108
- if (req.path.includes('/analytics/')) {
123
+ // Skip logging for logs endpoints to avoid infinite loops
124
+ if (req.path.includes('/logs/')) {
109
125
  return;
110
126
  }
111
127
 
@@ -121,6 +137,7 @@ export async function createApp() {
121
137
  timestamp: new Date().toISOString(),
122
138
  });
123
139
  });
140
+
124
141
  next();
125
142
  });
126
143
 
@@ -142,11 +159,9 @@ export async function createApp() {
142
159
  });
143
160
  });
144
161
 
145
- // Mount auth routes
162
+ // Mount all routes
146
163
  apiRouter.use('/auth', authRouter);
147
- apiRouter.use('/database/tables', databaseTablesRouter);
148
- apiRouter.use('/database/records', databaseRecordsRouter);
149
- apiRouter.use('/database/advance', databaseAdvanceRouter);
164
+ apiRouter.use('/database', databaseRouter);
150
165
  apiRouter.use('/storage', storageRouter);
151
166
  apiRouter.use('/metadata', metadataRouter);
152
167
  apiRouter.use('/logs', logsRouter);
@@ -154,37 +169,11 @@ export async function createApp() {
154
169
  apiRouter.use('/functions', functionsRouter);
155
170
  apiRouter.use('/secrets', secretsRouter);
156
171
  apiRouter.use('/usage', usageRouter);
157
- apiRouter.use('/openapi', openAPIRouter);
158
- apiRouter.use('/agent-docs', agentDocsRouter);
159
172
  apiRouter.use('/ai', aiRouter);
160
173
 
161
174
  // Mount all API routes under /api prefix
162
175
  app.use('/api', apiRouter);
163
176
 
164
- // Add direct OpenAPI route at /openapi
165
- app.get('/openapi', async (_req: Request, res: Response) => {
166
- try {
167
- const { OpenAPIService } = await import('@/core/documentation/openapi.js');
168
- const openAPIService = OpenAPIService.getInstance();
169
- const openAPIDocument = await openAPIService.generateOpenAPIDocument();
170
- res.json(openAPIDocument);
171
- } catch {
172
- res.status(500).json({ error: 'Failed to generate OpenAPI document' });
173
- }
174
- });
175
-
176
- // Add direct AI agent documentation route at /agent-docs
177
- app.get('/agent-docs', async (_req: Request, res: Response) => {
178
- try {
179
- const { AgentAPIDocService } = await import('@/core/documentation/agent.js');
180
- const agentAPIDocService = AgentAPIDocService.getInstance();
181
- const agentDocs = await agentAPIDocService.generateAgentDocumentation();
182
- res.json(agentDocs);
183
- } catch {
184
- res.status(500).json({ error: 'Failed to generate agent API documentation' });
185
- }
186
- });
187
-
188
177
  // Proxy function execution to Deno runtime
189
178
  app.all('/functions/:slug', async (req: Request, res: Response) => {
190
179
  try {
@@ -224,19 +213,26 @@ export async function createApp() {
224
213
  }
225
214
  });
226
215
 
227
- // Always try to serve frontend if it exists
228
- const frontendPath = path.join(__dirname, 'frontend');
216
+ // Serve auth app
217
+ const authAppPath = path.join(__dirname, 'auth');
218
+ if (fs.existsSync(authAppPath)) {
219
+ app.use('/auth', express.static(authAppPath));
220
+ app.get('/auth*', (_req: Request, res: Response) => {
221
+ res.sendFile(path.join(authAppPath, 'index.html'));
222
+ });
223
+ } else if (!isProduction()) {
224
+ const authAppUrl = process.env.AUTH_APP_URL || 'http://localhost:7132';
225
+ logger.info('Auth app not built, proxying to development server', { authAppUrl });
226
+ }
229
227
 
230
- // Check if frontend build exists
228
+ // Serve main frontend if it exists
229
+ const frontendPath = path.join(__dirname, 'frontend');
231
230
  if (fs.existsSync(frontendPath)) {
231
+ app.use(express.static(frontendPath, { index: false }));
232
232
  // Catch all handler for SPA routes
233
- app.get('/cloud*', (_req: Request, res: Response) => {
234
- res.sendFile(path.join(frontendPath, 'index.html'));
235
- });
236
- app.get('/dashboard*', (_req: Request, res: Response) => {
233
+ app.get(['/cloud*', '/dashboard*'], (_req: Request, res: Response) => {
237
234
  res.sendFile(path.join(frontendPath, 'index.html'));
238
235
  });
239
- app.use(express.static(frontendPath));
240
236
  } else {
241
237
  // Catch-all for 404 errors - Traditional REST format
242
238
  app.use('*', (req: Request, res: Response) => {
@@ -266,7 +262,7 @@ async function initializeServer() {
266
262
  });
267
263
 
268
264
  // Initialize Socket.IO service
269
- const socketService = SocketService.getInstance();
265
+ const socketService = SocketManager.getInstance();
270
266
  socketService.initialize(server);
271
267
  } catch (error) {
272
268
  logger.error('Failed to initialize server', {
@@ -1,11 +1,21 @@
1
1
  import { Pool } from 'pg';
2
- import { DatabaseManager } from '@/core/database/manager.js';
2
+ import { DatabaseManager } from '@/infra/database/database.manager.js';
3
3
  import logger from '@/utils/logger.js';
4
4
  import { AIConfigurationSchema, AIConfigurationWithUsageSchema } from '@insforge/shared-schemas';
5
5
 
6
6
  export class AIConfigService {
7
+ private static instance: AIConfigService;
7
8
  private pool: Pool | null = null;
8
9
 
10
+ private constructor() {}
11
+
12
+ public static getInstance(): AIConfigService {
13
+ if (!AIConfigService.instance) {
14
+ AIConfigService.instance = new AIConfigService();
15
+ }
16
+ return AIConfigService.instance;
17
+ }
18
+
9
19
  private getPool(): Pool {
10
20
  if (!this.pool) {
11
21
  this.pool = DatabaseManager.getInstance().getPool();
@@ -20,9 +30,8 @@ export class AIConfigService {
20
30
  modelId: string,
21
31
  systemPrompt?: string
22
32
  ): Promise<{ id: string }> {
23
- const client = await this.getPool().connect();
24
33
  try {
25
- const result = await client.query(
34
+ const result = await this.getPool().query(
26
35
  `INSERT INTO _ai_configs (input_modality, output_modality, provider, model_id, system_prompt)
27
36
  VALUES ($1, $2, $3, $4, $5)
28
37
  RETURNING id`,
@@ -34,17 +43,14 @@ export class AIConfigService {
34
43
  } catch (error) {
35
44
  logger.error('Failed to create AI configuration', { error });
36
45
  throw new Error('Failed to create AI configuration');
37
- } finally {
38
- client.release();
39
46
  }
40
47
  }
41
48
 
42
49
  async findAll(): Promise<AIConfigurationWithUsageSchema[]> {
43
- const client = await this.getPool().connect();
44
50
  try {
45
51
  // Use a single query with aggregation to get configs with usage stats
46
- const result = await client.query(
47
- `SELECT
52
+ const result = await this.getPool().query(
53
+ `SELECT
48
54
  c.id,
49
55
  c.input_modality as "inputModality",
50
56
  c.output_modality as "outputModality",
@@ -63,7 +69,7 @@ export class AIConfigService {
63
69
  );
64
70
 
65
71
  return result.rows.map((row) => ({
66
- id: row.id,
72
+ id: row.id, // UUID
67
73
  inputModality: row.inputModality,
68
74
  outputModality: row.outputModality,
69
75
  provider: row.provider,
@@ -80,16 +86,13 @@ export class AIConfigService {
80
86
  } catch (error) {
81
87
  logger.error('Failed to fetch AI configurations with usage', { error });
82
88
  throw new Error('Failed to fetch AI configurations');
83
- } finally {
84
- client.release();
85
89
  }
86
90
  }
87
91
 
88
92
  async update(id: string, systemPrompt: string | null): Promise<boolean> {
89
- const client = await this.getPool().connect();
90
93
  try {
91
- const result = await client.query(
92
- `UPDATE _ai_configs
94
+ const result = await this.getPool().query(
95
+ `UPDATE _ai_configs
93
96
  SET system_prompt = $1, updated_at = NOW()
94
97
  WHERE id = $2`,
95
98
  [systemPrompt, id]
@@ -103,15 +106,12 @@ export class AIConfigService {
103
106
  } catch (error) {
104
107
  logger.error('Failed to update AI configuration', { error, id });
105
108
  throw new Error('Failed to update AI configuration');
106
- } finally {
107
- client.release();
108
109
  }
109
110
  }
110
111
 
111
112
  async delete(id: string): Promise<boolean> {
112
- const client = await this.getPool().connect();
113
113
  try {
114
- const result = await client.query('DELETE FROM _ai_configs WHERE id = $1', [id]);
114
+ const result = await this.getPool().query('DELETE FROM _ai_configs WHERE id = $1', [id]);
115
115
 
116
116
  const success = (result.rowCount ?? 0) > 0;
117
117
  if (success) {
@@ -121,15 +121,12 @@ export class AIConfigService {
121
121
  } catch (error) {
122
122
  logger.error('Failed to delete AI configuration', { error, id });
123
123
  throw new Error('Failed to delete AI configuration');
124
- } finally {
125
- client.release();
126
124
  }
127
125
  }
128
126
 
129
127
  async findByModelId(modelId: string): Promise<AIConfigurationSchema | null> {
130
- const client = await this.getPool().connect();
131
128
  try {
132
- const result = await client.query(
129
+ const result = await this.getPool().query(
133
130
  `SELECT id, input_modality as "inputModality", output_modality as "outputModality", provider, model_id as "modelId", system_prompt as "systemPrompt", created_at, updated_at
134
131
  FROM _ai_configs
135
132
  WHERE model_id = $1`,
@@ -155,8 +152,6 @@ export class AIConfigService {
155
152
  modelId,
156
153
  });
157
154
  throw new Error('Failed to fetch AI configuration');
158
- } finally {
159
- client.release();
160
155
  }
161
156
  }
162
157