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,781 +0,0 @@
1
- import jwt from 'jsonwebtoken';
2
- import bcrypt from 'bcryptjs';
3
- import crypto from 'crypto';
4
- import axios from 'axios';
5
- import { OAuth2Client } from 'google-auth-library';
6
- import dotenv from 'dotenv';
7
- import { verifyCloudToken } from '@/utils/cloud-token.js';
8
- import path from 'path';
9
- import fs from 'fs';
10
- import { fileURLToPath } from 'url';
11
- import { DatabaseManager } from '@/core/database/manager.js';
12
- import logger from '@/utils/logger.js';
13
- import type {
14
- UserSchema,
15
- CreateUserResponse,
16
- CreateSessionResponse,
17
- CreateAdminSessionResponse,
18
- TokenPayloadSchema,
19
- AuthMetadataSchema,
20
- } from '@insforge/shared-schemas';
21
- import { OAuthConfigService } from './oauth';
22
- import { GitHubEmailInfo, GitHubUserInfo, GoogleUserInfo, UserRecord } from '@/types/auth';
23
- import { ADMIN_ID } from '@/utils/constants';
24
-
25
- const JWT_SECRET = () => process.env.JWT_SECRET ?? '';
26
- const JWT_EXPIRES_IN = '7d';
27
-
28
- /**
29
- * Simplified JWT-based auth service
30
- * Handles all authentication operations including OAuth
31
- */
32
- export class AuthService {
33
- private static instance: AuthService;
34
- private adminEmail: string;
35
- private adminPassword: string;
36
- private db;
37
- private processedCodes: Set<string>;
38
- private tokenCache: Map<string, { access_token: string; id_token: string }>;
39
-
40
- private constructor() {
41
- // Load .env file if not already loaded
42
- if (!process.env.JWT_SECRET) {
43
- const __filename = fileURLToPath(import.meta.url);
44
- const __dirname = path.dirname(__filename);
45
- const envPath = path.resolve(__dirname, '../../../../.env');
46
- if (fs.existsSync(envPath)) {
47
- dotenv.config({ path: envPath });
48
- } else {
49
- logger.warn('No .env file found, using default environment variables.');
50
- dotenv.config();
51
- }
52
- }
53
-
54
- if (!process.env.JWT_SECRET) {
55
- throw new Error('JWT_SECRET environment variable is required');
56
- }
57
-
58
- this.adminEmail = process.env.ADMIN_EMAIL ?? '';
59
- this.adminPassword = process.env.ADMIN_PASSWORD ?? '';
60
-
61
- if (!this.adminEmail || !this.adminPassword) {
62
- throw new Error('ADMIN_EMAIL and ADMIN_PASSWORD environment variables are required');
63
- }
64
-
65
- const dbManager = DatabaseManager.getInstance();
66
- this.db = dbManager.getDb();
67
-
68
- // Initialize OAuth helpers
69
- this.processedCodes = new Set();
70
- this.tokenCache = new Map();
71
-
72
- logger.info('AuthService initialized');
73
- }
74
-
75
- public static getInstance(): AuthService {
76
- if (!AuthService.instance) {
77
- AuthService.instance = new AuthService();
78
- }
79
- return AuthService.instance;
80
- }
81
-
82
- /**
83
- * Transform database user to API format (snake_case to camelCase)
84
- */
85
- private dbUserToApiUser(dbUser: UserRecord): UserSchema {
86
- return {
87
- id: dbUser.id,
88
- email: dbUser.email,
89
- name: dbUser.name,
90
- emailVerified: dbUser.email_verified,
91
- createdAt: dbUser.created_at,
92
- updatedAt: dbUser.updated_at,
93
- };
94
- }
95
-
96
- /**
97
- * Generate JWT token for users and admins
98
- */
99
- generateToken(payload: TokenPayloadSchema): string {
100
- return jwt.sign(payload, JWT_SECRET(), {
101
- algorithm: 'HS256',
102
- expiresIn: JWT_EXPIRES_IN,
103
- });
104
- }
105
-
106
- /**
107
- * Generate anonymous JWT token (never expires)
108
- */
109
- generateAnonToken(): string {
110
- const payload = {
111
- sub: 'anonymous',
112
- email: 'anon@insforge.com',
113
- role: 'anon',
114
- };
115
- return jwt.sign(payload, JWT_SECRET(), {
116
- algorithm: 'HS256',
117
- // No expiresIn means token never expires
118
- });
119
- }
120
-
121
- /**
122
- * Verify JWT token
123
- */
124
- verifyToken(token: string): TokenPayloadSchema {
125
- try {
126
- const decoded = jwt.verify(token, JWT_SECRET()) as TokenPayloadSchema;
127
- return {
128
- sub: decoded.sub,
129
- email: decoded.email,
130
- role: decoded.role || 'authenticated',
131
- };
132
- } catch {
133
- throw new Error('Invalid token');
134
- }
135
- }
136
-
137
- /**
138
- * User registration
139
- */
140
- async register(email: string, password: string, name?: string): Promise<CreateUserResponse> {
141
- const existingUser = await this.db
142
- .prepare('SELECT id FROM _accounts WHERE email = ?')
143
- .get(email);
144
-
145
- if (existingUser) {
146
- throw new Error('User already exists');
147
- }
148
-
149
- const hashedPassword = await bcrypt.hash(password, 10);
150
- const userId = crypto.randomUUID();
151
-
152
- await this.db
153
- .prepare(
154
- `
155
- INSERT INTO _accounts (id, email, password, name, email_verified, created_at, updated_at)
156
- VALUES (?, ?, ?, ?, ?, NOW(), NOW())
157
- `
158
- )
159
- .run(userId, email, hashedPassword, name || null, false);
160
-
161
- await this.db
162
- .prepare(
163
- `
164
- INSERT INTO users (id, nickname, created_at, updated_at)
165
- VALUES (?, ?, NOW(), NOW())
166
- `
167
- )
168
- .run(userId, name || null);
169
-
170
- const dbUser = await this.db
171
- .prepare(
172
- 'SELECT id, email, name, email_verified, created_at, updated_at FROM _accounts WHERE id = ?'
173
- )
174
- .get(userId);
175
- const user = this.dbUserToApiUser(dbUser);
176
- const accessToken = this.generateToken({ sub: userId, email, role: 'authenticated' });
177
-
178
- return { user, accessToken };
179
- }
180
-
181
- /**
182
- * User login
183
- */
184
- async login(email: string, password: string): Promise<CreateSessionResponse> {
185
- const dbUser = await this.db.prepare('SELECT * FROM _accounts WHERE email = ?').get(email);
186
-
187
- if (!dbUser || !dbUser.password) {
188
- throw new Error('Invalid credentials');
189
- }
190
-
191
- const validPassword = await bcrypt.compare(password, dbUser.password);
192
- if (!validPassword) {
193
- throw new Error('Invalid credentials');
194
- }
195
-
196
- const user = this.dbUserToApiUser(dbUser);
197
- const accessToken = this.generateToken({
198
- sub: dbUser.id,
199
- email: dbUser.email,
200
- role: 'authenticated',
201
- });
202
-
203
- return { user, accessToken };
204
- }
205
-
206
- /**
207
- * Admin login (validates against env variables only)
208
- */
209
- adminLogin(email: string, password: string): CreateAdminSessionResponse {
210
- // Simply validate against environment variables
211
- if (email !== this.adminEmail || password !== this.adminPassword) {
212
- throw new Error('Invalid admin credentials');
213
- }
214
-
215
- // Use a fixed admin ID for the system administrator
216
-
217
- // Return admin user with JWT token - no database interaction
218
- const accessToken = this.generateToken({ sub: ADMIN_ID, email, role: 'project_admin' });
219
-
220
- return {
221
- user: {
222
- id: ADMIN_ID,
223
- email: email,
224
- name: 'Administrator',
225
- emailVerified: true,
226
- createdAt: new Date().toISOString(),
227
- updatedAt: new Date().toISOString(),
228
- },
229
- accessToken,
230
- };
231
- }
232
-
233
- /**
234
- * Admin login with authorization token (validates JWT from external issuer)
235
- */
236
- async adminLoginWithAuthorizationCode(code: string): Promise<CreateAdminSessionResponse> {
237
- try {
238
- // Use the helper function to verify cloud token
239
- const { payload } = await verifyCloudToken(code);
240
-
241
- // If verification succeeds, extract user info and generate internal token
242
- const adminId = payload['userId'] || ADMIN_ID;
243
- const email = payload['email'] || payload['sub'] || 'admin@insforge.local';
244
-
245
- // Generate internal access token
246
- const accessToken = this.generateToken({
247
- sub: adminId as string,
248
- email: email as string,
249
- role: 'project_admin',
250
- });
251
-
252
- return {
253
- user: {
254
- id: adminId as string,
255
- email: email as string,
256
- name: 'Administrator',
257
- emailVerified: true,
258
- createdAt: new Date().toISOString(),
259
- updatedAt: new Date().toISOString(),
260
- },
261
- accessToken,
262
- };
263
- } catch (error) {
264
- logger.error('Admin token verification failed:', error);
265
- throw new Error('Invalid admin credentials');
266
- }
267
- }
268
-
269
- /**
270
- * Find or create third-party user (main OAuth user handler)
271
- * Adapted from 3-table to 2-table structure
272
- */
273
- async findOrCreateThirdPartyUser(
274
- provider: string,
275
- providerId: string,
276
- email: string,
277
- userName: string,
278
- avatarUrl: string,
279
- identityData: GoogleUserInfo | GitHubUserInfo | Record<string, unknown>
280
- ): Promise<CreateSessionResponse> {
281
- // First, try to find existing user by provider ID in _account_providers table
282
- const account = await this.db
283
- .prepare('SELECT * FROM _account_providers WHERE provider = ? AND provider_account_id = ?')
284
- .get(provider, providerId);
285
-
286
- if (account) {
287
- // Found existing OAuth user, update last login time
288
- await this.db
289
- .prepare(
290
- 'UPDATE _account_providers SET updated_at = CURRENT_TIMESTAMP WHERE provider = ? AND provider_account_id = ?'
291
- )
292
- .run(provider, providerId);
293
-
294
- const dbUser = await this.db
295
- .prepare(
296
- 'SELECT id, email, name, email_verified, created_at, updated_at FROM _accounts WHERE id = ?'
297
- )
298
- .get(account.user_id);
299
-
300
- const user = this.dbUserToApiUser(dbUser);
301
- const accessToken = this.generateToken({
302
- sub: user.id,
303
- email: user.email,
304
- role: 'authenticated',
305
- });
306
-
307
- return { user, accessToken };
308
- }
309
-
310
- // If not found by provider_id, try to find by email in _user table
311
- const existingUser = await this.db
312
- .prepare('SELECT * FROM _accounts WHERE email = ?')
313
- .get(email);
314
-
315
- if (existingUser) {
316
- // Found existing user by email, create _account_providers record to link OAuth
317
- await this.db
318
- .prepare(
319
- `
320
- INSERT INTO _account_providers (
321
- user_id, provider, provider_account_id,
322
- provider_data, created_at, updated_at
323
- )
324
- VALUES (?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
325
- `
326
- )
327
- .run(existingUser.id, provider, providerId, JSON.stringify(identityData));
328
-
329
- const user = this.dbUserToApiUser(existingUser);
330
- const accessToken = this.generateToken({
331
- sub: existingUser.id,
332
- email: existingUser.email,
333
- role: 'authenticated',
334
- });
335
-
336
- return { user, accessToken };
337
- }
338
-
339
- // Create new user with OAuth data
340
- return this.createThirdPartyUser(
341
- provider,
342
- userName,
343
- email,
344
- providerId,
345
- identityData,
346
- avatarUrl
347
- );
348
- }
349
-
350
- /**
351
- * Create new third-party user
352
- */
353
- private async createThirdPartyUser(
354
- provider: string,
355
- userName: string,
356
- email: string,
357
- providerId: string,
358
- identityData: GoogleUserInfo | GitHubUserInfo | Record<string, unknown>,
359
- avatarUrl: string
360
- ): Promise<CreateSessionResponse> {
361
- const userId = crypto.randomUUID();
362
-
363
- await this.db.exec('BEGIN');
364
-
365
- try {
366
- // Create user record (without password for OAuth users)
367
- await this.db
368
- .prepare(
369
- `
370
- INSERT INTO _accounts (id, email, name, email_verified, created_at, updated_at)
371
- VALUES (?, ?, ?, true, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
372
- `
373
- )
374
- .run(userId, email, userName);
375
-
376
- await this.db
377
- .prepare(
378
- `
379
- INSERT INTO users (id, nickname, avatar_url, created_at, updated_at)
380
- VALUES (?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
381
- `
382
- )
383
- .run(userId, userName, avatarUrl);
384
-
385
- // Create _account_providers record
386
- await this.db
387
- .prepare(
388
- `
389
- INSERT INTO _account_providers (
390
- user_id, provider, provider_account_id,
391
- provider_data, created_at, updated_at
392
- )
393
- VALUES (?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
394
- `
395
- )
396
- .run(
397
- userId,
398
- provider,
399
- providerId,
400
- JSON.stringify({ ...identityData, avatar_url: avatarUrl })
401
- );
402
-
403
- await this.db.exec('COMMIT');
404
-
405
- const user: UserSchema = {
406
- id: userId,
407
- email,
408
- name: userName,
409
- emailVerified: true,
410
- createdAt: new Date().toISOString(),
411
- updatedAt: new Date().toISOString(),
412
- };
413
-
414
- const accessToken = this.generateToken({
415
- sub: userId,
416
- email,
417
- role: 'authenticated',
418
- });
419
-
420
- return { user, accessToken };
421
- } catch (error) {
422
- await this.db.exec('ROLLBACK');
423
- throw error;
424
- }
425
- }
426
-
427
- /**
428
- * Generate Google OAuth authorization URL
429
- */
430
- async generateGoogleAuthUrl(state?: string): Promise<string | undefined> {
431
- const oauthConfigService = OAuthConfigService.getInstance();
432
- const config = await oauthConfigService.getConfigByProvider('google');
433
-
434
- if (!config) {
435
- throw new Error('Google OAuth not configured');
436
- }
437
-
438
- const selfBaseUrl = process.env.API_BASE_URL || 'http://localhost:7130';
439
-
440
- if (config?.useSharedKey) {
441
- if (!state) {
442
- logger.warn('Shared Google OAuth called without state parameter');
443
- throw new Error('State parameter is required for shared Google OAuth');
444
- }
445
- // Use shared keys if configured
446
- const cloudBaseUrl = process.env.CLOUD_API_HOST || 'https://api.insforge.dev';
447
- const redirectUri = `${selfBaseUrl}/api/auth/oauth/shared/callback/${state}`;
448
- const authUrl = await fetch(
449
- `${cloudBaseUrl}/auth/v1/shared/google?redirect_uri=${encodeURIComponent(redirectUri)}`,
450
- {
451
- method: 'GET',
452
- headers: {
453
- 'Content-Type': 'application/json',
454
- },
455
- }
456
- );
457
- if (!authUrl.ok) {
458
- logger.error('Failed to fetch Google auth URL:', {
459
- status: authUrl.status,
460
- statusText: authUrl.statusText,
461
- });
462
- throw new Error(`Failed to fetch Google auth URL: ${authUrl.statusText}`);
463
- }
464
- const responseData = (await authUrl.json()) as { auth_url?: string; url?: string };
465
- return responseData.auth_url || responseData.url || '';
466
- }
467
-
468
- logger.debug('Google OAuth Config (fresh from DB):', {
469
- clientId: config.clientId ? 'SET' : 'NOT SET',
470
- });
471
-
472
- const authUrl = new URL('https://accounts.google.com/o/oauth2/v2/auth');
473
- authUrl.searchParams.set('client_id', config.clientId ?? '');
474
- authUrl.searchParams.set('redirect_uri', `${selfBaseUrl}/api/auth/oauth/google/callback`);
475
- authUrl.searchParams.set('response_type', 'code');
476
- authUrl.searchParams.set(
477
- 'scope',
478
- config.scopes ? config.scopes.join(' ') : 'openid email profile'
479
- );
480
- authUrl.searchParams.set('access_type', 'offline');
481
- if (state) {
482
- authUrl.searchParams.set('state', state);
483
- }
484
-
485
- return authUrl.toString();
486
- }
487
-
488
- /**
489
- * Generate GitHub OAuth authorization URL - ALWAYS reads fresh from DB
490
- */
491
- async generateGitHubAuthUrl(state?: string): Promise<string> {
492
- const oauthConfigService = OAuthConfigService.getInstance();
493
- const config = await oauthConfigService.getConfigByProvider('github');
494
-
495
- if (!config) {
496
- throw new Error('GitHub OAuth not configured');
497
- }
498
-
499
- const selfBaseUrl = process.env.API_BASE_URL || 'http://localhost:7130';
500
-
501
- if (config?.useSharedKey) {
502
- if (!state) {
503
- logger.warn('Shared GitHub OAuth called without state parameter');
504
- throw new Error('State parameter is required for shared GitHub OAuth');
505
- }
506
- // Use shared keys if configured
507
- const cloudBaseUrl = process.env.CLOUD_API_HOST || 'https://api.insforge.dev';
508
- const redirectUri = `${selfBaseUrl}/api/auth/oauth/shared/callback/${state}`;
509
- const authUrl = await fetch(
510
- `${cloudBaseUrl}/auth/v1/shared/github?redirect_uri=${encodeURIComponent(redirectUri)}`,
511
- {
512
- method: 'GET',
513
- headers: {
514
- 'Content-Type': 'application/json',
515
- },
516
- }
517
- );
518
- if (!authUrl.ok) {
519
- logger.error('Failed to fetch GitHub auth URL:', {
520
- status: authUrl.status,
521
- statusText: authUrl.statusText,
522
- });
523
- throw new Error(`Failed to fetch GitHub auth URL: ${authUrl.statusText}`);
524
- }
525
- const responseData = (await authUrl.json()) as { auth_url?: string; url?: string };
526
- return responseData.auth_url || responseData.url || '';
527
- }
528
-
529
- logger.debug('GitHub OAuth Config (fresh from DB):', {
530
- clientId: config.clientId ? 'SET' : 'NOT SET',
531
- });
532
-
533
- const authUrl = new URL('https://github.com/login/oauth/authorize');
534
- authUrl.searchParams.set('client_id', config.clientId ?? '');
535
- authUrl.searchParams.set('redirect_uri', `${selfBaseUrl}/api/auth/oauth/github/callback`);
536
- authUrl.searchParams.set('scope', config.scopes ? config.scopes.join(' ') : 'user:email');
537
- if (state) {
538
- authUrl.searchParams.set('state', state);
539
- }
540
-
541
- return authUrl.toString();
542
- }
543
-
544
- /**
545
- * Exchange Google code for tokens
546
- */
547
- async exchangeCodeToTokenByGoogle(
548
- code: string
549
- ): Promise<{ access_token: string; id_token: string }> {
550
- // Check cache first
551
- if (this.processedCodes.has(code)) {
552
- const cachedTokens = this.tokenCache.get(code);
553
- if (cachedTokens) {
554
- logger.debug('Returning cached tokens for already processed code.');
555
- return cachedTokens;
556
- }
557
- throw new Error('Authorization code is currently being processed.');
558
- }
559
-
560
- const oauthConfigService = OAuthConfigService.getInstance();
561
- const config = await oauthConfigService.getConfigByProvider('google');
562
-
563
- if (!config) {
564
- throw new Error('Google OAuth not configured');
565
- }
566
-
567
- try {
568
- this.processedCodes.add(code);
569
-
570
- logger.info('Exchanging Google code for tokens', {
571
- hasCode: !!code,
572
- clientId: config.clientId?.substring(0, 10) + '...',
573
- });
574
-
575
- const clientSecret = await oauthConfigService.getClientSecretByProvider('google');
576
- const selfBaseUrl = process.env.API_BASE_URL || 'http://localhost:7130';
577
- const response = await axios.post('https://oauth2.googleapis.com/token', {
578
- code,
579
- client_id: config.clientId,
580
- client_secret: clientSecret,
581
- redirect_uri: `${selfBaseUrl}/api/auth/oauth/google/callback`,
582
- grant_type: 'authorization_code',
583
- });
584
-
585
- if (!response.data.access_token || !response.data.id_token) {
586
- throw new Error('Failed to get tokens from Google');
587
- }
588
-
589
- const result = {
590
- access_token: response.data.access_token,
591
- id_token: response.data.id_token,
592
- };
593
-
594
- // Cache the successful token exchange
595
- this.tokenCache.set(code, result);
596
-
597
- // Set a timeout to clear the code and cache to prevent memory leaks
598
- setTimeout(() => {
599
- this.processedCodes.delete(code);
600
- this.tokenCache.delete(code);
601
- }, 60000); // 1 minute timeout
602
-
603
- return result;
604
- } catch (error) {
605
- // If the request fails, remove the code immediately to allow for a retry
606
- this.processedCodes.delete(code);
607
-
608
- if (axios.isAxiosError(error) && error.response) {
609
- logger.error('Google token exchange failed', {
610
- status: error.response.status,
611
- error: error.response.data,
612
- });
613
- throw new Error(`Google OAuth error: ${JSON.stringify(error.response.data)}`);
614
- }
615
- throw error;
616
- }
617
- }
618
-
619
- /**
620
- * Verify Google ID token and get user info
621
- */
622
- async verifyGoogleToken(idToken: string) {
623
- const oauthConfigService = OAuthConfigService.getInstance();
624
- const config = await oauthConfigService.getConfigByProvider('google');
625
-
626
- if (!config) {
627
- throw new Error('Google OAuth not configured');
628
- }
629
-
630
- const clientSecret = await oauthConfigService.getClientSecretByProvider('google');
631
-
632
- if (!clientSecret) {
633
- throw new Error('Google Client Secret not conifgured.');
634
- }
635
-
636
- // Create OAuth2Client with fresh config
637
- const googleClient = new OAuth2Client(config.clientId, clientSecret, config.redirectUri);
638
-
639
- try {
640
- // Properly verify the ID token with Google's servers
641
- const ticket = await googleClient.verifyIdToken({
642
- idToken,
643
- audience: config.clientId,
644
- });
645
-
646
- const payload = ticket.getPayload();
647
- if (!payload) {
648
- throw new Error('Invalid Google token payload');
649
- }
650
-
651
- return {
652
- sub: payload.sub,
653
- email: payload.email || '',
654
- email_verified: payload.email_verified || false,
655
- name: payload.name || '',
656
- picture: payload.picture || '',
657
- given_name: payload.given_name || '',
658
- family_name: payload.family_name || '',
659
- locale: payload.locale || '',
660
- };
661
- } catch (error) {
662
- logger.error('Google token verification failed:', error);
663
- throw new Error(`Google token verification failed: ${error}`);
664
- }
665
- }
666
-
667
- /**
668
- * Find or create Google user
669
- */
670
- async findOrCreateGoogleUser(googleUserInfo: GoogleUserInfo): Promise<CreateSessionResponse> {
671
- const userName = googleUserInfo.name || googleUserInfo.email.split('@')[0];
672
- return this.findOrCreateThirdPartyUser(
673
- 'google',
674
- googleUserInfo.sub,
675
- googleUserInfo.email,
676
- userName,
677
- googleUserInfo.picture || '',
678
- googleUserInfo
679
- );
680
- }
681
-
682
- /**
683
- * Exchange GitHub code for access token
684
- */
685
- async exchangeGitHubCodeForToken(code: string): Promise<string> {
686
- const oauthConfigService = OAuthConfigService.getInstance();
687
- const config = await oauthConfigService.getConfigByProvider('github');
688
-
689
- if (!config) {
690
- throw new Error('GitHub OAuth not configured');
691
- }
692
-
693
- const clientSecret = await oauthConfigService.getClientSecretByProvider('github');
694
- const selfBaseUrl = process.env.API_BASE_URL || 'http://localhost:7130';
695
- const response = await axios.post(
696
- 'https://github.com/login/oauth/access_token',
697
- {
698
- client_id: config.clientId,
699
- client_secret: clientSecret,
700
- code,
701
- redirect_uri: `${selfBaseUrl}/api/auth/oauth/github/callback`,
702
- },
703
- {
704
- headers: {
705
- Accept: 'application/json',
706
- },
707
- }
708
- );
709
-
710
- if (!response.data.access_token) {
711
- throw new Error('Failed to get access token from GitHub');
712
- }
713
-
714
- return response.data.access_token;
715
- }
716
-
717
- /**
718
- * Get GitHub user info
719
- */
720
- async getGitHubUserInfo(accessToken: string) {
721
- const userResponse = await axios.get('https://api.github.com/user', {
722
- headers: {
723
- Authorization: `Bearer ${accessToken}`,
724
- },
725
- });
726
-
727
- // GitHub doesn't always return email in user endpoint
728
- let email = userResponse.data.email;
729
-
730
- if (!email) {
731
- const emailResponse = await axios.get('https://api.github.com/user/emails', {
732
- headers: {
733
- Authorization: `Bearer ${accessToken}`,
734
- },
735
- });
736
-
737
- const primaryEmail = emailResponse.data.find((e: GitHubEmailInfo) => e.primary);
738
- email = primaryEmail ? primaryEmail.email : emailResponse.data[0]?.email;
739
- }
740
-
741
- return {
742
- id: userResponse.data.id,
743
- login: userResponse.data.login,
744
- name: userResponse.data.name,
745
- email: email || `${userResponse.data.login}@users.noreply.github.com`,
746
- avatar_url: userResponse.data.avatar_url,
747
- };
748
- }
749
-
750
- /**
751
- * Find or create GitHub user
752
- */
753
- async findOrCreateGitHubUser(githubUserInfo: GitHubUserInfo): Promise<CreateSessionResponse> {
754
- const userName = githubUserInfo.name || githubUserInfo.login;
755
- const email = githubUserInfo.email || `${githubUserInfo.login}@users.noreply.github.com`;
756
-
757
- return this.findOrCreateThirdPartyUser(
758
- 'github',
759
- githubUserInfo.id.toString(),
760
- email,
761
- userName,
762
- githubUserInfo.avatar_url || '',
763
- githubUserInfo
764
- );
765
- }
766
-
767
- async getMetadata(): Promise<AuthMetadataSchema> {
768
- const oAuthConfigService = OAuthConfigService.getInstance();
769
- const oAuthConfigs = await oAuthConfigService.getAllConfigs();
770
- return {
771
- oauths: oAuthConfigs,
772
- };
773
- }
774
-
775
- /**
776
- * Get database instance for direct queries
777
- */
778
- getDb() {
779
- return this.db;
780
- }
781
- }