insforge 1.2.10 → 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 (335) hide show
  1. package/.claude-plugin/marketplace.json +20 -20
  2. package/.dockerignore +60 -60
  3. package/.env.example +83 -77
  4. package/.github/ISSUE_TEMPLATE/bug_report.yml +36 -36
  5. package/.github/ISSUE_TEMPLATE/config.yml +11 -11
  6. package/.github/ISSUE_TEMPLATE/feature_request.yml +26 -26
  7. package/.github/PULL_REQUEST_TEMPLATE.md +7 -7
  8. package/.github/copilot-instructions.md +146 -146
  9. package/.github/workflows/build-image.yml +65 -65
  10. package/.github/workflows/ci-premerge-check.yml +23 -23
  11. package/.github/workflows/e2e.yml +63 -63
  12. package/.github/workflows/lint-and-format.yml +32 -32
  13. package/.prettierignore +64 -64
  14. package/CHANGELOG.md +44 -44
  15. package/CLAUDE_PLUGIN.md +104 -104
  16. package/CODE_OF_CONDUCT.md +128 -128
  17. package/CONTRIBUTING.md +125 -125
  18. package/Dockerfile +30 -30
  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 -182
  23. package/assets/Dark.svg +23 -23
  24. package/auth/package.json +28 -28
  25. package/auth/src/lib/broadcastService.ts +117 -115
  26. package/auth/src/pages/SignInPage.tsx +60 -57
  27. package/auth/src/pages/SignUpPage.tsx +60 -57
  28. package/auth/tsconfig.json +32 -32
  29. package/auth/tsconfig.node.json +11 -11
  30. package/backend/package.json +78 -75
  31. package/backend/src/api/routes/ai/index.routes.ts +3 -3
  32. package/backend/src/api/routes/auth/index.routes.ts +667 -570
  33. package/backend/src/api/routes/auth/oauth.routes.ts +473 -448
  34. package/backend/src/api/routes/database/advance.routes.ts +37 -16
  35. package/backend/src/api/routes/database/index.routes.ts +78 -1
  36. package/backend/src/api/routes/database/records.routes.ts +10 -10
  37. package/backend/src/api/routes/database/tables.routes.ts +0 -14
  38. package/backend/src/api/routes/docs/index.routes.ts +75 -76
  39. package/backend/src/api/routes/email/index.routes.ts +35 -0
  40. package/backend/src/api/routes/functions/index.routes.ts +18 -12
  41. package/backend/src/api/routes/metadata/index.routes.ts +12 -0
  42. package/backend/src/api/routes/realtime/channels.routes.ts +81 -0
  43. package/backend/src/api/routes/realtime/index.routes.ts +12 -0
  44. package/backend/src/api/routes/realtime/messages.routes.ts +48 -0
  45. package/backend/src/api/routes/realtime/permissions.routes.ts +19 -0
  46. package/backend/src/api/routes/storage/index.routes.ts +18 -12
  47. package/backend/src/api/routes/usage/index.routes.ts +6 -4
  48. package/backend/src/infra/database/database.manager.ts +14 -1
  49. package/backend/src/infra/database/migrations/000_create-base-tables.sql +141 -141
  50. package/backend/src/infra/database/migrations/001_create-helper-functions.sql +40 -40
  51. package/backend/src/infra/database/migrations/002_rename-auth-tables.sql +29 -29
  52. package/backend/src/infra/database/migrations/003_create-users-table.sql +55 -55
  53. package/backend/src/infra/database/migrations/004_add-reload-postgrest-func.sql +23 -23
  54. package/backend/src/infra/database/migrations/005_enable-project-admin-modify-users.sql +29 -29
  55. package/backend/src/infra/database/migrations/006_modify-ai-usage-table.sql +24 -24
  56. package/backend/src/infra/database/migrations/007_drop-metadata-table.sql +1 -1
  57. package/backend/src/infra/database/migrations/008_add-system-tables.sql +76 -76
  58. package/backend/src/infra/database/migrations/009_add-function-secrets.sql +23 -23
  59. package/backend/src/infra/database/migrations/010_modify-ai-config-modalities.sql +93 -93
  60. package/backend/src/infra/database/migrations/011_refactor-secrets-table.sql +15 -15
  61. package/backend/src/infra/database/migrations/012_add-storage-uploaded-by.sql +7 -7
  62. package/backend/src/infra/database/migrations/013_create-auth-schema-functions.sql +44 -44
  63. package/backend/src/infra/database/migrations/014_add-updated-at-trigger-user-table.sql +7 -7
  64. package/backend/src/infra/database/migrations/015_create-auth-config-and-email-otp-tables.sql +59 -59
  65. package/backend/src/infra/database/migrations/016_update-auth-config-and-email-otp.sql +24 -24
  66. package/backend/src/infra/database/migrations/017_create-realtime-schema.sql +233 -0
  67. package/backend/src/infra/realtime/realtime.manager.ts +246 -0
  68. package/backend/src/infra/realtime/webhook-sender.ts +82 -0
  69. package/backend/src/infra/security/token.manager.ts +219 -125
  70. package/backend/src/infra/socket/socket.manager.ts +198 -64
  71. package/backend/src/providers/ai/openrouter.provider.ts +12 -9
  72. package/backend/src/providers/email/base.provider.ts +4 -7
  73. package/backend/src/providers/email/cloud.provider.ts +84 -0
  74. package/backend/src/providers/oauth/apple.provider.ts +266 -0
  75. package/backend/src/providers/oauth/index.ts +1 -0
  76. package/backend/src/server.ts +317 -284
  77. package/backend/src/services/ai/ai-model.service.ts +5 -5
  78. package/backend/src/services/ai/chat-completion.service.ts +4 -4
  79. package/backend/src/services/ai/image-generation.service.ts +3 -3
  80. package/backend/src/services/auth/auth.service.ts +14 -0
  81. package/backend/src/services/database/database-table.service.ts +0 -9
  82. package/backend/src/services/database/database.service.ts +127 -0
  83. package/backend/src/services/email/email.service.ts +5 -7
  84. package/backend/src/services/realtime/index.ts +3 -0
  85. package/backend/src/services/realtime/realtime-auth.service.ts +104 -0
  86. package/backend/src/services/realtime/realtime-channel.service.ts +237 -0
  87. package/backend/src/services/realtime/realtime-message.service.ts +260 -0
  88. package/backend/src/types/auth.ts +11 -0
  89. package/backend/src/types/realtime.ts +18 -0
  90. package/backend/src/types/socket.ts +7 -31
  91. package/backend/src/utils/cookies.ts +35 -0
  92. package/backend/src/utils/s3-config-loader.ts +64 -0
  93. package/backend/src/utils/seed.ts +301 -298
  94. package/backend/src/utils/sql-parser.ts +90 -0
  95. package/backend/tests/README.md +133 -133
  96. package/backend/tests/cleanup-all-test-data.sh +230 -230
  97. package/backend/tests/cloud/test-s3-multitenant.sh +131 -131
  98. package/backend/tests/local/comprehensive-curl-tests.sh +155 -155
  99. package/backend/tests/local/test-ai-config.sh +129 -129
  100. package/backend/tests/local/test-ai-usage.sh +80 -80
  101. package/backend/tests/local/test-auth-router.sh +143 -143
  102. package/backend/tests/local/test-database-router.sh +222 -222
  103. package/backend/tests/local/test-e2e.sh +240 -240
  104. package/backend/tests/local/test-fk-errors.sh +96 -96
  105. package/backend/tests/local/test-functions.sh +123 -123
  106. package/backend/tests/local/test-id-field.sh +200 -200
  107. package/backend/tests/local/test-logs.sh +132 -132
  108. package/backend/tests/local/test-public-bucket.sh +264 -264
  109. package/backend/tests/local/test-secrets.sh +249 -249
  110. package/backend/tests/local/test-serverless-functions.sh.disabled +325 -325
  111. package/backend/tests/local/test-traditional-rest.sh +208 -208
  112. package/backend/tests/manual/README.md +50 -50
  113. package/backend/tests/manual/create-large-table-simple.sql +10 -10
  114. package/backend/tests/manual/seed-large-table.sql +100 -100
  115. package/backend/tests/manual/setup-large-table-extras.sql +33 -33
  116. package/backend/tests/manual/test-bulk-upsert.sh +409 -409
  117. package/backend/tests/manual/test-database-advance.sh +296 -296
  118. package/backend/tests/manual/test-postgrest-stability.sh +191 -191
  119. package/backend/tests/manual/test-rawsql-export-import.sh +411 -411
  120. package/backend/tests/manual/test-rawsql-modes.sh +244 -244
  121. package/backend/tests/manual/test-universal-storage.sh +263 -263
  122. package/backend/tests/manual/test-users.sql +17 -17
  123. package/backend/tests/run-all-tests.sh +139 -139
  124. package/backend/tests/setup.ts +0 -0
  125. package/backend/tests/test-config.sh +338 -338
  126. package/backend/tests/unit/analyze-query.test.ts +697 -0
  127. package/backend/tsconfig.json +22 -22
  128. package/claude-plugin/.claude-plugin/plugin.json +24 -24
  129. package/claude-plugin/README.md +133 -133
  130. package/claude-plugin/skills/insforge-schema-patterns/SKILL.md +270 -270
  131. package/docker-compose.prod.yml +204 -200
  132. package/docker-compose.yml +232 -228
  133. package/docker-init/db/db-init.sql +97 -97
  134. package/docker-init/db/jwt.sql +5 -5
  135. package/docker-init/db/postgresql.conf +16 -16
  136. package/docker-init/logs/vector.yml +236 -236
  137. package/docs/README.md +44 -44
  138. package/docs/agent-docs/real-time.md +269 -0
  139. package/docs/changelog.mdx +119 -67
  140. package/docs/core-concepts/ai/architecture.mdx +372 -372
  141. package/docs/core-concepts/ai/sdk.mdx +213 -213
  142. package/docs/core-concepts/authentication/architecture.mdx +278 -278
  143. package/docs/core-concepts/authentication/sdk.mdx +414 -414
  144. package/docs/core-concepts/authentication/ui-components/customization.mdx +529 -529
  145. package/docs/core-concepts/authentication/ui-components/nextjs.mdx +221 -221
  146. package/docs/core-concepts/authentication/ui-components/react-router.mdx +184 -184
  147. package/docs/core-concepts/authentication/ui-components/react.mdx +129 -129
  148. package/docs/core-concepts/database/architecture.mdx +255 -255
  149. package/docs/core-concepts/database/sdk.mdx +382 -382
  150. package/docs/core-concepts/email/architecture.mdx +101 -0
  151. package/docs/core-concepts/email/sdk.mdx +53 -0
  152. package/docs/core-concepts/functions/architecture.mdx +105 -105
  153. package/docs/core-concepts/functions/sdk.mdx +184 -184
  154. package/docs/core-concepts/realtime/architecture.mdx +446 -0
  155. package/docs/core-concepts/realtime/sdk.mdx +409 -0
  156. package/docs/core-concepts/storage/architecture.mdx +243 -243
  157. package/docs/core-concepts/storage/sdk.mdx +253 -253
  158. package/docs/deployment/README.md +94 -94
  159. package/docs/deployment/deploy-to-aws-ec2.md +564 -564
  160. package/docs/deployment/deploy-to-azure-virtual-machines.md +312 -312
  161. package/docs/deployment/deploy-to-google-cloud-compute-engine.md +613 -613
  162. package/docs/deployment/deploy-to-render.md +441 -441
  163. package/docs/deprecated/insforge-auth-api.md +214 -214
  164. package/docs/deprecated/insforge-auth-sdk.md +99 -99
  165. package/docs/deprecated/insforge-db-api.md +358 -358
  166. package/docs/deprecated/insforge-db-sdk.md +139 -139
  167. package/docs/deprecated/insforge-debug-sdk.md +156 -156
  168. package/docs/deprecated/insforge-debug.md +64 -64
  169. package/docs/deprecated/insforge-instructions.md +123 -123
  170. package/docs/deprecated/insforge-project.md +117 -117
  171. package/docs/deprecated/insforge-storage-api.md +278 -278
  172. package/docs/deprecated/insforge-storage-sdk.md +158 -158
  173. package/docs/docs.json +232 -210
  174. package/docs/examples/framework-guides/nextjs.mdx +131 -131
  175. package/docs/examples/framework-guides/nuxt.mdx +165 -165
  176. package/docs/examples/framework-guides/react.mdx +165 -165
  177. package/docs/examples/framework-guides/svelte.mdx +153 -153
  178. package/docs/examples/framework-guides/vue.mdx +159 -159
  179. package/docs/examples/overview.mdx +67 -67
  180. package/docs/favicon.svg +19 -19
  181. package/docs/images/changelog/dec-2025/ai-integration.png +0 -0
  182. package/docs/images/changelog/dec-2025/ai-models.webp +0 -0
  183. package/docs/images/changelog/dec-2025/alipay-payment.webp +0 -0
  184. package/docs/images/changelog/dec-2025/apple-login.jpg +0 -0
  185. package/docs/images/changelog/dec-2025/mcp-installer.png +0 -0
  186. package/docs/images/changelog/dec-2025/realtime-module.jpg +0 -0
  187. package/docs/images/icons/ai.svg +4 -4
  188. package/docs/images/logos/nextjs.svg +4 -4
  189. package/docs/images/logos/nuxt.svg +4 -4
  190. package/docs/images/logos/react.svg +5 -5
  191. package/docs/images/logos/svelte.svg +4 -4
  192. package/docs/images/logos/vue.svg +5 -5
  193. package/docs/insforge-instructions-sdk.md +89 -88
  194. package/docs/introduction.mdx +45 -45
  195. package/docs/logo/dark.svg +22 -22
  196. package/docs/logo/light.svg +20 -20
  197. package/docs/partnership.mdx +651 -646
  198. package/docs/quickstart.mdx +82 -82
  199. package/docs/showcase.mdx +52 -52
  200. package/docs/snippets/sdk-installation.mdx +21 -21
  201. package/docs/snippets/service-icons.mdx +27 -27
  202. package/examples/oauth/frontend-oauth-example.html +250 -250
  203. package/examples/response-examples.md +443 -443
  204. package/frontend/components.json +17 -17
  205. package/frontend/package.json +69 -69
  206. package/frontend/src/assets/icons/checkbox_checked.svg +6 -6
  207. package/frontend/src/assets/icons/checkbox_undetermined.svg +6 -6
  208. package/frontend/src/assets/icons/checked.svg +3 -3
  209. package/frontend/src/assets/icons/connected.svg +3 -3
  210. package/frontend/src/assets/icons/error.svg +3 -3
  211. package/frontend/src/assets/icons/loader.svg +9 -9
  212. package/frontend/src/assets/icons/pencil.svg +4 -4
  213. package/frontend/src/assets/icons/refresh.svg +4 -4
  214. package/frontend/src/assets/icons/step_active.svg +3 -3
  215. package/frontend/src/assets/icons/step_inactive.svg +11 -11
  216. package/frontend/src/assets/icons/warning.svg +3 -3
  217. package/frontend/src/assets/logos/apple.svg +3 -3
  218. package/frontend/src/assets/logos/claude_code.svg +3 -3
  219. package/frontend/src/assets/logos/cline.svg +6 -6
  220. package/frontend/src/assets/logos/cursor.svg +20 -20
  221. package/frontend/src/assets/logos/discord.svg +8 -8
  222. package/frontend/src/assets/logos/facebook.svg +3 -3
  223. package/frontend/src/assets/logos/gemini.svg +19 -19
  224. package/frontend/src/assets/logos/github.svg +5 -5
  225. package/frontend/src/assets/logos/google.svg +13 -13
  226. package/frontend/src/assets/logos/grok.svg +10 -10
  227. package/frontend/src/assets/logos/insforge_dark.svg +15 -15
  228. package/frontend/src/assets/logos/insforge_light.svg +15 -15
  229. package/frontend/src/assets/logos/instagram.svg +1 -1
  230. package/frontend/src/assets/logos/linkedin.svg +3 -3
  231. package/frontend/src/assets/logos/openai.svg +10 -10
  232. package/frontend/src/assets/logos/roo_code.svg +9 -9
  233. package/frontend/src/assets/logos/spotify.svg +16 -16
  234. package/frontend/src/assets/logos/tiktok.svg +5 -5
  235. package/frontend/src/assets/logos/trae.svg +3 -3
  236. package/frontend/src/assets/logos/windsurf.svg +10 -10
  237. package/frontend/src/assets/logos/x.svg +3 -3
  238. package/frontend/src/components/layout/AppHeader.tsx +9 -10
  239. package/frontend/src/features/auth/components/OAuthConfigDialog.tsx +1 -0
  240. package/frontend/src/features/auth/components/UsersDataGrid.tsx +6 -0
  241. package/frontend/src/features/auth/helpers.tsx +8 -0
  242. package/frontend/src/features/auth/{page → pages}/UsersPage.tsx +0 -28
  243. package/frontend/src/features/database/components/SQLModal.tsx +75 -0
  244. package/frontend/src/features/database/components/TableForm.tsx +0 -4
  245. package/frontend/src/features/database/hooks/useDatabase.ts +66 -0
  246. package/frontend/src/features/database/hooks/useTables.ts +32 -28
  247. package/frontend/src/features/database/index.ts +1 -0
  248. package/frontend/src/features/database/{page → pages}/FunctionsPage.tsx +29 -37
  249. package/frontend/src/features/database/{page → pages}/IndexesPage.tsx +35 -47
  250. package/frontend/src/features/database/{page → pages}/PoliciesPage.tsx +43 -54
  251. package/frontend/src/features/database/{page → pages}/TablesPage.tsx +0 -42
  252. package/frontend/src/features/database/{page → pages}/TriggersPage.tsx +35 -47
  253. package/frontend/src/features/database/services/advance.service.ts +0 -26
  254. package/frontend/src/features/database/services/database.service.ts +55 -0
  255. package/frontend/src/features/database/services/table.service.ts +0 -6
  256. package/frontend/src/features/functions/{page → pages}/FunctionsPage.tsx +21 -44
  257. package/frontend/src/features/functions/{page → pages}/SecretsPage.tsx +11 -9
  258. package/frontend/src/features/logs/hooks/useMcpUsage.ts +13 -66
  259. package/frontend/src/features/realtime/components/ChannelRow.tsx +83 -0
  260. package/frontend/src/features/realtime/components/EditChannelModal.tsx +246 -0
  261. package/frontend/src/features/realtime/components/MessageRow.tsx +85 -0
  262. package/frontend/src/features/realtime/components/RealtimeEmptyState.tsx +30 -0
  263. package/frontend/src/features/realtime/hooks/useRealtime.ts +218 -0
  264. package/frontend/src/features/realtime/index.ts +11 -0
  265. package/frontend/src/features/realtime/pages/RealtimeChannelsPage.tsx +172 -0
  266. package/frontend/src/features/realtime/pages/RealtimeMessagesPage.tsx +211 -0
  267. package/frontend/src/features/realtime/pages/RealtimePermissionsPage.tsx +191 -0
  268. package/frontend/src/features/realtime/services/realtime.service.ts +107 -0
  269. package/frontend/src/features/storage/{page → pages}/StoragePage.tsx +1 -29
  270. package/frontend/src/features/visualizer/components/SchemaVisualizer.tsx +3 -3
  271. package/frontend/src/features/visualizer/{page → pages}/VisualizerPage.tsx +1 -35
  272. package/frontend/src/lib/contexts/SocketContext.tsx +119 -75
  273. package/frontend/src/lib/routing/AppRoutes.tsx +35 -20
  274. package/frontend/src/lib/utils/cloudMessaging.ts +1 -1
  275. package/frontend/src/lib/utils/menuItems.ts +24 -0
  276. package/frontend/src/lib/utils/utils.ts +14 -1
  277. package/frontend/tsconfig.json +25 -25
  278. package/frontend/tsconfig.node.json +9 -9
  279. package/functions/deno.json +24 -24
  280. package/functions/server.ts +315 -315
  281. package/i18n/README.ar.md +130 -130
  282. package/i18n/README.de.md +130 -130
  283. package/i18n/README.es.md +154 -154
  284. package/i18n/README.fr.md +134 -134
  285. package/i18n/README.hi.md +129 -129
  286. package/i18n/README.ja.md +174 -174
  287. package/i18n/README.ko.md +136 -136
  288. package/i18n/README.pt-BR.md +131 -131
  289. package/i18n/README.ru.md +129 -129
  290. package/i18n/README.zh-CN.md +133 -133
  291. package/openapi/ai.yaml +715 -715
  292. package/openapi/auth.yaml +1244 -1244
  293. package/openapi/email.yaml +158 -0
  294. package/openapi/functions.yaml +475 -475
  295. package/openapi/health.yaml +29 -29
  296. package/openapi/logs.yaml +223 -223
  297. package/openapi/metadata.yaml +177 -177
  298. package/openapi/realtime.yaml +699 -0
  299. package/openapi/records.yaml +381 -381
  300. package/openapi/secrets.yaml +370 -370
  301. package/openapi/storage.yaml +875 -875
  302. package/openapi/tables.yaml +463 -463
  303. package/package.json +97 -97
  304. package/shared-schemas/package.json +31 -31
  305. package/shared-schemas/src/ai.schema.ts +63 -59
  306. package/shared-schemas/src/auth-api.schema.ts +352 -339
  307. package/shared-schemas/src/auth.schema.ts +1 -1
  308. package/shared-schemas/src/database-api.schema.ts +32 -1
  309. package/shared-schemas/src/database.schema.ts +39 -0
  310. package/shared-schemas/src/docs.schema.ts +26 -0
  311. package/shared-schemas/src/email-api.schema.ts +30 -0
  312. package/shared-schemas/src/index.ts +4 -0
  313. package/shared-schemas/src/metadata.schema.ts +9 -0
  314. package/shared-schemas/src/realtime-api.schema.ts +111 -0
  315. package/shared-schemas/src/realtime.schema.ts +143 -0
  316. package/shared-schemas/tsconfig.json +21 -21
  317. package/tsconfig.json +7 -7
  318. package/zeabur/README.md +13 -13
  319. package/zeabur/template.yml +1032 -1032
  320. package/.cursor/rules/cursor-rules.mdc +0 -94
  321. package/frontend/src/features/database/hooks/useFullMetadata.ts +0 -18
  322. package/test-gemini.sh +0 -35
  323. package/test-usage-admin.sh +0 -57
  324. package/test-usage.sh +0 -50
  325. /package/frontend/src/features/ai/{page → pages}/AIPage.tsx +0 -0
  326. /package/frontend/src/features/auth/{page → pages}/AuthMethodsPage.tsx +0 -0
  327. /package/frontend/src/features/auth/{page → pages}/ConfigurationPage.tsx +0 -0
  328. /package/frontend/src/features/dashboard/{page → pages}/DashboardPage.tsx +0 -0
  329. /package/frontend/src/features/database/{page → pages}/SQLEditorPage.tsx +0 -0
  330. /package/frontend/src/features/database/{page → pages}/TemplatesPage.tsx +0 -0
  331. /package/frontend/src/features/login/{page → pages}/CloudLoginPage.tsx +0 -0
  332. /package/frontend/src/features/login/{page → pages}/LoginPage.tsx +0 -0
  333. /package/frontend/src/features/logs/{page → pages}/AuditsPage.tsx +0 -0
  334. /package/frontend/src/features/logs/{page → pages}/LogsPage.tsx +0 -0
  335. /package/frontend/src/features/logs/{page → pages}/MCPLogsPage.tsx +0 -0
