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,284 +1,317 @@
1
- import express, { Request, Response, NextFunction } from 'express';
2
- import cors from 'cors';
3
- import rateLimit from 'express-rate-limit';
4
- import dotenv from 'dotenv';
5
- import path from 'path';
6
- import { fileURLToPath } from 'url';
7
- import fs from 'fs';
8
- import authRouter from '@/api/routes/auth/index.routes.js';
9
- import databaseRouter from '@/api/routes/database/index.routes.js';
10
- import { storageRouter } from '@/api/routes/storage/index.routes.js';
11
- import { metadataRouter } from '@/api/routes/metadata/index.routes.js';
12
- import { logsRouter } from '@/api/routes/logs/index.routes.js';
13
- import { docsRouter } from '@/api/routes/docs/index.routes.js';
14
- import functionsRouter from '@/api/routes/functions/index.routes.js';
15
- import secretsRouter from '@/api/routes/secrets/index.routes.js';
16
- import { usageRouter } from '@/api/routes/usage/index.routes.js';
17
- import { aiRouter } from '@/api/routes/ai/index.routes.js';
18
- import { errorMiddleware } from '@/api/middlewares/error.js';
19
- import fetch, { HeadersInit } from 'node-fetch';
20
- import { DatabaseManager } from '@/infra/database/database.manager.js';
21
- import { LogService } from '@/services/logs/log.service.js';
22
- import { StorageService } from '@/services/storage/storage.service.js';
23
- import { SocketManager } from '@/infra/socket/socket.manager.js';
24
- import { seedBackend } from '@/utils/seed.js';
25
- import logger from '@/utils/logger.js';
26
- import { isProduction } from './utils/environment.js';
27
- import packageJson from '../../package.json';
28
-
29
- const __filename = fileURLToPath(import.meta.url);
30
- const __dirname = path.dirname(__filename);
31
-
32
- // Load .env file from the root directory (parent of backend)
33
- const envPath = path.resolve(__dirname, '../../.env');
34
- if (fs.existsSync(envPath)) {
35
- dotenv.config({ path: envPath });
36
- } else {
37
- // Fallback to default behavior (looks in current working directory)
38
- dotenv.config();
39
- }
40
-
41
- export async function createApp() {
42
- // Initialize database first
43
- const dbManager = DatabaseManager.getInstance();
44
- await dbManager.initialize(); // create data/app.db
45
-
46
- // Initialize storage service
47
- const storageService = StorageService.getInstance();
48
- await storageService.initialize(); // create data/storage
49
-
50
- // Initialize logs service
51
- const logService = LogService.getInstance();
52
- await logService.initialize(); // connect to CloudWatch
53
-
54
- const app = express();
55
-
56
- // Enable trust proxy setting for rate limiting behind proxies/load balancers
57
- app.set('trust proxy', true);
58
-
59
- const limiter = rateLimit({
60
- windowMs: 15 * 60 * 1000,
61
- max: 1000,
62
- message: 'Too many requests from this IP',
63
- });
64
-
65
- // Basic middleware
66
- app.use(
67
- cors({
68
- origin: true, // Allow all origins (matches Better Auth's trustedOrigins: ['*'])
69
- credentials: true, // Allow cookies/credentials
70
- })
71
- );
72
- if (isProduction()) {
73
- app.use(limiter);
74
- }
75
- app.use((req: Request, res: Response, next: NextFunction) => {
76
- const startTime = Date.now();
77
- const originalSend = res.send;
78
- const originalJson = res.json;
79
-
80
- // Track response size
81
- let responseSize = 0;
82
-
83
- // Override send method
84
- res.send = function (
85
- data: string | Buffer | Record<string, unknown> | unknown[] | number | boolean
86
- ) {
87
- if (data !== undefined && data !== null) {
88
- if (typeof data === 'string') {
89
- responseSize = Buffer.byteLength(data);
90
- } else if (Buffer.isBuffer(data)) {
91
- responseSize = data.length;
92
- } else if (typeof data === 'number' || typeof data === 'boolean') {
93
- responseSize = Buffer.byteLength(String(data));
94
- } else {
95
- try {
96
- responseSize = Buffer.byteLength(JSON.stringify(data));
97
- } catch {
98
- // Handle circular references or unstringifiable objects
99
- responseSize = 0;
100
- }
101
- }
102
- }
103
- return originalSend.call(this, data);
104
- };
105
-
106
- // Override json method
107
- res.json = function (
108
- data: Record<string, unknown> | unknown[] | string | number | boolean | null
109
- ) {
110
- if (data !== undefined) {
111
- try {
112
- responseSize = Buffer.byteLength(JSON.stringify(data));
113
- } catch {
114
- // Handle circular references or unstringifiable objects
115
- responseSize = 0;
116
- }
117
- }
118
- return originalJson.call(this, data);
119
- };
120
-
121
- // Log after response is finished
122
- res.on('finish', () => {
123
- // Skip logging for logs endpoints to avoid infinite loops
124
- if (req.path.includes('/logs/')) {
125
- return;
126
- }
127
-
128
- const duration = Date.now() - startTime;
129
- logger.info('HTTP Request', {
130
- method: req.method,
131
- path: req.path,
132
- status: res.statusCode,
133
- size: responseSize,
134
- duration: `${duration}ms`,
135
- ip: req.ip || req.socket.remoteAddress,
136
- userAgent: req.headers['user-agent'],
137
- timestamp: new Date().toISOString(),
138
- });
139
- });
140
-
141
- next();
142
- });
143
-
144
- // Apply JSON middleware
145
- app.use(express.json({ limit: '100mb' }));
146
- app.use(express.urlencoded({ extended: true, limit: '10mb' }));
147
-
148
- // Create API router and mount all API routes under /api
149
- const apiRouter = express.Router();
150
-
151
- apiRouter.get('/health', (_req: Request, res: Response) => {
152
- // Traditional REST: return data directly
153
- const version = packageJson.version;
154
- res.json({
155
- status: 'ok',
156
- version,
157
- service: 'Insforge OSS Backend',
158
- timestamp: new Date().toISOString(),
159
- });
160
- });
161
-
162
- // Mount all routes
163
- apiRouter.use('/auth', authRouter);
164
- apiRouter.use('/database', databaseRouter);
165
- apiRouter.use('/storage', storageRouter);
166
- apiRouter.use('/metadata', metadataRouter);
167
- apiRouter.use('/logs', logsRouter);
168
- apiRouter.use('/docs', docsRouter);
169
- apiRouter.use('/functions', functionsRouter);
170
- apiRouter.use('/secrets', secretsRouter);
171
- apiRouter.use('/usage', usageRouter);
172
- apiRouter.use('/ai', aiRouter);
173
-
174
- // Mount all API routes under /api prefix
175
- app.use('/api', apiRouter);
176
-
177
- // Proxy function execution to Deno runtime
178
- app.all('/functions/:slug', async (req: Request, res: Response) => {
179
- try {
180
- const { slug } = req.params;
181
- const denoUrl = process.env.DENO_RUNTIME_URL || 'http://localhost:7133';
182
-
183
- // Simple direct proxy - just pass everything through
184
- const response = await fetch(
185
- `${denoUrl}/${slug}${req.url.includes('?') ? req.url.substring(req.url.indexOf('?')) : ''}`,
186
- {
187
- method: req.method,
188
- headers: req.headers as HeadersInit,
189
- body: ['GET', 'HEAD'].includes(req.method) ? undefined : JSON.stringify(req.body),
190
- }
191
- );
192
-
193
- // Get response text
194
- const responseText = await response.text();
195
-
196
- res
197
- .status(response.status)
198
- .set('Content-Type', response.headers.get('content-type') || 'application/json')
199
- .set('Access-Control-Allow-Origin', '*')
200
- .send(responseText);
201
- } catch (error) {
202
- logger.error('Failed to proxy to Deno runtime', {
203
- error: error instanceof Error ? error.message : String(error),
204
- stack: error instanceof Error ? error.stack : undefined,
205
- slug: req.params.slug,
206
- });
207
-
208
- // Return the actual error from Deno or connection error
209
- const errorMessage = error instanceof Error ? error.message : String(error);
210
- res.status(502).json({
211
- error: errorMessage,
212
- });
213
- }
214
- });
215
-
216
- // Serve auth app
217
- const authAppPath = path.join(__dirname, 'auth');
218
- if (fs.existsSync(authAppPath)) {
219
- app.use('/auth', express.static(authAppPath));
220
- app.get('/auth*', (_req: Request, res: Response) => {
221
- res.sendFile(path.join(authAppPath, 'index.html'));
222
- });
223
- } else if (!isProduction()) {
224
- const authAppUrl = process.env.AUTH_APP_URL || 'http://localhost:7132';
225
- logger.info('Auth app not built, proxying to development server', { authAppUrl });
226
- }
227
-
228
- // Serve main frontend if it exists
229
- const frontendPath = path.join(__dirname, 'frontend');
230
- if (fs.existsSync(frontendPath)) {
231
- app.use(express.static(frontendPath, { index: false }));
232
- // Catch all handler for SPA routes
233
- app.get(['/cloud*', '/dashboard*'], (_req: Request, res: Response) => {
234
- res.sendFile(path.join(frontendPath, 'index.html'));
235
- });
236
- } else {
237
- // Catch-all for 404 errors - Traditional REST format
238
- app.use('*', (req: Request, res: Response) => {
239
- res.status(404).json({
240
- error: 'NOT_FOUND',
241
- message: `Endpoint ${req.originalUrl} not found`,
242
- statusCode: 404,
243
- nextActions: 'Please check the API documentation for available endpoints',
244
- });
245
- });
246
- }
247
-
248
- app.use(errorMiddleware);
249
- await seedBackend();
250
-
251
- return app;
252
- }
253
-
254
- // Use PORT from environment variable, fallback to 7130
255
- const PORT = parseInt(process.env.PORT || '7130');
256
-
257
- async function initializeServer() {
258
- try {
259
- const app = await createApp();
260
- const server = app.listen(PORT, () => {
261
- logger.info(`Backend API service listening on port ${PORT}`);
262
- });
263
-
264
- // Initialize Socket.IO service
265
- const socketService = SocketManager.getInstance();
266
- socketService.initialize(server);
267
- } catch (error) {
268
- logger.error('Failed to initialize server', {
269
- error: error instanceof Error ? error.message : String(error),
270
- stack: error instanceof Error ? error.stack : undefined,
271
- });
272
- process.exit(1);
273
- }
274
- }
275
-
276
- void initializeServer();
277
-
278
- function cleanup() {
279
- logger.info('Shutting down gracefully...');
280
- process.exit(0);
281
- }
282
-
283
- process.on('SIGINT', cleanup);
284
- process.on('SIGTERM', cleanup);
1
+ import express, { Request, Response, NextFunction } from 'express';
2
+ import cors from 'cors';
3
+ import cookieParser from 'cookie-parser';
4
+ import rateLimit from 'express-rate-limit';
5
+ import dotenv from 'dotenv';
6
+ import path from 'path';
7
+ import { fileURLToPath } from 'url';
8
+ import fs from 'fs';
9
+ import authRouter from '@/api/routes/auth/index.routes.js';
10
+ import databaseRouter from '@/api/routes/database/index.routes.js';
11
+ import { storageRouter } from '@/api/routes/storage/index.routes.js';
12
+ import { metadataRouter } from '@/api/routes/metadata/index.routes.js';
13
+ import { logsRouter } from '@/api/routes/logs/index.routes.js';
14
+ import { docsRouter } from '@/api/routes/docs/index.routes.js';
15
+ import functionsRouter from '@/api/routes/functions/index.routes.js';
16
+ import secretsRouter from '@/api/routes/secrets/index.routes.js';
17
+ import { usageRouter } from '@/api/routes/usage/index.routes.js';
18
+ import { aiRouter } from '@/api/routes/ai/index.routes.js';
19
+ import { realtimeRouter } from '@/api/routes/realtime/index.routes.js';
20
+ import { emailRouter } from '@/api/routes/email/index.routes.js';
21
+ import { errorMiddleware } from '@/api/middlewares/error.js';
22
+ import { RealtimeManager } from '@/infra/realtime/realtime.manager.js';
23
+ import fetch, { HeadersInit } from 'node-fetch';
24
+ import { DatabaseManager } from '@/infra/database/database.manager.js';
25
+ import { LogService } from '@/services/logs/log.service.js';
26
+ import { StorageService } from '@/services/storage/storage.service.js';
27
+ import { SocketManager } from '@/infra/socket/socket.manager.js';
28
+ import { seedBackend } from '@/utils/seed.js';
29
+ import logger from '@/utils/logger.js';
30
+ import { initSqlParser } from '@/utils/sql-parser.js';
31
+ import { isProduction } from './utils/environment.js';
32
+ import packageJson from '../../package.json';
33
+
34
+ const __filename = fileURLToPath(import.meta.url);
35
+ const __dirname = path.dirname(__filename);
36
+
37
+ // Load .env file from the root directory (parent of backend)
38
+ const envPath = path.resolve(__dirname, '../../.env');
39
+ if (fs.existsSync(envPath)) {
40
+ dotenv.config({ path: envPath });
41
+ } else {
42
+ // Fallback to default behavior (looks in current working directory)
43
+ dotenv.config();
44
+ }
45
+
46
+ export async function createApp() {
47
+ // Initialize database first
48
+ const dbManager = DatabaseManager.getInstance();
49
+ await dbManager.initialize(); // create data/app.db
50
+
51
+ // Initialize storage service
52
+ const storageService = StorageService.getInstance();
53
+ await storageService.initialize(); // create data/storage
54
+
55
+ // Initialize logs service
56
+ const logService = LogService.getInstance();
57
+ await logService.initialize(); // connect to CloudWatch
58
+
59
+ // Initialize SQL parser WASM module
60
+ await initSqlParser();
61
+
62
+ const app = express();
63
+
64
+ // Enable trust proxy setting for rate limiting behind proxies/load balancers
65
+ app.set('trust proxy', true);
66
+
67
+ const limiter = rateLimit({
68
+ windowMs: 15 * 60 * 1000,
69
+ max: 1000,
70
+ message: 'Too many requests from this IP',
71
+ });
72
+
73
+ // Basic middleware
74
+ app.use(
75
+ cors({
76
+ origin: true, // Allow all origins (matches Better Auth's trustedOrigins: ['*'])
77
+ credentials: true, // Allow cookies/credentials
78
+ })
79
+ );
80
+ app.use(cookieParser()); // Parse cookies for refresh token handling
81
+ if (isProduction()) {
82
+ app.use(limiter);
83
+ }
84
+ app.use((req: Request, res: Response, next: NextFunction) => {
85
+ const startTime = Date.now();
86
+ const originalSend = res.send;
87
+ const originalJson = res.json;
88
+
89
+ // Track response size
90
+ let responseSize = 0;
91
+
92
+ // Override send method
93
+ res.send = function (
94
+ data: string | Buffer | Record<string, unknown> | unknown[] | number | boolean
95
+ ) {
96
+ if (data !== undefined && data !== null) {
97
+ if (typeof data === 'string') {
98
+ responseSize = Buffer.byteLength(data);
99
+ } else if (Buffer.isBuffer(data)) {
100
+ responseSize = data.length;
101
+ } else if (typeof data === 'number' || typeof data === 'boolean') {
102
+ responseSize = Buffer.byteLength(String(data));
103
+ } else {
104
+ try {
105
+ responseSize = Buffer.byteLength(JSON.stringify(data));
106
+ } catch {
107
+ // Handle circular references or unstringifiable objects
108
+ responseSize = 0;
109
+ }
110
+ }
111
+ }
112
+ return originalSend.call(this, data);
113
+ };
114
+
115
+ // Override json method
116
+ res.json = function (
117
+ data: Record<string, unknown> | unknown[] | string | number | boolean | null
118
+ ) {
119
+ if (data !== undefined) {
120
+ try {
121
+ responseSize = Buffer.byteLength(JSON.stringify(data));
122
+ } catch {
123
+ // Handle circular references or unstringifiable objects
124
+ responseSize = 0;
125
+ }
126
+ }
127
+ return originalJson.call(this, data);
128
+ };
129
+
130
+ // Log after response is finished
131
+ res.on('finish', () => {
132
+ // Skip logging for logs endpoints to avoid infinite loops
133
+ if (req.path.includes('/logs/')) {
134
+ return;
135
+ }
136
+
137
+ const duration = Date.now() - startTime;
138
+ logger.info('HTTP Request', {
139
+ method: req.method,
140
+ path: req.path,
141
+ status: res.statusCode,
142
+ size: responseSize,
143
+ duration: `${duration}ms`,
144
+ ip: req.ip || req.socket.remoteAddress,
145
+ userAgent: req.headers['user-agent'],
146
+ timestamp: new Date().toISOString(),
147
+ });
148
+ });
149
+
150
+ next();
151
+ });
152
+
153
+ // Apply JSON middleware
154
+ app.use(express.json({ limit: '100mb' }));
155
+ app.use(express.urlencoded({ extended: true, limit: '10mb' }));
156
+
157
+ // Create API router and mount all API routes under /api
158
+ const apiRouter = express.Router();
159
+
160
+ apiRouter.get('/health', (_req: Request, res: Response) => {
161
+ const version = packageJson.version;
162
+ res.json({
163
+ status: 'ok',
164
+ version,
165
+ service: 'Insforge OSS Backend',
166
+ timestamp: new Date().toISOString(),
167
+ });
168
+ });
169
+
170
+ // Mount all routes
171
+ apiRouter.use('/auth', authRouter);
172
+ apiRouter.use('/database', databaseRouter);
173
+ apiRouter.use('/storage', storageRouter);
174
+ apiRouter.use('/metadata', metadataRouter);
175
+ apiRouter.use('/logs', logsRouter);
176
+ apiRouter.use('/docs', docsRouter);
177
+ apiRouter.use('/functions', functionsRouter);
178
+ apiRouter.use('/secrets', secretsRouter);
179
+ apiRouter.use('/usage', usageRouter);
180
+ apiRouter.use('/ai', aiRouter);
181
+ apiRouter.use('/realtime', realtimeRouter);
182
+ apiRouter.use('/email', emailRouter);
183
+
184
+ // Mount all API routes under /api prefix
185
+ app.use('/api', apiRouter);
186
+
187
+ // Proxy function execution to Deno runtime
188
+ app.all('/functions/:slug', async (req: Request, res: Response) => {
189
+ try {
190
+ const { slug } = req.params;
191
+ const denoUrl = process.env.DENO_RUNTIME_URL || 'http://localhost:7133';
192
+
193
+ // Simple direct proxy - just pass everything through
194
+ const response = await fetch(
195
+ `${denoUrl}/${slug}${req.url.includes('?') ? req.url.substring(req.url.indexOf('?')) : ''}`,
196
+ {
197
+ method: req.method,
198
+ headers: req.headers as HeadersInit,
199
+ body: ['GET', 'HEAD'].includes(req.method) ? undefined : JSON.stringify(req.body),
200
+ }
201
+ );
202
+
203
+ // Get response text
204
+ const responseText = await response.text();
205
+
206
+ res
207
+ .status(response.status)
208
+ .set('Content-Type', response.headers.get('content-type') || 'application/json')
209
+ .set('Access-Control-Allow-Origin', '*')
210
+ .send(responseText);
211
+ } catch (error) {
212
+ logger.error('Failed to proxy to Deno runtime', {
213
+ error: error instanceof Error ? error.message : String(error),
214
+ stack: error instanceof Error ? error.stack : undefined,
215
+ slug: req.params.slug,
216
+ });
217
+
218
+ // Return the actual error from Deno or connection error
219
+ const errorMessage = error instanceof Error ? error.message : String(error);
220
+ res.status(502).json({
221
+ error: errorMessage,
222
+ });
223
+ }
224
+ });
225
+
226
+ // Serve auth app
227
+ const authAppPath = path.join(__dirname, 'auth');
228
+ if (fs.existsSync(authAppPath)) {
229
+ app.use('/auth', express.static(authAppPath));
230
+ app.get('/auth*', (_req: Request, res: Response) => {
231
+ res.sendFile(path.join(authAppPath, 'index.html'));
232
+ });
233
+ } else if (!isProduction()) {
234
+ const authAppUrl = process.env.AUTH_APP_URL || 'http://localhost:7132';
235
+ logger.info('Auth app not built, proxying to development server', { authAppUrl });
236
+ }
237
+
238
+ // Serve main frontend if it exists
239
+ const frontendPath = path.join(__dirname, 'frontend');
240
+ if (fs.existsSync(frontendPath)) {
241
+ app.use(express.static(frontendPath, { index: false }));
242
+ // Catch all handler for SPA routes
243
+ app.get(['/cloud*', '/dashboard*'], (_req: Request, res: Response) => {
244
+ res.sendFile(path.join(frontendPath, 'index.html'));
245
+ });
246
+ } else {
247
+ // Catch-all for 404 errors - Traditional REST format
248
+ app.use('*', (req: Request, res: Response) => {
249
+ res.status(404).json({
250
+ error: 'NOT_FOUND',
251
+ message: `Endpoint ${req.originalUrl} not found`,
252
+ statusCode: 404,
253
+ nextActions: 'Please check the API documentation for available endpoints',
254
+ });
255
+ });
256
+ }
257
+
258
+ app.use(errorMiddleware);
259
+ await seedBackend();
260
+
261
+ return app;
262
+ }
263
+
264
+ // Use PORT from environment variable, fallback to 7130
265
+ const PORT = parseInt(process.env.PORT || '7130');
266
+
267
+ async function initializeServer() {
268
+ try {
269
+ const app = await createApp();
270
+ const server = app.listen(PORT, () => {
271
+ logger.info(`Backend API service listening on port ${PORT}`);
272
+ });
273
+
274
+ // Initialize Socket.IO service
275
+ const socketService = SocketManager.getInstance();
276
+ socketService.initialize(server);
277
+
278
+ // Initialize RealtimeManager (pg_notify listener)
279
+ const realtimeManager = RealtimeManager.getInstance();
280
+ await realtimeManager.initialize();
281
+ } catch (error) {
282
+ logger.error('Failed to initialize server', {
283
+ error: error instanceof Error ? error.message : String(error),
284
+ stack: error instanceof Error ? error.stack : undefined,
285
+ });
286
+ process.exit(1);
287
+ }
288
+ }
289
+
290
+ void initializeServer();
291
+
292
+ async function cleanup() {
293
+ logger.info('Shutting down gracefully...');
294
+
295
+ try {
296
+ const realtimeManager = RealtimeManager.getInstance();
297
+ await realtimeManager.close();
298
+ } catch (error) {
299
+ logger.error('Error closing RealtimeManager', {
300
+ error: error instanceof Error ? error.message : String(error),
301
+ });
302
+ }
303
+
304
+ try {
305
+ const socketService = SocketManager.getInstance();
306
+ socketService.close();
307
+ } catch (error) {
308
+ logger.error('Error closing SocketManager', {
309
+ error: error instanceof Error ? error.message : String(error),
310
+ });
311
+ }
312
+
313
+ process.exit(0);
314
+ }
315
+
316
+ process.on('SIGINT', () => void cleanup());
317
+ process.on('SIGTERM', () => void cleanup());
@@ -1,5 +1,5 @@
1
1
  import { isCloudEnvironment } from '@/utils/environment.js';
