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
@@ -1,11 +1,21 @@
1
1
  import { Pool } from 'pg';
2
- import { DatabaseManager } from '@/core/database/manager.js';
2
+ import { DatabaseManager } from '@/infra/database/database.manager.js';
3
3
  import logger from '@/utils/logger.js';
4
4
  import { AIConfigurationSchema, AIConfigurationWithUsageSchema } from '@insforge/shared-schemas';
5
5
 
6
6
  export class AIConfigService {
7
+ private static instance: AIConfigService;
7
8
  private pool: Pool | null = null;
8
9
 
10
+ private constructor() {}
11
+
12
+ public static getInstance(): AIConfigService {
13
+ if (!AIConfigService.instance) {
14
+ AIConfigService.instance = new AIConfigService();
15
+ }
16
+ return AIConfigService.instance;
17
+ }
18
+
9
19
  private getPool(): Pool {
10
20
  if (!this.pool) {
11
21
  this.pool = DatabaseManager.getInstance().getPool();
@@ -20,9 +30,8 @@ export class AIConfigService {
20
30
  modelId: string,
21
31
  systemPrompt?: string
22
32
  ): Promise<{ id: string }> {
23
- const client = await this.getPool().connect();
24
33
  try {
25
- const result = await client.query(
34
+ const result = await this.getPool().query(
26
35
  `INSERT INTO _ai_configs (input_modality, output_modality, provider, model_id, system_prompt)
27
36
  VALUES ($1, $2, $3, $4, $5)
28
37
  RETURNING id`,
@@ -34,17 +43,14 @@ export class AIConfigService {
34
43
  } catch (error) {
35
44
  logger.error('Failed to create AI configuration', { error });
36
45
  throw new Error('Failed to create AI configuration');
37
- } finally {
38
- client.release();
39
46
  }
40
47
  }
41
48
 
42
49
  async findAll(): Promise<AIConfigurationWithUsageSchema[]> {
43
- const client = await this.getPool().connect();
44
50
  try {
45
51
  // Use a single query with aggregation to get configs with usage stats
46
- const result = await client.query(
47
- `SELECT
52
+ const result = await this.getPool().query(
53
+ `SELECT
48
54
  c.id,
49
55
  c.input_modality as "inputModality",
50
56
  c.output_modality as "outputModality",
@@ -63,7 +69,7 @@ export class AIConfigService {
63
69
  );
64
70
 
65
71
  return result.rows.map((row) => ({
66
- id: row.id,
72
+ id: row.id, // UUID
67
73
  inputModality: row.inputModality,
68
74
  outputModality: row.outputModality,
69
75
  provider: row.provider,
@@ -80,16 +86,13 @@ export class AIConfigService {
80
86
  } catch (error) {
81
87
  logger.error('Failed to fetch AI configurations with usage', { error });
82
88
  throw new Error('Failed to fetch AI configurations');
83
- } finally {
84
- client.release();
85
89
  }
86
90
  }
87
91
 
88
92
  async update(id: string, systemPrompt: string | null): Promise<boolean> {
89
- const client = await this.getPool().connect();
90
93
  try {
91
- const result = await client.query(
92
- `UPDATE _ai_configs
94
+ const result = await this.getPool().query(
95
+ `UPDATE _ai_configs
93
96
  SET system_prompt = $1, updated_at = NOW()
94
97
  WHERE id = $2`,
95
98
  [systemPrompt, id]
@@ -103,15 +106,12 @@ export class AIConfigService {
103
106
  } catch (error) {
104
107
  logger.error('Failed to update AI configuration', { error, id });
105
108
  throw new Error('Failed to update AI configuration');
106
- } finally {
107
- client.release();
108
109
  }
109
110
  }
110
111
 
111
112
  async delete(id: string): Promise<boolean> {
112
- const client = await this.getPool().connect();
113
113
  try {
114
- const result = await client.query('DELETE FROM _ai_configs WHERE id = $1', [id]);
114
+ const result = await this.getPool().query('DELETE FROM _ai_configs WHERE id = $1', [id]);
115
115
 
116
116
  const success = (result.rowCount ?? 0) > 0;
117
117
  if (success) {
@@ -121,15 +121,12 @@ export class AIConfigService {
121
121
  } catch (error) {
122
122
  logger.error('Failed to delete AI configuration', { error, id });
123
123
  throw new Error('Failed to delete AI configuration');
124
- } finally {
125
- client.release();
126
124
  }
127
125
  }
128
126
 
129
127
  async findByModelId(modelId: string): Promise<AIConfigurationSchema | null> {
130
- const client = await this.getPool().connect();
131
128
  try {
132
- const result = await client.query(
129
+ const result = await this.getPool().query(
133
130
  `SELECT id, input_modality as "inputModality", output_modality as "outputModality", provider, model_id as "modelId", system_prompt as "systemPrompt", created_at, updated_at
134
131
  FROM _ai_configs
135
132
  WHERE model_id = $1`,
@@ -155,8 +152,6 @@ export class AIConfigService {
155
152
  modelId,
156
153
  });
157
154
  throw new Error('Failed to fetch AI configuration');
158
- } finally {
159
- client.release();
160
155
  }
161
156
  }
162
157
 
@@ -0,0 +1,60 @@
1
+ import { isCloudEnvironment } from '@/utils/environment.js';
2
+ import { OpenRouterProvider } from '@/providers/ai/openrouter.provider.js';
3
+ import type { RawOpenRouterModel } from '@/types/ai.js';
4
+ import type { AIModelSchema } from '@insforge/shared-schemas';
5
+ import { calculatePriceLevel, filterAndSortModalities, getProviderOrder } from './helpers.js';
6
+
7
+ export class AIModelService {
8
+ /**
9
+ * Get all available AI models
10
+ * Fetches from cloud API if in cloud environment, otherwise from OpenRouter directly
11
+ */
12
+ static async getModels(): Promise<AIModelSchema[]> {
13
+ const openRouterProvider = OpenRouterProvider.getInstance();
14
+ const configured = openRouterProvider.isConfigured();
15
+
16
+ if (!configured) {
17
+ return [];
18
+ }
19
+
20
+ // Get API key from OpenRouter provider
21
+ const apiKey = await openRouterProvider.getApiKey();
22
+
23
+ // Determine the API endpoint based on environment
24
+ const apiUrl = isCloudEnvironment()
25
+ ? 'https://api.insforge.dev/ai/v1/models'
26
+ : 'https://openrouter.ai/api/v1/models/user';
27
+
28
+ // Fetch models from the appropriate endpoint
29
+ const response = await fetch(apiUrl, {
30
+ headers: {
31
+ Authorization: `Bearer ${apiKey}`,
32
+ },
33
+ });
34
+
35
+ if (!response.ok) {
36
+ throw new Error(`Failed to fetch models: ${response.statusText}`);
37
+ }
38
+
39
+ const data = (await response.json()) as { data: RawOpenRouterModel[] };
40
+ const rawModels = data.data || [];
41
+
42
+ const models: AIModelSchema[] = rawModels
43
+ .map((rawModel) => ({
44
+ id: rawModel.id, // OpenRouter provided model ID
45
+ modelId: rawModel.id,
46
+ provider: 'openrouter',
47
+ inputModality: filterAndSortModalities(rawModel.architecture?.input_modalities || []),
48
+ outputModality: filterAndSortModalities(rawModel.architecture?.output_modalities || []),
49
+ priceLevel: calculatePriceLevel(rawModel.pricing),
50
+ }))
51
+ .sort((a, b) => {
52
+ const [aCompany = '', bCompany = ''] = [a.id.split('/')[0], b.id.split('/')[0]];
53
+
54
+ const orderDiff = getProviderOrder(aCompany) - getProviderOrder(bCompany);
55
+ return orderDiff !== 0 ? orderDiff : a.id.localeCompare(b.id);
56
+ });
57
+
58
+ return models || [];
59
+ }
60
+ }
@@ -1,5 +1,5 @@
1
1
  import { Pool } from 'pg';
2
- import { DatabaseManager } from '@/core/database/manager.js';
2
+ import { DatabaseManager } from '@/infra/database/database.manager.js';
3
3
  import logger from '@/utils/logger.js';
4
4
  import type {
5
5
  AIUsageDataSchema,
@@ -9,8 +9,18 @@ import type {
9
9
  } from '@insforge/shared-schemas';
10
10
 
11
11
  export class AIUsageService {
12
+ private static instance: AIUsageService;
12
13
  private pool: Pool | null = null;
13
14
 
15
+ private constructor() {}
16
+
17
+ public static getInstance(): AIUsageService {
18
+ if (!AIUsageService.instance) {
19
+ AIUsageService.instance = new AIUsageService();
20
+ }
21
+ return AIUsageService.instance;
22
+ }
23
+
14
24
  private getPool(): Pool {
15
25
  if (!this.pool) {
16
26
  this.pool = DatabaseManager.getInstance().getPool();
@@ -19,9 +29,8 @@ export class AIUsageService {
19
29
  }
20
30
 
21
31
  async trackUsage(data: AIUsageDataSchema): Promise<{ id: string }> {
22
- const client = await this.getPool().connect();
23
32
  try {
24
- const result = await client.query(
33
+ const result = await this.getPool().query(
25
34
  `INSERT INTO _ai_usage (config_id, input_tokens, output_tokens, image_count, image_resolution)
26
35
  VALUES ($1, $2, $3, $4, $5)
27
36
  RETURNING id`,
@@ -46,8 +55,6 @@ export class AIUsageService {
46
55
  } catch (error) {
47
56
  logger.error('Failed to track AI usage', { error, data });
48
57
  throw new Error('Failed to track AI usage');
49
- } finally {
50
- client.release();
51
58
  }
52
59
  }
53
60
 
@@ -59,9 +66,8 @@ export class AIUsageService {
59
66
  ): Promise<{ id: string }> {
60
67
  const totalTokens = (inputTokens || 0) + (outputTokens || 0);
61
68
 
62
- const client = await this.getPool().connect();
63
69
  try {
64
- const usageResult = await client.query(
70
+ const usageResult = await this.getPool().query(
65
71
  `INSERT INTO _ai_usage (config_id, input_tokens, output_tokens, model_id)
66
72
  VALUES ($1, $2, $3, $4)
67
73
  RETURNING id`,
@@ -81,8 +87,6 @@ export class AIUsageService {
81
87
  } catch (error) {
82
88
  logger.error('Failed to track chat usage', { error, configId });
83
89
  throw new Error('Failed to track chat usage');
84
- } finally {
85
- client.release();
86
90
  }
87
91
  }
88
92
 
@@ -94,9 +98,8 @@ export class AIUsageService {
94
98
  outputTokens?: number,
95
99
  modelId?: string
96
100
  ): Promise<{ id: string }> {
97
- const client = await this.getPool().connect();
98
101
  try {
99
- const usageResult = await client.query(
102
+ const usageResult = await this.getPool().query(
100
103
  `INSERT INTO _ai_usage (config_id, image_count, image_resolution, input_tokens, output_tokens, model_id)
101
104
  VALUES ($1, $2, $3, $4, $5, $6)
102
105
  RETURNING id`,
@@ -124,8 +127,6 @@ export class AIUsageService {
124
127
  } catch (error) {
125
128
  logger.error('Failed to track image usage', { error, configId });
126
129
  throw new Error('Failed to track image usage');
127
- } finally {
128
- client.release();
129
130
  }
130
131
  }
131
132
 
@@ -134,10 +135,9 @@ export class AIUsageService {
134
135
  startDate?: Date,
135
136
  endDate?: Date
136
137
  ): Promise<AIUsageRecordSchema[]> {
137
- const client = await this.getPool().connect();
138
138
  try {
139
139
  let query = `
140
- SELECT id, config_id as "configId", input_tokens as "inputTokens",
140
+ SELECT id, config_id as "configId", input_tokens as "inputTokens",
141
141
  output_tokens as "outputTokens", image_count as "imageCount",
142
142
  image_resolution as "imageResolution", created_at as "createdAt"
143
143
  FROM _ai_usage
@@ -158,14 +158,12 @@ export class AIUsageService {
158
158
 
159
159
  query += ' ORDER BY created_at DESC';
160
160
 
161
- const result = await client.query(query, params);
161
+ const result = await this.getPool().query(query, params);
162
162
 
163
163
  return result.rows;
164
164
  } catch (error) {
165
165
  logger.error('Failed to fetch usage by config', { error, configId });
166
166
  throw new Error('Failed to fetch usage records');
167
- } finally {
168
- client.release();
169
167
  }
170
168
  }
171
169
 
@@ -174,10 +172,9 @@ export class AIUsageService {
174
172
  startDate?: Date,
175
173
  endDate?: Date
176
174
  ): Promise<AIUsageSummarySchema> {
177
- const client = await this.getPool().connect();
178
175
  try {
179
176
  let query = `
180
- SELECT
177
+ SELECT
181
178
  COALESCE(SUM(input_tokens), 0) as "totalInputTokens",
182
179
  COALESCE(SUM(output_tokens), 0) as "totalOutputTokens",
183
180
  COALESCE(SUM(COALESCE(input_tokens, 0) + COALESCE(output_tokens, 0)), 0) as "totalTokens",
@@ -204,7 +201,7 @@ export class AIUsageService {
204
201
  query += ` AND created_at <= $${params.length}`;
205
202
  }
206
203
 
207
- const result = await client.query(query, params);
204
+ const result = await this.getPool().query(query, params);
208
205
 
209
206
  return {
210
207
  totalInputTokens: parseInt(result.rows[0].totalInputTokens),
@@ -216,8 +213,6 @@ export class AIUsageService {
216
213
  } catch (error) {
217
214
  logger.error('Failed to fetch usage summary', { error, configId });
218
215
  throw new Error('Failed to fetch usage summary');
219
- } finally {
220
- client.release();
221
216
  }
222
217
  }
223
218
 
@@ -227,21 +222,21 @@ export class AIUsageService {
227
222
  limit?: number,
228
223
  offset?: number
229
224
  ): Promise<ListAIUsageResponse> {
230
- const client = await this.getPool().connect();
231
225
  try {
232
226
  let query = `
233
- SELECT
234
- u.id,
235
- u.config_id as "configId",
236
- u.input_tokens as "inputTokens",
237
- u.output_tokens as "outputTokens",
227
+ SELECT
228
+ u.id,
229
+ u.config_id as "configId",
230
+ u.input_tokens as "inputTokens",
231
+ u.output_tokens as "outputTokens",
238
232
  u.image_count as "imageCount",
239
- u.image_resolution as "imageResolution",
233
+ u.image_resolution as "imageResolution",
240
234
  u.created_at as "createdAt",
241
235
  u.model_id as "modelId",
242
236
  COALESCE(u.model_id, c.model_id) as "model",
243
237
  c.provider,
244
- c.modality
238
+ c.input_modality as "inputModality",
239
+ c.output_modality as "outputModality"
245
240
  FROM _ai_usage u
246
241
  LEFT JOIN _ai_configs c ON u.config_id = c.id
247
242
  WHERE 1=1
@@ -260,7 +255,7 @@ export class AIUsageService {
260
255
  }
261
256
 
262
257
  const countQuery = `SELECT COUNT(*) as total FROM (${query}) as subquery`;
263
- const countResult = await client.query(countQuery, params);
258
+ const countResult = await this.getPool().query(countQuery, params);
264
259
 
265
260
  query += ' ORDER BY u.created_at DESC';
266
261
 
@@ -274,7 +269,7 @@ export class AIUsageService {
274
269
  query += ` OFFSET $${params.length}`;
275
270
  }
276
271
 
277
- const result = await client.query(query, params);
272
+ const result = await this.getPool().query(query, params);
278
273
 
279
274
  return {
280
275
  records: result.rows,
@@ -283,8 +278,6 @@ export class AIUsageService {
283
278
  } catch (error) {
284
279
  logger.error('Failed to fetch all usage records', { error });
285
280
  throw new Error('Failed to fetch usage records');
286
- } finally {
287
- client.release();
288
281
  }
289
282
  }
290
283
  }
@@ -1,19 +1,29 @@
1
1
  import OpenAI from 'openai';
2
- import { AIUsageService } from './usage';
3
- import { AIConfigService } from './config';
4
- import { AIClientService } from './client';
2
+ import { AIUsageService } from './ai-usage.service.js';
3
+ import { AIConfigService } from './ai-config.service.js';
4
+ import { OpenRouterProvider } from '@/providers/ai/openrouter.provider.js';
5
5
  import type {
6
6
  AIConfigurationSchema,
7
7
  ChatCompletionResponse,
8
8
  ChatMessageSchema,
9
9
  } from '@insforge/shared-schemas';
10
10
  import logger from '@/utils/logger.js';
11
- import { ChatCompletionOptions } from '@/types/ai';
11
+ import { ChatCompletionOptions } from '@/types/ai.js';
12
12
 
13
- export class ChatService {
14
- private aiUsageService = new AIUsageService();
15
- private aiConfigService = new AIConfigService();
16
- private aiCredentialsService = AIClientService.getInstance();
13
+ export class ChatCompletionService {
14
+ private static instance: ChatCompletionService;
15
+ private aiUsageService = AIUsageService.getInstance();
16
+ private aiConfigService = AIConfigService.getInstance();
17
+ private openRouterProvider = OpenRouterProvider.getInstance();
18
+
19
+ private constructor() {}
20
+
21
+ public static getInstance(): ChatCompletionService {
22
+ if (!ChatCompletionService.instance) {
23
+ ChatCompletionService.instance = new ChatCompletionService();
24
+ }
25
+ return ChatCompletionService.instance;
26
+ }
17
27
 
18
28
  /**
19
29
  * Format messages for OpenAI API with multimodal support
@@ -31,8 +41,8 @@ export class ChatService {
31
41
 
32
42
  // Format conversation messages
33
43
  for (const msg of messages) {
34
- // Check if message has images
35
- if (msg.images && msg.images.length > 0) {
44
+ // Check if message has images (legacy format), new format image is within the content array
45
+ if (msg.images && msg.images.length && typeof msg.content === 'string') {
36
46
  // Build multimodal content array
37
47
  const content = [
38
48
  { type: 'text', text: msg.content },
@@ -47,11 +57,11 @@ export class ChatService {
47
57
  content,
48
58
  } as OpenAI.Chat.ChatCompletionMessageParam);
49
59
  } else {
50
- // Simple text message
60
+ // Simple text message or new format (content array)
51
61
  formattedMessages.push({
52
62
  role: msg.role as 'system' | 'user' | 'assistant',
53
63
  content: msg.content,
54
- });
64
+ } as OpenAI.Chat.ChatCompletionMessageParam);
55
65
  }
56
66
  }
57
67
 
@@ -81,23 +91,24 @@ export class ChatService {
81
91
  options: ChatCompletionOptions
82
92
  ): Promise<ChatCompletionResponse> {
83
93
  try {
84
- // Get the client (handles validation and initialization automatically)
85
- const client = await this.aiCredentialsService.getClient();
86
-
87
94
  // Validate model and get config
88
95
  const aiConfig = await this.validateAndGetConfig(options.model);
89
96
 
90
97
  // Apply system prompt from config if available
91
98
  const formattedMessages = this.formatMessages(messages, aiConfig?.systemPrompt);
92
-
93
- const response = await client.chat.completions.create({
99
+ const request: OpenAI.Chat.ChatCompletionCreateParamsNonStreaming = {
94
100
  model: options.model,
95
101
  messages: formattedMessages,
96
102
  temperature: options.temperature ?? 0.7,
97
103
  max_tokens: options.maxTokens ?? 4096,
98
104
  top_p: options.topP,
99
105
  stream: false,
100
- });
106
+ };
107
+
108
+ // Send request with automatic renewal and retry logic
109
+ const response = await this.openRouterProvider.sendRequest((client) =>
110
+ client.chat.completions.create(request)
111
+ );
101
112
 
102
113
  // Extract token usage if available
103
114
  const tokenUsage = response.usage
@@ -122,7 +133,7 @@ export class ChatService {
122
133
  text: response.choices[0]?.message?.content || '',
123
134
  metadata: {
124
135
  model: options.model,
125
- ...tokenUsage,
136
+ usage: tokenUsage,
126
137
  },
127
138
  };
128
139
  } catch (error) {
@@ -146,23 +157,25 @@ export class ChatService {
146
157
  tokenUsage?: { promptTokens?: number; completionTokens?: number; totalTokens?: number };
147
158
  }> {
148
159
  try {
149
- // Get the client (handles validation and initialization automatically)
150
- const client = await this.aiCredentialsService.getClient();
151
-
152
160
  // Validate model and get config
153
161
  const aiConfig = await this.validateAndGetConfig(options.model);
154
162
 
155
163
  // Apply system prompt from config if available
156
164
  const formattedMessages = this.formatMessages(messages, aiConfig?.systemPrompt);
157
165
 
158
- const stream = await client.chat.completions.create({
166
+ const request: OpenAI.Chat.ChatCompletionCreateParamsStreaming = {
159
167
  model: options.model,
160
168
  messages: formattedMessages,
161
169
  temperature: options.temperature ?? 0.7,
162
170
  max_tokens: options.maxTokens ?? 4096,
163
171
  top_p: options.topP,
164
172
  stream: true,
165
- });
173
+ };
174
+
175
+ // Send request with automatic renewal and retry logic
176
+ const stream = await this.openRouterProvider.sendRequest((client) =>
177
+ client.chat.completions.create(request)
178
+ );
166
179
 
167
180
  const tokenUsage = {
168
181
  promptTokens: 0,
@@ -0,0 +1,64 @@
1
+ import type { RawOpenRouterModel } from '@/types/ai.js';
2
+ import type { ModalitySchema } from '@insforge/shared-schemas';
3
+
4
+ const MODALITY_ORDER = ['text', 'image', 'audio', 'video', 'file'];
5
+ const PROVIDER_ORDER: Record<string, number> = {
6
+ openai: 1,
7
+ anthropic: 2,
8
+ google: 3,
9
+ amazon: 4,
10
+ };
11
+
12
+ /**
13
+ * Sort modalities by predefined order
14
+ */
15
+ export function sortModalities(modalities: string[]): string[] {
16
+ return [...modalities].sort((a, b) => {
17
+ const aIndex = MODALITY_ORDER.indexOf(a);
18
+ const bIndex = MODALITY_ORDER.indexOf(b);
19
+ return aIndex - bIndex;
20
+ });
21
+ }
22
+
23
+ /**
24
+ * Filter to only supported modalities and sort
25
+ */
26
+ export function filterAndSortModalities(modalities: string[]): ModalitySchema[] {
27
+ const supportedModalities: ModalitySchema[] = ['text', 'image'];
28
+ const filtered = modalities.filter((m): m is ModalitySchema =>
29
+ supportedModalities.includes(m as ModalitySchema)
30
+ );
31
+ return sortModalities(filtered) as ModalitySchema[];
32
+ }
33
+
34
+ /**
35
+ * Calculate price level (0-3)
36
+ */
37
+ export function calculatePriceLevel(pricing: RawOpenRouterModel['pricing']): number {
38
+ if (!pricing) {
39
+ return 0;
40
+ }
41
+ if (pricing.prompt === '0' && pricing.completion === '0') {
42
+ return 0;
43
+ }
44
+
45
+ const promptCostPerToken = parseFloat(pricing.prompt) || 0;
46
+ const completionCostPerToken = parseFloat(pricing.completion) || 0;
47
+ const avgCostPer1M = ((promptCostPerToken + completionCostPerToken) / 2) * 1000000;
48
+
49
+ if (avgCostPer1M <= 3) {
50
+ return 1;
51
+ }
52
+ if (avgCostPer1M <= 15) {
53
+ return 2;
54
+ }
55
+ return 3;
56
+ }
57
+
58
+ /**
59
+ * Get provider order for sorting
60
+ */
61
+ export function getProviderOrder(modelId: string): number {
62
+ const companyId = modelId.split('/')[0]?.toLowerCase() || '';
63
+ return PROVIDER_ORDER[companyId] || 999;
64
+ }
@@ -1,20 +1,20 @@
1
1
  import OpenAI from 'openai';
2
2
 
3
- import { AIUsageService } from './usage';
4
- import { AIConfigService } from './config';
5
- import { AIClientService } from './client';
3
+ import { AIUsageService } from './ai-usage.service.js';
4
+ import { AIConfigService } from './ai-config.service.js';
5
+ import { OpenRouterProvider } from '@/providers/ai/openrouter.provider.js';
6
6
  import type {
7
7
  AIConfigurationSchema,
8
8
  ImageGenerationRequest,
9
9
  ImageGenerationResponse,
10
10
  } from '@insforge/shared-schemas';
11
11
  import logger from '@/utils/logger.js';
12
- import { OpenRouterImageMessage } from '@/types/ai';
12
+ import { OpenRouterImageMessage } from '@/types/ai.js';
13
13
 
14
- export class ImageService {
15
- private static aiUsageService = new AIUsageService();
16
- private static aiConfigService = new AIConfigService();
17
- private static aiCredentialsService = AIClientService.getInstance();
14
+ export class ImageGenerationService {
15
+ private static aiUsageService = AIUsageService.getInstance();
16
+ private static aiConfigService = AIConfigService.getInstance();
17
+ private static openRouterProvider = OpenRouterProvider.getInstance();
18
18
 
19
19
  /**
20
20
  * Validate model and get config
@@ -22,7 +22,7 @@ export class ImageService {
22
22
  private static async validateAndGetConfig(
23
23
  modelId: string
24
24
  ): Promise<AIConfigurationSchema | null> {
25
- const aiConfig = await ImageService.aiConfigService.findByModelId(modelId);
25
+ const aiConfig = await ImageGenerationService.aiConfigService.findByModelId(modelId);
26
26
  if (!aiConfig) {
27
27
  throw new Error(
28
28
  `Model ${modelId} is not enabled. Please contact your administrator to enable this model.`
@@ -36,11 +36,8 @@ export class ImageService {
36
36
  * @param options - Image generation options
37
37
  */
38
38
  static async generate(options: ImageGenerationRequest): Promise<ImageGenerationResponse> {
39
- // Get the client (handles validation and initialization automatically)
40
- const client = await this.aiCredentialsService.getClient();
41
-
42
39
  // Validate model and get config
43
- const aiConfig = await ImageService.validateAndGetConfig(options.model);
40
+ const aiConfig = await ImageGenerationService.validateAndGetConfig(options.model);
44
41
 
45
42
  const model = options.model;
46
43
 
@@ -77,10 +74,11 @@ export class ImageService {
77
74
  modalities: ['text', 'image'],
78
75
  };
79
76
 
80
- // Use OpenRouter's standard chat completions API
81
- // Cast the extended request to the base OpenAI type for the SDK call
82
- const response = (await client.chat.completions.create(
83
- request as OpenAI.Chat.ChatCompletionCreateParamsNonStreaming
77
+ // Send request with automatic renewal and retry logic
78
+ const response = (await this.openRouterProvider.sendRequest((client) =>
79
+ client.chat.completions.create(
80
+ request as OpenAI.Chat.ChatCompletionCreateParamsNonStreaming
81
+ )
84
82
  )) as OpenAI.Chat.ChatCompletion;
85
83
 
86
84
  // Initialize the result
@@ -99,7 +97,7 @@ export class ImageService {
99
97
  };
100
98
 
101
99
  // Process the OpenAI-compatible response
102
- if (response.choices && response.choices.length > 0) {
100
+ if (response.choices && response.choices.length) {
103
101
  for (const choice of response.choices) {
104
102
  const message = choice.message;
105
103
 
@@ -135,7 +133,7 @@ export class ImageService {
135
133
  const inputTokens = result.metadata?.usage?.promptTokens;
136
134
  const outputTokens = result.metadata?.usage?.completionTokens;
137
135
 
138
- await ImageService.aiUsageService.trackImageGenerationUsage(
136
+ await ImageGenerationService.aiUsageService.trackImageGenerationUsage(
139
137
  aiConfig.id,
140
138
  result.images.length,
141
139
  undefined, // image resolution not available from OpenRouter
@@ -0,0 +1,13 @@
1
+ export { AIConfigService } from './ai-config.service.js';
2
+ export { AIModelService } from './ai-model.service.js';
3
+ export { AIUsageService } from './ai-usage.service.js';
4
+ export { ChatCompletionService } from './chat-completion.service.js';
5
+ export { ImageGenerationService } from './image-generation.service.js';
6
+
7
+ // Helper functions
8
+ export {
9
+ sortModalities,
10
+ filterAndSortModalities,
11
+ calculatePriceLevel,
12
+ getProviderOrder,
13
+ } from './helpers.js';