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
@@ -1,780 +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 email = payload['email'] || payload['sub'] || 'admin@insforge.local';
243
-
244
- // Generate internal access token
245
- const accessToken = this.generateToken({
246
- sub: ADMIN_ID,
247
- email: email as string,
248
- role: 'project_admin',
249
- });
250
-
251
- return {
252
- user: {
253
- id: ADMIN_ID,
254
- email: email as string,
255
- name: 'Administrator',
256
- emailVerified: true,
257
- createdAt: new Date().toISOString(),
258
- updatedAt: new Date().toISOString(),
259
- },
260
- accessToken,
261
- };
262
- } catch (error) {
263
- logger.error('Admin token verification failed:', error);
264
- throw new Error('Invalid admin credentials');
265
- }
266
- }
267
-
268
- /**
269
- * Find or create third-party user (main OAuth user handler)
270
- * Adapted from 3-table to 2-table structure
271
- */
272
- async findOrCreateThirdPartyUser(
273
- provider: string,
274
- providerId: string,
275
- email: string,
276
- userName: string,
277
- avatarUrl: string,
278
- identityData: GoogleUserInfo | GitHubUserInfo | Record<string, unknown>
279
- ): Promise<CreateSessionResponse> {
280
- // First, try to find existing user by provider ID in _account_providers table
281
- const account = await this.db
282
- .prepare('SELECT * FROM _account_providers WHERE provider = ? AND provider_account_id = ?')
283
- .get(provider, providerId);
284
-
285
- if (account) {
286
- // Found existing OAuth user, update last login time
287
- await this.db
288
- .prepare(
289
- 'UPDATE _account_providers SET updated_at = CURRENT_TIMESTAMP WHERE provider = ? AND provider_account_id = ?'
290
- )
291
- .run(provider, providerId);
292
-
293
- const dbUser = await this.db
294
- .prepare(
295
- 'SELECT id, email, name, email_verified, created_at, updated_at FROM _accounts WHERE id = ?'
296
- )
297
- .get(account.user_id);
298
-
299
- const user = this.dbUserToApiUser(dbUser);
300
- const accessToken = this.generateToken({
301
- sub: user.id,
302
- email: user.email,
303
- role: 'authenticated',
304
- });
305
-
306
- return { user, accessToken };
307
- }
308
-
309
- // If not found by provider_id, try to find by email in _user table
310
- const existingUser = await this.db
311
- .prepare('SELECT * FROM _accounts WHERE email = ?')
312
- .get(email);
313
-
314
- if (existingUser) {
315
- // Found existing user by email, create _account_providers record to link OAuth
316
- await this.db
317
- .prepare(
318
- `
319
- INSERT INTO _account_providers (
320
- user_id, provider, provider_account_id,
321
- provider_data, created_at, updated_at
322
- )
323
- VALUES (?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
324
- `
325
- )
326
- .run(existingUser.id, provider, providerId, JSON.stringify(identityData));
327
-
328
- const user = this.dbUserToApiUser(existingUser);
329
- const accessToken = this.generateToken({
330
- sub: existingUser.id,
331
- email: existingUser.email,
332
- role: 'authenticated',
333
- });
334
-
335
- return { user, accessToken };
336
- }
337
-
338
- // Create new user with OAuth data
339
- return this.createThirdPartyUser(
340
- provider,
341
- userName,
342
- email,
343
- providerId,
344
- identityData,
345
- avatarUrl
346
- );
347
- }
348
-
349
- /**
350
- * Create new third-party user
351
- */
352
- private async createThirdPartyUser(
353
- provider: string,
354
- userName: string,
355
- email: string,
356
- providerId: string,
357
- identityData: GoogleUserInfo | GitHubUserInfo | Record<string, unknown>,
358
- avatarUrl: string
359
- ): Promise<CreateSessionResponse> {
360
- const userId = crypto.randomUUID();
361
-
362
- await this.db.exec('BEGIN');
363
-
364
- try {
365
- // Create user record (without password for OAuth users)
366
- await this.db
367
- .prepare(
368
- `
369
- INSERT INTO _accounts (id, email, name, email_verified, created_at, updated_at)
370
- VALUES (?, ?, ?, true, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
371
- `
372
- )
373
- .run(userId, email, userName);
374
-
375
- await this.db
376
- .prepare(
377
- `
378
- INSERT INTO users (id, nickname, avatar_url, created_at, updated_at)
379
- VALUES (?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
380
- `
381
- )
382
- .run(userId, userName, avatarUrl);
383
-
384
- // Create _account_providers record
385
- await this.db
386
- .prepare(
387
- `
388
- INSERT INTO _account_providers (
389
- user_id, provider, provider_account_id,
390
- provider_data, created_at, updated_at
391
- )
392
- VALUES (?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
393
- `
394
- )
395
- .run(
396
- userId,
397
- provider,
398
- providerId,
399
- JSON.stringify({ ...identityData, avatar_url: avatarUrl })
400
- );
401
-
402
- await this.db.exec('COMMIT');
403
-
404
- const user: UserSchema = {
405
- id: userId,
406
- email,
407
- name: userName,
408
- emailVerified: true,
409
- createdAt: new Date().toISOString(),
410
- updatedAt: new Date().toISOString(),
411
- };
412
-
413
- const accessToken = this.generateToken({
414
- sub: userId,
415
- email,
416
- role: 'authenticated',
417
- });
418
-
419
- return { user, accessToken };
420
- } catch (error) {
421
- await this.db.exec('ROLLBACK');
422
- throw error;
423
- }
424
- }
425
-
426
- /**
427
- * Generate Google OAuth authorization URL
428
- */
429
- async generateGoogleAuthUrl(state?: string): Promise<string | undefined> {
430
- const oauthConfigService = OAuthConfigService.getInstance();
431
- const config = await oauthConfigService.getConfigByProvider('google');
432
-
433
- if (!config) {
434
- throw new Error('Google OAuth not configured');
435
- }
436
-
437
- const selfBaseUrl = process.env.API_BASE_URL || 'http://localhost:7130';
438
-
439
- if (config?.useSharedKey) {
440
- if (!state) {
441
- logger.warn('Shared Google OAuth called without state parameter');
442
- throw new Error('State parameter is required for shared Google OAuth');
443
- }
444
- // Use shared keys if configured
445
- const cloudBaseUrl = process.env.CLOUD_API_HOST || 'https://api.insforge.dev';
446
- const redirectUri = `${selfBaseUrl}/api/auth/oauth/shared/callback/${state}`;
447
- const authUrl = await fetch(
448
- `${cloudBaseUrl}/auth/v1/shared/google?redirect_uri=${encodeURIComponent(redirectUri)}`,
449
- {
450
- method: 'GET',
451
- headers: {
452
- 'Content-Type': 'application/json',
453
- },
454
- }
455
- );
456
- if (!authUrl.ok) {
457
- logger.error('Failed to fetch Google auth URL:', {
458
- status: authUrl.status,
459
- statusText: authUrl.statusText,
460
- });
461
- throw new Error(`Failed to fetch Google auth URL: ${authUrl.statusText}`);
462
- }
463
- const responseData = (await authUrl.json()) as { auth_url?: string; url?: string };
464
- return responseData.auth_url || responseData.url || '';
465
- }
466
-
467
- logger.debug('Google OAuth Config (fresh from DB):', {
468
- clientId: config.clientId ? 'SET' : 'NOT SET',
469
- });
470
-
471
- const authUrl = new URL('https://accounts.google.com/o/oauth2/v2/auth');
472
- authUrl.searchParams.set('client_id', config.clientId ?? '');
473
- authUrl.searchParams.set('redirect_uri', `${selfBaseUrl}/api/auth/oauth/google/callback`);
474
- authUrl.searchParams.set('response_type', 'code');
475
- authUrl.searchParams.set(
476
- 'scope',
477
- config.scopes ? config.scopes.join(' ') : 'openid email profile'
478
- );
479
- authUrl.searchParams.set('access_type', 'offline');
480
- if (state) {
481
- authUrl.searchParams.set('state', state);
482
- }
483
-
484
- return authUrl.toString();
485
- }
486
-
487
- /**
488
- * Generate GitHub OAuth authorization URL - ALWAYS reads fresh from DB
489
- */
490
- async generateGitHubAuthUrl(state?: string): Promise<string> {
491
- const oauthConfigService = OAuthConfigService.getInstance();
492
- const config = await oauthConfigService.getConfigByProvider('github');
493
-
494
- if (!config) {
495
- throw new Error('GitHub OAuth not configured');
496
- }
497
-
498
- const selfBaseUrl = process.env.API_BASE_URL || 'http://localhost:7130';
499
-
500
- if (config?.useSharedKey) {
501
- if (!state) {
502
- logger.warn('Shared GitHub OAuth called without state parameter');
503
- throw new Error('State parameter is required for shared GitHub OAuth');
504
- }
505
- // Use shared keys if configured
506
- const cloudBaseUrl = process.env.CLOUD_API_HOST || 'https://api.insforge.dev';
507
- const redirectUri = `${selfBaseUrl}/api/auth/oauth/shared/callback/${state}`;
508
- const authUrl = await fetch(
509
- `${cloudBaseUrl}/auth/v1/shared/github?redirect_uri=${encodeURIComponent(redirectUri)}`,
510
- {
511
- method: 'GET',
512
- headers: {
513
- 'Content-Type': 'application/json',
514
- },
515
- }
516
- );
517
- if (!authUrl.ok) {
518
- logger.error('Failed to fetch GitHub auth URL:', {
519
- status: authUrl.status,
520
- statusText: authUrl.statusText,
521
- });
522
- throw new Error(`Failed to fetch GitHub auth URL: ${authUrl.statusText}`);
523
- }
524
- const responseData = (await authUrl.json()) as { auth_url?: string; url?: string };
525
- return responseData.auth_url || responseData.url || '';
526
- }
527
-
528
- logger.debug('GitHub OAuth Config (fresh from DB):', {
529
- clientId: config.clientId ? 'SET' : 'NOT SET',
530
- });
531
-
532
- const authUrl = new URL('https://github.com/login/oauth/authorize');
533
- authUrl.searchParams.set('client_id', config.clientId ?? '');
534
- authUrl.searchParams.set('redirect_uri', `${selfBaseUrl}/api/auth/oauth/github/callback`);
535
- authUrl.searchParams.set('scope', config.scopes ? config.scopes.join(' ') : 'user:email');
536
- if (state) {
537
- authUrl.searchParams.set('state', state);
538
- }
539
-
540
- return authUrl.toString();
541
- }
542
-
543
- /**
544
- * Exchange Google code for tokens
545
- */
546
- async exchangeCodeToTokenByGoogle(
547
- code: string
548
- ): Promise<{ access_token: string; id_token: string }> {
549
- // Check cache first
550
- if (this.processedCodes.has(code)) {
551
- const cachedTokens = this.tokenCache.get(code);
552
- if (cachedTokens) {
553
- logger.debug('Returning cached tokens for already processed code.');
554
- return cachedTokens;
555
- }
556
- throw new Error('Authorization code is currently being processed.');
557
- }
558
-
559
- const oauthConfigService = OAuthConfigService.getInstance();
560
- const config = await oauthConfigService.getConfigByProvider('google');
561
-
562
- if (!config) {
563
- throw new Error('Google OAuth not configured');
564
- }
565
-
566
- try {
567
- this.processedCodes.add(code);
568
-
569
- logger.info('Exchanging Google code for tokens', {
570
- hasCode: !!code,
571
- clientId: config.clientId?.substring(0, 10) + '...',
572
- });
573
-
574
- const clientSecret = await oauthConfigService.getClientSecretByProvider('google');
575
- const selfBaseUrl = process.env.API_BASE_URL || 'http://localhost:7130';
576
- const response = await axios.post('https://oauth2.googleapis.com/token', {
577
- code,
578
- client_id: config.clientId,
579
- client_secret: clientSecret,
580
- redirect_uri: `${selfBaseUrl}/api/auth/oauth/google/callback`,
581
- grant_type: 'authorization_code',
582
- });
583
-
584
- if (!response.data.access_token || !response.data.id_token) {
585
- throw new Error('Failed to get tokens from Google');
586
- }
587
-
588
- const result = {
589
- access_token: response.data.access_token,
590
- id_token: response.data.id_token,
591
- };
592
-
593
- // Cache the successful token exchange
594
- this.tokenCache.set(code, result);
595
-
596
- // Set a timeout to clear the code and cache to prevent memory leaks
597
- setTimeout(() => {
598
- this.processedCodes.delete(code);
599
- this.tokenCache.delete(code);
600
- }, 60000); // 1 minute timeout
601
-
602
- return result;
603
- } catch (error) {
604
- // If the request fails, remove the code immediately to allow for a retry
605
- this.processedCodes.delete(code);
606
-
607
- if (axios.isAxiosError(error) && error.response) {
608
- logger.error('Google token exchange failed', {
609
- status: error.response.status,
610
- error: error.response.data,
611
- });
612
- throw new Error(`Google OAuth error: ${JSON.stringify(error.response.data)}`);
613
- }
614
- throw error;
615
- }
616
- }
617
-
618
- /**
619
- * Verify Google ID token and get user info
620
- */
621
- async verifyGoogleToken(idToken: string) {
622
- const oauthConfigService = OAuthConfigService.getInstance();
623
- const config = await oauthConfigService.getConfigByProvider('google');
624
-
625
- if (!config) {
626
- throw new Error('Google OAuth not configured');
627
- }
628
-
629
- const clientSecret = await oauthConfigService.getClientSecretByProvider('google');
630
-
631
- if (!clientSecret) {
632
- throw new Error('Google Client Secret not conifgured.');
633
- }
634
-
635
- // Create OAuth2Client with fresh config
636
- const googleClient = new OAuth2Client(config.clientId, clientSecret, config.redirectUri);
637
-
638
- try {
639
- // Properly verify the ID token with Google's servers
640
- const ticket = await googleClient.verifyIdToken({
641
- idToken,
642
- audience: config.clientId,
643
- });
644
-
645
- const payload = ticket.getPayload();
646
- if (!payload) {
647
- throw new Error('Invalid Google token payload');
648
- }
649
-
650
- return {
651
- sub: payload.sub,
652
- email: payload.email || '',
653
- email_verified: payload.email_verified || false,
654
- name: payload.name || '',
655
- picture: payload.picture || '',
656
- given_name: payload.given_name || '',
657
- family_name: payload.family_name || '',
658
- locale: payload.locale || '',
659
- };
660
- } catch (error) {
661
- logger.error('Google token verification failed:', error);
662
- throw new Error(`Google token verification failed: ${error}`);
663
- }
664
- }
665
-
666
- /**
667
- * Find or create Google user
668
- */
669
- async findOrCreateGoogleUser(googleUserInfo: GoogleUserInfo): Promise<CreateSessionResponse> {
670
- const userName = googleUserInfo.name || googleUserInfo.email.split('@')[0];
671
- return this.findOrCreateThirdPartyUser(
672
- 'google',
673
- googleUserInfo.sub,
674
- googleUserInfo.email,
675
- userName,
676
- googleUserInfo.picture || '',
677
- googleUserInfo
678
- );
679
- }
680
-
681
- /**
682
- * Exchange GitHub code for access token
683
- */
684
- async exchangeGitHubCodeForToken(code: string): Promise<string> {
685
- const oauthConfigService = OAuthConfigService.getInstance();
686
- const config = await oauthConfigService.getConfigByProvider('github');
687
-
688
- if (!config) {
689
- throw new Error('GitHub OAuth not configured');
690
- }
691
-
692
- const clientSecret = await oauthConfigService.getClientSecretByProvider('github');
693
- const selfBaseUrl = process.env.API_BASE_URL || 'http://localhost:7130';
694
- const response = await axios.post(
695
- 'https://github.com/login/oauth/access_token',
696
- {
697
- client_id: config.clientId,
698
- client_secret: clientSecret,
699
- code,
700
- redirect_uri: `${selfBaseUrl}/api/auth/oauth/github/callback`,
701
- },
702
- {
703
- headers: {
704
- Accept: 'application/json',
705
- },
706
- }
707
- );
708
-
709
- if (!response.data.access_token) {
710
- throw new Error('Failed to get access token from GitHub');
711
- }
712
-
713
- return response.data.access_token;
714
- }
715
-
716
- /**
717
- * Get GitHub user info
718
- */
719
- async getGitHubUserInfo(accessToken: string) {
720
- const userResponse = await axios.get('https://api.github.com/user', {
721
- headers: {
722
- Authorization: `Bearer ${accessToken}`,
723
- },
724
- });
725
-
726
- // GitHub doesn't always return email in user endpoint
727
- let email = userResponse.data.email;
728
-
729
- if (!email) {
730
- const emailResponse = await axios.get('https://api.github.com/user/emails', {
731
- headers: {
732
- Authorization: `Bearer ${accessToken}`,
733
- },
734
- });
735
-
736
- const primaryEmail = emailResponse.data.find((e: GitHubEmailInfo) => e.primary);
737
- email = primaryEmail ? primaryEmail.email : emailResponse.data[0]?.email;
738
- }
739
-
740
- return {
741
- id: userResponse.data.id,
742
- login: userResponse.data.login,
743
- name: userResponse.data.name,
744
- email: email || `${userResponse.data.login}@users.noreply.github.com`,
745
- avatar_url: userResponse.data.avatar_url,
746
- };
747
- }
748
-
749
- /**
750
- * Find or create GitHub user
751
- */
752
- async findOrCreateGitHubUser(githubUserInfo: GitHubUserInfo): Promise<CreateSessionResponse> {
753
- const userName = githubUserInfo.name || githubUserInfo.login;
754
- const email = githubUserInfo.email || `${githubUserInfo.login}@users.noreply.github.com`;
755
-
756
- return this.findOrCreateThirdPartyUser(
757
- 'github',
758
- githubUserInfo.id.toString(),
759
- email,
760
- userName,
761
- githubUserInfo.avatar_url || '',
762
- githubUserInfo
763
- );
764
- }
765
-
766
- async getMetadata(): Promise<AuthMetadataSchema> {
767
- const oAuthConfigService = OAuthConfigService.getInstance();
768
- const oAuthConfigs = await oAuthConfigService.getAllConfigs();
769
- return {
770
- oauths: oAuthConfigs,
771
- };
772
- }
773
-
774
- /**
775
- * Get database instance for direct queries
776
- */
777
- getDb() {
778
- return this.db;
779
- }
780
- }