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
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { EmailProvider } from '@/providers/email/base.provider.js';
|
|
2
|
+
import { CloudEmailProvider } from '@/providers/email/cloud.provider.js';
|
|
3
|
+
import { EmailTemplate } from '@/types/email.js';
|
|
4
|
+
import logger from '@/utils/logger.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Email service that orchestrates different email providers
|
|
8
|
+
*/
|
|
9
|
+
export class EmailService {
|
|
10
|
+
private static instance: EmailService;
|
|
11
|
+
private provider: EmailProvider;
|
|
12
|
+
|
|
13
|
+
private constructor() {
|
|
14
|
+
// For now, we only support cloud provider
|
|
15
|
+
// In the future, this can be configured via environment variables
|
|
16
|
+
// Example:
|
|
17
|
+
// if (process.env.EMAIL_PROVIDER === 'smtp') {
|
|
18
|
+
// this.provider = new SMTPEmailProvider(config.email.smtp);
|
|
19
|
+
// } else if (process.env.EMAIL_PROVIDER === 'sendgrid') {
|
|
20
|
+
// this.provider = new SendGridEmailProvider(config.email.sendgrid);
|
|
21
|
+
// } else {
|
|
22
|
+
// this.provider = new CloudEmailProvider();
|
|
23
|
+
// }
|
|
24
|
+
|
|
25
|
+
this.provider = new CloudEmailProvider();
|
|
26
|
+
logger.info('Using email provider: Cloud (Insforge)');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Get singleton instance of EmailService
|
|
31
|
+
*/
|
|
32
|
+
public static getInstance(): EmailService {
|
|
33
|
+
if (!EmailService.instance) {
|
|
34
|
+
EmailService.instance = new EmailService();
|
|
35
|
+
}
|
|
36
|
+
return EmailService.instance;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Send email using predefined template
|
|
41
|
+
* @param email - Recipient email address
|
|
42
|
+
* @param name - Recipient name
|
|
43
|
+
* @param template - Template type
|
|
44
|
+
* @param variables - Variables to use in the email template
|
|
45
|
+
*/
|
|
46
|
+
public async sendWithTemplate(
|
|
47
|
+
email: string,
|
|
48
|
+
name: string,
|
|
49
|
+
template: EmailTemplate,
|
|
50
|
+
variables?: Record<string, string>
|
|
51
|
+
): Promise<void> {
|
|
52
|
+
return this.provider.sendWithTemplate(email, name, template, variables);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Send raw email (if provider supports it)
|
|
57
|
+
* @param to - Recipient email address
|
|
58
|
+
* @param subject - Email subject
|
|
59
|
+
* @param html - HTML email body
|
|
60
|
+
* @param text - Plain text email body (optional)
|
|
61
|
+
*/
|
|
62
|
+
public async sendRaw(to: string, subject: string, html: string, text?: string): Promise<void> {
|
|
63
|
+
if (!this.provider.sendRaw) {
|
|
64
|
+
throw new Error('Current email provider does not support raw email sending');
|
|
65
|
+
}
|
|
66
|
+
return this.provider.sendRaw(to, subject, html, text);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Check if current provider supports templates
|
|
71
|
+
*/
|
|
72
|
+
public supportsTemplates(): boolean {
|
|
73
|
+
return this.provider.supportsTemplates();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { DatabaseManager } from '@/
|
|
1
|
+
import { DatabaseManager } from '@/infra/database/database.manager.js';
|
|
2
2
|
import {
|
|
3
3
|
EdgeFunctionMetadataSchema,
|
|
4
4
|
FunctionUploadRequest,
|
|
5
5
|
FunctionUpdateRequest,
|
|
6
6
|
} from '@insforge/shared-schemas';
|
|
7
7
|
import logger from '@/utils/logger.js';
|
|
8
|
-
import { DatabaseError } from 'pg';
|
|
8
|
+
import { DatabaseError, Pool } from 'pg';
|
|
9
9
|
import fetch from 'node-fetch';
|
|
10
|
-
import { AppError } from '@/api/
|
|
10
|
+
import { AppError } from '@/api/middlewares/error.js';
|
|
11
11
|
import { ERROR_CODES } from '@/types/error-constants.js';
|
|
12
12
|
|
|
13
13
|
export interface FunctionWithRuntime {
|
|
@@ -17,19 +17,25 @@ export interface FunctionWithRuntime {
|
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export class
|
|
21
|
-
private static instance:
|
|
22
|
-
private
|
|
20
|
+
export class FunctionService {
|
|
21
|
+
private static instance: FunctionService;
|
|
22
|
+
private pool: Pool | null = null;
|
|
23
23
|
|
|
24
|
-
private constructor() {
|
|
25
|
-
|
|
24
|
+
private constructor() {}
|
|
25
|
+
|
|
26
|
+
static getInstance(): FunctionService {
|
|
27
|
+
if (!FunctionService.instance) {
|
|
28
|
+
FunctionService.instance = new FunctionService();
|
|
29
|
+
}
|
|
30
|
+
return FunctionService.instance;
|
|
26
31
|
}
|
|
27
32
|
|
|
28
|
-
|
|
29
|
-
if (!
|
|
30
|
-
|
|
33
|
+
private getPool(): Pool {
|
|
34
|
+
if (!this.pool) {
|
|
35
|
+
const dbManager = DatabaseManager.getInstance();
|
|
36
|
+
this.pool = dbManager.getPool();
|
|
31
37
|
}
|
|
32
|
-
return
|
|
38
|
+
return this.pool;
|
|
33
39
|
}
|
|
34
40
|
|
|
35
41
|
/**
|
|
@@ -37,15 +43,15 @@ export class FunctionsService {
|
|
|
37
43
|
*/
|
|
38
44
|
async listFunctions(): Promise<FunctionWithRuntime> {
|
|
39
45
|
try {
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
const result = await this.getPool().query(
|
|
47
|
+
`SELECT
|
|
48
|
+
id, slug, name, description, status,
|
|
49
|
+
created_at, updated_at, deployed_at
|
|
50
|
+
FROM _functions
|
|
51
|
+
ORDER BY created_at DESC`
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const functions = result.rows;
|
|
49
55
|
|
|
50
56
|
// Check if Deno runtime is healthy
|
|
51
57
|
let runtimeHealthy = false;
|
|
@@ -82,17 +88,16 @@ export class FunctionsService {
|
|
|
82
88
|
*/
|
|
83
89
|
async getFunction(slug: string): Promise<Record<string, unknown> | undefined> {
|
|
84
90
|
try {
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
return func;
|
|
91
|
+
const result = await this.getPool().query(
|
|
92
|
+
`SELECT
|
|
93
|
+
id, slug, name, description, code, status,
|
|
94
|
+
created_at, updated_at, deployed_at
|
|
95
|
+
FROM _functions
|
|
96
|
+
WHERE slug = $1`,
|
|
97
|
+
[slug]
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
return result.rows[0];
|
|
96
101
|
} catch (error) {
|
|
97
102
|
logger.error('Failed to get function', {
|
|
98
103
|
error: error instanceof Error ? error.message : String(error),
|
|
@@ -107,6 +112,7 @@ export class FunctionsService {
|
|
|
107
112
|
* Create a new function
|
|
108
113
|
*/
|
|
109
114
|
async createFunction(data: FunctionUploadRequest): Promise<Record<string, unknown>> {
|
|
115
|
+
const client = await this.getPool().connect();
|
|
110
116
|
try {
|
|
111
117
|
const { name, code, description, status } = data;
|
|
112
118
|
const slug = data.slug || name.toLowerCase().replace(/\s+/g, '-');
|
|
@@ -118,29 +124,27 @@ export class FunctionsService {
|
|
|
118
124
|
const id = crypto.randomUUID();
|
|
119
125
|
|
|
120
126
|
// Insert function
|
|
121
|
-
await
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
.run(id, slug, name, description || null, code, status);
|
|
127
|
+
await client.query(
|
|
128
|
+
`INSERT INTO _functions (id, slug, name, description, code, status)
|
|
129
|
+
VALUES ($1, $2, $3, $4, $5, $6)`,
|
|
130
|
+
[id, slug, name, description || null, code, status]
|
|
131
|
+
);
|
|
127
132
|
|
|
128
133
|
// If status is active, update deployed_at
|
|
129
134
|
if (status === 'active') {
|
|
130
|
-
await
|
|
131
|
-
|
|
132
|
-
|
|
135
|
+
await client.query(`UPDATE _functions SET deployed_at = CURRENT_TIMESTAMP WHERE id = $1`, [
|
|
136
|
+
id,
|
|
137
|
+
]);
|
|
133
138
|
}
|
|
134
139
|
|
|
135
140
|
// Fetch the created function
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
return created;
|
|
141
|
+
const result = await client.query(
|
|
142
|
+
`SELECT id, slug, name, description, status, created_at
|
|
143
|
+
FROM _functions WHERE id = $1`,
|
|
144
|
+
[id]
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
return result.rows[0];
|
|
144
148
|
} catch (error) {
|
|
145
149
|
// Re-throw AppErrors as-is
|
|
146
150
|
if (error instanceof AppError) {
|
|
@@ -162,6 +166,8 @@ export class FunctionsService {
|
|
|
162
166
|
}
|
|
163
167
|
|
|
164
168
|
throw error;
|
|
169
|
+
} finally {
|
|
170
|
+
client.release();
|
|
165
171
|
}
|
|
166
172
|
}
|
|
167
173
|
|
|
@@ -172,10 +178,13 @@ export class FunctionsService {
|
|
|
172
178
|
slug: string,
|
|
173
179
|
updates: FunctionUpdateRequest
|
|
174
180
|
): Promise<Record<string, unknown> | null> {
|
|
181
|
+
const client = await this.getPool().connect();
|
|
175
182
|
try {
|
|
176
183
|
// Check if function exists
|
|
177
|
-
const
|
|
178
|
-
|
|
184
|
+
const existingResult = await client.query('SELECT id FROM _functions WHERE slug = $1', [
|
|
185
|
+
slug,
|
|
186
|
+
]);
|
|
187
|
+
if (existingResult.rows.length === 0) {
|
|
179
188
|
return null;
|
|
180
189
|
}
|
|
181
190
|
|
|
@@ -186,50 +195,48 @@ export class FunctionsService {
|
|
|
186
195
|
|
|
187
196
|
// Update fields
|
|
188
197
|
if (updates.name !== undefined) {
|
|
189
|
-
await
|
|
190
|
-
.prepare('UPDATE _functions SET name = ? WHERE slug = ?')
|
|
191
|
-
.run(updates.name, slug);
|
|
198
|
+
await client.query('UPDATE _functions SET name = $1 WHERE slug = $2', [updates.name, slug]);
|
|
192
199
|
}
|
|
193
200
|
|
|
194
201
|
if (updates.description !== undefined) {
|
|
195
|
-
await
|
|
196
|
-
.
|
|
197
|
-
|
|
202
|
+
await client.query('UPDATE _functions SET description = $1 WHERE slug = $2', [
|
|
203
|
+
updates.description,
|
|
204
|
+
slug,
|
|
205
|
+
]);
|
|
198
206
|
}
|
|
199
207
|
|
|
200
208
|
if (updates.code !== undefined) {
|
|
201
|
-
await
|
|
202
|
-
.prepare('UPDATE _functions SET code = ? WHERE slug = ?')
|
|
203
|
-
.run(updates.code, slug);
|
|
209
|
+
await client.query('UPDATE _functions SET code = $1 WHERE slug = $2', [updates.code, slug]);
|
|
204
210
|
}
|
|
205
211
|
|
|
206
212
|
if (updates.status !== undefined) {
|
|
207
|
-
await
|
|
208
|
-
.
|
|
209
|
-
|
|
213
|
+
await client.query('UPDATE _functions SET status = $1 WHERE slug = $2', [
|
|
214
|
+
updates.status,
|
|
215
|
+
slug,
|
|
216
|
+
]);
|
|
210
217
|
|
|
211
218
|
// Update deployed_at if status changes to active
|
|
212
219
|
if (updates.status === 'active') {
|
|
213
|
-
await
|
|
214
|
-
|
|
215
|
-
|
|
220
|
+
await client.query(
|
|
221
|
+
'UPDATE _functions SET deployed_at = CURRENT_TIMESTAMP WHERE slug = $1',
|
|
222
|
+
[slug]
|
|
223
|
+
);
|
|
216
224
|
}
|
|
217
225
|
}
|
|
218
226
|
|
|
219
227
|
// Update updated_at
|
|
220
|
-
await
|
|
221
|
-
|
|
222
|
-
|
|
228
|
+
await client.query('UPDATE _functions SET updated_at = CURRENT_TIMESTAMP WHERE slug = $1', [
|
|
229
|
+
slug,
|
|
230
|
+
]);
|
|
223
231
|
|
|
224
232
|
// Fetch updated function
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
return updated;
|
|
233
|
+
const result = await client.query(
|
|
234
|
+
`SELECT id, slug, name, description, status, updated_at
|
|
235
|
+
FROM _functions WHERE slug = $1`,
|
|
236
|
+
[slug]
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
return result.rows[0];
|
|
233
240
|
} catch (error) {
|
|
234
241
|
logger.error('Failed to update function', {
|
|
235
242
|
error: error instanceof Error ? error.message : String(error),
|
|
@@ -237,6 +244,8 @@ export class FunctionsService {
|
|
|
237
244
|
slug,
|
|
238
245
|
});
|
|
239
246
|
throw error;
|
|
247
|
+
} finally {
|
|
248
|
+
client.release();
|
|
240
249
|
}
|
|
241
250
|
}
|
|
242
251
|
|
|
@@ -245,9 +254,9 @@ export class FunctionsService {
|
|
|
245
254
|
*/
|
|
246
255
|
async deleteFunction(slug: string): Promise<boolean> {
|
|
247
256
|
try {
|
|
248
|
-
const result = await this.
|
|
257
|
+
const result = await this.getPool().query('DELETE FROM _functions WHERE slug = $1', [slug]);
|
|
249
258
|
|
|
250
|
-
if (result.
|
|
259
|
+
if (result.rowCount === 0) {
|
|
251
260
|
return false;
|
|
252
261
|
}
|
|
253
262
|
|
|
@@ -267,15 +276,13 @@ export class FunctionsService {
|
|
|
267
276
|
*/
|
|
268
277
|
async getMetadata(): Promise<Array<EdgeFunctionMetadataSchema>> {
|
|
269
278
|
try {
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
return functions as Array<EdgeFunctionMetadataSchema>;
|
|
279
|
+
const result = await this.getPool().query(
|
|
280
|
+
`SELECT slug, name, description, status
|
|
281
|
+
FROM _functions
|
|
282
|
+
ORDER BY created_at DESC`
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
return result.rows as Array<EdgeFunctionMetadataSchema>;
|
|
279
286
|
} catch (error) {
|
|
280
287
|
logger.error('Failed to get edge functions metadata', {
|
|
281
288
|
error: error instanceof Error ? error.message : String(error),
|
|
@@ -1,20 +1,26 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Pool } from 'pg';
|
|
2
|
+
import { DatabaseManager } from '@/infra/database/database.manager.js';
|
|
2
3
|
import logger from '@/utils/logger.js';
|
|
3
|
-
import { AppError } from '@/api/
|
|
4
|
+
import { AppError } from '@/api/middlewares/error.js';
|
|
4
5
|
import { ERROR_CODES } from '@/types/error-constants.js';
|
|
5
6
|
import type { AuditLogEntry, AuditLogQuery } from '@/types/logs.js';
|
|
6
7
|
import { AuditLogSchema, GetAuditLogStatsResponse } from '@insforge/shared-schemas';
|
|
7
8
|
|
|
8
9
|
export class AuditService {
|
|
9
10
|
private static instance: AuditService;
|
|
10
|
-
private
|
|
11
|
+
private pool: Pool | null = null;
|
|
11
12
|
|
|
12
13
|
private constructor() {
|
|
13
|
-
const dbManager = DatabaseManager.getInstance();
|
|
14
|
-
this.db = dbManager.getDb();
|
|
15
14
|
logger.info('AuditService initialized');
|
|
16
15
|
}
|
|
17
16
|
|
|
17
|
+
private getPool(): Pool {
|
|
18
|
+
if (!this.pool) {
|
|
19
|
+
this.pool = DatabaseManager.getInstance().getPool();
|
|
20
|
+
}
|
|
21
|
+
return this.pool;
|
|
22
|
+
}
|
|
23
|
+
|
|
18
24
|
public static getInstance(): AuditService {
|
|
19
25
|
if (!AuditService.instance) {
|
|
20
26
|
AuditService.instance = new AuditService();
|
|
@@ -27,19 +33,21 @@ export class AuditService {
|
|
|
27
33
|
*/
|
|
28
34
|
async log(entry: AuditLogEntry): Promise<AuditLogSchema> {
|
|
29
35
|
try {
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
.get(
|
|
36
|
+
const pool = this.getPool();
|
|
37
|
+
const result = await pool.query(
|
|
38
|
+
`INSERT INTO _audit_logs (actor, action, module, details, ip_address)
|
|
39
|
+
VALUES ($1, $2, $3, $4, $5)
|
|
40
|
+
RETURNING *`,
|
|
41
|
+
[
|
|
37
42
|
entry.actor,
|
|
38
43
|
entry.action,
|
|
39
44
|
entry.module,
|
|
40
45
|
entry.details ? JSON.stringify(entry.details) : null,
|
|
41
|
-
entry.ip_address || null
|
|
42
|
-
|
|
46
|
+
entry.ip_address || null,
|
|
47
|
+
]
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const row = result.rows[0];
|
|
43
51
|
|
|
44
52
|
logger.info('Audit log created', {
|
|
45
53
|
actor: entry.actor,
|
|
@@ -48,14 +56,14 @@ export class AuditService {
|
|
|
48
56
|
});
|
|
49
57
|
|
|
50
58
|
return {
|
|
51
|
-
id:
|
|
52
|
-
actor:
|
|
53
|
-
action:
|
|
54
|
-
module:
|
|
55
|
-
details:
|
|
56
|
-
ipAddress:
|
|
57
|
-
createdAt:
|
|
58
|
-
updatedAt:
|
|
59
|
+
id: row.id,
|
|
60
|
+
actor: row.actor,
|
|
61
|
+
action: row.action,
|
|
62
|
+
module: row.module,
|
|
63
|
+
details: row.details,
|
|
64
|
+
ipAddress: row.ip_address,
|
|
65
|
+
createdAt: row.created_at,
|
|
66
|
+
updatedAt: row.updated_at,
|
|
59
67
|
};
|
|
60
68
|
} catch (error) {
|
|
61
69
|
logger.error('Failed to create audit log', error);
|
|
@@ -68,6 +76,8 @@ export class AuditService {
|
|
|
68
76
|
*/
|
|
69
77
|
async query(query: AuditLogQuery): Promise<{ records: AuditLogSchema[]; total: number }> {
|
|
70
78
|
try {
|
|
79
|
+
const pool = this.getPool();
|
|
80
|
+
|
|
71
81
|
// Build base WHERE clause
|
|
72
82
|
let whereClause = 'WHERE 1=1';
|
|
73
83
|
const params: unknown[] = [];
|
|
@@ -100,8 +110,8 @@ export class AuditService {
|
|
|
100
110
|
|
|
101
111
|
// Get total count first
|
|
102
112
|
const countSql = `SELECT COUNT(*) as count FROM _audit_logs ${whereClause}`;
|
|
103
|
-
const countResult =
|
|
104
|
-
const total = countResult.count;
|
|
113
|
+
const countResult = await pool.query(countSql, params);
|
|
114
|
+
const total = parseInt(countResult.rows[0].count, 10);
|
|
105
115
|
|
|
106
116
|
// Get paginated records
|
|
107
117
|
let dataSql = `SELECT * FROM _audit_logs ${whereClause} ORDER BY created_at DESC`;
|
|
@@ -117,10 +127,10 @@ export class AuditService {
|
|
|
117
127
|
dataParams.push(query.offset);
|
|
118
128
|
}
|
|
119
129
|
|
|
120
|
-
const
|
|
130
|
+
const dataResult = await pool.query(dataSql, dataParams);
|
|
121
131
|
|
|
122
132
|
return {
|
|
123
|
-
records:
|
|
133
|
+
records: dataResult.rows.map((record) => ({
|
|
124
134
|
id: record.id,
|
|
125
135
|
actor: record.actor,
|
|
126
136
|
action: record.action,
|
|
@@ -143,18 +153,21 @@ export class AuditService {
|
|
|
143
153
|
*/
|
|
144
154
|
async getById(id: string): Promise<AuditLogSchema | null> {
|
|
145
155
|
try {
|
|
146
|
-
const
|
|
156
|
+
const pool = this.getPool();
|
|
157
|
+
const result = await pool.query('SELECT * FROM _audit_logs WHERE id = $1', [id]);
|
|
158
|
+
|
|
159
|
+
const row = result.rows[0];
|
|
147
160
|
|
|
148
|
-
return
|
|
161
|
+
return row
|
|
149
162
|
? {
|
|
150
|
-
id:
|
|
151
|
-
actor:
|
|
152
|
-
action:
|
|
153
|
-
module:
|
|
154
|
-
details:
|
|
155
|
-
ipAddress:
|
|
156
|
-
createdAt:
|
|
157
|
-
updatedAt:
|
|
163
|
+
id: row.id,
|
|
164
|
+
actor: row.actor,
|
|
165
|
+
action: row.action,
|
|
166
|
+
module: row.module,
|
|
167
|
+
details: row.details,
|
|
168
|
+
ipAddress: row.ip_address,
|
|
169
|
+
createdAt: row.created_at,
|
|
170
|
+
updatedAt: row.updated_at,
|
|
158
171
|
}
|
|
159
172
|
: null;
|
|
160
173
|
} catch (error) {
|
|
@@ -168,50 +181,52 @@ export class AuditService {
|
|
|
168
181
|
*/
|
|
169
182
|
async getStats(days: number = 7): Promise<GetAuditLogStatsResponse> {
|
|
170
183
|
try {
|
|
184
|
+
const pool = this.getPool();
|
|
171
185
|
const startDate = new Date();
|
|
172
186
|
startDate.setDate(startDate.getDate() - days);
|
|
173
187
|
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
188
|
+
const totalLogsResult = await pool.query(
|
|
189
|
+
'SELECT COUNT(*) as count FROM _audit_logs WHERE created_at >= $1',
|
|
190
|
+
[startDate.toISOString()]
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
const uniqueActorsResult = await pool.query(
|
|
194
|
+
'SELECT COUNT(DISTINCT actor) as count FROM _audit_logs WHERE created_at >= $1',
|
|
195
|
+
[startDate.toISOString()]
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
const uniqueModulesResult = await pool.query(
|
|
199
|
+
'SELECT COUNT(DISTINCT module) as count FROM _audit_logs WHERE created_at >= $1',
|
|
200
|
+
[startDate.toISOString()]
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
const actionsByModuleResult = await pool.query(
|
|
204
|
+
`SELECT module, COUNT(*) as count
|
|
205
|
+
FROM _audit_logs
|
|
206
|
+
WHERE created_at >= $1
|
|
207
|
+
GROUP BY module`,
|
|
208
|
+
[startDate.toISOString()]
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
const recentActivityResult = await pool.query(
|
|
212
|
+
`SELECT * FROM _audit_logs
|
|
213
|
+
WHERE created_at >= $1
|
|
214
|
+
ORDER BY created_at DESC
|
|
215
|
+
LIMIT 10`,
|
|
216
|
+
[startDate.toISOString()]
|
|
217
|
+
);
|
|
203
218
|
|
|
204
219
|
const moduleStats: Record<string, number> = {};
|
|
205
|
-
|
|
206
|
-
moduleStats[row.module] = parseInt(row.count);
|
|
220
|
+
actionsByModuleResult.rows.forEach((row: { module: string; count: string }) => {
|
|
221
|
+
moduleStats[row.module] = parseInt(row.count, 10);
|
|
207
222
|
});
|
|
208
223
|
|
|
209
224
|
return {
|
|
210
|
-
totalLogs: parseInt(
|
|
211
|
-
uniqueActors: parseInt(
|
|
212
|
-
uniqueModules: parseInt(
|
|
225
|
+
totalLogs: parseInt(totalLogsResult.rows[0]?.count || '0', 10),
|
|
226
|
+
uniqueActors: parseInt(uniqueActorsResult.rows[0]?.count || '0', 10),
|
|
227
|
+
uniqueModules: parseInt(uniqueModulesResult.rows[0]?.count || '0', 10),
|
|
213
228
|
actionsByModule: moduleStats,
|
|
214
|
-
recentActivity:
|
|
229
|
+
recentActivity: recentActivityResult.rows.map((record) => ({
|
|
215
230
|
id: record.id,
|
|
216
231
|
actor: record.actor,
|
|
217
232
|
action: record.action,
|
|
@@ -233,14 +248,16 @@ export class AuditService {
|
|
|
233
248
|
*/
|
|
234
249
|
async cleanup(daysToKeep: number = 90): Promise<number> {
|
|
235
250
|
try {
|
|
251
|
+
const pool = this.getPool();
|
|
236
252
|
const cutoffDate = new Date();
|
|
237
253
|
cutoffDate.setDate(cutoffDate.getDate() - daysToKeep);
|
|
238
254
|
|
|
239
|
-
const result = await
|
|
240
|
-
|
|
241
|
-
|
|
255
|
+
const result = await pool.query(
|
|
256
|
+
'DELETE FROM _audit_logs WHERE created_at < $1 RETURNING id',
|
|
257
|
+
[cutoffDate.toISOString()]
|
|
258
|
+
);
|
|
242
259
|
|
|
243
|
-
const deletedCount = result.length;
|
|
260
|
+
const deletedCount = result.rows.length;
|
|
244
261
|
|
|
245
262
|
if (deletedCount > 0) {
|
|
246
263
|
logger.info(`Cleaned up ${deletedCount} audit logs older than ${daysToKeep} days`);
|