insforge 0.3.2 → 1.2.10
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/.cursor/rules/cursor-rules.mdc +94 -0
- package/.dockerignore +3 -0
- package/.env.example +33 -4
- package/.github/ISSUE_TEMPLATE/bug_report.yml +13 -60
- package/.github/ISSUE_TEMPLATE/config.yml +2 -2
- package/.github/ISSUE_TEMPLATE/feature_request.yml +10 -63
- package/.github/PULL_REQUEST_TEMPLATE.md +7 -0
- package/.github/workflows/build-image.yml +2 -1
- package/.github/workflows/e2e.yml +63 -0
- package/CHANGELOG.md +41 -0
- package/CLAUDE_PLUGIN.md +104 -0
- package/CODE_OF_CONDUCT.md +128 -0
- package/CONTRIBUTING.md +1 -1
- package/Dockerfile +4 -1
- package/README.md +66 -18
- 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 +115 -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 +57 -0
- package/auth/src/pages/SignUpPage.tsx +57 -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 +9 -9
- 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} +20 -24
- package/backend/src/api/routes/auth/index.routes.ts +570 -0
- package/backend/src/api/routes/auth/oauth.routes.ts +448 -0
- package/backend/src/api/routes/{database.advance.ts → database/advance.routes.ts} +107 -65
- package/backend/src/api/routes/database/index.routes.ts +13 -0
- package/backend/src/api/routes/{database.records.ts → database/records.routes.ts} +22 -8
- package/backend/src/api/routes/{database.tables.ts → database/tables.routes.ts} +20 -23
- package/backend/src/api/routes/docs/index.routes.ts +76 -0
- package/backend/src/api/routes/functions/index.routes.ts +188 -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} +21 -31
- package/backend/src/api/routes/{secrets.ts → secrets/index.routes.ts} +27 -22
- package/backend/src/api/routes/{storage.ts → storage/index.routes.ts} +34 -53
- package/backend/src/api/routes/usage/index.routes.ts +89 -0
- package/backend/src/infra/config/app.config.ts +51 -0
- package/backend/src/{core/database/manager.ts → infra/database/database.manager.ts} +76 -85
- 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/{core/secrets/encryption.ts → infra/security/encryption.manager.ts} +3 -2
- package/backend/src/infra/security/token.manager.ts +125 -0
- package/backend/src/{core/socket/socket.ts → infra/socket/socket.manager.ts} +15 -15
- package/backend/src/providers/ai/openrouter.provider.ts +377 -0
- package/backend/src/providers/email/base.provider.ts +41 -0
- package/backend/src/providers/email/cloud.provider.ts +187 -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/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 +7 -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 +70 -74
- 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 +1136 -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 +811 -0
- package/backend/src/services/email/email.service.ts +75 -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/{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 +66 -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/{core/socket/types.ts → types/socket.ts} +5 -6
- package/backend/src/utils/environment.ts +9 -3
- package/backend/src/utils/logger.ts +20 -2
- package/backend/src/utils/seed.ts +150 -57
- package/backend/src/utils/sql-parser.ts +1 -1
- package/backend/src/utils/utils.ts +114 -0
- package/backend/src/utils/validations.ts +40 -4
- 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 +1 -1
- package/backend/tests/local/test-e2e.sh +1 -1
- package/backend/tests/local/test-functions.sh +123 -0
- package/backend/tests/local/test-logs.sh +132 -0
- package/backend/tests/local/test-public-bucket.sh +3 -3
- package/backend/tests/local/test-secrets.sh +14 -12
- package/backend/tests/local/test-traditional-rest.sh +2 -2
- package/backend/tests/manual/test-rawsql-modes.sh +244 -0
- package/backend/tests/test-config.sh +37 -1
- 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 +1 -1
- 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 +60 -4
- package/docker-compose.yml +65 -4
- package/docker-init/db/db-init.sql +6 -34
- package/docker-init/logs/vector.yml +236 -0
- package/docs/README.md +44 -0
- package/docs/changelog.mdx +67 -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/functions/architecture.mdx +105 -0
- package/docs/core-concepts/functions/sdk.mdx +184 -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/docs.json +210 -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/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 +55 -374
- package/docs/introduction.mdx +45 -0
- package/docs/logo/dark.svg +22 -0
- package/docs/logo/light.svg +20 -0
- package/docs/partnership.mdx +647 -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/frontend/package.json +10 -4
- package/frontend/src/App.tsx +13 -82
- package/frontend/src/assets/icons/connected.svg +3 -0
- package/frontend/src/assets/icons/loader.svg +9 -0
- package/frontend/src/assets/logos/apple.svg +4 -0
- package/frontend/src/assets/logos/discord.svg +1 -1
- package/frontend/src/assets/logos/facebook.svg +3 -0
- 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/spotify.svg +17 -0
- package/frontend/src/assets/logos/tiktok.svg +6 -0
- 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 +133 -92
- 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/page/AIPage.tsx +67 -79
- 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 +53 -30
- package/frontend/src/features/auth/components/UserFormDialog.tsx +13 -6
- package/frontend/src/features/auth/components/UsersDataGrid.tsx +44 -14
- package/frontend/src/features/auth/components/index.ts +5 -0
- package/frontend/src/features/auth/helpers.tsx +200 -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/page/AuthMethodsPage.tsx +275 -0
- package/frontend/src/features/auth/page/ConfigurationPage.tsx +395 -0
- package/frontend/src/features/auth/page/UsersPage.tsx +285 -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/page/DashboardPage.tsx +187 -169
- 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/TableEmptyState.tsx +6 -5
- package/frontend/src/features/database/components/TableForm.tsx +28 -15
- 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/useFullMetadata.ts +18 -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 +131 -0
- package/frontend/src/features/database/index.ts +6 -1
- package/frontend/src/features/database/page/FunctionsPage.tsx +211 -0
- package/frontend/src/features/database/page/IndexesPage.tsx +240 -0
- package/frontend/src/features/database/page/PoliciesPage.tsx +248 -0
- package/frontend/src/features/database/page/SQLEditorPage.tsx +382 -0
- package/frontend/src/features/database/page/{DatabasePage.tsx → TablesPage.tsx} +186 -185
- package/frontend/src/features/database/page/TemplatesPage.tsx +39 -0
- package/frontend/src/features/database/page/TriggersPage.tsx +242 -0
- package/frontend/src/features/database/services/advance.service.ts +66 -0
- package/frontend/src/features/database/services/{database.service.ts → record.service.ts} +67 -64
- package/frontend/src/features/database/services/table.service.ts +64 -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/page/FunctionsPage.tsx +160 -17
- package/frontend/src/features/functions/{components/SecretsContent.tsx → page/SecretsPage.tsx} +8 -12
- 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/page/CloudLoginPage.tsx +79 -54
- package/frontend/src/features/login/page/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 +181 -0
- package/frontend/src/features/logs/index.ts +8 -2
- package/frontend/src/features/logs/page/AuditsPage.tsx +91 -38
- package/frontend/src/features/logs/page/LogsPage.tsx +152 -0
- package/frontend/src/features/logs/page/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/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/StoragePage.tsx +41 -115
- 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/page/VisualizerPage.tsx +33 -29
- 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 +5 -6
- 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 +84 -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 +183 -0
- package/frontend/src/lib/utils/{validation-schemas.ts → schemaValidations.ts} +10 -5
- package/frontend/src/lib/utils/utils.ts +19 -1
- package/frontend/src/vite-env.d.ts +1 -0
- package/frontend/vite.config.ts +5 -3
- package/functions/server.ts +28 -3
- 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 +31 -4
- package/openapi/auth.yaml +827 -146
- package/package.json +16 -7
- package/shared-schemas/package.json +1 -1
- package/shared-schemas/src/ai-api.schema.ts +34 -58
- package/shared-schemas/src/ai.schema.ts +5 -0
- package/shared-schemas/src/auth-api.schema.ts +154 -8
- package/shared-schemas/src/auth.schema.ts +42 -6
- package/shared-schemas/src/cloud-events.schema.ts +57 -0
- package/shared-schemas/src/database-api.schema.ts +3 -3
- package/shared-schemas/src/database.schema.ts +1 -1
- package/shared-schemas/src/index.ts +1 -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 +9 -4
- package/test-gemini.sh +35 -0
- package/test-usage-admin.sh +57 -0
- package/test-usage.sh +50 -0
- 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 -781
- 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/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/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/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/login/components/AuthErrorBoundary.tsx +0 -87
- package/frontend/src/features/login/components/PrivateRoute.tsx +0 -24
- 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/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/backend/{migrations → src/infra/database/migrations}/000_create-base-tables.sql +0 -0
- /package/backend/{migrations → src/infra/database/migrations}/001_create-helper-functions.sql +0 -0
- /package/backend/{migrations → src/infra/database/migrations}/002_rename-auth-tables.sql +0 -0
- /package/backend/{migrations → src/infra/database/migrations}/003_create-users-table.sql +0 -0
- /package/backend/{migrations → src/infra/database/migrations}/004_add-reload-postgrest-func.sql +0 -0
- /package/backend/{migrations → src/infra/database/migrations}/005_enable-project-admin-modify-users.sql +0 -0
- /package/backend/{migrations → src/infra/database/migrations}/006_modify-ai-usage-table.sql +0 -0
- /package/backend/{migrations → src/infra/database/migrations}/007_drop-metadata-table.sql +0 -0
- /package/backend/{migrations → src/infra/database/migrations}/008_add-system-tables.sql +0 -0
- /package/backend/{migrations → src/infra/database/migrations}/009_add-function-secrets.sql +0 -0
- /package/backend/{migrations → src/infra/database/migrations}/010_modify-ai-config-modalities.sql +0 -0
- /package/backend/{migrations → src/infra/database/migrations}/011_refactor-secrets-table.sql +0 -0
- /package/backend/{migrations → src/infra/database/migrations}/012_add-storage-uploaded-by.sql +0 -0
- /package/frontend/src/{features/metadata → lib}/services/metadata.service.ts +0 -0
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { Router, Response, NextFunction } from 'express';
|
|
2
|
-
import {
|
|
3
|
-
import { verifyAdmin, AuthRequest } from '@/api/
|
|
4
|
-
import { AuditService } from '@/
|
|
5
|
-
import { AppError } from '@/api/
|
|
2
|
+
import { SecretService } from '@/services/secrets/secret.service.js';
|
|
3
|
+
import { verifyAdmin, AuthRequest } from '@/api/middlewares/auth.js';
|
|
4
|
+
import { AuditService } from '@/services/logs/audit.service.js';
|
|
5
|
+
import { AppError } from '@/api/middlewares/error.js';
|
|
6
6
|
import { ERROR_CODES } from '@/types/error-constants.js';
|
|
7
|
+
import { successResponse } from '@/utils/response.js';
|
|
7
8
|
|
|
8
9
|
const router = Router();
|
|
9
|
-
const
|
|
10
|
+
const secretService = SecretService.getInstance();
|
|
10
11
|
const auditService = AuditService.getInstance();
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -15,8 +16,8 @@ const auditService = AuditService.getInstance();
|
|
|
15
16
|
*/
|
|
16
17
|
router.get('/', verifyAdmin, async (_req: AuthRequest, res: Response, next: NextFunction) => {
|
|
17
18
|
try {
|
|
18
|
-
const secrets = await
|
|
19
|
-
res
|
|
19
|
+
const secrets = await secretService.listSecrets();
|
|
20
|
+
successResponse(res, { secrets });
|
|
20
21
|
} catch (error) {
|
|
21
22
|
next(error);
|
|
22
23
|
}
|
|
@@ -29,7 +30,7 @@ router.get('/', verifyAdmin, async (_req: AuthRequest, res: Response, next: Next
|
|
|
29
30
|
router.get('/:key', verifyAdmin, async (req: AuthRequest, res: Response, next: NextFunction) => {
|
|
30
31
|
try {
|
|
31
32
|
const { key } = req.params;
|
|
32
|
-
const value = await
|
|
33
|
+
const value = await secretService.getSecretByKey(key);
|
|
33
34
|
|
|
34
35
|
if (value === null) {
|
|
35
36
|
throw new AppError(`Secret not found: ${key}`, 404, ERROR_CODES.NOT_FOUND);
|
|
@@ -44,7 +45,7 @@ router.get('/:key', verifyAdmin, async (req: AuthRequest, res: Response, next: N
|
|
|
44
45
|
ip_address: req.ip,
|
|
45
46
|
});
|
|
46
47
|
|
|
47
|
-
res
|
|
48
|
+
successResponse(res, { key, value });
|
|
48
49
|
} catch (error) {
|
|
49
50
|
next(error);
|
|
50
51
|
}
|
|
@@ -73,12 +74,12 @@ router.post('/', verifyAdmin, async (req: AuthRequest, res: Response, next: Next
|
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
// Check if secret already exists
|
|
76
|
-
const existing = await
|
|
77
|
+
const existing = await secretService.getSecretByKey(key);
|
|
77
78
|
if (existing !== null) {
|
|
78
79
|
throw new AppError(`Secret already exists: ${key}`, 409, ERROR_CODES.INVALID_INPUT);
|
|
79
80
|
}
|
|
80
81
|
|
|
81
|
-
const result = await
|
|
82
|
+
const result = await secretService.createSecret({
|
|
82
83
|
key,
|
|
83
84
|
value,
|
|
84
85
|
isReserved: isReserved || false,
|
|
@@ -94,11 +95,15 @@ router.post('/', verifyAdmin, async (req: AuthRequest, res: Response, next: Next
|
|
|
94
95
|
ip_address: req.ip,
|
|
95
96
|
});
|
|
96
97
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
98
|
+
successResponse(
|
|
99
|
+
res,
|
|
100
|
+
{
|
|
101
|
+
success: true,
|
|
102
|
+
message: `Secret ${key} has been created successfully`,
|
|
103
|
+
id: result.id,
|
|
104
|
+
},
|
|
105
|
+
201
|
|
106
|
+
);
|
|
102
107
|
} catch (error) {
|
|
103
108
|
next(error);
|
|
104
109
|
}
|
|
@@ -114,14 +119,14 @@ router.put('/:key', verifyAdmin, async (req: AuthRequest, res: Response, next: N
|
|
|
114
119
|
const { value, isActive, isReserved, expiresAt } = req.body;
|
|
115
120
|
|
|
116
121
|
// Get existing secret
|
|
117
|
-
const secrets = await
|
|
122
|
+
const secrets = await secretService.listSecrets();
|
|
118
123
|
const secret = secrets.find((s) => s.key === key);
|
|
119
124
|
|
|
120
125
|
if (!secret) {
|
|
121
126
|
throw new AppError(`Secret not found: ${key}`, 404, ERROR_CODES.NOT_FOUND);
|
|
122
127
|
}
|
|
123
128
|
|
|
124
|
-
const success = await
|
|
129
|
+
const success = await secretService.updateSecret(secret.id, {
|
|
125
130
|
value,
|
|
126
131
|
isActive,
|
|
127
132
|
isReserved,
|
|
@@ -141,7 +146,7 @@ router.put('/:key', verifyAdmin, async (req: AuthRequest, res: Response, next: N
|
|
|
141
146
|
ip_address: req.ip,
|
|
142
147
|
});
|
|
143
148
|
|
|
144
|
-
res
|
|
149
|
+
successResponse(res, {
|
|
145
150
|
success: true,
|
|
146
151
|
message: `Secret ${key} has been updated successfully`,
|
|
147
152
|
});
|
|
@@ -159,7 +164,7 @@ router.delete('/:key', verifyAdmin, async (req: AuthRequest, res: Response, next
|
|
|
159
164
|
const { key } = req.params;
|
|
160
165
|
|
|
161
166
|
// Get existing secret
|
|
162
|
-
const secrets = await
|
|
167
|
+
const secrets = await secretService.listSecrets();
|
|
163
168
|
const secret = secrets.find((s) => s.key === key);
|
|
164
169
|
|
|
165
170
|
if (!secret) {
|
|
@@ -172,7 +177,7 @@ router.delete('/:key', verifyAdmin, async (req: AuthRequest, res: Response, next
|
|
|
172
177
|
}
|
|
173
178
|
|
|
174
179
|
// Mark as inactive instead of hard delete
|
|
175
|
-
const success = await
|
|
180
|
+
const success = await secretService.updateSecret(secret.id, { isActive: false });
|
|
176
181
|
|
|
177
182
|
if (!success) {
|
|
178
183
|
throw new AppError(`Failed to delete secret: ${key}`, 500, ERROR_CODES.INTERNAL_ERROR);
|
|
@@ -187,7 +192,7 @@ router.delete('/:key', verifyAdmin, async (req: AuthRequest, res: Response, next
|
|
|
187
192
|
ip_address: req.ip,
|
|
188
193
|
});
|
|
189
194
|
|
|
190
|
-
res
|
|
195
|
+
successResponse(res, {
|
|
191
196
|
success: true,
|
|
192
197
|
message: `Secret ${key} has been deleted successfully`,
|
|
193
198
|
});
|
|
@@ -1,20 +1,14 @@
|
|
|
1
1
|
import { Router, Request, Response, NextFunction } from 'express';
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { StorageService } from '@/core/storage/storage.js';
|
|
6
|
-
import { DatabaseManager } from '@/core/database/manager.js';
|
|
2
|
+
import { verifyAdmin, AuthRequest, verifyUser } from '@/api/middlewares/auth.js';
|
|
3
|
+
import { AppError } from '@/api/middlewares/error.js';
|
|
4
|
+
import { StorageService } from '@/services/storage/storage.service.js';
|
|
7
5
|
import { successResponse } from '@/utils/response.js';
|
|
8
|
-
import { upload, handleUploadError } from '@/api/
|
|
6
|
+
import { upload, handleUploadError } from '@/api/middlewares/upload.js';
|
|
9
7
|
import { ERROR_CODES } from '@/types/error-constants.js';
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
} from '@insforge/shared-schemas';
|
|
15
|
-
import { SocketService } from '@/core/socket/socket';
|
|
16
|
-
import { DataUpdateResourceType, ServerEvents } from '@/core/socket/types';
|
|
17
|
-
import { AuditService } from '@/core/logs/audit.js';
|
|
8
|
+
import { createBucketRequestSchema, updateBucketRequestSchema } from '@insforge/shared-schemas';
|
|
9
|
+
import { SocketManager } from '@/infra/socket/socket.manager.js';
|
|
10
|
+
import { DataUpdateResourceType, ServerEvents } from '@/types/socket.js';
|
|
11
|
+
import { AuditService } from '@/services/logs/audit.service.js';
|
|
18
12
|
|
|
19
13
|
const router = Router();
|
|
20
14
|
const auditService = AuditService.getInstance();
|
|
@@ -40,24 +34,19 @@ const conditionalAuth = async (req: Request, res: Response, next: NextFunction)
|
|
|
40
34
|
return verifyUser(req, res, next);
|
|
41
35
|
};
|
|
42
36
|
|
|
43
|
-
// GET /api/storage/buckets - List all buckets (requires
|
|
37
|
+
// GET /api/storage/buckets - List all buckets (requires admin)
|
|
44
38
|
router.get('/buckets', verifyAdmin, async (req: AuthRequest, res: Response, next: NextFunction) => {
|
|
45
39
|
try {
|
|
46
|
-
const
|
|
40
|
+
const storageService = StorageService.getInstance();
|
|
41
|
+
const buckets = await storageService.listBuckets();
|
|
47
42
|
|
|
48
|
-
// Get all buckets with their metadata from _storage_buckets table
|
|
49
|
-
const buckets = (await db
|
|
50
|
-
.prepare('SELECT name, public, created_at FROM _storage_buckets ORDER BY name')
|
|
51
|
-
.all()) as StorageBucketSchema[];
|
|
52
|
-
|
|
53
|
-
// Traditional REST: return array directly
|
|
54
43
|
successResponse(res, buckets);
|
|
55
44
|
} catch (error) {
|
|
56
45
|
next(error);
|
|
57
46
|
}
|
|
58
47
|
});
|
|
59
48
|
|
|
60
|
-
// POST /api/storage/buckets - Create a new bucket (requires
|
|
49
|
+
// POST /api/storage/buckets - Create a new bucket (requires admin)
|
|
61
50
|
router.post(
|
|
62
51
|
'/buckets',
|
|
63
52
|
verifyAdmin,
|
|
@@ -89,9 +78,9 @@ router.post(
|
|
|
89
78
|
ip_address: req.ip,
|
|
90
79
|
});
|
|
91
80
|
|
|
92
|
-
const socket =
|
|
81
|
+
const socket = SocketManager.getInstance();
|
|
93
82
|
socket.broadcastToRoom('role:project_admin', ServerEvents.DATA_UPDATE, {
|
|
94
|
-
resource: DataUpdateResourceType.
|
|
83
|
+
resource: DataUpdateResourceType.BUCKETS,
|
|
95
84
|
});
|
|
96
85
|
|
|
97
86
|
const accessInfo = isPublic
|
|
@@ -160,11 +149,11 @@ router.patch(
|
|
|
160
149
|
ip_address: req.ip,
|
|
161
150
|
});
|
|
162
151
|
|
|
163
|
-
const socket =
|
|
152
|
+
const socket = SocketManager.getInstance();
|
|
164
153
|
socket.broadcastToRoom('role:project_admin', ServerEvents.DATA_UPDATE, {
|
|
165
|
-
resource: DataUpdateResourceType.
|
|
154
|
+
resource: DataUpdateResourceType.BUCKETS,
|
|
166
155
|
data: {
|
|
167
|
-
|
|
156
|
+
bucketName,
|
|
168
157
|
},
|
|
169
158
|
});
|
|
170
159
|
|
|
@@ -287,17 +276,11 @@ router.post(
|
|
|
287
276
|
throw new AppError('File is required', 400, ERROR_CODES.STORAGE_INVALID_PARAMETER);
|
|
288
277
|
}
|
|
289
278
|
|
|
290
|
-
// Generate a unique key for the object
|
|
291
|
-
const timestamp = Date.now();
|
|
292
|
-
const randomStr = Math.random().toString(36).substring(2, 8);
|
|
293
|
-
const fileExt = req.file.originalname ? path.extname(req.file.originalname) : '';
|
|
294
|
-
const baseName = req.file.originalname
|
|
295
|
-
? path.basename(req.file.originalname, fileExt)
|
|
296
|
-
: 'file';
|
|
297
|
-
const sanitizedBaseName = baseName.replace(/[^a-zA-Z0-9-_]/g, '-').substring(0, 32);
|
|
298
|
-
const objectKey = `${sanitizedBaseName}-${timestamp}-${randomStr}${fileExt}`;
|
|
299
|
-
|
|
300
279
|
const storageService = StorageService.getInstance();
|
|
280
|
+
|
|
281
|
+
// Generate a unique key for the object using service
|
|
282
|
+
const objectKey = storageService.generateObjectKey(req.file.originalname);
|
|
283
|
+
|
|
301
284
|
const storedFile = await storageService.putObject(
|
|
302
285
|
bucketName,
|
|
303
286
|
objectKey,
|
|
@@ -339,12 +322,10 @@ router.get(
|
|
|
339
322
|
}
|
|
340
323
|
|
|
341
324
|
const storageService = StorageService.getInstance();
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
Number(expiresIn)
|
|
347
|
-
);
|
|
325
|
+
|
|
326
|
+
// Get download strategy (service auto-calculates expiry based on bucket visibility)
|
|
327
|
+
const strategy = await storageService.getDownloadStrategy(bucketName, objectKey);
|
|
328
|
+
|
|
348
329
|
if (strategy.method === 'presigned') {
|
|
349
330
|
return res.redirect(strategy.url);
|
|
350
331
|
}
|
|
@@ -397,9 +378,9 @@ router.delete(
|
|
|
397
378
|
ip_address: req.ip,
|
|
398
379
|
});
|
|
399
380
|
|
|
400
|
-
const socket =
|
|
381
|
+
const socket = SocketManager.getInstance();
|
|
401
382
|
socket.broadcastToRoom('role:project_admin', ServerEvents.DATA_UPDATE, {
|
|
402
|
-
resource: DataUpdateResourceType.
|
|
383
|
+
resource: DataUpdateResourceType.BUCKETS,
|
|
403
384
|
});
|
|
404
385
|
|
|
405
386
|
successResponse(
|
|
@@ -432,7 +413,12 @@ router.delete(
|
|
|
432
413
|
|
|
433
414
|
// Delete specific object
|
|
434
415
|
const storageService = StorageService.getInstance();
|
|
435
|
-
const deleted = await storageService.deleteObject(
|
|
416
|
+
const deleted = await storageService.deleteObject(
|
|
417
|
+
bucketName,
|
|
418
|
+
objectKey,
|
|
419
|
+
req.user?.id,
|
|
420
|
+
req.user?.role === 'project_admin'
|
|
421
|
+
);
|
|
436
422
|
|
|
437
423
|
if (!deleted) {
|
|
438
424
|
throw new AppError('Object not found', 404, ERROR_CODES.NOT_FOUND);
|
|
@@ -525,14 +511,9 @@ router.post(
|
|
|
525
511
|
async (req: AuthRequest | Request, res: Response, next: NextFunction) => {
|
|
526
512
|
try {
|
|
527
513
|
const { bucketName, objectKey } = req.params;
|
|
528
|
-
const { expiresIn = 3600 } = req.body;
|
|
529
514
|
|
|
530
515
|
const storageService = StorageService.getInstance();
|
|
531
|
-
const strategy = await storageService.getDownloadStrategy(
|
|
532
|
-
bucketName,
|
|
533
|
-
objectKey,
|
|
534
|
-
Number(expiresIn)
|
|
535
|
-
);
|
|
516
|
+
const strategy = await storageService.getDownloadStrategy(bucketName, objectKey);
|
|
536
517
|
|
|
537
518
|
successResponse(res, strategy);
|
|
538
519
|
} catch (error) {
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { Router, NextFunction, Response } from 'express';
|
|
2
|
+
import {
|
|
3
|
+
verifyCloudBackend,
|
|
4
|
+
verifyApiKey,
|
|
5
|
+
verifyAdmin,
|
|
6
|
+
AuthRequest,
|
|
7
|
+
} from '@/api/middlewares/auth.js';
|
|
8
|
+
import { SocketManager } from '@/infra/socket/socket.manager.js';
|
|
9
|
+
import { ServerEvents } from '@/types/socket.js';
|
|
10
|
+
import { UsageService } from '@/services/usage/usage.service.js';
|
|
11
|
+
import { successResponse } from '@/utils/response.js';
|
|
12
|
+
import { AppError } from '@/api/middlewares/error.js';
|
|
13
|
+
import { ERROR_CODES } from '@/types/error-constants.js';
|
|
14
|
+
|
|
15
|
+
export const usageRouter = Router();
|
|
16
|
+
const usageService = UsageService.getInstance();
|
|
17
|
+
|
|
18
|
+
// Create MCP tool usage record
|
|
19
|
+
usageRouter.post(
|
|
20
|
+
'/mcp',
|
|
21
|
+
verifyApiKey,
|
|
22
|
+
async (req: AuthRequest, res: Response, next: NextFunction) => {
|
|
23
|
+
try {
|
|
24
|
+
const { tool_name, success = true } = req.body;
|
|
25
|
+
|
|
26
|
+
if (!tool_name) {
|
|
27
|
+
throw new AppError('tool_name is required', 400, ERROR_CODES.INVALID_INPUT);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Create MCP usage record via service
|
|
31
|
+
const result = await usageService.recordMCPUsage(tool_name, success);
|
|
32
|
+
|
|
33
|
+
// Broadcast MCP tool usage to frontend via socket
|
|
34
|
+
const socketService = SocketManager.getInstance();
|
|
35
|
+
|
|
36
|
+
socketService.broadcastToRoom('role:project_admin', ServerEvents.MCP_CONNECTED, {
|
|
37
|
+
tool_name,
|
|
38
|
+
created_at: result.created_at,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
successResponse(res, { success: true });
|
|
42
|
+
} catch (error) {
|
|
43
|
+
next(error);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
// Get MCP usage records
|
|
49
|
+
usageRouter.get(
|
|
50
|
+
'/mcp',
|
|
51
|
+
verifyAdmin,
|
|
52
|
+
async (req: AuthRequest, res: Response, next: NextFunction) => {
|
|
53
|
+
try {
|
|
54
|
+
const { limit = '5', success = 'true' } = req.query;
|
|
55
|
+
|
|
56
|
+
// Get MCP usage records via service
|
|
57
|
+
const records = await usageService.getMCPUsage(parseInt(limit as string), success === 'true');
|
|
58
|
+
|
|
59
|
+
successResponse(res, { records });
|
|
60
|
+
} catch (error) {
|
|
61
|
+
next(error);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
// Get usage statistics (called by cloud backend)
|
|
67
|
+
usageRouter.get(
|
|
68
|
+
'/stats',
|
|
69
|
+
verifyCloudBackend,
|
|
70
|
+
async (req: AuthRequest, res: Response, next: NextFunction) => {
|
|
71
|
+
try {
|
|
72
|
+
const { start_date, end_date } = req.query;
|
|
73
|
+
|
|
74
|
+
if (!start_date || !end_date) {
|
|
75
|
+
throw new AppError('start_date and end_date are required', 400, ERROR_CODES.INVALID_INPUT);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Get usage statistics via service
|
|
79
|
+
const stats = await usageService.getUsageStats(
|
|
80
|
+
new Date(start_date as string),
|
|
81
|
+
new Date(end_date as string)
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
successResponse(res, stats);
|
|
85
|
+
} catch (error) {
|
|
86
|
+
next(error);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
);
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export interface AppConfig {
|
|
2
|
+
app: {
|
|
3
|
+
port: number;
|
|
4
|
+
jwtSecret: string;
|
|
5
|
+
apiKey: string;
|
|
6
|
+
logLevel: string;
|
|
7
|
+
};
|
|
8
|
+
database: {
|
|
9
|
+
host: string;
|
|
10
|
+
port: number;
|
|
11
|
+
username: string;
|
|
12
|
+
password: string;
|
|
13
|
+
databaseName: string;
|
|
14
|
+
};
|
|
15
|
+
cloud: {
|
|
16
|
+
storageBucket: string;
|
|
17
|
+
instanceProfile: string;
|
|
18
|
+
apiHost: string;
|
|
19
|
+
projectId: string;
|
|
20
|
+
appKey: string;
|
|
21
|
+
cloudFrontUrl: string;
|
|
22
|
+
cloudFrontKeyPairId: string;
|
|
23
|
+
cloudFrontPrivateKey: string;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const config: AppConfig = {
|
|
28
|
+
app: {
|
|
29
|
+
port: parseInt(process.env.PORT || '3000', 10),
|
|
30
|
+
jwtSecret: process.env.JWT_SECRET || 'your_jwt_secret',
|
|
31
|
+
apiKey: process.env.ACCESS_API_KEY || 'your_api_key',
|
|
32
|
+
logLevel: process.env.LOG_LEVEL || 'info',
|
|
33
|
+
},
|
|
34
|
+
database: {
|
|
35
|
+
host: process.env.POSTGRES_HOST || 'localhost',
|
|
36
|
+
port: parseInt(process.env.POSTGRES_PORT || '5432', 10),
|
|
37
|
+
username: process.env.POSTGRES_USERNAME || 'user',
|
|
38
|
+
password: process.env.POSTGRES_PASSWORD || 'password',
|
|
39
|
+
databaseName: process.env.POSTGRES_NAME || 'insforge',
|
|
40
|
+
},
|
|
41
|
+
cloud: {
|
|
42
|
+
storageBucket: process.env.AWS_S3_BUCKET || 'insforge-test-bucket',
|
|
43
|
+
instanceProfile: process.env.AWS_INSTANCE_PROFILE_NAME || 'insforge-instance-profile',
|
|
44
|
+
apiHost: process.env.CLOUD_API_HOST || 'https://api.insforge.dev',
|
|
45
|
+
projectId: process.env.PROJECT_ID || 'local',
|
|
46
|
+
appKey: process.env.APP_KEY || 'default-app-key',
|
|
47
|
+
cloudFrontUrl: process.env.AWS_CLOUDFRONT_URL || '',
|
|
48
|
+
cloudFrontKeyPairId: process.env.AWS_CLOUDFRONT_KEY_PAIR_ID || '',
|
|
49
|
+
cloudFrontPrivateKey: process.env.AWS_CLOUDFRONT_PRIVATE_KEY || '',
|
|
50
|
+
},
|
|
51
|
+
};
|
|
@@ -2,6 +2,7 @@ import { Pool } from 'pg';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import fs from 'fs/promises';
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
5
|
+
import { DatabaseMetadataSchema } from '@insforge/shared-schemas';
|
|
5
6
|
|
|
6
7
|
const __filename = fileURLToPath(import.meta.url);
|
|
7
8
|
const __dirname = path.dirname(__filename);
|
|
@@ -46,91 +47,6 @@ export class DatabaseManager {
|
|
|
46
47
|
await client.query('COMMIT');
|
|
47
48
|
}
|
|
48
49
|
|
|
49
|
-
// PostgreSQL-specific prepare method that returns a query object similar to better-sqlite3
|
|
50
|
-
prepare(sql: string) {
|
|
51
|
-
return {
|
|
52
|
-
all: async (...params: unknown[]) => {
|
|
53
|
-
const client = await this.pool.connect();
|
|
54
|
-
try {
|
|
55
|
-
// Convert SQLite parameter placeholders (?) to PostgreSQL ($1, $2, etc.)
|
|
56
|
-
let pgSql = sql;
|
|
57
|
-
let paramIndex = 1;
|
|
58
|
-
while (pgSql.includes('?')) {
|
|
59
|
-
pgSql = pgSql.replace('?', `$${paramIndex}`);
|
|
60
|
-
paramIndex++;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const result = await client.query(pgSql, params);
|
|
64
|
-
return result.rows;
|
|
65
|
-
} finally {
|
|
66
|
-
client.release();
|
|
67
|
-
}
|
|
68
|
-
},
|
|
69
|
-
|
|
70
|
-
get: async (...params: unknown[]) => {
|
|
71
|
-
const client = await this.pool.connect();
|
|
72
|
-
try {
|
|
73
|
-
// Convert SQLite parameter placeholders
|
|
74
|
-
let pgSql = sql;
|
|
75
|
-
let paramIndex = 1;
|
|
76
|
-
while (pgSql.includes('?')) {
|
|
77
|
-
pgSql = pgSql.replace('?', `$${paramIndex}`);
|
|
78
|
-
paramIndex++;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const result = await client.query(pgSql, params);
|
|
82
|
-
return result.rows[0] || null;
|
|
83
|
-
} finally {
|
|
84
|
-
client.release();
|
|
85
|
-
}
|
|
86
|
-
},
|
|
87
|
-
|
|
88
|
-
run: async (...params: unknown[]) => {
|
|
89
|
-
const client = await this.pool.connect();
|
|
90
|
-
try {
|
|
91
|
-
// Convert SQLite parameter placeholders
|
|
92
|
-
let pgSql = sql;
|
|
93
|
-
let paramIndex = 1;
|
|
94
|
-
while (pgSql.includes('?')) {
|
|
95
|
-
pgSql = pgSql.replace('?', `$${paramIndex}`);
|
|
96
|
-
paramIndex++;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const result = await client.query(pgSql, params);
|
|
100
|
-
return {
|
|
101
|
-
changes: result.rowCount || 0,
|
|
102
|
-
lastInsertRowid: null, // PostgreSQL doesn't have this concept
|
|
103
|
-
};
|
|
104
|
-
} finally {
|
|
105
|
-
client.release();
|
|
106
|
-
}
|
|
107
|
-
},
|
|
108
|
-
|
|
109
|
-
exec: async () => {
|
|
110
|
-
const client = await this.pool.connect();
|
|
111
|
-
try {
|
|
112
|
-
await client.query(sql);
|
|
113
|
-
} finally {
|
|
114
|
-
client.release();
|
|
115
|
-
}
|
|
116
|
-
},
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
getDb() {
|
|
121
|
-
return {
|
|
122
|
-
prepare: (sql: string) => this.prepare(sql),
|
|
123
|
-
exec: async (sql: string) => {
|
|
124
|
-
const client = await this.pool.connect();
|
|
125
|
-
try {
|
|
126
|
-
await client.query(sql);
|
|
127
|
-
} finally {
|
|
128
|
-
client.release();
|
|
129
|
-
}
|
|
130
|
-
},
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
|
|
134
50
|
static async getColumnTypeMap(tableName: string): Promise<Record<string, string>> {
|
|
135
51
|
const instance = DatabaseManager.getInstance();
|
|
136
52
|
const client = await instance.pool.connect();
|
|
@@ -168,6 +84,81 @@ export class DatabaseManager {
|
|
|
168
84
|
}
|
|
169
85
|
}
|
|
170
86
|
|
|
87
|
+
async getMetadata(): Promise<DatabaseMetadataSchema> {
|
|
88
|
+
const client = await this.pool.connect();
|
|
89
|
+
try {
|
|
90
|
+
// Fetch all tables, database size, and record counts in parallel
|
|
91
|
+
const [allTables, databaseSize, countResults] = await Promise.all([
|
|
92
|
+
this.getUserTables(),
|
|
93
|
+
this.getDatabaseSizeInGB(),
|
|
94
|
+
// Get all counts in a single query using UNION ALL
|
|
95
|
+
(async () => {
|
|
96
|
+
try {
|
|
97
|
+
const tablesResult = await client.query(
|
|
98
|
+
`
|
|
99
|
+
SELECT table_name as name
|
|
100
|
+
FROM information_schema.tables
|
|
101
|
+
WHERE table_schema = 'public'
|
|
102
|
+
AND table_type = 'BASE TABLE'
|
|
103
|
+
AND (table_name NOT LIKE '\\_%')
|
|
104
|
+
ORDER BY table_name
|
|
105
|
+
`
|
|
106
|
+
);
|
|
107
|
+
const tableNames = tablesResult.rows.map((row: { name: string }) => row.name);
|
|
108
|
+
|
|
109
|
+
if (tableNames.length === 0) {
|
|
110
|
+
return [];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Build a UNION ALL query to get all counts in one query
|
|
114
|
+
const unionQuery = tableNames
|
|
115
|
+
.map(
|
|
116
|
+
(tableName) =>
|
|
117
|
+
`SELECT '${tableName.replace(/'/g, "''")}' as table_name, COUNT(*) as count FROM "${tableName}"`
|
|
118
|
+
)
|
|
119
|
+
.join(' UNION ALL ');
|
|
120
|
+
|
|
121
|
+
const result = await client.query(unionQuery);
|
|
122
|
+
return result.rows as { table_name: string; count: number }[];
|
|
123
|
+
} catch {
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
126
|
+
})(),
|
|
127
|
+
]);
|
|
128
|
+
|
|
129
|
+
// Map the count results to a lookup object
|
|
130
|
+
const countMap = new Map(countResults.map((r) => [r.table_name, Number(r.count)]));
|
|
131
|
+
|
|
132
|
+
const tableMetadatas = allTables.map((tableName) => ({
|
|
133
|
+
tableName,
|
|
134
|
+
recordCount: countMap.get(tableName) || 0,
|
|
135
|
+
}));
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
tables: tableMetadatas,
|
|
139
|
+
totalSizeInGB: databaseSize,
|
|
140
|
+
hint: 'To retrieve detailed schema information for a specific table, call the get-table-schema tool with the table name.',
|
|
141
|
+
};
|
|
142
|
+
} finally {
|
|
143
|
+
client.release();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async getDatabaseSizeInGB(): Promise<number> {
|
|
148
|
+
const client = await this.pool.connect();
|
|
149
|
+
try {
|
|
150
|
+
// Query PostgreSQL for database size
|
|
151
|
+
const result = await client.query(`SELECT pg_database_size(current_database()) as size`);
|
|
152
|
+
|
|
153
|
+
// PostgreSQL returns size in bytes, convert to GB
|
|
154
|
+
return (result.rows[0]?.size || 0) / (1024 * 1024 * 1024);
|
|
155
|
+
} catch {
|
|
156
|
+
return 0;
|
|
157
|
+
} finally {
|
|
158
|
+
client.release();
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
171
162
|
getPool(): Pool {
|
|
172
163
|
return this.pool;
|
|
173
164
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
-- Migration: 013 - Create auth schema and copy helper functions
|
|
2
|
+
-- Creates auth schema if it doesn't exist and copies JWT helper functions
|
|
3
|
+
|
|
4
|
+
-- Create auth schema if not exists
|
|
5
|
+
CREATE SCHEMA IF NOT EXISTS auth;
|
|
6
|
+
|
|
7
|
+
-- Function to get current user ID from JWT (in auth schema)
|
|
8
|
+
CREATE OR REPLACE FUNCTION auth.uid()
|
|
9
|
+
RETURNS uuid
|
|
10
|
+
LANGUAGE sql STABLE
|
|
11
|
+
AS $$
|
|
12
|
+
SELECT
|
|
13
|
+
nullif(
|
|
14
|
+
coalesce(
|
|
15
|
+
current_setting('request.jwt.claim.sub', true),
|
|
16
|
+
(current_setting('request.jwt.claims', true)::jsonb ->> 'sub')
|
|
17
|
+
),
|
|
18
|
+
''
|
|
19
|
+
)::uuid
|
|
20
|
+
$$;
|
|
21
|
+
|
|
22
|
+
-- Function to get current user role from JWT (in auth schema)
|
|
23
|
+
CREATE OR REPLACE FUNCTION auth.role()
|
|
24
|
+
RETURNS text
|
|
25
|
+
LANGUAGE sql STABLE
|
|
26
|
+
AS $$
|
|
27
|
+
SELECT
|
|
28
|
+
coalesce(
|
|
29
|
+
current_setting('request.jwt.claim.role', true),
|
|
30
|
+
(current_setting('request.jwt.claims', true)::jsonb ->> 'role')
|
|
31
|
+
)::text
|
|
32
|
+
$$;
|
|
33
|
+
|
|
34
|
+
-- Function to get current user email from JWT (in auth schema)
|
|
35
|
+
CREATE OR REPLACE FUNCTION auth.email()
|
|
36
|
+
RETURNS text
|
|
37
|
+
LANGUAGE sql STABLE
|
|
38
|
+
AS $$
|
|
39
|
+
SELECT
|
|
40
|
+
coalesce(
|
|
41
|
+
current_setting('request.jwt.claim.email', true),
|
|
42
|
+
(current_setting('request.jwt.claims', true)::jsonb ->> 'email')
|
|
43
|
+
)::text
|
|
44
|
+
$$;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
-- Migration: 014 - Add updated_at trigger to users table
|
|
2
|
+
-- Adds the updated_at trigger to the users table for automatic timestamp management
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
DROP TRIGGER IF EXISTS update_users_updated_at ON users;
|
|
6
|
+
CREATE TRIGGER update_users_updated_at
|
|
7
|
+
BEFORE UPDATE ON users
|
|
8
|
+
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|