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.
- package/.claude-plugin/marketplace.json +20 -0
- package/.dockerignore +60 -57
- package/.env.example +84 -49
- package/.github/ISSUE_TEMPLATE/bug_report.yml +36 -83
- package/.github/ISSUE_TEMPLATE/config.yml +11 -11
- package/.github/ISSUE_TEMPLATE/feature_request.yml +26 -79
- package/.github/PULL_REQUEST_TEMPLATE.md +7 -0
- package/.github/copilot-instructions.md +146 -146
- package/.github/workflows/build-image.yml +66 -65
- package/.github/workflows/ci-premerge-check.yml +23 -23
- package/.github/workflows/e2e.yml +63 -0
- package/.github/workflows/lint-and-format.yml +32 -32
- package/.prettierignore +64 -64
- package/CHANGELOG.md +44 -3
- package/CLAUDE_PLUGIN.md +104 -0
- package/CODE_OF_CONDUCT.md +128 -0
- package/CONTRIBUTING.md +125 -125
- package/Dockerfile +30 -27
- package/GITHUB_OAUTH_SETUP.md +49 -49
- package/GOOGLE_OAUTH_SETUP.md +148 -148
- package/LICENSE +201 -201
- package/README.md +182 -134
- package/assets/Dark.svg +23 -23
- package/assets/mcpInstallv2.png +0 -0
- package/assets/sampleResponse.png +0 -0
- package/auth/index.html +13 -0
- package/auth/package.json +28 -0
- package/auth/public/favicon.ico +0 -0
- package/auth/src/App.tsx +33 -0
- package/auth/src/components/ErrorCard.tsx +37 -0
- package/auth/src/components/Layout.tsx +13 -0
- package/auth/src/index.css +19 -0
- package/auth/src/lib/broadcastService.ts +117 -0
- package/auth/src/lib/utils.ts +11 -0
- package/auth/src/main.tsx +22 -0
- package/auth/src/pages/ForgotPasswordPage.tsx +11 -0
- package/auth/src/pages/ResetPasswordPage.tsx +11 -0
- package/auth/src/pages/SignInPage.tsx +60 -0
- package/auth/src/pages/SignUpPage.tsx +60 -0
- package/auth/src/pages/VerifyEmailPage.tsx +20 -0
- package/auth/src/vite-env.d.ts +10 -0
- package/auth/tsconfig.json +32 -0
- package/auth/tsconfig.node.json +11 -0
- package/auth/vite.config.ts +25 -0
- package/backend/package.json +78 -75
- package/backend/src/api/{middleware → middlewares}/auth.ts +8 -9
- package/backend/src/api/middlewares/rate-limiters.ts +127 -0
- package/backend/src/api/routes/{ai.ts → ai/index.routes.ts} +22 -26
- package/backend/src/api/routes/auth/index.routes.ts +667 -0
- package/backend/src/api/routes/auth/oauth.routes.ts +473 -0
- package/backend/src/api/routes/{database.advance.ts → database/advance.routes.ts} +128 -65
- package/backend/src/api/routes/database/index.routes.ts +90 -0
- package/backend/src/api/routes/{database.records.ts → database/records.routes.ts} +26 -12
- package/backend/src/api/routes/{database.tables.ts → database/tables.routes.ts} +6 -23
- package/backend/src/api/routes/docs/index.routes.ts +75 -0
- package/backend/src/api/routes/email/index.routes.ts +35 -0
- package/backend/src/api/routes/functions/index.routes.ts +194 -0
- package/backend/src/api/routes/{logs.ts → logs/index.routes.ts} +25 -30
- package/backend/src/api/routes/{metadata.ts → metadata/index.routes.ts} +33 -31
- package/backend/src/api/routes/realtime/channels.routes.ts +81 -0
- package/backend/src/api/routes/realtime/index.routes.ts +12 -0
- package/backend/src/api/routes/realtime/messages.routes.ts +48 -0
- package/backend/src/api/routes/realtime/permissions.routes.ts +19 -0
- package/backend/src/api/routes/{secrets.ts → secrets/index.routes.ts} +27 -22
- package/backend/src/api/routes/{storage.ts → storage/index.routes.ts} +48 -61
- package/backend/src/api/routes/usage/index.routes.ts +91 -0
- package/backend/src/infra/config/app.config.ts +51 -0
- package/backend/src/infra/database/database.manager.ts +182 -0
- package/backend/{migrations → src/infra/database/migrations}/000_create-base-tables.sql +141 -141
- package/backend/{migrations → src/infra/database/migrations}/001_create-helper-functions.sql +40 -40
- package/backend/{migrations → src/infra/database/migrations}/002_rename-auth-tables.sql +29 -29
- package/backend/{migrations → src/infra/database/migrations}/003_create-users-table.sql +55 -55
- package/backend/{migrations → src/infra/database/migrations}/004_add-reload-postgrest-func.sql +23 -23
- package/backend/{migrations → src/infra/database/migrations}/005_enable-project-admin-modify-users.sql +29 -29
- package/backend/{migrations → src/infra/database/migrations}/006_modify-ai-usage-table.sql +24 -24
- package/backend/{migrations → src/infra/database/migrations}/007_drop-metadata-table.sql +1 -1
- package/backend/{migrations → src/infra/database/migrations}/008_add-system-tables.sql +76 -76
- package/backend/{migrations → src/infra/database/migrations}/009_add-function-secrets.sql +23 -23
- package/backend/{migrations → src/infra/database/migrations}/010_modify-ai-config-modalities.sql +93 -93
- package/backend/{migrations → src/infra/database/migrations}/011_refactor-secrets-table.sql +15 -15
- package/backend/{migrations → src/infra/database/migrations}/012_add-storage-uploaded-by.sql +7 -7
- package/backend/src/infra/database/migrations/013_create-auth-schema-functions.sql +44 -0
- package/backend/src/infra/database/migrations/014_add-updated-at-trigger-user-table.sql +8 -0
- package/backend/src/infra/database/migrations/015_create-auth-config-and-email-otp-tables.sql +60 -0
- package/backend/src/infra/database/migrations/016_update-auth-config-and-email-otp.sql +24 -0
- package/backend/src/infra/database/migrations/017_create-realtime-schema.sql +233 -0
- package/backend/src/infra/realtime/realtime.manager.ts +246 -0
- package/backend/src/infra/realtime/webhook-sender.ts +82 -0
- package/backend/src/{core/secrets/encryption.ts → infra/security/encryption.manager.ts} +3 -2
- package/backend/src/infra/security/token.manager.ts +219 -0
- package/backend/src/infra/socket/socket.manager.ts +522 -0
- package/backend/src/providers/ai/openrouter.provider.ts +380 -0
- package/backend/src/providers/email/base.provider.ts +38 -0
- package/backend/src/providers/email/cloud.provider.ts +271 -0
- package/backend/src/{core/logs/providers → providers/logs}/base.provider.ts +11 -11
- package/backend/src/{core/logs/providers → providers/logs}/cloudwatch.provider.ts +61 -38
- package/backend/src/providers/logs/local.provider.ts +185 -0
- package/backend/src/providers/oauth/apple.provider.ts +266 -0
- package/backend/src/providers/oauth/base.provider.ts +29 -0
- package/backend/src/providers/oauth/discord.provider.ts +195 -0
- package/backend/src/providers/oauth/facebook.provider.ts +194 -0
- package/backend/src/providers/oauth/github.provider.ts +208 -0
- package/backend/src/providers/oauth/google.provider.ts +249 -0
- package/backend/src/providers/oauth/index.ts +8 -0
- package/backend/src/providers/oauth/linkedin.provider.ts +240 -0
- package/backend/src/providers/oauth/microsoft.provider.ts +169 -0
- package/backend/src/providers/oauth/x.provider.ts +202 -0
- package/backend/src/providers/storage/base.provider.ts +29 -0
- package/backend/src/providers/storage/local.provider.ts +103 -0
- package/backend/src/providers/storage/s3.provider.ts +313 -0
- package/backend/src/server.ts +317 -288
- package/backend/src/{core/ai/config.ts → services/ai/ai-config.service.ts} +19 -24
- package/backend/src/services/ai/ai-model.service.ts +60 -0
- package/backend/src/{core/ai/usage.ts → services/ai/ai-usage.service.ts} +28 -35
- package/backend/src/{core/ai/chat.ts → services/ai/chat-completion.service.ts} +37 -24
- package/backend/src/services/ai/helpers.ts +64 -0
- package/backend/src/{core/ai/image.ts → services/ai/image-generation.service.ts} +17 -19
- package/backend/src/services/ai/index.ts +13 -0
- package/backend/src/services/auth/auth-config.service.ts +250 -0
- package/backend/src/services/auth/auth-otp.service.ts +424 -0
- package/backend/src/services/auth/auth.service.ts +1150 -0
- package/backend/src/services/auth/index.ts +4 -0
- package/backend/src/{core/auth/oauth.ts → services/auth/oauth-config.service.ts} +106 -52
- package/backend/src/{core/database/advance.ts → services/database/database-advance.service.ts} +97 -131
- package/backend/src/services/database/database-table.service.ts +802 -0
- package/backend/src/services/database/database.service.ts +127 -0
- package/backend/src/services/email/email.service.ts +73 -0
- package/backend/src/{core/functions/functions.ts → services/functions/function.service.ts} +95 -88
- package/backend/src/{core/logs/audit.ts → services/logs/audit.service.ts} +92 -75
- package/backend/src/services/logs/log.service.ts +73 -0
- package/backend/src/services/realtime/index.ts +3 -0
- package/backend/src/services/realtime/realtime-auth.service.ts +104 -0
- package/backend/src/services/realtime/realtime-channel.service.ts +237 -0
- package/backend/src/services/realtime/realtime-message.service.ts +260 -0
- package/backend/src/{core/secrets/secrets.ts → services/secrets/secret.service.ts} +48 -66
- package/backend/src/services/storage/storage.service.ts +617 -0
- package/backend/src/services/usage/usage.service.ts +149 -0
- package/backend/src/types/auth.ts +77 -2
- package/backend/src/types/email.ts +8 -0
- package/backend/src/types/error-constants.ts +4 -0
- package/backend/src/types/logs.ts +0 -29
- package/backend/src/types/realtime.ts +18 -0
- package/backend/src/{core/socket/types.ts → types/socket.ts} +11 -36
- package/backend/src/utils/cookies.ts +35 -0
- package/backend/src/utils/environment.ts +9 -3
- package/backend/src/utils/logger.ts +20 -2
- package/backend/src/utils/s3-config-loader.ts +64 -0
- package/backend/src/utils/seed.ts +301 -205
- package/backend/src/utils/sql-parser.ts +91 -1
- package/backend/src/utils/utils.ts +114 -0
- package/backend/src/utils/validations.ts +40 -4
- package/backend/tests/README.md +133 -133
- package/backend/tests/cleanup-all-test-data.sh +230 -230
- package/backend/tests/cloud/test-s3-multitenant.sh +131 -131
- package/backend/tests/local/comprehensive-curl-tests.sh +155 -155
- package/backend/tests/local/test-ai-config.sh +129 -0
- package/backend/tests/local/test-ai-usage.sh +80 -0
- package/backend/tests/local/test-auth-router.sh +143 -143
- package/backend/tests/local/test-database-router.sh +222 -222
- package/backend/tests/local/test-e2e.sh +240 -240
- package/backend/tests/local/test-fk-errors.sh +96 -96
- package/backend/tests/local/test-functions.sh +123 -0
- package/backend/tests/local/test-id-field.sh +200 -200
- package/backend/tests/local/test-logs.sh +132 -0
- package/backend/tests/local/test-public-bucket.sh +264 -264
- package/backend/tests/local/test-secrets.sh +249 -247
- package/backend/tests/local/test-serverless-functions.sh.disabled +325 -325
- package/backend/tests/local/test-traditional-rest.sh +208 -208
- package/backend/tests/manual/README.md +50 -50
- package/backend/tests/manual/create-large-table-simple.sql +10 -10
- package/backend/tests/manual/seed-large-table.sql +100 -100
- package/backend/tests/manual/setup-large-table-extras.sql +33 -33
- package/backend/tests/manual/test-bulk-upsert.sh +409 -409
- package/backend/tests/manual/test-database-advance.sh +296 -296
- package/backend/tests/manual/test-postgrest-stability.sh +191 -191
- package/backend/tests/manual/test-rawsql-export-import.sh +411 -411
- package/backend/tests/manual/test-rawsql-modes.sh +244 -0
- package/backend/tests/manual/test-universal-storage.sh +263 -263
- package/backend/tests/manual/test-users.sql +17 -17
- package/backend/tests/run-all-tests.sh +139 -139
- package/backend/tests/setup.ts +0 -0
- package/backend/tests/test-config.sh +338 -302
- package/backend/tests/unit/analyze-query.test.ts +697 -0
- package/backend/tests/unit/cloud-token.test.ts +48 -0
- package/backend/tests/unit/constant.test.ts +8 -0
- package/backend/tests/unit/email.test.ts +372 -0
- package/backend/tests/unit/environment.test.ts +59 -0
- package/backend/tests/unit/helpers.test.ts +63 -0
- package/backend/tests/unit/logger.test.ts +22 -0
- package/backend/tests/unit/rate-limit.test.ts +154 -0
- package/backend/tests/unit/response.test.ts +58 -0
- package/backend/tests/unit/sql-parser.test.ts +74 -0
- package/backend/tests/unit/uuid.test.ts +21 -0
- package/backend/tests/unit/validations.test.ts +80 -0
- package/backend/tsconfig.json +22 -22
- package/backend/vitest.config.ts +11 -0
- package/claude-plugin/.claude-plugin/plugin.json +24 -0
- package/claude-plugin/README.md +133 -0
- package/claude-plugin/skills/insforge-schema-patterns/SKILL.md +270 -0
- package/docker-compose.prod.yml +204 -144
- package/docker-compose.yml +232 -167
- package/docker-init/db/db-init.sql +97 -125
- package/docker-init/db/jwt.sql +5 -5
- package/docker-init/db/postgresql.conf +16 -16
- package/docker-init/logs/vector.yml +236 -0
- package/docs/README.md +44 -0
- package/docs/agent-docs/real-time.md +269 -0
- package/docs/changelog.mdx +119 -0
- package/docs/core-concepts/ai/architecture.mdx +373 -0
- package/docs/core-concepts/ai/sdk.mdx +213 -0
- package/docs/core-concepts/authentication/architecture.mdx +278 -0
- package/docs/core-concepts/authentication/sdk.mdx +414 -0
- package/docs/core-concepts/authentication/ui-components/customization.mdx +529 -0
- package/docs/core-concepts/authentication/ui-components/nextjs.mdx +221 -0
- package/docs/core-concepts/authentication/ui-components/react-router.mdx +184 -0
- package/docs/core-concepts/authentication/ui-components/react.mdx +129 -0
- package/docs/core-concepts/database/architecture.mdx +256 -0
- package/docs/core-concepts/database/sdk.mdx +382 -0
- package/docs/core-concepts/email/architecture.mdx +101 -0
- package/docs/core-concepts/email/sdk.mdx +53 -0
- package/docs/core-concepts/functions/architecture.mdx +105 -0
- package/docs/core-concepts/functions/sdk.mdx +184 -0
- package/docs/core-concepts/realtime/architecture.mdx +446 -0
- package/docs/core-concepts/realtime/sdk.mdx +409 -0
- package/docs/core-concepts/storage/architecture.mdx +243 -0
- package/docs/core-concepts/storage/sdk.mdx +253 -0
- package/docs/deployment/README.md +94 -0
- package/docs/deployment/deploy-to-aws-ec2.md +565 -0
- package/docs/deployment/deploy-to-azure-virtual-machines.md +313 -0
- package/docs/deployment/deploy-to-google-cloud-compute-engine.md +613 -0
- package/docs/deployment/deploy-to-render.md +441 -0
- package/docs/deprecated/insforge-auth-api.md +214 -214
- package/docs/deprecated/insforge-auth-sdk.md +99 -99
- package/docs/deprecated/insforge-db-api.md +358 -358
- package/docs/deprecated/insforge-db-sdk.md +139 -139
- package/docs/deprecated/insforge-debug-sdk.md +156 -156
- package/docs/deprecated/insforge-debug.md +64 -64
- package/docs/deprecated/insforge-instructions.md +123 -123
- package/docs/deprecated/insforge-project.md +117 -117
- package/docs/deprecated/insforge-storage-api.md +278 -278
- package/docs/deprecated/insforge-storage-sdk.md +158 -158
- package/docs/docs.json +232 -0
- package/docs/examples/framework-guides/nextjs.mdx +131 -0
- package/docs/examples/framework-guides/nuxt.mdx +165 -0
- package/docs/examples/framework-guides/react.mdx +165 -0
- package/docs/examples/framework-guides/svelte.mdx +153 -0
- package/docs/examples/framework-guides/vue.mdx +159 -0
- package/docs/examples/overview.mdx +67 -0
- package/docs/favicon.svg +19 -0
- package/docs/images/changelog/dec-2025/ai-integration.png +0 -0
- package/docs/images/changelog/dec-2025/ai-models.webp +0 -0
- package/docs/images/changelog/dec-2025/alipay-payment.webp +0 -0
- package/docs/images/changelog/dec-2025/apple-login.jpg +0 -0
- package/docs/images/changelog/dec-2025/mcp-installer.png +0 -0
- package/docs/images/changelog/dec-2025/realtime-module.jpg +0 -0
- package/docs/images/changelog/nov-2025/auth-components.webp +0 -0
- package/docs/images/changelog/nov-2025/database-metadata.webp +0 -0
- package/docs/images/changelog/nov-2025/quickstart-prompts.webp +0 -0
- package/docs/images/changelog/nov-2025/sql-editor.webp +0 -0
- package/docs/images/changelog/nov-2025/usage-page.webp +0 -0
- package/docs/images/changelog/october-2025/csv-upload.webp +0 -0
- package/docs/images/changelog/october-2025/logs-feature.webp +0 -0
- package/docs/images/changelog/october-2025/oauth-providers.webp +0 -0
- package/docs/images/checks-passed.png +0 -0
- package/docs/images/dashboard-connect-expanded.png +0 -0
- package/docs/images/dashboard-connect.png +0 -0
- package/docs/images/hero-dark.png +0 -0
- package/docs/images/hero-light.png +0 -0
- package/docs/images/icons/ai.svg +4 -0
- package/docs/images/icons/auth.svg +1 -0
- package/docs/images/icons/database.svg +1 -0
- package/docs/images/icons/function.svg +1 -0
- package/docs/images/icons/storage.svg +1 -0
- package/docs/images/logos/nextjs.svg +4 -0
- package/docs/images/logos/nuxt.svg +4 -0
- package/docs/images/logos/react.svg +5 -0
- package/docs/images/logos/svelte.svg +4 -0
- package/docs/images/logos/vue.svg +5 -0
- package/docs/images/mcp-install.png +0 -0
- package/docs/images/onboarding-mcp.png +0 -0
- package/docs/insforge-instructions-sdk.md +89 -407
- package/docs/introduction.mdx +45 -0
- package/docs/logo/dark.svg +22 -0
- package/docs/logo/light.svg +20 -0
- package/docs/partnership.mdx +652 -0
- package/docs/quickstart.mdx +83 -0
- package/docs/showcase/2048-arena.png +0 -0
- package/docs/showcase/framegen-cloud.png +0 -0
- package/docs/showcase/line-connect-race.png +0 -0
- package/docs/showcase/moment-vibe.png +0 -0
- package/docs/showcase/national-flags.png +0 -0
- package/docs/showcase/pokemon-vibe.png +0 -0
- package/docs/showcase/pure-browse-buy.png +0 -0
- package/docs/showcase.mdx +52 -0
- package/docs/snippets/sdk-installation.mdx +22 -0
- package/docs/snippets/service-icons.mdx +27 -0
- package/eslint.config.js +10 -3
- package/examples/oauth/frontend-oauth-example.html +250 -250
- package/examples/response-examples.md +443 -443
- package/frontend/components.json +17 -17
- package/frontend/package.json +69 -63
- package/frontend/src/App.tsx +13 -82
- package/frontend/src/assets/icons/checkbox_checked.svg +6 -6
- package/frontend/src/assets/icons/checkbox_undetermined.svg +6 -6
- package/frontend/src/assets/icons/checked.svg +3 -3
- package/frontend/src/assets/icons/connected.svg +3 -0
- package/frontend/src/assets/icons/error.svg +3 -3
- package/frontend/src/assets/icons/loader.svg +9 -0
- package/frontend/src/assets/icons/pencil.svg +4 -4
- package/frontend/src/assets/icons/refresh.svg +4 -4
- package/frontend/src/assets/icons/step_active.svg +3 -3
- package/frontend/src/assets/icons/step_inactive.svg +11 -11
- package/frontend/src/assets/icons/warning.svg +3 -3
- package/frontend/src/assets/logos/apple.svg +4 -0
- package/frontend/src/assets/logos/claude_code.svg +3 -3
- package/frontend/src/assets/logos/cline.svg +6 -6
- package/frontend/src/assets/logos/cursor.svg +20 -20
- package/frontend/src/assets/logos/discord.svg +8 -8
- package/frontend/src/assets/logos/facebook.svg +3 -0
- package/frontend/src/assets/logos/gemini.svg +19 -19
- package/frontend/src/assets/logos/github.svg +5 -5
- package/frontend/src/assets/logos/google.svg +13 -13
- package/frontend/src/assets/logos/grok.svg +10 -10
- package/frontend/src/assets/logos/insforge_dark.svg +15 -15
- package/frontend/src/assets/logos/insforge_light.svg +15 -15
- package/frontend/src/assets/logos/instagram.svg +2 -0
- package/frontend/src/assets/logos/linkedin.svg +3 -0
- package/frontend/src/assets/logos/microsoft.svg +1 -0
- package/frontend/src/assets/logos/openai.svg +10 -10
- package/frontend/src/assets/logos/roo_code.svg +9 -9
- package/frontend/src/assets/logos/spotify.svg +17 -0
- package/frontend/src/assets/logos/tiktok.svg +6 -0
- package/frontend/src/assets/logos/trae.svg +3 -3
- package/frontend/src/assets/logos/windsurf.svg +10 -10
- package/frontend/src/assets/logos/x.svg +3 -0
- package/frontend/src/components/Checkbox.tsx +27 -29
- package/frontend/src/components/CodeBlock.tsx +55 -2
- package/frontend/src/components/CodeEditor.tsx +92 -0
- package/frontend/src/components/ConfirmDialog.tsx +1 -1
- package/frontend/src/components/ConnectCTA.tsx +38 -0
- package/frontend/src/components/CopyButton.tsx +52 -15
- package/frontend/src/components/ErrorState.tsx +1 -2
- package/frontend/src/components/FeatureSidebar.tsx +6 -6
- package/frontend/src/components/FeatureSidebarItem.tsx +2 -2
- package/frontend/src/components/JsonHighlight.tsx +21 -9
- package/frontend/src/components/ProjectInfoModal.tsx +128 -0
- package/frontend/src/components/PromptDialog.tsx +1 -4
- package/frontend/src/components/SearchInput.tsx +1 -2
- package/frontend/src/components/Stepper.tsx +53 -0
- package/frontend/src/components/ThemeToggle.tsx +3 -3
- package/frontend/src/components/datagrid/DataGrid.tsx +25 -32
- package/frontend/src/components/datagrid/cell-editors/DateCellEditor.tsx +1 -2
- package/frontend/src/components/datagrid/cell-editors/JsonCellEditor.tsx +2 -4
- package/frontend/src/components/datagrid/index.ts +23 -0
- package/frontend/src/components/index.ts +23 -30
- package/frontend/src/components/layout/AppHeader.tsx +131 -91
- package/frontend/src/components/layout/AppSidebar.tsx +80 -170
- package/frontend/src/components/layout/Layout.tsx +12 -23
- package/frontend/src/components/layout/PrimaryMenu.tsx +187 -0
- package/frontend/src/components/layout/SecondaryMenu.tsx +70 -0
- package/frontend/src/components/layout/index.ts +5 -0
- package/frontend/src/components/radix/Tooltip.tsx +24 -13
- package/frontend/src/components/radix/index.ts +22 -0
- package/frontend/src/features/ai/components/AIConfigCard.tsx +129 -83
- package/frontend/src/features/ai/components/AIEmptyState.tsx +12 -7
- package/frontend/src/features/ai/components/ModalityFilterSidebar.tsx +101 -0
- package/frontend/src/features/ai/components/ModelSelectionDialog.tsx +135 -0
- package/frontend/src/features/ai/components/ModelSelectionGrid.tsx +51 -0
- package/frontend/src/features/ai/components/SystemPromptDialog.tsx +118 -0
- package/frontend/src/features/ai/components/index.ts +6 -0
- package/frontend/src/features/ai/helpers.ts +57 -71
- package/frontend/src/features/ai/hooks/useAIConfigs.ts +39 -113
- package/frontend/src/features/ai/hooks/useAIUsage.ts +0 -2
- package/frontend/src/features/ai/pages/AIPage.tsx +166 -0
- package/frontend/src/features/ai/services/ai.service.ts +5 -5
- package/frontend/src/features/auth/components/AuthPreview.tsx +96 -0
- package/frontend/src/features/auth/components/OAuthConfigDialog.tsx +54 -30
- package/frontend/src/features/auth/components/UserFormDialog.tsx +13 -6
- package/frontend/src/features/auth/components/UsersDataGrid.tsx +50 -14
- package/frontend/src/features/auth/components/index.ts +5 -0
- package/frontend/src/features/auth/helpers.tsx +208 -0
- package/frontend/src/features/auth/hooks/useAnonToken.ts +30 -0
- package/frontend/src/features/auth/hooks/useAuthConfig.ts +48 -0
- package/frontend/src/features/auth/hooks/useOAuthConfig.ts +14 -10
- package/frontend/src/features/auth/hooks/useUsers.ts +43 -5
- package/frontend/src/features/auth/index.ts +3 -2
- package/frontend/src/features/auth/pages/AuthMethodsPage.tsx +275 -0
- package/frontend/src/features/auth/pages/ConfigurationPage.tsx +395 -0
- package/frontend/src/features/auth/pages/UsersPage.tsx +257 -0
- package/frontend/src/features/auth/services/anonToken.service.ts +11 -0
- package/frontend/src/features/auth/services/config.service.ts +19 -0
- package/frontend/src/features/auth/services/{oauth.service.ts → oauth-config.service.ts} +4 -4
- package/frontend/src/features/auth/services/{auth.service.ts → user.service.ts} +7 -53
- package/frontend/src/features/dashboard/components/ConnectionSuccessBanner.tsx +35 -0
- package/frontend/src/features/dashboard/components/PromptCard.tsx +21 -0
- package/frontend/src/features/dashboard/components/PromptDialog.tsx +103 -0
- package/frontend/src/features/dashboard/components/StatsCard.tsx +50 -0
- package/frontend/src/features/dashboard/components/index.ts +4 -0
- package/frontend/src/features/dashboard/pages/DashboardPage.tsx +212 -0
- package/frontend/src/features/dashboard/prompts/ai-chatbot.ts +13 -0
- package/frontend/src/features/dashboard/prompts/crm-system.ts +13 -0
- package/frontend/src/features/dashboard/prompts/ecommerce-platform.ts +12 -0
- package/frontend/src/features/dashboard/prompts/index.ts +31 -0
- package/frontend/src/features/dashboard/prompts/instagram-clone.ts +11 -0
- package/frontend/src/features/dashboard/prompts/notion-clone.ts +14 -0
- package/frontend/src/features/dashboard/prompts/reddit-clone.ts +12 -0
- package/frontend/src/features/database/components/DatabaseDataGrid.tsx +48 -17
- package/frontend/src/features/database/components/ForeignKeyCell.tsx +15 -34
- package/frontend/src/features/database/components/ForeignKeyPopover.tsx +19 -20
- package/frontend/src/features/database/components/LinkRecordModal.tsx +120 -125
- package/frontend/src/features/database/components/RecordFormDialog.tsx +22 -33
- package/frontend/src/features/database/components/RecordFormField.tsx +45 -47
- package/frontend/src/features/database/components/SQLModal.tsx +75 -0
- package/frontend/src/features/database/components/TableEmptyState.tsx +6 -5
- package/frontend/src/features/database/components/TableForm.tsx +28 -19
- package/frontend/src/features/database/components/TableFormColumn.tsx +2 -3
- package/frontend/src/features/database/components/TableSidebar.tsx +1 -1
- package/frontend/src/features/database/components/TablesEmptyState.tsx +48 -0
- package/frontend/src/features/database/components/TemplateCard.tsx +37 -0
- package/frontend/src/features/database/components/TemplatePreview.tsx +92 -0
- package/frontend/src/features/database/components/index.ts +19 -0
- package/frontend/src/features/database/constants.ts +28 -2
- package/frontend/src/features/database/contexts/SQLEditorContext.tsx +188 -0
- package/frontend/src/features/database/helpers.ts +2 -2
- package/frontend/src/features/database/hooks/useCSVImport.ts +29 -0
- package/frontend/src/features/database/hooks/useDatabase.ts +66 -0
- package/frontend/src/features/database/hooks/useRawSQL.ts +55 -0
- package/frontend/src/features/database/hooks/useRecords.ts +139 -0
- package/frontend/src/features/database/hooks/useTables.ts +135 -0
- package/frontend/src/features/database/index.ts +7 -1
- package/frontend/src/features/database/pages/FunctionsPage.tsx +203 -0
- package/frontend/src/features/database/pages/IndexesPage.tsx +228 -0
- package/frontend/src/features/database/pages/PoliciesPage.tsx +237 -0
- package/frontend/src/features/database/pages/SQLEditorPage.tsx +382 -0
- package/frontend/src/features/database/{page/DatabasePage.tsx → pages/TablesPage.tsx} +168 -209
- package/frontend/src/features/database/pages/TemplatesPage.tsx +39 -0
- package/frontend/src/features/database/pages/TriggersPage.tsx +230 -0
- package/frontend/src/features/database/services/advance.service.ts +40 -0
- package/frontend/src/features/database/services/database.service.ts +33 -194
- package/frontend/src/features/database/services/record.service.ts +219 -0
- package/frontend/src/features/database/services/table.service.ts +58 -0
- package/frontend/src/features/database/templates/ai-chatbot.ts +402 -0
- package/frontend/src/features/database/templates/crm-system.ts +528 -0
- package/frontend/src/features/database/templates/ecommerce-platform.ts +553 -0
- package/frontend/src/features/database/templates/index.ts +34 -0
- package/frontend/src/features/database/templates/instagram-clone.ts +222 -0
- package/frontend/src/features/database/templates/notion-clone.ts +483 -0
- package/frontend/src/features/database/templates/reddit-clone.ts +526 -0
- package/frontend/src/features/functions/components/FunctionRow.tsx +2 -1
- package/frontend/src/features/functions/components/FunctionsSidebar.tsx +1 -1
- package/frontend/src/features/functions/components/SecretRow.tsx +1 -1
- package/frontend/src/features/functions/components/index.ts +5 -0
- package/frontend/src/features/functions/hooks/useFunctions.ts +4 -4
- package/frontend/src/features/{secrets → functions}/hooks/useSecrets.ts +5 -5
- package/frontend/src/features/functions/pages/FunctionsPage.tsx +148 -0
- package/frontend/src/features/functions/{components/SecretsContent.tsx → pages/SecretsPage.tsx} +19 -21
- package/frontend/src/features/functions/services/{functions.service.ts → function.service.ts} +2 -2
- package/frontend/src/features/{secrets/services/secrets.service.ts → functions/services/secret.service.ts} +2 -2
- package/frontend/src/features/login/hooks/usePartnerOrigin.ts +27 -0
- package/frontend/src/features/login/pages/CloudLoginPage.tsx +118 -0
- package/frontend/src/features/login/{page → pages}/LoginPage.tsx +16 -23
- package/frontend/src/features/login/services/partnership.service.ts +65 -0
- package/frontend/src/features/logs/components/LogsDataGrid.tsx +89 -0
- package/frontend/src/features/logs/components/SeverityBadge.tsx +18 -0
- package/frontend/src/features/logs/components/index.ts +2 -0
- package/frontend/src/features/logs/helpers.ts +24 -0
- package/frontend/src/features/logs/hooks/useAuditLogs.ts +4 -4
- package/frontend/src/features/logs/hooks/useLogSources.ts +137 -0
- package/frontend/src/features/logs/hooks/useLogs.ts +163 -0
- package/frontend/src/features/logs/hooks/useMcpUsage.ts +128 -0
- package/frontend/src/features/logs/index.ts +8 -2
- package/frontend/src/features/logs/{page → pages}/AuditsPage.tsx +91 -38
- package/frontend/src/features/logs/pages/LogsPage.tsx +152 -0
- package/frontend/src/features/logs/pages/MCPLogsPage.tsx +84 -0
- package/frontend/src/features/logs/services/audit.service.ts +63 -0
- package/frontend/src/features/logs/services/log.service.ts +15 -110
- package/frontend/src/features/logs/services/usage.service.ts +31 -0
- package/frontend/src/features/onboard/components/McpConnectionStatus.tsx +68 -0
- package/frontend/src/features/onboard/components/OnboardingModal.tsx +267 -0
- package/frontend/src/features/onboard/components/VideoDemoModal.tsx +38 -0
- package/frontend/src/features/onboard/components/index.ts +4 -0
- package/frontend/src/features/onboard/components/mcp/CursorDeeplinkGenerator.tsx +2 -2
- package/frontend/src/features/onboard/components/mcp/{mcp-helper.tsx → helpers.tsx} +8 -8
- package/frontend/src/features/onboard/components/mcp/index.ts +2 -3
- package/frontend/src/features/onboard/index.ts +13 -3
- package/frontend/src/features/realtime/components/ChannelRow.tsx +83 -0
- package/frontend/src/features/realtime/components/EditChannelModal.tsx +246 -0
- package/frontend/src/features/realtime/components/MessageRow.tsx +85 -0
- package/frontend/src/features/realtime/components/RealtimeEmptyState.tsx +30 -0
- package/frontend/src/features/realtime/hooks/useRealtime.ts +218 -0
- package/frontend/src/features/realtime/index.ts +11 -0
- package/frontend/src/features/realtime/pages/RealtimeChannelsPage.tsx +172 -0
- package/frontend/src/features/realtime/pages/RealtimeMessagesPage.tsx +211 -0
- package/frontend/src/features/realtime/pages/RealtimePermissionsPage.tsx +191 -0
- package/frontend/src/features/realtime/services/realtime.service.ts +107 -0
- package/frontend/src/features/storage/components/BucketEmptyState.tsx +9 -6
- package/frontend/src/features/storage/components/BucketFormDialog.tsx +25 -41
- package/frontend/src/features/storage/components/FilePreviewDialog.tsx +20 -8
- package/frontend/src/features/storage/components/StorageDataGrid.tsx +4 -3
- package/frontend/src/features/storage/components/StorageManager.tsx +23 -34
- package/frontend/src/features/storage/components/index.ts +12 -0
- package/frontend/src/features/storage/hooks/useStorage.ts +208 -0
- package/frontend/src/features/storage/{page → pages}/StoragePage.tsx +41 -143
- package/frontend/src/features/storage/services/storage.service.ts +22 -1
- package/frontend/src/features/visualizer/components/AuthNode.tsx +72 -56
- package/frontend/src/features/visualizer/components/BucketNode.tsx +4 -4
- package/frontend/src/features/visualizer/components/SchemaVisualizer.tsx +108 -80
- package/frontend/src/features/visualizer/components/TableNode.tsx +34 -41
- package/frontend/src/features/visualizer/components/VisualizerSkeleton.tsx +12 -4
- package/frontend/src/features/visualizer/pages/VisualizerPage.tsx +97 -0
- package/frontend/src/index.css +1 -0
- package/frontend/src/lib/analytics/posthog.tsx +27 -0
- package/frontend/src/lib/contexts/AuthContext.tsx +38 -31
- package/frontend/src/lib/contexts/SocketContext.tsx +123 -80
- package/frontend/src/{features/metadata → lib}/hooks/useMetadata.ts +1 -1
- package/frontend/src/lib/hooks/useToast.tsx +6 -2
- package/frontend/src/lib/routing/AppRoutes.tsx +99 -0
- package/frontend/src/lib/routing/RequireAuth.tsx +27 -0
- package/frontend/src/lib/utils/cloudMessaging.ts +20 -0
- package/frontend/src/lib/utils/menuItems.ts +207 -0
- package/frontend/src/lib/utils/{validation-schemas.ts → schemaValidations.ts} +10 -5
- package/frontend/src/lib/utils/utils.ts +32 -1
- package/frontend/src/vite-env.d.ts +1 -0
- package/frontend/tsconfig.json +25 -25
- package/frontend/tsconfig.node.json +9 -9
- package/frontend/vite.config.ts +5 -3
- package/functions/deno.json +24 -24
- package/functions/server.ts +315 -290
- package/functions/worker-template.js +15 -4
- package/i18n/README.ar.md +130 -0
- package/i18n/README.de.md +130 -0
- package/i18n/README.es.md +154 -0
- package/i18n/README.fr.md +134 -0
- package/i18n/README.hi.md +129 -0
- package/i18n/README.ja.md +174 -0
- package/i18n/README.ko.md +137 -0
- package/i18n/README.pt-BR.md +131 -0
- package/i18n/README.ru.md +129 -0
- package/i18n/README.zh-CN.md +133 -0
- package/openapi/ai.yaml +715 -688
- package/openapi/auth.yaml +1244 -563
- package/openapi/email.yaml +158 -0
- package/openapi/functions.yaml +475 -475
- package/openapi/health.yaml +29 -29
- package/openapi/logs.yaml +223 -223
- package/openapi/metadata.yaml +177 -177
- package/openapi/realtime.yaml +699 -0
- package/openapi/records.yaml +381 -381
- package/openapi/secrets.yaml +370 -370
- package/openapi/storage.yaml +875 -875
- package/openapi/tables.yaml +463 -463
- package/package.json +97 -88
- package/shared-schemas/package.json +31 -31
- package/shared-schemas/src/ai-api.schema.ts +34 -58
- package/shared-schemas/src/ai.schema.ts +63 -54
- package/shared-schemas/src/auth-api.schema.ts +352 -193
- package/shared-schemas/src/auth.schema.ts +43 -7
- package/shared-schemas/src/cloud-events.schema.ts +57 -0
- package/shared-schemas/src/database-api.schema.ts +35 -4
- package/shared-schemas/src/database.schema.ts +40 -1
- package/shared-schemas/src/docs.schema.ts +26 -0
- package/shared-schemas/src/email-api.schema.ts +30 -0
- package/shared-schemas/src/index.ts +5 -0
- package/shared-schemas/src/logs-api.schema.ts +7 -1
- package/shared-schemas/src/logs.schema.ts +26 -0
- package/shared-schemas/src/metadata.schema.ts +18 -4
- package/shared-schemas/src/realtime-api.schema.ts +111 -0
- package/shared-schemas/src/realtime.schema.ts +143 -0
- package/shared-schemas/tsconfig.json +21 -21
- package/tsconfig.json +7 -7
- package/zeabur/README.md +13 -0
- package/zeabur/template.yml +1032 -0
- package/.github/workflows/deploy-aws.yml +0 -130
- package/backend/src/api/routes/agent.ts +0 -29
- package/backend/src/api/routes/auth.oauth.ts +0 -482
- package/backend/src/api/routes/auth.ts +0 -386
- package/backend/src/api/routes/docs.ts +0 -66
- package/backend/src/api/routes/functions.ts +0 -183
- package/backend/src/api/routes/openapi.ts +0 -82
- package/backend/src/api/routes/usage.ts +0 -96
- package/backend/src/core/ai/client.ts +0 -242
- package/backend/src/core/ai/model.ts +0 -117
- package/backend/src/core/auth/auth.ts +0 -780
- package/backend/src/core/database/manager.ts +0 -178
- package/backend/src/core/database/table.ts +0 -772
- package/backend/src/core/documentation/agent.ts +0 -689
- package/backend/src/core/documentation/openapi.ts +0 -856
- package/backend/src/core/logs/analytics.ts +0 -76
- package/backend/src/core/logs/providers/localdb.provider.ts +0 -246
- package/backend/src/core/socket/socket.ts +0 -388
- package/backend/src/core/storage/storage.ts +0 -923
- package/backend/src/utils/cloud-token.ts +0 -39
- package/backend/src/utils/helpers.ts +0 -49
- package/backend/src/utils/uuid.ts +0 -9
- package/backend/tests/manual/test-better-auth.sh +0 -303
- package/docker-init/db/logs.sql +0 -9
- package/frontend/README.md +0 -112
- package/frontend/src/components/datagrid/index.tsx +0 -20
- package/frontend/src/components/layout/CloudLayout.tsx +0 -95
- package/frontend/src/features/ai/components/AIConfigDialog.tsx +0 -76
- package/frontend/src/features/ai/components/AIConfigForm.tsx +0 -222
- package/frontend/src/features/ai/components/fields/ModalityField.tsx +0 -87
- package/frontend/src/features/ai/components/fields/ModelSelectionField.tsx +0 -134
- package/frontend/src/features/ai/components/fields/SystemPromptField.tsx +0 -33
- package/frontend/src/features/ai/page/AIPage.tsx +0 -178
- package/frontend/src/features/auth/components/AddOAuthDialog.tsx +0 -106
- package/frontend/src/features/auth/components/AuthMethodTab.tsx +0 -238
- package/frontend/src/features/auth/components/UsersTab.tsx +0 -114
- package/frontend/src/features/auth/page/AuthenticationPage.tsx +0 -169
- package/frontend/src/features/dashboard/page/DashboardPage.tsx +0 -194
- package/frontend/src/features/database/hooks/UseLinkModal.tsx +0 -78
- package/frontend/src/features/functions/components/FunctionViewer.tsx +0 -46
- package/frontend/src/features/functions/components/FunctionsContent.tsx +0 -88
- package/frontend/src/features/functions/page/FunctionsPage.tsx +0 -28
- package/frontend/src/features/login/components/AuthErrorBoundary.tsx +0 -87
- package/frontend/src/features/login/components/PrivateRoute.tsx +0 -24
- package/frontend/src/features/login/page/CloudLoginPage.tsx +0 -93
- package/frontend/src/features/logs/components/AnalyticsLogsTable.tsx +0 -313
- package/frontend/src/features/logs/components/LogsTable.tsx +0 -199
- package/frontend/src/features/logs/page/AnalyticsLogsPage.tsx +0 -530
- package/frontend/src/features/metadata/index.ts +0 -0
- package/frontend/src/features/metadata/page/MetadataPage.tsx +0 -136
- package/frontend/src/features/onboard/components/CompletionCard.tsx +0 -41
- package/frontend/src/features/onboard/components/OnboardButton.tsx +0 -84
- package/frontend/src/features/onboard/components/StepContent.tsx +0 -91
- package/frontend/src/features/onboard/components/TestConnectionStep.tsx +0 -53
- package/frontend/src/features/onboard/components/mcp/McpInstallation.tsx +0 -144
- package/frontend/src/features/onboard/page/OnBoardPage.tsx +0 -104
- package/frontend/src/features/onboard/types.ts +0 -8
- package/frontend/src/features/visualizer/page/VisualizerPage.tsx +0 -127
- package/frontend/src/lib/contexts/OnboardStepContext.tsx +0 -68
- package/frontend/src/lib/hooks/useOnboardingCompletion.ts +0 -29
- /package/backend/src/api/{middleware → middlewares}/error.ts +0 -0
- /package/backend/src/api/{middleware → middlewares}/upload.ts +0 -0
- /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 '@/
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 '@/
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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
|
|
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 {
|
|
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
|
|
14
|
-
private
|
|
15
|
-
private
|
|
16
|
-
private
|
|
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
|
|
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
|
-
|
|
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
|
|
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 {
|
|
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
|
|
15
|
-
private static aiUsageService =
|
|
16
|
-
private static aiConfigService =
|
|
17
|
-
private static
|
|
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
|
|
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
|
|
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
|
-
//
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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
|
|
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
|
|
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';
|