insforge 0.3.3 → 1.3.0

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 (635) hide show
  1. package/.claude-plugin/marketplace.json +20 -0
  2. package/.dockerignore +60 -57
  3. package/.env.example +84 -49
  4. package/.github/ISSUE_TEMPLATE/bug_report.yml +36 -83
  5. package/.github/ISSUE_TEMPLATE/config.yml +11 -11
  6. package/.github/ISSUE_TEMPLATE/feature_request.yml +26 -79
  7. package/.github/PULL_REQUEST_TEMPLATE.md +7 -0
  8. package/.github/copilot-instructions.md +146 -146
  9. package/.github/workflows/build-image.yml +66 -65
  10. package/.github/workflows/ci-premerge-check.yml +23 -23
  11. package/.github/workflows/e2e.yml +63 -0
  12. package/.github/workflows/lint-and-format.yml +32 -32
  13. package/.prettierignore +64 -64
  14. package/CHANGELOG.md +44 -3
  15. package/CLAUDE_PLUGIN.md +104 -0
  16. package/CODE_OF_CONDUCT.md +128 -0
  17. package/CONTRIBUTING.md +125 -125
  18. package/Dockerfile +30 -27
  19. package/GITHUB_OAUTH_SETUP.md +49 -49
  20. package/GOOGLE_OAUTH_SETUP.md +148 -148
  21. package/LICENSE +201 -201
  22. package/README.md +182 -134
  23. package/assets/Dark.svg +23 -23
  24. package/assets/mcpInstallv2.png +0 -0
  25. package/assets/sampleResponse.png +0 -0
  26. package/auth/index.html +13 -0
  27. package/auth/package.json +28 -0
  28. package/auth/public/favicon.ico +0 -0
  29. package/auth/src/App.tsx +33 -0
  30. package/auth/src/components/ErrorCard.tsx +37 -0
  31. package/auth/src/components/Layout.tsx +13 -0
  32. package/auth/src/index.css +19 -0
  33. package/auth/src/lib/broadcastService.ts +117 -0
  34. package/auth/src/lib/utils.ts +11 -0
  35. package/auth/src/main.tsx +22 -0
  36. package/auth/src/pages/ForgotPasswordPage.tsx +11 -0
  37. package/auth/src/pages/ResetPasswordPage.tsx +11 -0
  38. package/auth/src/pages/SignInPage.tsx +60 -0
  39. package/auth/src/pages/SignUpPage.tsx +60 -0
  40. package/auth/src/pages/VerifyEmailPage.tsx +20 -0
  41. package/auth/src/vite-env.d.ts +10 -0
  42. package/auth/tsconfig.json +32 -0
  43. package/auth/tsconfig.node.json +11 -0
  44. package/auth/vite.config.ts +25 -0
  45. package/backend/package.json +78 -75
  46. package/backend/src/api/{middleware → middlewares}/auth.ts +8 -9
  47. package/backend/src/api/middlewares/rate-limiters.ts +127 -0
  48. package/backend/src/api/routes/{ai.ts → ai/index.routes.ts} +22 -26
  49. package/backend/src/api/routes/auth/index.routes.ts +667 -0
  50. package/backend/src/api/routes/auth/oauth.routes.ts +473 -0
  51. package/backend/src/api/routes/{database.advance.ts → database/advance.routes.ts} +128 -65
  52. package/backend/src/api/routes/database/index.routes.ts +90 -0
  53. package/backend/src/api/routes/{database.records.ts → database/records.routes.ts} +26 -12
  54. package/backend/src/api/routes/{database.tables.ts → database/tables.routes.ts} +6 -23
  55. package/backend/src/api/routes/docs/index.routes.ts +75 -0
  56. package/backend/src/api/routes/email/index.routes.ts +35 -0
  57. package/backend/src/api/routes/functions/index.routes.ts +194 -0
  58. package/backend/src/api/routes/{logs.ts → logs/index.routes.ts} +25 -30
  59. package/backend/src/api/routes/{metadata.ts → metadata/index.routes.ts} +33 -31
  60. package/backend/src/api/routes/realtime/channels.routes.ts +81 -0
  61. package/backend/src/api/routes/realtime/index.routes.ts +12 -0
  62. package/backend/src/api/routes/realtime/messages.routes.ts +48 -0
  63. package/backend/src/api/routes/realtime/permissions.routes.ts +19 -0
  64. package/backend/src/api/routes/{secrets.ts → secrets/index.routes.ts} +27 -22
  65. package/backend/src/api/routes/{storage.ts → storage/index.routes.ts} +48 -61
  66. package/backend/src/api/routes/usage/index.routes.ts +91 -0
  67. package/backend/src/infra/config/app.config.ts +51 -0
  68. package/backend/src/infra/database/database.manager.ts +182 -0
  69. package/backend/{migrations → src/infra/database/migrations}/000_create-base-tables.sql +141 -141
  70. package/backend/{migrations → src/infra/database/migrations}/001_create-helper-functions.sql +40 -40
  71. package/backend/{migrations → src/infra/database/migrations}/002_rename-auth-tables.sql +29 -29
  72. package/backend/{migrations → src/infra/database/migrations}/003_create-users-table.sql +55 -55
  73. package/backend/{migrations → src/infra/database/migrations}/004_add-reload-postgrest-func.sql +23 -23
  74. package/backend/{migrations → src/infra/database/migrations}/005_enable-project-admin-modify-users.sql +29 -29
  75. package/backend/{migrations → src/infra/database/migrations}/006_modify-ai-usage-table.sql +24 -24
  76. package/backend/{migrations → src/infra/database/migrations}/007_drop-metadata-table.sql +1 -1
  77. package/backend/{migrations → src/infra/database/migrations}/008_add-system-tables.sql +76 -76
  78. package/backend/{migrations → src/infra/database/migrations}/009_add-function-secrets.sql +23 -23
  79. package/backend/{migrations → src/infra/database/migrations}/010_modify-ai-config-modalities.sql +93 -93
  80. package/backend/{migrations → src/infra/database/migrations}/011_refactor-secrets-table.sql +15 -15
  81. package/backend/{migrations → src/infra/database/migrations}/012_add-storage-uploaded-by.sql +7 -7
  82. package/backend/src/infra/database/migrations/013_create-auth-schema-functions.sql +44 -0
  83. package/backend/src/infra/database/migrations/014_add-updated-at-trigger-user-table.sql +8 -0
  84. package/backend/src/infra/database/migrations/015_create-auth-config-and-email-otp-tables.sql +60 -0
  85. package/backend/src/infra/database/migrations/016_update-auth-config-and-email-otp.sql +24 -0
  86. package/backend/src/infra/database/migrations/017_create-realtime-schema.sql +233 -0
  87. package/backend/src/infra/realtime/realtime.manager.ts +246 -0
  88. package/backend/src/infra/realtime/webhook-sender.ts +82 -0
  89. package/backend/src/{core/secrets/encryption.ts → infra/security/encryption.manager.ts} +3 -2
  90. package/backend/src/infra/security/token.manager.ts +219 -0
  91. package/backend/src/infra/socket/socket.manager.ts +522 -0
  92. package/backend/src/providers/ai/openrouter.provider.ts +380 -0
  93. package/backend/src/providers/email/base.provider.ts +38 -0
  94. package/backend/src/providers/email/cloud.provider.ts +271 -0
  95. package/backend/src/{core/logs/providers → providers/logs}/base.provider.ts +11 -11
  96. package/backend/src/{core/logs/providers → providers/logs}/cloudwatch.provider.ts +61 -38
  97. package/backend/src/providers/logs/local.provider.ts +185 -0
  98. package/backend/src/providers/oauth/apple.provider.ts +266 -0
  99. package/backend/src/providers/oauth/base.provider.ts +29 -0
  100. package/backend/src/providers/oauth/discord.provider.ts +195 -0
  101. package/backend/src/providers/oauth/facebook.provider.ts +194 -0
  102. package/backend/src/providers/oauth/github.provider.ts +208 -0
  103. package/backend/src/providers/oauth/google.provider.ts +249 -0
  104. package/backend/src/providers/oauth/index.ts +8 -0
  105. package/backend/src/providers/oauth/linkedin.provider.ts +240 -0
  106. package/backend/src/providers/oauth/microsoft.provider.ts +169 -0
  107. package/backend/src/providers/oauth/x.provider.ts +202 -0
  108. package/backend/src/providers/storage/base.provider.ts +29 -0
  109. package/backend/src/providers/storage/local.provider.ts +103 -0
  110. package/backend/src/providers/storage/s3.provider.ts +313 -0
  111. package/backend/src/server.ts +317 -288
  112. package/backend/src/{core/ai/config.ts → services/ai/ai-config.service.ts} +19 -24
  113. package/backend/src/services/ai/ai-model.service.ts +60 -0
  114. package/backend/src/{core/ai/usage.ts → services/ai/ai-usage.service.ts} +28 -35
  115. package/backend/src/{core/ai/chat.ts → services/ai/chat-completion.service.ts} +37 -24
  116. package/backend/src/services/ai/helpers.ts +64 -0
  117. package/backend/src/{core/ai/image.ts → services/ai/image-generation.service.ts} +17 -19
  118. package/backend/src/services/ai/index.ts +13 -0
  119. package/backend/src/services/auth/auth-config.service.ts +250 -0
  120. package/backend/src/services/auth/auth-otp.service.ts +424 -0
  121. package/backend/src/services/auth/auth.service.ts +1150 -0
  122. package/backend/src/services/auth/index.ts +4 -0
  123. package/backend/src/{core/auth/oauth.ts → services/auth/oauth-config.service.ts} +106 -52
  124. package/backend/src/{core/database/advance.ts → services/database/database-advance.service.ts} +97 -131
  125. package/backend/src/services/database/database-table.service.ts +802 -0
  126. package/backend/src/services/database/database.service.ts +127 -0
  127. package/backend/src/services/email/email.service.ts +73 -0
  128. package/backend/src/{core/functions/functions.ts → services/functions/function.service.ts} +95 -88
  129. package/backend/src/{core/logs/audit.ts → services/logs/audit.service.ts} +92 -75
  130. package/backend/src/services/logs/log.service.ts +73 -0
  131. package/backend/src/services/realtime/index.ts +3 -0
  132. package/backend/src/services/realtime/realtime-auth.service.ts +104 -0
  133. package/backend/src/services/realtime/realtime-channel.service.ts +237 -0
  134. package/backend/src/services/realtime/realtime-message.service.ts +260 -0
  135. package/backend/src/{core/secrets/secrets.ts → services/secrets/secret.service.ts} +48 -66
  136. package/backend/src/services/storage/storage.service.ts +617 -0
  137. package/backend/src/services/usage/usage.service.ts +149 -0
  138. package/backend/src/types/auth.ts +77 -2
  139. package/backend/src/types/email.ts +8 -0
  140. package/backend/src/types/error-constants.ts +4 -0
  141. package/backend/src/types/logs.ts +0 -29
  142. package/backend/src/types/realtime.ts +18 -0
  143. package/backend/src/{core/socket/types.ts → types/socket.ts} +11 -36
  144. package/backend/src/utils/cookies.ts +35 -0
  145. package/backend/src/utils/environment.ts +9 -3
  146. package/backend/src/utils/logger.ts +20 -2
  147. package/backend/src/utils/s3-config-loader.ts +64 -0
  148. package/backend/src/utils/seed.ts +301 -205
  149. package/backend/src/utils/sql-parser.ts +91 -1
  150. package/backend/src/utils/utils.ts +114 -0
  151. package/backend/src/utils/validations.ts +40 -4
  152. package/backend/tests/README.md +133 -133
  153. package/backend/tests/cleanup-all-test-data.sh +230 -230
  154. package/backend/tests/cloud/test-s3-multitenant.sh +131 -131
  155. package/backend/tests/local/comprehensive-curl-tests.sh +155 -155
  156. package/backend/tests/local/test-ai-config.sh +129 -0
  157. package/backend/tests/local/test-ai-usage.sh +80 -0
  158. package/backend/tests/local/test-auth-router.sh +143 -143
  159. package/backend/tests/local/test-database-router.sh +222 -222
  160. package/backend/tests/local/test-e2e.sh +240 -240
  161. package/backend/tests/local/test-fk-errors.sh +96 -96
  162. package/backend/tests/local/test-functions.sh +123 -0
  163. package/backend/tests/local/test-id-field.sh +200 -200
  164. package/backend/tests/local/test-logs.sh +132 -0
  165. package/backend/tests/local/test-public-bucket.sh +264 -264
  166. package/backend/tests/local/test-secrets.sh +249 -247
  167. package/backend/tests/local/test-serverless-functions.sh.disabled +325 -325
  168. package/backend/tests/local/test-traditional-rest.sh +208 -208
  169. package/backend/tests/manual/README.md +50 -50
  170. package/backend/tests/manual/create-large-table-simple.sql +10 -10
  171. package/backend/tests/manual/seed-large-table.sql +100 -100
  172. package/backend/tests/manual/setup-large-table-extras.sql +33 -33
  173. package/backend/tests/manual/test-bulk-upsert.sh +409 -409
  174. package/backend/tests/manual/test-database-advance.sh +296 -296
  175. package/backend/tests/manual/test-postgrest-stability.sh +191 -191
  176. package/backend/tests/manual/test-rawsql-export-import.sh +411 -411
  177. package/backend/tests/manual/test-rawsql-modes.sh +244 -0
  178. package/backend/tests/manual/test-universal-storage.sh +263 -263
  179. package/backend/tests/manual/test-users.sql +17 -17
  180. package/backend/tests/run-all-tests.sh +139 -139
  181. package/backend/tests/setup.ts +0 -0
  182. package/backend/tests/test-config.sh +338 -302
  183. package/backend/tests/unit/analyze-query.test.ts +697 -0
  184. package/backend/tests/unit/cloud-token.test.ts +48 -0
  185. package/backend/tests/unit/constant.test.ts +8 -0
  186. package/backend/tests/unit/email.test.ts +372 -0
  187. package/backend/tests/unit/environment.test.ts +59 -0
  188. package/backend/tests/unit/helpers.test.ts +63 -0
  189. package/backend/tests/unit/logger.test.ts +22 -0
  190. package/backend/tests/unit/rate-limit.test.ts +154 -0
  191. package/backend/tests/unit/response.test.ts +58 -0
  192. package/backend/tests/unit/sql-parser.test.ts +74 -0
  193. package/backend/tests/unit/uuid.test.ts +21 -0
  194. package/backend/tests/unit/validations.test.ts +80 -0
  195. package/backend/tsconfig.json +22 -22
  196. package/backend/vitest.config.ts +11 -0
  197. package/claude-plugin/.claude-plugin/plugin.json +24 -0
  198. package/claude-plugin/README.md +133 -0
  199. package/claude-plugin/skills/insforge-schema-patterns/SKILL.md +270 -0
  200. package/docker-compose.prod.yml +204 -144
  201. package/docker-compose.yml +232 -167
  202. package/docker-init/db/db-init.sql +97 -125
  203. package/docker-init/db/jwt.sql +5 -5
  204. package/docker-init/db/postgresql.conf +16 -16
  205. package/docker-init/logs/vector.yml +236 -0
  206. package/docs/README.md +44 -0
  207. package/docs/agent-docs/real-time.md +269 -0
  208. package/docs/changelog.mdx +119 -0
  209. package/docs/core-concepts/ai/architecture.mdx +373 -0
  210. package/docs/core-concepts/ai/sdk.mdx +213 -0
  211. package/docs/core-concepts/authentication/architecture.mdx +278 -0
  212. package/docs/core-concepts/authentication/sdk.mdx +414 -0
  213. package/docs/core-concepts/authentication/ui-components/customization.mdx +529 -0
  214. package/docs/core-concepts/authentication/ui-components/nextjs.mdx +221 -0
  215. package/docs/core-concepts/authentication/ui-components/react-router.mdx +184 -0
  216. package/docs/core-concepts/authentication/ui-components/react.mdx +129 -0
  217. package/docs/core-concepts/database/architecture.mdx +256 -0
  218. package/docs/core-concepts/database/sdk.mdx +382 -0
  219. package/docs/core-concepts/email/architecture.mdx +101 -0
  220. package/docs/core-concepts/email/sdk.mdx +53 -0
  221. package/docs/core-concepts/functions/architecture.mdx +105 -0
  222. package/docs/core-concepts/functions/sdk.mdx +184 -0
  223. package/docs/core-concepts/realtime/architecture.mdx +446 -0
  224. package/docs/core-concepts/realtime/sdk.mdx +409 -0
  225. package/docs/core-concepts/storage/architecture.mdx +243 -0
  226. package/docs/core-concepts/storage/sdk.mdx +253 -0
  227. package/docs/deployment/README.md +94 -0
  228. package/docs/deployment/deploy-to-aws-ec2.md +565 -0
  229. package/docs/deployment/deploy-to-azure-virtual-machines.md +313 -0
  230. package/docs/deployment/deploy-to-google-cloud-compute-engine.md +613 -0
  231. package/docs/deployment/deploy-to-render.md +441 -0
  232. package/docs/deprecated/insforge-auth-api.md +214 -214
  233. package/docs/deprecated/insforge-auth-sdk.md +99 -99
  234. package/docs/deprecated/insforge-db-api.md +358 -358
  235. package/docs/deprecated/insforge-db-sdk.md +139 -139
  236. package/docs/deprecated/insforge-debug-sdk.md +156 -156
  237. package/docs/deprecated/insforge-debug.md +64 -64
  238. package/docs/deprecated/insforge-instructions.md +123 -123
  239. package/docs/deprecated/insforge-project.md +117 -117
  240. package/docs/deprecated/insforge-storage-api.md +278 -278
  241. package/docs/deprecated/insforge-storage-sdk.md +158 -158
  242. package/docs/docs.json +232 -0
  243. package/docs/examples/framework-guides/nextjs.mdx +131 -0
  244. package/docs/examples/framework-guides/nuxt.mdx +165 -0
  245. package/docs/examples/framework-guides/react.mdx +165 -0
  246. package/docs/examples/framework-guides/svelte.mdx +153 -0
  247. package/docs/examples/framework-guides/vue.mdx +159 -0
  248. package/docs/examples/overview.mdx +67 -0
  249. package/docs/favicon.svg +19 -0
  250. package/docs/images/changelog/dec-2025/ai-integration.png +0 -0
  251. package/docs/images/changelog/dec-2025/ai-models.webp +0 -0
  252. package/docs/images/changelog/dec-2025/alipay-payment.webp +0 -0
  253. package/docs/images/changelog/dec-2025/apple-login.jpg +0 -0
  254. package/docs/images/changelog/dec-2025/mcp-installer.png +0 -0
  255. package/docs/images/changelog/dec-2025/realtime-module.jpg +0 -0
  256. package/docs/images/changelog/nov-2025/auth-components.webp +0 -0
  257. package/docs/images/changelog/nov-2025/database-metadata.webp +0 -0
  258. package/docs/images/changelog/nov-2025/quickstart-prompts.webp +0 -0
  259. package/docs/images/changelog/nov-2025/sql-editor.webp +0 -0
  260. package/docs/images/changelog/nov-2025/usage-page.webp +0 -0
  261. package/docs/images/changelog/october-2025/csv-upload.webp +0 -0
  262. package/docs/images/changelog/october-2025/logs-feature.webp +0 -0
  263. package/docs/images/changelog/october-2025/oauth-providers.webp +0 -0
  264. package/docs/images/checks-passed.png +0 -0
  265. package/docs/images/dashboard-connect-expanded.png +0 -0
  266. package/docs/images/dashboard-connect.png +0 -0
  267. package/docs/images/hero-dark.png +0 -0
  268. package/docs/images/hero-light.png +0 -0
  269. package/docs/images/icons/ai.svg +4 -0
  270. package/docs/images/icons/auth.svg +1 -0
  271. package/docs/images/icons/database.svg +1 -0
  272. package/docs/images/icons/function.svg +1 -0
  273. package/docs/images/icons/storage.svg +1 -0
  274. package/docs/images/logos/nextjs.svg +4 -0
  275. package/docs/images/logos/nuxt.svg +4 -0
  276. package/docs/images/logos/react.svg +5 -0
  277. package/docs/images/logos/svelte.svg +4 -0
  278. package/docs/images/logos/vue.svg +5 -0
  279. package/docs/images/mcp-install.png +0 -0
  280. package/docs/images/onboarding-mcp.png +0 -0
  281. package/docs/insforge-instructions-sdk.md +89 -407
  282. package/docs/introduction.mdx +45 -0
  283. package/docs/logo/dark.svg +22 -0
  284. package/docs/logo/light.svg +20 -0
  285. package/docs/partnership.mdx +652 -0
  286. package/docs/quickstart.mdx +83 -0
  287. package/docs/showcase/2048-arena.png +0 -0
  288. package/docs/showcase/framegen-cloud.png +0 -0
  289. package/docs/showcase/line-connect-race.png +0 -0
  290. package/docs/showcase/moment-vibe.png +0 -0
  291. package/docs/showcase/national-flags.png +0 -0
  292. package/docs/showcase/pokemon-vibe.png +0 -0
  293. package/docs/showcase/pure-browse-buy.png +0 -0
  294. package/docs/showcase.mdx +52 -0
  295. package/docs/snippets/sdk-installation.mdx +22 -0
  296. package/docs/snippets/service-icons.mdx +27 -0
  297. package/eslint.config.js +10 -3
  298. package/examples/oauth/frontend-oauth-example.html +250 -250
  299. package/examples/response-examples.md +443 -443
  300. package/frontend/components.json +17 -17
  301. package/frontend/package.json +69 -63
  302. package/frontend/src/App.tsx +13 -82
  303. package/frontend/src/assets/icons/checkbox_checked.svg +6 -6
  304. package/frontend/src/assets/icons/checkbox_undetermined.svg +6 -6
  305. package/frontend/src/assets/icons/checked.svg +3 -3
  306. package/frontend/src/assets/icons/connected.svg +3 -0
  307. package/frontend/src/assets/icons/error.svg +3 -3
  308. package/frontend/src/assets/icons/loader.svg +9 -0
  309. package/frontend/src/assets/icons/pencil.svg +4 -4
  310. package/frontend/src/assets/icons/refresh.svg +4 -4
  311. package/frontend/src/assets/icons/step_active.svg +3 -3
  312. package/frontend/src/assets/icons/step_inactive.svg +11 -11
  313. package/frontend/src/assets/icons/warning.svg +3 -3
  314. package/frontend/src/assets/logos/apple.svg +4 -0
  315. package/frontend/src/assets/logos/claude_code.svg +3 -3
  316. package/frontend/src/assets/logos/cline.svg +6 -6
  317. package/frontend/src/assets/logos/cursor.svg +20 -20
  318. package/frontend/src/assets/logos/discord.svg +8 -8
  319. package/frontend/src/assets/logos/facebook.svg +3 -0
  320. package/frontend/src/assets/logos/gemini.svg +19 -19
  321. package/frontend/src/assets/logos/github.svg +5 -5
  322. package/frontend/src/assets/logos/google.svg +13 -13
  323. package/frontend/src/assets/logos/grok.svg +10 -10
  324. package/frontend/src/assets/logos/insforge_dark.svg +15 -15
  325. package/frontend/src/assets/logos/insforge_light.svg +15 -15
  326. package/frontend/src/assets/logos/instagram.svg +2 -0
  327. package/frontend/src/assets/logos/linkedin.svg +3 -0
  328. package/frontend/src/assets/logos/microsoft.svg +1 -0
  329. package/frontend/src/assets/logos/openai.svg +10 -10
  330. package/frontend/src/assets/logos/roo_code.svg +9 -9
  331. package/frontend/src/assets/logos/spotify.svg +17 -0
  332. package/frontend/src/assets/logos/tiktok.svg +6 -0
  333. package/frontend/src/assets/logos/trae.svg +3 -3
  334. package/frontend/src/assets/logos/windsurf.svg +10 -10
  335. package/frontend/src/assets/logos/x.svg +3 -0
  336. package/frontend/src/components/Checkbox.tsx +27 -29
  337. package/frontend/src/components/CodeBlock.tsx +55 -2
  338. package/frontend/src/components/CodeEditor.tsx +92 -0
  339. package/frontend/src/components/ConfirmDialog.tsx +1 -1
  340. package/frontend/src/components/ConnectCTA.tsx +38 -0
  341. package/frontend/src/components/CopyButton.tsx +52 -15
  342. package/frontend/src/components/ErrorState.tsx +1 -2
  343. package/frontend/src/components/FeatureSidebar.tsx +6 -6
  344. package/frontend/src/components/FeatureSidebarItem.tsx +2 -2
  345. package/frontend/src/components/JsonHighlight.tsx +21 -9
  346. package/frontend/src/components/ProjectInfoModal.tsx +128 -0
  347. package/frontend/src/components/PromptDialog.tsx +1 -4
  348. package/frontend/src/components/SearchInput.tsx +1 -2
  349. package/frontend/src/components/Stepper.tsx +53 -0
  350. package/frontend/src/components/ThemeToggle.tsx +3 -3
  351. package/frontend/src/components/datagrid/DataGrid.tsx +25 -32
  352. package/frontend/src/components/datagrid/cell-editors/DateCellEditor.tsx +1 -2
  353. package/frontend/src/components/datagrid/cell-editors/JsonCellEditor.tsx +2 -4
  354. package/frontend/src/components/datagrid/index.ts +23 -0
  355. package/frontend/src/components/index.ts +23 -30
  356. package/frontend/src/components/layout/AppHeader.tsx +131 -91
  357. package/frontend/src/components/layout/AppSidebar.tsx +80 -170
  358. package/frontend/src/components/layout/Layout.tsx +12 -23
  359. package/frontend/src/components/layout/PrimaryMenu.tsx +187 -0
  360. package/frontend/src/components/layout/SecondaryMenu.tsx +70 -0
  361. package/frontend/src/components/layout/index.ts +5 -0
  362. package/frontend/src/components/radix/Tooltip.tsx +24 -13
  363. package/frontend/src/components/radix/index.ts +22 -0
  364. package/frontend/src/features/ai/components/AIConfigCard.tsx +129 -83
  365. package/frontend/src/features/ai/components/AIEmptyState.tsx +12 -7
  366. package/frontend/src/features/ai/components/ModalityFilterSidebar.tsx +101 -0
  367. package/frontend/src/features/ai/components/ModelSelectionDialog.tsx +135 -0
  368. package/frontend/src/features/ai/components/ModelSelectionGrid.tsx +51 -0
  369. package/frontend/src/features/ai/components/SystemPromptDialog.tsx +118 -0
  370. package/frontend/src/features/ai/components/index.ts +6 -0
  371. package/frontend/src/features/ai/helpers.ts +57 -71
  372. package/frontend/src/features/ai/hooks/useAIConfigs.ts +39 -113
  373. package/frontend/src/features/ai/hooks/useAIUsage.ts +0 -2
  374. package/frontend/src/features/ai/pages/AIPage.tsx +166 -0
  375. package/frontend/src/features/ai/services/ai.service.ts +5 -5
  376. package/frontend/src/features/auth/components/AuthPreview.tsx +96 -0
  377. package/frontend/src/features/auth/components/OAuthConfigDialog.tsx +54 -30
  378. package/frontend/src/features/auth/components/UserFormDialog.tsx +13 -6
  379. package/frontend/src/features/auth/components/UsersDataGrid.tsx +50 -14
  380. package/frontend/src/features/auth/components/index.ts +5 -0
  381. package/frontend/src/features/auth/helpers.tsx +208 -0
  382. package/frontend/src/features/auth/hooks/useAnonToken.ts +30 -0
  383. package/frontend/src/features/auth/hooks/useAuthConfig.ts +48 -0
  384. package/frontend/src/features/auth/hooks/useOAuthConfig.ts +14 -10
  385. package/frontend/src/features/auth/hooks/useUsers.ts +43 -5
  386. package/frontend/src/features/auth/index.ts +3 -2
  387. package/frontend/src/features/auth/pages/AuthMethodsPage.tsx +275 -0
  388. package/frontend/src/features/auth/pages/ConfigurationPage.tsx +395 -0
  389. package/frontend/src/features/auth/pages/UsersPage.tsx +257 -0
  390. package/frontend/src/features/auth/services/anonToken.service.ts +11 -0
  391. package/frontend/src/features/auth/services/config.service.ts +19 -0
  392. package/frontend/src/features/auth/services/{oauth.service.ts → oauth-config.service.ts} +4 -4
  393. package/frontend/src/features/auth/services/{auth.service.ts → user.service.ts} +7 -53
  394. package/frontend/src/features/dashboard/components/ConnectionSuccessBanner.tsx +35 -0
  395. package/frontend/src/features/dashboard/components/PromptCard.tsx +21 -0
  396. package/frontend/src/features/dashboard/components/PromptDialog.tsx +103 -0
  397. package/frontend/src/features/dashboard/components/StatsCard.tsx +50 -0
  398. package/frontend/src/features/dashboard/components/index.ts +4 -0
  399. package/frontend/src/features/dashboard/pages/DashboardPage.tsx +212 -0
  400. package/frontend/src/features/dashboard/prompts/ai-chatbot.ts +13 -0
  401. package/frontend/src/features/dashboard/prompts/crm-system.ts +13 -0
  402. package/frontend/src/features/dashboard/prompts/ecommerce-platform.ts +12 -0
  403. package/frontend/src/features/dashboard/prompts/index.ts +31 -0
  404. package/frontend/src/features/dashboard/prompts/instagram-clone.ts +11 -0
  405. package/frontend/src/features/dashboard/prompts/notion-clone.ts +14 -0
  406. package/frontend/src/features/dashboard/prompts/reddit-clone.ts +12 -0
  407. package/frontend/src/features/database/components/DatabaseDataGrid.tsx +48 -17
  408. package/frontend/src/features/database/components/ForeignKeyCell.tsx +15 -34
  409. package/frontend/src/features/database/components/ForeignKeyPopover.tsx +19 -20
  410. package/frontend/src/features/database/components/LinkRecordModal.tsx +120 -125
  411. package/frontend/src/features/database/components/RecordFormDialog.tsx +22 -33
  412. package/frontend/src/features/database/components/RecordFormField.tsx +45 -47
  413. package/frontend/src/features/database/components/SQLModal.tsx +75 -0
  414. package/frontend/src/features/database/components/TableEmptyState.tsx +6 -5
  415. package/frontend/src/features/database/components/TableForm.tsx +28 -19
  416. package/frontend/src/features/database/components/TableFormColumn.tsx +2 -3
  417. package/frontend/src/features/database/components/TableSidebar.tsx +1 -1
  418. package/frontend/src/features/database/components/TablesEmptyState.tsx +48 -0
  419. package/frontend/src/features/database/components/TemplateCard.tsx +37 -0
  420. package/frontend/src/features/database/components/TemplatePreview.tsx +92 -0
  421. package/frontend/src/features/database/components/index.ts +19 -0
  422. package/frontend/src/features/database/constants.ts +28 -2
  423. package/frontend/src/features/database/contexts/SQLEditorContext.tsx +188 -0
  424. package/frontend/src/features/database/helpers.ts +2 -2
  425. package/frontend/src/features/database/hooks/useCSVImport.ts +29 -0
  426. package/frontend/src/features/database/hooks/useDatabase.ts +66 -0
  427. package/frontend/src/features/database/hooks/useRawSQL.ts +55 -0
  428. package/frontend/src/features/database/hooks/useRecords.ts +139 -0
  429. package/frontend/src/features/database/hooks/useTables.ts +135 -0
  430. package/frontend/src/features/database/index.ts +7 -1
  431. package/frontend/src/features/database/pages/FunctionsPage.tsx +203 -0
  432. package/frontend/src/features/database/pages/IndexesPage.tsx +228 -0
  433. package/frontend/src/features/database/pages/PoliciesPage.tsx +237 -0
  434. package/frontend/src/features/database/pages/SQLEditorPage.tsx +382 -0
  435. package/frontend/src/features/database/{page/DatabasePage.tsx → pages/TablesPage.tsx} +168 -209
  436. package/frontend/src/features/database/pages/TemplatesPage.tsx +39 -0
  437. package/frontend/src/features/database/pages/TriggersPage.tsx +230 -0
  438. package/frontend/src/features/database/services/advance.service.ts +40 -0
  439. package/frontend/src/features/database/services/database.service.ts +33 -194
  440. package/frontend/src/features/database/services/record.service.ts +219 -0
  441. package/frontend/src/features/database/services/table.service.ts +58 -0
  442. package/frontend/src/features/database/templates/ai-chatbot.ts +402 -0
  443. package/frontend/src/features/database/templates/crm-system.ts +528 -0
  444. package/frontend/src/features/database/templates/ecommerce-platform.ts +553 -0
  445. package/frontend/src/features/database/templates/index.ts +34 -0
  446. package/frontend/src/features/database/templates/instagram-clone.ts +222 -0
  447. package/frontend/src/features/database/templates/notion-clone.ts +483 -0
  448. package/frontend/src/features/database/templates/reddit-clone.ts +526 -0
  449. package/frontend/src/features/functions/components/FunctionRow.tsx +2 -1
  450. package/frontend/src/features/functions/components/FunctionsSidebar.tsx +1 -1
  451. package/frontend/src/features/functions/components/SecretRow.tsx +1 -1
  452. package/frontend/src/features/functions/components/index.ts +5 -0
  453. package/frontend/src/features/functions/hooks/useFunctions.ts +4 -4
  454. package/frontend/src/features/{secrets → functions}/hooks/useSecrets.ts +5 -5
  455. package/frontend/src/features/functions/pages/FunctionsPage.tsx +148 -0
  456. package/frontend/src/features/functions/{components/SecretsContent.tsx → pages/SecretsPage.tsx} +19 -21
  457. package/frontend/src/features/functions/services/{functions.service.ts → function.service.ts} +2 -2
  458. package/frontend/src/features/{secrets/services/secrets.service.ts → functions/services/secret.service.ts} +2 -2
  459. package/frontend/src/features/login/hooks/usePartnerOrigin.ts +27 -0
  460. package/frontend/src/features/login/pages/CloudLoginPage.tsx +118 -0
  461. package/frontend/src/features/login/{page → pages}/LoginPage.tsx +16 -23
  462. package/frontend/src/features/login/services/partnership.service.ts +65 -0
  463. package/frontend/src/features/logs/components/LogsDataGrid.tsx +89 -0
  464. package/frontend/src/features/logs/components/SeverityBadge.tsx +18 -0
  465. package/frontend/src/features/logs/components/index.ts +2 -0
  466. package/frontend/src/features/logs/helpers.ts +24 -0
  467. package/frontend/src/features/logs/hooks/useAuditLogs.ts +4 -4
  468. package/frontend/src/features/logs/hooks/useLogSources.ts +137 -0
  469. package/frontend/src/features/logs/hooks/useLogs.ts +163 -0
  470. package/frontend/src/features/logs/hooks/useMcpUsage.ts +128 -0
  471. package/frontend/src/features/logs/index.ts +8 -2
  472. package/frontend/src/features/logs/{page → pages}/AuditsPage.tsx +91 -38
  473. package/frontend/src/features/logs/pages/LogsPage.tsx +152 -0
  474. package/frontend/src/features/logs/pages/MCPLogsPage.tsx +84 -0
  475. package/frontend/src/features/logs/services/audit.service.ts +63 -0
  476. package/frontend/src/features/logs/services/log.service.ts +15 -110
  477. package/frontend/src/features/logs/services/usage.service.ts +31 -0
  478. package/frontend/src/features/onboard/components/McpConnectionStatus.tsx +68 -0
  479. package/frontend/src/features/onboard/components/OnboardingModal.tsx +267 -0
  480. package/frontend/src/features/onboard/components/VideoDemoModal.tsx +38 -0
  481. package/frontend/src/features/onboard/components/index.ts +4 -0
  482. package/frontend/src/features/onboard/components/mcp/CursorDeeplinkGenerator.tsx +2 -2
  483. package/frontend/src/features/onboard/components/mcp/{mcp-helper.tsx → helpers.tsx} +8 -8
  484. package/frontend/src/features/onboard/components/mcp/index.ts +2 -3
  485. package/frontend/src/features/onboard/index.ts +13 -3
  486. package/frontend/src/features/realtime/components/ChannelRow.tsx +83 -0
  487. package/frontend/src/features/realtime/components/EditChannelModal.tsx +246 -0
  488. package/frontend/src/features/realtime/components/MessageRow.tsx +85 -0
  489. package/frontend/src/features/realtime/components/RealtimeEmptyState.tsx +30 -0
  490. package/frontend/src/features/realtime/hooks/useRealtime.ts +218 -0
  491. package/frontend/src/features/realtime/index.ts +11 -0
  492. package/frontend/src/features/realtime/pages/RealtimeChannelsPage.tsx +172 -0
  493. package/frontend/src/features/realtime/pages/RealtimeMessagesPage.tsx +211 -0
  494. package/frontend/src/features/realtime/pages/RealtimePermissionsPage.tsx +191 -0
  495. package/frontend/src/features/realtime/services/realtime.service.ts +107 -0
  496. package/frontend/src/features/storage/components/BucketEmptyState.tsx +9 -6
  497. package/frontend/src/features/storage/components/BucketFormDialog.tsx +25 -41
  498. package/frontend/src/features/storage/components/FilePreviewDialog.tsx +20 -8
  499. package/frontend/src/features/storage/components/StorageDataGrid.tsx +4 -3
  500. package/frontend/src/features/storage/components/StorageManager.tsx +23 -34
  501. package/frontend/src/features/storage/components/index.ts +12 -0
  502. package/frontend/src/features/storage/hooks/useStorage.ts +208 -0
  503. package/frontend/src/features/storage/{page → pages}/StoragePage.tsx +41 -143
  504. package/frontend/src/features/storage/services/storage.service.ts +22 -1
  505. package/frontend/src/features/visualizer/components/AuthNode.tsx +72 -56
  506. package/frontend/src/features/visualizer/components/BucketNode.tsx +4 -4
  507. package/frontend/src/features/visualizer/components/SchemaVisualizer.tsx +108 -80
  508. package/frontend/src/features/visualizer/components/TableNode.tsx +34 -41
  509. package/frontend/src/features/visualizer/components/VisualizerSkeleton.tsx +12 -4
  510. package/frontend/src/features/visualizer/pages/VisualizerPage.tsx +97 -0
  511. package/frontend/src/index.css +1 -0
  512. package/frontend/src/lib/analytics/posthog.tsx +27 -0
  513. package/frontend/src/lib/contexts/AuthContext.tsx +38 -31
  514. package/frontend/src/lib/contexts/SocketContext.tsx +123 -80
  515. package/frontend/src/{features/metadata → lib}/hooks/useMetadata.ts +1 -1
  516. package/frontend/src/lib/hooks/useToast.tsx +6 -2
  517. package/frontend/src/lib/routing/AppRoutes.tsx +99 -0
  518. package/frontend/src/lib/routing/RequireAuth.tsx +27 -0
  519. package/frontend/src/lib/utils/cloudMessaging.ts +20 -0
  520. package/frontend/src/lib/utils/menuItems.ts +207 -0
  521. package/frontend/src/lib/utils/{validation-schemas.ts → schemaValidations.ts} +10 -5
  522. package/frontend/src/lib/utils/utils.ts +32 -1
  523. package/frontend/src/vite-env.d.ts +1 -0
  524. package/frontend/tsconfig.json +25 -25
  525. package/frontend/tsconfig.node.json +9 -9
  526. package/frontend/vite.config.ts +5 -3
  527. package/functions/deno.json +24 -24
  528. package/functions/server.ts +315 -290
  529. package/functions/worker-template.js +15 -4
  530. package/i18n/README.ar.md +130 -0
  531. package/i18n/README.de.md +130 -0
  532. package/i18n/README.es.md +154 -0
  533. package/i18n/README.fr.md +134 -0
  534. package/i18n/README.hi.md +129 -0
  535. package/i18n/README.ja.md +174 -0
  536. package/i18n/README.ko.md +137 -0
  537. package/i18n/README.pt-BR.md +131 -0
  538. package/i18n/README.ru.md +129 -0
  539. package/i18n/README.zh-CN.md +133 -0
  540. package/openapi/ai.yaml +715 -688
  541. package/openapi/auth.yaml +1244 -563
  542. package/openapi/email.yaml +158 -0
  543. package/openapi/functions.yaml +475 -475
  544. package/openapi/health.yaml +29 -29
  545. package/openapi/logs.yaml +223 -223
  546. package/openapi/metadata.yaml +177 -177
  547. package/openapi/realtime.yaml +699 -0
  548. package/openapi/records.yaml +381 -381
  549. package/openapi/secrets.yaml +370 -370
  550. package/openapi/storage.yaml +875 -875
  551. package/openapi/tables.yaml +463 -463
  552. package/package.json +97 -88
  553. package/shared-schemas/package.json +31 -31
  554. package/shared-schemas/src/ai-api.schema.ts +34 -58
  555. package/shared-schemas/src/ai.schema.ts +63 -54
  556. package/shared-schemas/src/auth-api.schema.ts +352 -193
  557. package/shared-schemas/src/auth.schema.ts +43 -7
  558. package/shared-schemas/src/cloud-events.schema.ts +57 -0
  559. package/shared-schemas/src/database-api.schema.ts +35 -4
  560. package/shared-schemas/src/database.schema.ts +40 -1
  561. package/shared-schemas/src/docs.schema.ts +26 -0
  562. package/shared-schemas/src/email-api.schema.ts +30 -0
  563. package/shared-schemas/src/index.ts +5 -0
  564. package/shared-schemas/src/logs-api.schema.ts +7 -1
  565. package/shared-schemas/src/logs.schema.ts +26 -0
  566. package/shared-schemas/src/metadata.schema.ts +18 -4
  567. package/shared-schemas/src/realtime-api.schema.ts +111 -0
  568. package/shared-schemas/src/realtime.schema.ts +143 -0
  569. package/shared-schemas/tsconfig.json +21 -21
  570. package/tsconfig.json +7 -7
  571. package/zeabur/README.md +13 -0
  572. package/zeabur/template.yml +1032 -0
  573. package/.github/workflows/deploy-aws.yml +0 -130
  574. package/backend/src/api/routes/agent.ts +0 -29
  575. package/backend/src/api/routes/auth.oauth.ts +0 -482
  576. package/backend/src/api/routes/auth.ts +0 -386
  577. package/backend/src/api/routes/docs.ts +0 -66
  578. package/backend/src/api/routes/functions.ts +0 -183
  579. package/backend/src/api/routes/openapi.ts +0 -82
  580. package/backend/src/api/routes/usage.ts +0 -96
  581. package/backend/src/core/ai/client.ts +0 -242
  582. package/backend/src/core/ai/model.ts +0 -117
  583. package/backend/src/core/auth/auth.ts +0 -780
  584. package/backend/src/core/database/manager.ts +0 -178
  585. package/backend/src/core/database/table.ts +0 -772
  586. package/backend/src/core/documentation/agent.ts +0 -689
  587. package/backend/src/core/documentation/openapi.ts +0 -856
  588. package/backend/src/core/logs/analytics.ts +0 -76
  589. package/backend/src/core/logs/providers/localdb.provider.ts +0 -246
  590. package/backend/src/core/socket/socket.ts +0 -388
  591. package/backend/src/core/storage/storage.ts +0 -923
  592. package/backend/src/utils/cloud-token.ts +0 -39
  593. package/backend/src/utils/helpers.ts +0 -49
  594. package/backend/src/utils/uuid.ts +0 -9
  595. package/backend/tests/manual/test-better-auth.sh +0 -303
  596. package/docker-init/db/logs.sql +0 -9
  597. package/frontend/README.md +0 -112
  598. package/frontend/src/components/datagrid/index.tsx +0 -20
  599. package/frontend/src/components/layout/CloudLayout.tsx +0 -95
  600. package/frontend/src/features/ai/components/AIConfigDialog.tsx +0 -76
  601. package/frontend/src/features/ai/components/AIConfigForm.tsx +0 -222
  602. package/frontend/src/features/ai/components/fields/ModalityField.tsx +0 -87
  603. package/frontend/src/features/ai/components/fields/ModelSelectionField.tsx +0 -134
  604. package/frontend/src/features/ai/components/fields/SystemPromptField.tsx +0 -33
  605. package/frontend/src/features/ai/page/AIPage.tsx +0 -178
  606. package/frontend/src/features/auth/components/AddOAuthDialog.tsx +0 -106
  607. package/frontend/src/features/auth/components/AuthMethodTab.tsx +0 -238
  608. package/frontend/src/features/auth/components/UsersTab.tsx +0 -114
  609. package/frontend/src/features/auth/page/AuthenticationPage.tsx +0 -169
  610. package/frontend/src/features/dashboard/page/DashboardPage.tsx +0 -194
  611. package/frontend/src/features/database/hooks/UseLinkModal.tsx +0 -78
  612. package/frontend/src/features/functions/components/FunctionViewer.tsx +0 -46
  613. package/frontend/src/features/functions/components/FunctionsContent.tsx +0 -88
  614. package/frontend/src/features/functions/page/FunctionsPage.tsx +0 -28
  615. package/frontend/src/features/login/components/AuthErrorBoundary.tsx +0 -87
  616. package/frontend/src/features/login/components/PrivateRoute.tsx +0 -24
  617. package/frontend/src/features/login/page/CloudLoginPage.tsx +0 -93
  618. package/frontend/src/features/logs/components/AnalyticsLogsTable.tsx +0 -313
  619. package/frontend/src/features/logs/components/LogsTable.tsx +0 -199
  620. package/frontend/src/features/logs/page/AnalyticsLogsPage.tsx +0 -530
  621. package/frontend/src/features/metadata/index.ts +0 -0
  622. package/frontend/src/features/metadata/page/MetadataPage.tsx +0 -136
  623. package/frontend/src/features/onboard/components/CompletionCard.tsx +0 -41
  624. package/frontend/src/features/onboard/components/OnboardButton.tsx +0 -84
  625. package/frontend/src/features/onboard/components/StepContent.tsx +0 -91
  626. package/frontend/src/features/onboard/components/TestConnectionStep.tsx +0 -53
  627. package/frontend/src/features/onboard/components/mcp/McpInstallation.tsx +0 -144
  628. package/frontend/src/features/onboard/page/OnBoardPage.tsx +0 -104
  629. package/frontend/src/features/onboard/types.ts +0 -8
  630. package/frontend/src/features/visualizer/page/VisualizerPage.tsx +0 -127
  631. package/frontend/src/lib/contexts/OnboardStepContext.tsx +0 -68
  632. package/frontend/src/lib/hooks/useOnboardingCompletion.ts +0 -29
  633. /package/backend/src/api/{middleware → middlewares}/error.ts +0 -0
  634. /package/backend/src/api/{middleware → middlewares}/upload.ts +0 -0
  635. /package/frontend/src/{features/metadata → lib}/services/metadata.service.ts +0 -0