2
- import { AIClientService } from '@/providers/ai/openrouter.provider.js';
2
+ import { OpenRouterProvider } from '@/providers/ai/openrouter.provider.js';
3
3
  import type { RawOpenRouterModel } from '@/types/ai.js';
4
4
  import type { AIModelSchema } from '@insforge/shared-schemas';
5
5
  import { calculatePriceLevel, filterAndSortModalities, getProviderOrder } from './helpers.js';
@@ -10,15 +10,15 @@ export class AIModelService {
10
10
  * Fetches from cloud API if in cloud environment, otherwise from OpenRouter directly
11
11
  */
12
12
  static async getModels(): Promise<AIModelSchema[]> {
13
- const credentialsService = AIClientService.getInstance();
14
- const configured = credentialsService.isConfigured();
13
+ const openRouterProvider = OpenRouterProvider.getInstance();
14
+ const configured = openRouterProvider.isConfigured();
15
15
 
16
16
  if (!configured) {
17
17
  return [];
18
18
  }
19
19
 
20
- // Get API key from credentials service
21
- const apiKey = await credentialsService.getApiKey();
20
+ // Get API key from OpenRouter provider
21
+ const apiKey = await openRouterProvider.getApiKey();
22
22
 
23
23
  // Determine the API endpoint based on environment
24
24
  const apiUrl = isCloudEnvironment()