@@ -1,298 +1,301 @@
1
- import { DatabaseManager } from '@/infra/database/database.manager.js';
2
- import { TokenManager } from '@/infra/security/token.manager.js';
3
- import { AIConfigService } from '@/services/ai/ai-config.service.js';
4
- import { isCloudEnvironment } from '@/utils/environment.js';
5
- import logger from '@/utils/logger.js';
6
- import { SecretService } from '@/services/secrets/secret.service.js';
7
- import { OAuthConfigService } from '@/services/auth/oauth-config.service.js';
8
- import { OAuthProvidersSchema } from '@insforge/shared-schemas';
9
- import { AuthConfigService } from '@/services/auth/auth-config.service.js';
10
-
11
- /**
12
- * Validates admin credentials are configured
13
- * Admin is authenticated via environment variables, not stored in DB
14
- */
15
- function ensureFirstAdmin(adminEmail: string, adminPassword: string): void {
16
- if (adminEmail && adminPassword) {
17
- logger.info(`āœ… Admin configured: ${adminEmail}`);
18
- } else {
19
- logger.warn('āš ļø Admin credentials not configured - check ADMIN_EMAIL and ADMIN_PASSWORD');
20
- }
21
- }
22
-
23
- /**
24
- * Seeds default AI configurations for cloud environments
25
- */
26
- async function seedDefaultAIConfigs(): Promise<void> {
27
- // Only seed default AI configs in cloud environment
28
- if (!isCloudEnvironment()) {
29
- return;
30
- }
31
-
32
- const aiConfigService = AIConfigService.getInstance();
33
-
34
- // Check if AI configs already exist
35
- const existingConfigs = await aiConfigService.findAll();
36
-
37
- if (existingConfigs.length) {
38
- return;
39
- }
40
-
41
- await aiConfigService.create(
42
- ['text', 'image'],
43
- ['text'],
44
- 'openrouter',
45
- 'openai/gpt-4o',
46
- 'You are a helpful assistant.'
47
- );
48
-
49
- await aiConfigService.create(
50
- ['text', 'image'],
51
- ['text', 'image'],
52
- 'openrouter',
53
- 'google/gemini-3-pro-image-preview'
54
- );
55
-
56
- logger.info('āœ… Default AI models configured (cloud environment)');
57
- }
58
-
59
- /**
60
- * Seeds default auth configuration for cloud environments
61
- * Enables email verification with code-based verification method
62
- * Only inserts config if table is empty (first startup, never configured)
63
- */
64
- async function seedDefaultAuthConfig(): Promise<void> {
65
- const dbManager = DatabaseManager.getInstance();
66
- const pool = dbManager.getPool();
67
- const client = await pool.connect();
68
-
69
- try {
70
- const result = await client.query('SELECT COUNT(*) as count FROM _auth_configs');
71
- const hasConfig = result.rows.length > 0 && Number(result.rows[0].count) > 0;
72
-
73
- if (hasConfig) {
74
- const authConfigService = AuthConfigService.getInstance();
75
- const currentConfig = await authConfigService.getAuthConfig();
76
- logger.info(
77
- 'āœ… Email verification configured:',
78
- currentConfig.requireEmailVerification ? 'enabled' : 'disabled'
79
- );
80
- return;
81
- }
82
-
83
- // Table is empty - this is first startup, insert default cloud configuration
84
- // Note: Migration 016 will add verify_email_method, reset_password_method, sign_in_redirect_to
85
- // so we only insert fields that exist in migration 015
86
- await client.query(
87
- `INSERT INTO _auth_configs (
88
- require_email_verification,
89
- password_min_length,
90
- require_number,
91
- require_lowercase,
92
- require_uppercase,
93
- require_special_char
94
- ) VALUES ($1, $2, $3, $4, $5, $6)
95
- ON CONFLICT DO NOTHING`,
96
- [
97
- isCloudEnvironment(), // Enable email verification for cloud
98
- 6, // password_min_length
99
- false, // require_number
100
- false, // require_lowercase
101
- false, // require_uppercase
102
- false, // require_special_char
103
- ]
104
- );
105
-
106
- logger.info('āœ… Email verification enabled (cloud environment)');
107
- } catch (error) {
108
- logger.error('Failed to seed default auth config', {
109
- error: error instanceof Error ? error.message : String(error),
110
- });
111
- // Don't throw - this is not critical for app startup
112
- } finally {
113
- client.release();
114
- }
115
- }
116
-
117
- /**
118
- * Seeds default OAuth configurations for supported providers
119
- */
120
- async function seedDefaultOAuthConfigs(): Promise<void> {
121
- const oauthConfigService = OAuthConfigService.getInstance();
122
-
123
- try {
124
- // Check if OAuth configs already exist
125
- const existingConfigs = await oauthConfigService.getAllConfigs();
126
- const existingProviders = existingConfigs.map((config) => config.provider.toLowerCase());
127
-
128
- // Default providers to seed
129
- const defaultProviders: OAuthProvidersSchema[] = ['google', 'github'];
130
-
131
- for (const provider of defaultProviders) {
132
- if (!existingProviders.includes(provider)) {
133
- await oauthConfigService.createConfig({
134
- provider,
135
- useSharedKey: true,
136
- });
137
- logger.info(`āœ… Default ${provider} OAuth config created`);
138
- }
139
- }
140
- } catch (error) {
141
- logger.warn('Failed to seed OAuth configs', {
142
- error: error instanceof Error ? error.message : String(error),
143
- });
144
- // Don't throw error as OAuth configs are optional
145
- }
146
- }
147
-
148
- /**
149
- * Seeds OAuth configurations from local environment variables
150
- */
151
- async function seedLocalOAuthConfigs(): Promise<void> {
152
- const oauthConfigService = OAuthConfigService.getInstance();
153
-
154
- try {
155
- // Check if OAuth configs already exist
156
- const existingConfigs = await oauthConfigService.getAllConfigs();
157
- const existingProviders = existingConfigs.map((config) => config.provider.toLowerCase());
158
-
159
- // Environment variable mappings for OAuth providers
160
- const envMappings: Array<{
161
- provider: OAuthProvidersSchema;
162
- clientIdEnv: string;
163
- clientSecretEnv: string;
164
- }> = [
165
- {
166
- provider: 'google',
167
- clientIdEnv: 'GOOGLE_CLIENT_ID',
168
- clientSecretEnv: 'GOOGLE_CLIENT_SECRET',
169
- },
170
- {
171
- provider: 'github',
172
- clientIdEnv: 'GITHUB_CLIENT_ID',
173
- clientSecretEnv: 'GITHUB_CLIENT_SECRET',
174
- },
175
- {
176
- provider: 'discord',
177
- clientIdEnv: 'DISCORD_CLIENT_ID',
178
- clientSecretEnv: 'DISCORD_CLIENT_SECRET',
179
- },
180
- {
181
- provider: 'linkedin',
182
- clientIdEnv: 'LINKEDIN_CLIENT_ID',
183
- clientSecretEnv: 'LINKEDIN_CLIENT_SECRET',
184
- },
185
- {
186
- provider: 'microsoft',
187
- clientIdEnv: 'MICROSOFT_CLIENT_ID',
188
- clientSecretEnv: 'MICROSOFT_CLIENT_SECRET',
189
- },
190
- ];
191
-
192
- for (const { provider, clientIdEnv, clientSecretEnv } of envMappings) {
193
- const clientId = process.env[clientIdEnv];
194
- const clientSecret = process.env[clientSecretEnv];
195
-
196
- if (clientId && clientSecret && !existingProviders.includes(provider)) {
197
- await oauthConfigService.createConfig({
198
- provider,
199
- clientId,
200
- clientSecret,
201
- useSharedKey: false,
202
- });
203
- logger.info(`āœ… ${provider} OAuth config loaded from environment variables`);
204
- }
205
- }
206
- } catch (error) {
207
- logger.warn('Failed to seed local OAuth configs', {
208
- error: error instanceof Error ? error.message : String(error),
209
- });
210
- }
211
- }
212
-
213
- // Create api key, admin user, and default AI configs
214
- export async function seedBackend(): Promise<void> {
215
- const secretService = SecretService.getInstance();
216
-
217
- const dbManager = DatabaseManager.getInstance();
218
-
219
- const adminEmail = process.env.ADMIN_EMAIL || 'admin@example.com';
220
- const adminPassword = process.env.ADMIN_PASSWORD || 'change-this-password';
221
-
222
- try {
223
- logger.info(`\nšŸš€ Insforge Backend Starting...`);
224
-
225
- // Validate admin credentials are configured
226
- ensureFirstAdmin(adminEmail, adminPassword);
227
-
228
- // Initialize API key (from env or generate)
229
- const apiKey = await secretService.initializeApiKey();
230
-
231
- // Get database stats
232
- const tables = await dbManager.getUserTables();
233
-
234
- logger.info(`āœ… Database connected to PostgreSQL`, {
235
- host: process.env.POSTGRES_HOST || 'localhost',
236
- port: process.env.POSTGRES_PORT || '5432',
237
- database: process.env.POSTGRES_DB || 'insforge',
238
- });
239
- // Database connection info is already logged above
240
-
241
- if (tables.length) {
242
- logger.info(`āœ… Found ${tables.length} user tables`);
243
- }
244
-
245
- // seed AI configs for cloud environment
246
- await seedDefaultAIConfigs();
247
-
248
- // Enable email verification in cloud environment
249
- await seedDefaultAuthConfig();
250
-
251
- // add default OAuth configs in Cloud hosting
252
- if (isCloudEnvironment()) {
253
- await seedDefaultOAuthConfigs();
254
- } else {
255
- await seedLocalOAuthConfigs();
256
- }
257
-
258
- // Initialize reserved secrets for edge functions
259
- // Add INSFORGE_INTERNAL_URL for Deno-to-backend container communication
260
- const insforgInternalUrl = 'http://insforge:7130';
261
- const existingInternalUrlSecret = await secretService.getSecretByKey('INSFORGE_INTERNAL_URL');
262
-
263
- if (existingInternalUrlSecret === null) {
264
- await secretService.createSecret({
265
- key: 'INSFORGE_INTERNAL_URL',
266
- isReserved: true,
267
- value: insforgInternalUrl,
268
- });
269
- logger.info('āœ… INSFORGE_INTERNAL_URL secret initialized');
270
- }
271
-
272
- // Add ANON_KEY for public edge function access
273
- const existingAnonKeySecret = await secretService.getSecretByKey('ANON_KEY');
274
-
275
- if (existingAnonKeySecret === null) {
276
- const tokenManager = TokenManager.getInstance();
277
- const anonToken = tokenManager.generateAnonToken();
278
-
279
- await secretService.createSecret({
280
- key: 'ANON_KEY',
281
- isReserved: true,
282
- value: anonToken,
283
- });
284
- logger.info('āœ… ANON_KEY secret initialized');
285
- }
286
-
287
- logger.info(`API key generated: ${apiKey}`);
288
- logger.info(`Setup complete:
289
- - Save this API key for your apps!
290
- - Dashboard: http://localhost:7131
291
- - API: http://localhost:7130/api
292
- `);
293
- } catch (error) {
294
- logger.error('Error during setup', {
295
- error: error instanceof Error ? error.message : String(error),
296
- });
297
- }
298
- }
1
+ import { DatabaseManager } from '@/infra/database/database.manager.js';
2
+ import { TokenManager } from '@/infra/security/token.manager.js';
3
+ import { AIConfigService } from '@/services/ai/ai-config.service.js';
4
+ import { isCloudEnvironment } from '@/utils/environment.js';
5
+ import logger from '@/utils/logger.js';
6
+ import { SecretService } from '@/services/secrets/secret.service.js';
7
+ import { OAuthConfigService } from '@/services/auth/oauth-config.service.js';
8
+ import { OAuthProvidersSchema, aiConfigurationInputSchema } from '@insforge/shared-schemas';
9
+ import { z } from 'zod';
10
+ import { AuthConfigService } from '@/services/auth/auth-config.service.js';
11
+ import { fetchS3Config } from '@/utils/s3-config-loader.js';
12
+
13
+ /**
14
+ * Validates admin credentials are configured
15
+ * Admin is authenticated via environment variables, not stored in DB
16
+ */
17
+ function ensureFirstAdmin(adminEmail: string, adminPassword: string): void {
18
+ if (adminEmail && adminPassword) {
19
+ logger.info(`āœ… Admin configured: ${adminEmail}`);
20
+ } else {
21
+ logger.warn('āš ļø Admin credentials not configured - check ADMIN_EMAIL and ADMIN_PASSWORD');
22
+ }
23
+ }
24
+
25
+ /**
26
+ * Seeds default AI configurations from S3 config
27
+ */
28
+ async function seedDefaultAIConfigs(): Promise<void> {
29
+ const aiConfigService = AIConfigService.getInstance();
30
+
31
+ const existingConfigs = await aiConfigService.findAll();
32
+ if (existingConfigs.length) {
33
+ return;
34
+ }
35
+
36
+ const defaultModels =
37
+ await fetchS3Config<z.infer<typeof aiConfigurationInputSchema>[]>('default-ai-models.json');
38
+
39
+ if (!defaultModels || defaultModels.length === 0) {
40
+ logger.warn('āš ļø No default AI models configured - add via dashboard or check S3 config');
41
+ return;
42
+ }
43
+
44
+ const parsed = aiConfigurationInputSchema.array().safeParse(defaultModels);
45
+ if (!parsed.success) {
46
+ logger.error('āŒ Invalid AI models configuration from S3', {
47
+ error: parsed.error.message,
48
+ });
49
+ return;
50
+ }
51
+
52
+ const validatedModels = parsed.data;
53
+ for (const model of validatedModels) {
54
+ await aiConfigService.create(
55
+ model.inputModality,
56
+ model.outputModality,
57
+ model.provider,
58
+ model.modelId,
59
+ model.systemPrompt
60
+ );
61
+ }
62
+
63
+ logger.info(`āœ… Default AI models configured (${validatedModels.length} models)`);
64
+ }
65
+
66
+ /**
67
+ * Seeds default auth configuration for cloud environments
68
+ * Enables email verification with code-based verification method
69
+ * Only inserts config if table is empty (first startup, never configured)
70
+ */
71
+ async function seedDefaultAuthConfig(): Promise<void> {
72
+ const dbManager = DatabaseManager.getInstance();
73
+ const pool = dbManager.getPool();
74
+ const client = await pool.connect();
75
+
76
+ try {
77
+ const result = await client.query('SELECT COUNT(*) as count FROM _auth_configs');
78
+ const hasConfig = result.rows.length > 0 && Number(result.rows[0].count) > 0;
79
+
80
+ if (hasConfig) {
81
+ const authConfigService = AuthConfigService.getInstance();
82
+ const currentConfig = await authConfigService.getAuthConfig();
83
+ logger.info(
84
+ 'āœ… Email verification configured:',
85
+ currentConfig.requireEmailVerification ? 'enabled' : 'disabled'
86
+ );
87
+ return;
88
+ }
89
+
90
+ // Table is empty - this is first startup, insert default cloud configuration
91
+ // Note: Migration 016 will add verify_email_method, reset_password_method, sign_in_redirect_to
92
+ // so we only insert fields that exist in migration 015
93
+ await client.query(
94
+ `INSERT INTO _auth_configs (
95
+ require_email_verification,
96
+ password_min_length,
97
+ require_number,
98
+ require_lowercase,
99
+ require_uppercase,
100
+ require_special_char
101
+ ) VALUES ($1, $2, $3, $4, $5, $6)
102
+ ON CONFLICT DO NOTHING`,
103
+ [
104
+ isCloudEnvironment(), // Enable email verification for cloud
105
+ 6, // password_min_length
106
+ false, // require_number
107
+ false, // require_lowercase
108
+ false, // require_uppercase
109
+ false, // require_special_char
110
+ ]
111
+ );
112
+
113
+ logger.info('āœ… Email verification enabled (cloud environment)');
114
+ } catch (error) {
115
+ logger.error('Failed to seed default auth config', {
116
+ error: error instanceof Error ? error.message : String(error),
117
+ });
118
+ // Don't throw - this is not critical for app startup
119
+ } finally {
120
+ client.release();
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Seeds default OAuth configurations for supported providers
126
+ */
127
+ async function seedDefaultOAuthConfigs(): Promise<void> {
128
+ const oauthConfigService = OAuthConfigService.getInstance();
129
+
130
+ try {
131
+ // Check if OAuth configs already exist
132
+ const existingConfigs = await oauthConfigService.getAllConfigs();
133
+ const existingProviders = existingConfigs.map((config) => config.provider.toLowerCase());
134
+
135
+ // Default providers to seed
136
+ const defaultProviders: OAuthProvidersSchema[] = ['google', 'github'];
137
+
138
+ for (const provider of defaultProviders) {
139
+ if (!existingProviders.includes(provider)) {
140
+ await oauthConfigService.createConfig({
141
+ provider,
142
+ useSharedKey: true,
143
+ });
144
+ logger.info(`āœ… Default ${provider} OAuth config created`);
145
+ }
146
+ }
147
+ } catch (error) {
148
+ logger.warn('Failed to seed OAuth configs', {
149
+ error: error instanceof Error ? error.message : String(error),
150
+ });
151
+ // Don't throw error as OAuth configs are optional
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Seeds OAuth configurations from local environment variables
157
+ */
158
+ async function seedLocalOAuthConfigs(): Promise<void> {
159
+ const oauthConfigService = OAuthConfigService.getInstance();
160
+
161
+ try {
162
+ // Check if OAuth configs already exist
163
+ const existingConfigs = await oauthConfigService.getAllConfigs();
164
+ const existingProviders = existingConfigs.map((config) => config.provider.toLowerCase());
165
+
166
+ // Environment variable mappings for OAuth providers
167
+ const envMappings: Array<{
168
+ provider: OAuthProvidersSchema;
169
+ clientIdEnv: string;
170
+ clientSecretEnv: string;
171
+ }> = [
172
+ {
173
+ provider: 'google',
174
+ clientIdEnv: 'GOOGLE_CLIENT_ID',
175
+ clientSecretEnv: 'GOOGLE_CLIENT_SECRET',
176
+ },
177
+ {
178
+ provider: 'github',
179
+ clientIdEnv: 'GITHUB_CLIENT_ID',
180
+ clientSecretEnv: 'GITHUB_CLIENT_SECRET',
181
+ },
182
+ {
183
+ provider: 'discord',
184
+ clientIdEnv: 'DISCORD_CLIENT_ID',
185
+ clientSecretEnv: 'DISCORD_CLIENT_SECRET',
186
+ },
187
+ {
188
+ provider: 'linkedin',
189
+ clientIdEnv: 'LINKEDIN_CLIENT_ID',
190
+ clientSecretEnv: 'LINKEDIN_CLIENT_SECRET',
191
+ },
192
+ {
193
+ provider: 'microsoft',
194
+ clientIdEnv: 'MICROSOFT_CLIENT_ID',
195
+ clientSecretEnv: 'MICROSOFT_CLIENT_SECRET',
196
+ },
197
+ ];
198
+
199
+ for (const { provider, clientIdEnv, clientSecretEnv } of envMappings) {
200
+ const clientId = process.env[clientIdEnv];
201
+ const clientSecret = process.env[clientSecretEnv];
202
+
203
+ if (clientId && clientSecret && !existingProviders.includes(provider)) {
204
+ await oauthConfigService.createConfig({
205
+ provider,
206
+ clientId,
207
+ clientSecret,
208
+ useSharedKey: false,
209
+ });
210
+ logger.info(`āœ… ${provider} OAuth config loaded from environment variables`);
211
+ }
212
+ }
213
+ } catch (error) {
214
+ logger.warn('Failed to seed local OAuth configs', {
215
+ error: error instanceof Error ? error.message : String(error),
216
+ });
217
+ }
218
+ }
219
+
220
+ // Create api key, admin user, and default AI configs
221
+ export async function seedBackend(): Promise<void> {
222
+ const secretService = SecretService.getInstance();
223
+
224
+ const dbManager = DatabaseManager.getInstance();
225
+
226
+ const adminEmail = process.env.ADMIN_EMAIL || 'admin@example.com';
227
+ const adminPassword = process.env.ADMIN_PASSWORD || 'change-this-password';
228
+
229
+ try {
230
+ logger.info(`\nšŸš€ Insforge Backend Starting...`);
231
+
232
+ // Validate admin credentials are configured
233
+ ensureFirstAdmin(adminEmail, adminPassword);
234
+
235
+ // Initialize API key (from env or generate)
236
+ const apiKey = await secretService.initializeApiKey();
237
+
238
+ // Get database stats
239
+ const tables = await dbManager.getUserTables();
240
+
241
+ logger.info(`āœ… Database connected to PostgreSQL`, {
242
+ host: process.env.POSTGRES_HOST || 'localhost',
243
+ port: process.env.POSTGRES_PORT || '5432',
244
+ database: process.env.POSTGRES_DB || 'insforge',
245
+ });
246
+ // Database connection info is already logged above
247
+
248
+ if (tables.length) {
249
+ logger.info(`āœ… Found ${tables.length} user tables`);
250
+ }
251
+
252
+ // seed default configs for cloud environment
253
+ if (isCloudEnvironment()) {
254
+ await seedDefaultOAuthConfigs();
255
+ await seedDefaultAIConfigs();
256
+ await seedDefaultAuthConfig();
257
+ } else {
258
+ await seedLocalOAuthConfigs();
259
+ }
260
+
261
+ // Initialize reserved secrets for edge functions
262
+ // Add INSFORGE_INTERNAL_URL for Deno-to-backend container communication
263
+ const insforgInternalUrl = 'http://insforge:7130';
264
+ const existingInternalUrlSecret = await secretService.getSecretByKey('INSFORGE_INTERNAL_URL');
265
+
266
+ if (existingInternalUrlSecret === null) {
267
+ await secretService.createSecret({
268
+ key: 'INSFORGE_INTERNAL_URL',
269
+ isReserved: true,
270
+ value: insforgInternalUrl,
271
+ });
272
+ logger.info('āœ… INSFORGE_INTERNAL_URL secret initialized');
273
+ }
274
+
275
+ // Add ANON_KEY for public edge function access
276
+ const existingAnonKeySecret = await secretService.getSecretByKey('ANON_KEY');
277
+
278
+ if (existingAnonKeySecret === null) {
279
+ const tokenManager = TokenManager.getInstance();
280
+ const anonToken = tokenManager.generateAnonToken();
281
+
282
+ await secretService.createSecret({
283
+ key: 'ANON_KEY',
284
+ isReserved: true,
285
+ value: anonToken,
286
+ });
287
+ logger.info('āœ… ANON_KEY secret initialized');
288
+ }
289
+
290
+ logger.info(`API key generated: ${apiKey}`);
291
+ logger.info(`Setup complete:
292
+ - Save this API key for your apps!
293
+ - Dashboard: http://localhost:7131
294
+ - API: http://localhost:7130/api
295
+ `);
296
+ } catch (error) {
297
+ logger.error('Error during setup', {
298
+ error: error instanceof Error ? error.message : String(error),
299
+ });
300
+ }
301
+ }