@@ -0,0 +1,266 @@
1
+ import axios from 'axios';
2
+ import logger from '@/utils/logger.js';
3
+ import { getApiBaseUrl } from '@/utils/environment.js';
4
+ import { OAuthConfigService } from '@/services/auth/oauth-config.service.js';
5
+ import type { AppleUserInfo, OAuthUserData } from '@/types/auth.js';
6
+ import { OAuthProvider } from './base.provider.js';
7
+
8
+ /**
9
+ * Apple OAuth Service
10
+ * Handles all Apple Sign In operations including URL generation, token exchange, and user info verification
11
+ *
12
+ * Apple OAuth specifics:
13
+ * - Uses OIDC with JWT id_token
14
+ * - Callback receives POST request with code, id_token, and user data
15
+ * - User info (name, email) is only provided on first authorization
16
+ * - client_secret is a JWT signed with Apple's private key
17
+ */
18
+ export class AppleOAuthProvider implements OAuthProvider {
19
+ private static instance: AppleOAuthProvider;
20
+
21
+ private constructor() {
22
+ // No initialization needed - jose handles JWKS caching internally
23
+ }
24
+
25
+ public static getInstance(): AppleOAuthProvider {
26
+ if (!AppleOAuthProvider.instance) {
27
+ AppleOAuthProvider.instance = new AppleOAuthProvider();
28
+ }
29
+ return AppleOAuthProvider.instance;
30
+ }
31
+
32
+ /**
33
+ * Generate Apple OAuth authorization URL
34
+ */
35
+ async generateOAuthUrl(state?: string): Promise<string> {
36
+ const oAuthConfigService = OAuthConfigService.getInstance();
37
+ const config = await oAuthConfigService.getConfigByProvider('apple');
38
+
39
+ if (!config) {
40
+ throw new Error('Apple OAuth not configured');
41
+ }
42
+
43
+ const selfBaseUrl = getApiBaseUrl();
44
+
45
+ if (config?.useSharedKey) {
46
+ if (!state) {
47
+ logger.warn('Shared Apple OAuth called without state parameter');
48
+ throw new Error('State parameter is required for shared Apple OAuth');
49
+ }
50
+ // Use shared keys if configured
51
+ const cloudBaseUrl = process.env.CLOUD_API_HOST || 'https://api.insforge.dev';
52
+ const redirectUri = `${selfBaseUrl}/api/auth/oauth/shared/callback/${state}`;
53
+ const response = await axios.get(
54
+ `${cloudBaseUrl}/auth/v1/shared/apple?redirect_uri=${encodeURIComponent(redirectUri)}`,
55
+ {
56
+ headers: {
57
+ 'Content-Type': 'application/json',
58
+ },
59
+ }
60
+ );
61
+ return response.data.auth_url || response.data.url || '';
62
+ }
63
+
64
+ logger.debug('Apple OAuth Config (fresh from DB):', {
65
+ clientId: config.clientId ? 'SET' : 'NOT SET',
66
+ });
67
+
68
+ const authUrl = new URL('https://appleid.apple.com/auth/authorize');
69
+ authUrl.searchParams.set('client_id', config.clientId ?? '');
70
+ authUrl.searchParams.set('redirect_uri', `${selfBaseUrl}/api/auth/oauth/apple/callback`);
71
+ authUrl.searchParams.set('response_type', 'code id_token');
72
+ authUrl.searchParams.set('response_mode', 'form_post');
73
+ authUrl.searchParams.set(
74
+ 'scope',
75
+ config.scopes && config.scopes.length > 0 ? config.scopes.join(' ') : 'name email'
76
+ );
77
+ if (state) {
78
+ authUrl.searchParams.set('state', state);
79
+ }
80
+
81
+ return authUrl.toString();
82
+ }
83
+
84
+ /**
85
+ * Generate Apple client secret (JWT signed with private key)
86
+ * Apple requires a dynamically generated client_secret
87
+ */
88
+ private async generateClientSecret(): Promise<string> {
89
+ const oAuthConfigService = OAuthConfigService.getInstance();
90
+ const config = await oAuthConfigService.getConfigByProvider('apple');
91
+
92
+ if (!config) {
93
+ throw new Error('Apple OAuth not configured');
94
+ }
95
+
96
+ // Get additional config from client secret (stored as JSON with teamId, keyId, privateKey)
97
+ const secretData = await oAuthConfigService.getClientSecretByProvider('apple');
98
+ if (!secretData) {
99
+ throw new Error('Apple OAuth client secret not configured');
100
+ }
101
+
102
+ let appleConfig: { teamId: string; keyId: string; privateKey: string };
103
+ try {
104
+ appleConfig = JSON.parse(secretData);
105
+ } catch {
106
+ throw new Error(
107
+ 'Apple OAuth client secret must be a JSON object with teamId, keyId, and privateKey'
108
+ );
109
+ }
110
+
111
+ const { teamId, keyId, privateKey } = appleConfig;
112
+
113
+ if (!teamId || !keyId || !privateKey) {
114
+ throw new Error('Apple OAuth requires teamId, keyId, and privateKey in client secret');
115
+ }
116
+
117
+ // Use jose to sign the client secret JWT
118
+ const { SignJWT, importPKCS8 } = await import('jose');
119
+
120
+ const key = await importPKCS8(privateKey, 'ES256');
121
+
122
+ const clientSecret = await new SignJWT({})
123
+ .setProtectedHeader({ alg: 'ES256', kid: keyId })
124
+ .setIssuer(teamId)
125
+ .setSubject(config.clientId ?? '')
126
+ .setAudience('https://appleid.apple.com')
127
+ .setIssuedAt()
128
+ .setExpirationTime('180d') // 180 days (Apple allows up to 6 months)
129
+ .sign(key);
130
+
131
+ return clientSecret;
132
+ }
133
+
134
+ /**
135
+ * Exchange Apple authorization code for tokens
136
+ */
137
+ async exchangeCodeToToken(code: string): Promise<{ access_token: string; id_token: string }> {
138
+ const oAuthConfigService = OAuthConfigService.getInstance();
139
+ const config = await oAuthConfigService.getConfigByProvider('apple');
140
+
141
+ if (!config) {
142
+ throw new Error('Apple OAuth not configured');
143
+ }
144
+
145
+ try {
146
+ logger.info('Exchanging Apple code for tokens', {
147
+ hasCode: !!code,
148
+ clientId: config.clientId?.substring(0, 10) + '...',
149
+ });
150
+
151
+ const clientSecret = await this.generateClientSecret();
152
+ const selfBaseUrl = getApiBaseUrl();
153
+
154
+ const body = new URLSearchParams({
155
+ client_id: config.clientId ?? '',
156
+ client_secret: clientSecret,
157
+ code,
158
+ grant_type: 'authorization_code',
159
+ redirect_uri: `${selfBaseUrl}/api/auth/oauth/apple/callback`,
160
+ });
161
+
162
+ const response = await axios.post('https://appleid.apple.com/auth/token', body.toString(), {
163
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
164
+ });
165
+
166
+ if (!response.data.id_token) {
167
+ throw new Error('Failed to get id_token from Apple');
168
+ }
169
+
170
+ return {
171
+ access_token: response.data.access_token || '',
172
+ id_token: response.data.id_token,
173
+ };
174
+ } catch (error) {
175
+ if (axios.isAxiosError(error) && error.response) {
176
+ logger.error('Apple token exchange failed', {
177
+ status: error.response.status,
178
+ error: error.response.data,
179
+ });
180
+ throw new Error(`Apple OAuth error: ${JSON.stringify(error.response.data)}`);
181
+ }
182
+ throw error;
183
+ }
184
+ }
185
+
186
+ /**
187
+ * Verify Apple ID token and extract user info
188
+ */
189
+ async verifyIdToken(idToken: string): Promise<AppleUserInfo> {
190
+ const oAuthConfigService = OAuthConfigService.getInstance();
191
+ const config = await oAuthConfigService.getConfigByProvider('apple');
192
+
193
+ if (!config) {
194
+ throw new Error('Apple OAuth not configured');
195
+ }
196
+
197
+ try {
198
+ const { createRemoteJWKSet, jwtVerify } = await import('jose');
199
+ const JWKS = createRemoteJWKSet(new URL('https://appleid.apple.com/auth/keys'));
200
+
201
+ const { payload } = await jwtVerify(idToken, JWKS, {
202
+ issuer: 'https://appleid.apple.com',
203
+ audience: config.clientId,
204
+ });
205
+
206
+ return {
207
+ sub: String(payload.sub),
208
+ email: (payload.email as string) || '',
209
+ email_verified: payload.email_verified === 'true' || payload.email_verified === true,
210
+ is_private_email: payload.is_private_email === 'true' || payload.is_private_email === true,
211
+ };
212
+ } catch (error) {
213
+ logger.error('Apple ID token verification failed:', error);
214
+ throw new Error(`Apple token verification failed: ${error}`);
215
+ }
216
+ }
217
+
218
+ /**
219
+ * Handle Apple OAuth callback
220
+ * Note: Apple sends a POST request with form data
221
+ */
222
+ async handleCallback(payload: { code?: string; token?: string }): Promise<OAuthUserData> {
223
+ let appleUserInfo: AppleUserInfo;
224
+
225
+ if (payload.token) {
226
+ // Token provided directly (e.g., from mobile app)
227
+ appleUserInfo = await this.verifyIdToken(payload.token);
228
+ } else if (payload.code) {
229
+ // Exchange code for tokens
230
+ const tokens = await this.exchangeCodeToToken(payload.code);
231
+ appleUserInfo = await this.verifyIdToken(tokens.id_token);
232
+ } else {
233
+ throw new Error('No authorization code or token provided');
234
+ }
235
+
236
+ // Transform Apple user info to generic format
237
+ // Note: Apple only provides name on first authorization, so we use email as fallback
238
+ const userName = appleUserInfo.name || appleUserInfo.email.split('@')[0];
239
+ return {
240
+ provider: 'apple',
241
+ providerId: appleUserInfo.sub,
242
+ email: appleUserInfo.email,
243
+ userName,
244
+ avatarUrl: '', // Apple doesn't provide avatar
245
+ identityData: appleUserInfo,
246
+ };
247
+ }
248
+
249
+ /**
250
+ * Handle shared callback payload transformation
251
+ */
252
+ handleSharedCallback(payloadData: Record<string, unknown>): OAuthUserData {
253
+ const providerId = String(payloadData.providerId ?? '');
254
+ const email = String(payloadData.email ?? '');
255
+ const name = String(payloadData.name ?? '');
256
+
257
+ return {
258
+ provider: 'apple',
259
+ providerId,
260
+ email,
261
+ userName: name || email.split('@')[0],
262
+ avatarUrl: '',
263
+ identityData: payloadData,
264
+ };
265
+ }
266
+ }
@@ -0,0 +1,29 @@
1
+ import type { OAuthUserData } from '@/types/auth.js';
2
+
3
+ /**
4
+ * OAuth provider interface
5
+ * Defines the contract that all OAuth providers must implement
6
+ */
7
+ export interface OAuthProvider {
8
+ /**
9
+ * Generate OAuth authorization URL
10
+ * @param state - Optional state parameter for CSRF protection
11
+ * @returns Authorization URL
12
+ */
13
+ generateOAuthUrl(state?: string): Promise<string>;
14
+
15
+ /**
16
+ * Handle OAuth callback and exchange code/token for user info
17
+ * @param payload - OAuth callback payload containing code or token
18
+ * @returns User data from OAuth provider
19
+ */
20
+ handleCallback(payload: { code?: string; token?: string }): Promise<OAuthUserData>;
21
+
22
+ /**
23
+ * Handle shared OAuth callback (for shared keys)
24
+ * Optional - not all providers support shared OAuth
25
+ * @param payloadData - Payload data from shared OAuth callback
26
+ * @returns User data transformed to standard format
27
+ */
28
+ handleSharedCallback?(payloadData: Record<string, unknown>): OAuthUserData;
29
+ }
@@ -0,0 +1,195 @@
1
+ import axios from 'axios';
2
+ import logger from '@/utils/logger.js';
3
+ import { getApiBaseUrl } from '@/utils/environment.js';
4
+ import { OAuthConfigService } from '@/services/auth/oauth-config.service.js';
5
+ import { OAuthProvider } from './base.provider.js';
6
+ import type { DiscordUserInfo, OAuthUserData } from '@/types/auth.js';
7
+
8
+ /**
9
+ * Discord OAuth Service
10
+ * Handles all Discord OAuth operations including URL generation, token exchange, and user info retrieval
11
+ */
12
+ export class DiscordOAuthProvider implements OAuthProvider {
13
+ private static instance: DiscordOAuthProvider;
14
+
15
+ private constructor() {
16
+ // Initialize OAuth helpers if needed
17
+ }
18
+
19
+ public static getInstance(): DiscordOAuthProvider {
20
+ if (!DiscordOAuthProvider.instance) {
21
+ DiscordOAuthProvider.instance = new DiscordOAuthProvider();
22
+ }
23
+ return DiscordOAuthProvider.instance;
24
+ }
25
+
26
+ /**
27
+ * Generate Discord OAuth authorization URL
28
+ */
29
+ async generateOAuthUrl(state?: string): Promise<string> {
30
+ const oAuthConfigService = OAuthConfigService.getInstance();
31
+ const config = await oAuthConfigService.getConfigByProvider('discord');
32
+
33
+ if (!config) {
34
+ throw new Error('Discord OAuth not configured');
35
+ }
36
+
37
+ const selfBaseUrl = getApiBaseUrl();
38
+
39
+ if (config?.useSharedKey) {
40
+ if (!state) {
41
+ logger.warn('Shared Discord OAuth called without state parameter');
42
+ throw new Error('State parameter is required for shared Discord OAuth');
43
+ }
44
+ // Use shared keys if configured
45
+ const cloudBaseUrl = process.env.CLOUD_API_HOST || 'https://api.insforge.dev';
46
+ const redirectUri = `${selfBaseUrl}/api/auth/oauth/shared/callback/${state}`;
47
+ const response = await axios.get(
48
+ `${cloudBaseUrl}/auth/v1/shared/discord?redirect_uri=${encodeURIComponent(redirectUri)}`,
49
+ {
50
+ headers: {
51
+ 'Content-Type': 'application/json',
52
+ },
53
+ }
54
+ );
55
+ return response.data.auth_url || response.data.url || '';
56
+ }
57
+
58
+ logger.debug('Discord OAuth Config (fresh from DB):', {
59
+ clientId: config.clientId ? 'SET' : 'NOT SET',
60
+ });
61
+
62
+ const authUrl = new URL('https://discord.com/api/oauth2/authorize');
63
+ authUrl.searchParams.set('client_id', config.clientId ?? '');
64
+ authUrl.searchParams.set('redirect_uri', `${selfBaseUrl}/api/auth/oauth/discord/callback`);
65
+ authUrl.searchParams.set('response_type', 'code');
66
+ authUrl.searchParams.set('scope', config.scopes ? config.scopes.join(' ') : 'identify email');
67
+ if (state) {
68
+ authUrl.searchParams.set('state', state);
69
+ }
70
+
71
+ return authUrl.toString();
72
+ }
73
+
74
+ /**
75
+ * Exchange Discord code for access token
76
+ */
77
+ async exchangeCodeToToken(code: string): Promise<string> {
78
+ const oAuthConfigService = OAuthConfigService.getInstance();
79
+ const config = await oAuthConfigService.getConfigByProvider('discord');
80
+
81
+ if (!config) {
82
+ throw new Error('Discord OAuth not configured');
83
+ }
84
+
85
+ try {
86
+ logger.info('Exchanging Discord code for token', {
87
+ hasCode: !!code,
88
+ clientId: config.clientId?.substring(0, 10) + '...',
89
+ });
90
+
91
+ const clientSecret = await oAuthConfigService.getClientSecretByProvider('discord');
92
+ const selfBaseUrl = getApiBaseUrl();
93
+ const response = await axios.post(
94
+ 'https://discord.com/api/oauth2/token',
95
+ new URLSearchParams({
96
+ client_id: config.clientId ?? '',
97
+ client_secret: clientSecret ?? '',
98
+ code,
99
+ redirect_uri: `${selfBaseUrl}/api/auth/oauth/discord/callback`,
100
+ grant_type: 'authorization_code',
101
+ }).toString(),
102
+ {
103
+ headers: {
104
+ 'Content-Type': 'application/x-www-form-urlencoded',
105
+ },
106
+ }
107
+ );
108
+
109
+ if (!response.data.access_token) {
110
+ throw new Error('Failed to get access token from Discord');
111
+ }
112
+
113
+ return response.data.access_token;
114
+ } catch (error) {
115
+ if (axios.isAxiosError(error) && error.response) {
116
+ logger.error('Discord token exchange failed', {
117
+ status: error.response.status,
118
+ error: error.response.data,
119
+ });
120
+ throw new Error(`Discord OAuth error: ${JSON.stringify(error.response.data)}`);
121
+ }
122
+ throw error;
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Get Discord user info
128
+ */
129
+ async getUserInfo(accessToken: string): Promise<DiscordUserInfo> {
130
+ try {
131
+ const response = await axios.get('https://discord.com/api/users/@me', {
132
+ headers: {
133
+ Authorization: `Bearer ${accessToken}`,
134
+ },
135
+ });
136
+
137
+ return {
138
+ id: response.data.id,
139
+ username: response.data.global_name || response.data.username,
140
+ email: response.data.email,
141
+ avatar: response.data.avatar
142
+ ? `https://cdn.discordapp.com/avatars/${response.data.id}/${response.data.avatar}.png`
143
+ : '',
144
+ };
145
+ } catch (error) {
146
+ logger.error('Discord user info retrieval failed:', error);
147
+ throw new Error(`Failed to get Discord user info: ${error}`);
148
+ }
149
+ }
150
+
151
+ /**
152
+ * Handle Discord OAuth callback
153
+ */
154
+ async handleCallback(payload: { code?: string; token?: string }): Promise<OAuthUserData> {
155
+ if (!payload.code) {
156
+ throw new Error('No authorization code provided');
157
+ }
158
+
159
+ const accessToken = await this.exchangeCodeToToken(payload.code);
160
+ const discordUserInfo = await this.getUserInfo(accessToken);
161
+
162
+ // Transform Discord user info to generic format
163
+ const userName = discordUserInfo.username;
164
+ const email = discordUserInfo.email || `${discordUserInfo.id}@users.noreply.discord.local`;
165
+ return {
166
+ provider: 'discord',
167
+ providerId: discordUserInfo.id,
168
+ email,
169
+ userName,
170
+ avatarUrl: discordUserInfo.avatar || '',
171
+ identityData: discordUserInfo,
172
+ };
173
+ }
174
+
175
+ /**
176
+ * Handle shared callback payload transformation
177
+ */
178
+ handleSharedCallback(payloadData: Record<string, unknown>): OAuthUserData {
179
+ const providerId = String(payloadData.providerId ?? '');
180
+ const username = String(payloadData.username ?? '');
181
+ const emailField = String(payloadData.email ?? '');
182
+ const avatar = String(payloadData.avatar ?? '');
183
+
184
+ const email = emailField || `${providerId}@users.noreply.discord.local`;
185
+
186
+ return {
187
+ provider: 'discord',
188
+ providerId,
189
+ email,
190
+ userName: username,
191
+ avatarUrl: avatar,
192
+ identityData: payloadData,
193
+ };
194
+ }
195
+ }
@@ -0,0 +1,194 @@
1
+ import axios from 'axios';
2
+ import logger from '@/utils/logger.js';
3
+ import { getApiBaseUrl } from '@/utils/environment.js';
4
+ import { OAuthConfigService } from '@/services/auth/oauth-config.service.js';
5
+ import { OAuthProvider } from './base.provider.js';
6
+ import type { FacebookUserInfo, OAuthUserData } from '@/types/auth.js';
7
+
8
+ /**
9
+ * Facebook OAuth Service
10
+ * Handles all Facebook OAuth operations including URL generation, token exchange, and user info retrieval
11
+ */
12
+ export class FacebookOAuthProvider implements OAuthProvider {
13
+ private static instance: FacebookOAuthProvider;
14
+
15
+ private constructor() {
16
+ // Initialize OAuth helpers if needed
17
+ }
18
+
19
+ public static getInstance(): FacebookOAuthProvider {
20
+ if (!FacebookOAuthProvider.instance) {
21
+ FacebookOAuthProvider.instance = new FacebookOAuthProvider();
22
+ }
23
+ return FacebookOAuthProvider.instance;
24
+ }
25
+
26
+ /**
27
+ * Generate Facebook OAuth authorization URL
28
+ */
29
+ async generateOAuthUrl(state?: string): Promise<string> {
30
+ const oAuthConfigService = OAuthConfigService.getInstance();
31
+ const config = await oAuthConfigService.getConfigByProvider('facebook');
32
+
33
+ if (!config) {
34
+ throw new Error('Facebook OAuth not configured');
35
+ }
36
+
37
+ const selfBaseUrl = getApiBaseUrl();
38
+
39
+ if (config?.useSharedKey) {
40
+ if (!state) {
41
+ logger.warn('Shared Facebook OAuth called without state parameter');
42
+ throw new Error('State parameter is required for shared Facebook OAuth');
43
+ }
44
+ const cloudBaseUrl = process.env.CLOUD_API_HOST || 'https://api.insforge.dev';
45
+ const redirectUri = `${selfBaseUrl}/api/auth/oauth/shared/callback/${state}`;
46
+ const response = await axios.get(
47
+ `${cloudBaseUrl}/auth/v1/shared/facebook?redirect_uri=${encodeURIComponent(redirectUri)}`,
48
+ {
49
+ headers: {
50
+ 'Content-Type': 'application/json',
51
+ },
52
+ }
53
+ );
54
+ return response.data.auth_url || response.data.url || '';
55
+ }
56
+
57
+ logger.debug('Facebook OAuth Config (fresh from DB):', {
58
+ clientId: config.clientId ? 'SET' : 'NOT SET',
59
+ });
60
+
61
+ const authUrl = new URL('https://www.facebook.com/v21.0/dialog/oauth');
62
+ authUrl.searchParams.set('client_id', config.clientId ?? '');
63
+ authUrl.searchParams.set('redirect_uri', `${selfBaseUrl}/api/auth/oauth/facebook/callback`);
64
+ authUrl.searchParams.set('response_type', 'code');
65
+ authUrl.searchParams.set(
66
+ 'scope',
67
+ config.scopes ? config.scopes.join(',') : 'email,public_profile'
68
+ );
69
+ if (state) {
70
+ authUrl.searchParams.set('state', state);
71
+ }
72
+
73
+ return authUrl.toString();
74
+ }
75
+
76
+ /**
77
+ * Exchange Facebook code for access token
78
+ */
79
+ async exchangeCodeToToken(code: string): Promise<string> {
80
+ const oAuthConfigService = OAuthConfigService.getInstance();
81
+ const config = await oAuthConfigService.getConfigByProvider('facebook');
82
+
83
+ if (!config) {
84
+ throw new Error('Facebook OAuth not configured');
85
+ }
86
+
87
+ try {
88
+ logger.info('Exchanging Facebook code for token', {
89
+ hasCode: !!code,
90
+ clientId: config.clientId?.substring(0, 10) + '...',
91
+ });
92
+
93
+ const clientSecret = await oAuthConfigService.getClientSecretByProvider('facebook');
94
+ const selfBaseUrl = getApiBaseUrl();
95
+ const response = await axios.get('https://graph.facebook.com/v21.0/oauth/access_token', {
96
+ params: {
97
+ client_id: config.clientId,
98
+ client_secret: clientSecret,
99
+ code,
100
+ redirect_uri: `${selfBaseUrl}/api/auth/oauth/facebook/callback`,
101
+ },
102
+ });
103
+
104
+ if (!response.data.access_token) {
105
+ throw new Error('Failed to get access token from Facebook');
106
+ }
107
+
108
+ return response.data.access_token;
109
+ } catch (error) {
110
+ if (axios.isAxiosError(error) && error.response) {
111
+ logger.error('Facebook token exchange failed', {
112
+ status: error.response.status,
113
+ error: error.response.data,
114
+ });
115
+ throw new Error(`Facebook OAuth error: ${JSON.stringify(error.response.data)}`);
116
+ }
117
+ throw error;
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Get Facebook user info
123
+ */
124
+ async getUserInfo(accessToken: string): Promise<FacebookUserInfo> {
125
+ try {
126
+ const response = await axios.get('https://graph.facebook.com/v21.0/me', {
127
+ params: {
128
+ fields: 'id,email,name,first_name,last_name,picture',
129
+ access_token: accessToken,
130
+ },
131
+ });
132
+
133
+ return response.data;
134
+ } catch (error) {
135
+ logger.error('Facebook user info retrieval failed:', error);
136
+ throw new Error(`Failed to get Facebook user info: ${error}`);
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Handle Facebook OAuth callback
142
+ */
143
+ async handleCallback(payload: { code?: string; token?: string }): Promise<OAuthUserData> {
144
+ if (!payload.code) {
145
+ throw new Error('No authorization code provided');
146
+ }
147
+
148
+ const accessToken = await this.exchangeCodeToToken(payload.code);
149
+ const facebookUserInfo = await this.getUserInfo(accessToken);
150
+
151
+ // Transform Facebook user info to generic format
152
+ const email = facebookUserInfo.email || '';
153
+ const userName =
154
+ facebookUserInfo.name ||
155
+ facebookUserInfo.first_name ||
156
+ `User${facebookUserInfo.id.substring(0, 6)}`;
157
+ const avatarUrl = facebookUserInfo.picture?.data?.url || '';
158
+ return {
159
+ provider: 'facebook',
160
+ providerId: facebookUserInfo.id,
161
+ email,
162
+ userName,
163
+ avatarUrl,
164
+ identityData: facebookUserInfo,
165
+ };
166
+ }
167
+
168
+ /**
169
+ * Handle shared callback payload transformation
170
+ */
171
+ handleSharedCallback(payloadData: Record<string, unknown>): OAuthUserData {
172
+ const providerId = String(payloadData.providerId ?? '');
173
+ const email = String(payloadData.email ?? '');
174
+ const name = String(payloadData.name ?? '');
175
+ const firstName = String(payloadData.first_name ?? '');
176
+ const avatar = String(payloadData.avatar ?? '');
177
+
178
+ // Handle nested picture.data.url structure
179
+ const picture = payloadData.picture as { data?: { url?: string } } | undefined;
180
+ const pictureUrl = picture?.data?.url ?? '';
181
+
182
+ const userName = name || firstName || `User${providerId.substring(0, 6)}`;
183
+ const avatarUrl = pictureUrl || avatar;
184
+
185
+ return {
186
+ provider: 'facebook',
187
+ providerId,
188
+ email,
189
+ userName,
190
+ avatarUrl,
191
+ identityData: payloadData,
192
+ };
193
+ }
194
+ }