insforge 0.3.1
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/.dockerignore +58 -0
- package/.env.example +49 -0
- package/.github/ISSUE_TEMPLATE/bug_report.yml +83 -0
- package/.github/ISSUE_TEMPLATE/config.yml +11 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +79 -0
- package/.github/copilot-instructions.md +147 -0
- package/.github/workflows/build-image.yml +65 -0
- package/.github/workflows/ci-premerge-check.yml +24 -0
- package/.github/workflows/deploy-aws.yml +130 -0
- package/.github/workflows/lint-and-format.yml +33 -0
- package/.prettierignore +65 -0
- package/.prettierrc +9 -0
- package/CHANGELOG.md +3 -0
- package/CONTRIBUTING.md +126 -0
- package/Dockerfile +27 -0
- package/GITHUB_OAUTH_SETUP.md +49 -0
- package/GOOGLE_OAUTH_SETUP.md +148 -0
- package/LICENSE +201 -0
- package/README.md +134 -0
- package/assets/Dark.svg +23 -0
- package/assets/archDiagram.png +0 -0
- package/assets/banner.png +0 -0
- package/assets/mcpInstallv2.png +0 -0
- package/assets/sampleResponse.png +0 -0
- package/assets/signin.png +0 -0
- package/assets/userflow.png +0 -0
- package/backend/migrations/000_create-base-tables.sql +142 -0
- package/backend/migrations/001_create-helper-functions.sql +41 -0
- package/backend/migrations/002_rename-auth-tables.sql +30 -0
- package/backend/migrations/003_create-users-table.sql +56 -0
- package/backend/migrations/004_add-reload-postgrest-func.sql +24 -0
- package/backend/migrations/005_enable-project-admin-modify-users.sql +30 -0
- package/backend/migrations/006_modify-ai-usage-table.sql +25 -0
- package/backend/migrations/007_drop-metadata-table.sql +2 -0
- package/backend/migrations/008_add-system-tables.sql +77 -0
- package/backend/migrations/009_add-function-secrets.sql +24 -0
- package/backend/migrations/010_modify-ai-config-modalities.sql +93 -0
- package/backend/migrations/011_refactor-secrets-table.sql +15 -0
- package/backend/migrations/012_add-storage-uploaded-by.sql +8 -0
- package/backend/package.json +75 -0
- package/backend/src/api/middleware/auth.ts +240 -0
- package/backend/src/api/middleware/error.ts +231 -0
- package/backend/src/api/middleware/upload.ts +59 -0
- package/backend/src/api/routes/agent.ts +29 -0
- package/backend/src/api/routes/ai.ts +472 -0
- package/backend/src/api/routes/auth.oauth.ts +482 -0
- package/backend/src/api/routes/auth.ts +386 -0
- package/backend/src/api/routes/database.advance.ts +275 -0
- package/backend/src/api/routes/database.records.ts +246 -0
- package/backend/src/api/routes/database.tables.ts +161 -0
- package/backend/src/api/routes/docs.ts +66 -0
- package/backend/src/api/routes/functions.ts +183 -0
- package/backend/src/api/routes/logs.ts +150 -0
- package/backend/src/api/routes/metadata.ts +160 -0
- package/backend/src/api/routes/openapi.ts +82 -0
- package/backend/src/api/routes/secrets.ts +199 -0
- package/backend/src/api/routes/storage.ts +547 -0
- package/backend/src/api/routes/usage.ts +96 -0
- package/backend/src/core/ai/chat.ts +207 -0
- package/backend/src/core/ai/client.ts +242 -0
- package/backend/src/core/ai/config.ts +187 -0
- package/backend/src/core/ai/image.ts +156 -0
- package/backend/src/core/ai/model.ts +117 -0
- package/backend/src/core/ai/usage.ts +290 -0
- package/backend/src/core/auth/auth.ts +781 -0
- package/backend/src/core/auth/oauth.ts +398 -0
- package/backend/src/core/database/advance.ts +1074 -0
- package/backend/src/core/database/manager.ts +178 -0
- package/backend/src/core/database/table.ts +772 -0
- package/backend/src/core/documentation/agent.ts +689 -0
- package/backend/src/core/documentation/openapi.ts +856 -0
- package/backend/src/core/functions/functions.ts +310 -0
- package/backend/src/core/logs/analytics.ts +76 -0
- package/backend/src/core/logs/audit.ts +255 -0
- package/backend/src/core/logs/providers/base.provider.ts +83 -0
- package/backend/src/core/logs/providers/cloudwatch.provider.ts +510 -0
- package/backend/src/core/logs/providers/localdb.provider.ts +246 -0
- package/backend/src/core/secrets/encryption.ts +58 -0
- package/backend/src/core/secrets/secrets.ts +410 -0
- package/backend/src/core/socket/socket.ts +388 -0
- package/backend/src/core/socket/types.ts +79 -0
- package/backend/src/core/storage/storage.ts +923 -0
- package/backend/src/server.ts +288 -0
- package/backend/src/types/ai.ts +46 -0
- package/backend/src/types/auth.ts +90 -0
- package/backend/src/types/database.ts +136 -0
- package/backend/src/types/error-constants.ts +86 -0
- package/backend/src/types/logs.ts +47 -0
- package/backend/src/types/profile.ts +55 -0
- package/backend/src/types/storage.ts +23 -0
- package/backend/src/utils/cloud-token.ts +39 -0
- package/backend/src/utils/constants.ts +1 -0
- package/backend/src/utils/environment.ts +35 -0
- package/backend/src/utils/helpers.ts +49 -0
- package/backend/src/utils/logger.ts +13 -0
- package/backend/src/utils/response.ts +62 -0
- package/backend/src/utils/seed.ts +205 -0
- package/backend/src/utils/sql-parser.ts +63 -0
- package/backend/src/utils/uuid.ts +9 -0
- package/backend/src/utils/validations.ts +129 -0
- package/backend/tests/README.md +134 -0
- package/backend/tests/cleanup-all-test-data.sh +231 -0
- package/backend/tests/cloud/test-s3-multitenant.sh +132 -0
- package/backend/tests/local/comprehensive-curl-tests.sh +156 -0
- package/backend/tests/local/test-auth-router.sh +144 -0
- package/backend/tests/local/test-database-router.sh +222 -0
- package/backend/tests/local/test-e2e.sh +241 -0
- package/backend/tests/local/test-fk-errors.sh +97 -0
- package/backend/tests/local/test-id-field.sh +201 -0
- package/backend/tests/local/test-public-bucket.sh +265 -0
- package/backend/tests/local/test-secrets.sh +248 -0
- package/backend/tests/local/test-serverless-functions.sh.disabled +325 -0
- package/backend/tests/local/test-traditional-rest.sh +209 -0
- package/backend/tests/manual/README.md +51 -0
- package/backend/tests/manual/create-large-table-simple.sql +11 -0
- package/backend/tests/manual/seed-large-table.sql +101 -0
- package/backend/tests/manual/setup-large-table-extras.sql +34 -0
- package/backend/tests/manual/test-better-auth.sh +303 -0
- package/backend/tests/manual/test-bulk-upsert.sh +410 -0
- package/backend/tests/manual/test-database-advance.sh +297 -0
- package/backend/tests/manual/test-postgrest-stability.sh +192 -0
- package/backend/tests/manual/test-rawsql-export-import.sh +412 -0
- package/backend/tests/manual/test-universal-storage.sh +264 -0
- package/backend/tests/manual/test-users.sql +18 -0
- package/backend/tests/run-all-tests.sh +140 -0
- package/backend/tests/setup.ts +22 -0
- package/backend/tests/test-config.sh +303 -0
- package/backend/tsconfig.json +23 -0
- package/backend/tsup.config.ts +18 -0
- package/backend/vitest.config.ts +22 -0
- package/docker-compose.prod.yml +145 -0
- package/docker-compose.yml +167 -0
- package/docker-init/db/db-init.sql +125 -0
- package/docker-init/db/jwt.sql +5 -0
- package/docker-init/db/logs.sql +9 -0
- package/docker-init/db/postgresql.conf +17 -0
- package/docs/deprecated/insforge-auth-api.md +215 -0
- package/docs/deprecated/insforge-auth-sdk.md +100 -0
- package/docs/deprecated/insforge-db-api.md +359 -0
- package/docs/deprecated/insforge-db-sdk.md +140 -0
- package/docs/deprecated/insforge-debug-sdk.md +157 -0
- package/docs/deprecated/insforge-debug.md +65 -0
- package/docs/deprecated/insforge-instructions.md +124 -0
- package/docs/deprecated/insforge-project.md +118 -0
- package/docs/deprecated/insforge-storage-api.md +279 -0
- package/docs/deprecated/insforge-storage-sdk.md +159 -0
- package/docs/insforge-instructions-sdk.md +407 -0
- package/eslint.config.js +317 -0
- package/examples/oauth/frontend-oauth-example.html +251 -0
- package/examples/response-examples.md +444 -0
- package/frontend/README.md +112 -0
- package/frontend/components.json +17 -0
- package/frontend/index.html +13 -0
- package/frontend/package.json +63 -0
- package/frontend/public/favicon.ico +0 -0
- package/frontend/src/App.tsx +106 -0
- package/frontend/src/assets/icons/checkbox_checked.svg +6 -0
- package/frontend/src/assets/icons/checkbox_undetermined.svg +6 -0
- package/frontend/src/assets/icons/checked.svg +3 -0
- package/frontend/src/assets/icons/error.svg +3 -0
- package/frontend/src/assets/icons/pencil.svg +4 -0
- package/frontend/src/assets/icons/refresh.svg +4 -0
- package/frontend/src/assets/icons/step_active.svg +3 -0
- package/frontend/src/assets/icons/step_inactive.svg +11 -0
- package/frontend/src/assets/icons/warning.svg +3 -0
- package/frontend/src/assets/logos/amazon.svg +1 -0
- package/frontend/src/assets/logos/claude_code.svg +3 -0
- package/frontend/src/assets/logos/cline.svg +6 -0
- package/frontend/src/assets/logos/cursor.svg +20 -0
- package/frontend/src/assets/logos/discord.svg +9 -0
- package/frontend/src/assets/logos/gemini.svg +19 -0
- package/frontend/src/assets/logos/github.svg +5 -0
- package/frontend/src/assets/logos/google.svg +13 -0
- package/frontend/src/assets/logos/grok.svg +10 -0
- package/frontend/src/assets/logos/insforge_dark.svg +15 -0
- package/frontend/src/assets/logos/insforge_light.svg +15 -0
- package/frontend/src/assets/logos/openai.svg +10 -0
- package/frontend/src/assets/logos/roo_code.svg +9 -0
- package/frontend/src/assets/logos/trae.svg +3 -0
- package/frontend/src/assets/logos/windsurf.svg +10 -0
- package/frontend/src/components/ButtonWithLoading.tsx +27 -0
- package/frontend/src/components/Checkbox.tsx +61 -0
- package/frontend/src/components/CodeBlock.tsx +32 -0
- package/frontend/src/components/ConfirmDialog.tsx +96 -0
- package/frontend/src/components/CopyButton.tsx +69 -0
- package/frontend/src/components/DeleteActionButton.tsx +42 -0
- package/frontend/src/components/EmptyState.tsx +41 -0
- package/frontend/src/components/ErrorState.tsx +35 -0
- package/frontend/src/components/FeatureSidebar.tsx +126 -0
- package/frontend/src/components/FeatureSidebarItem.tsx +101 -0
- package/frontend/src/components/JsonHighlight.tsx +61 -0
- package/frontend/src/components/LoadingState.tsx +16 -0
- package/frontend/src/components/PaginationControls.tsx +54 -0
- package/frontend/src/components/PromptDialog.tsx +68 -0
- package/frontend/src/components/SearchInput.tsx +90 -0
- package/frontend/src/components/SelectionClearButton.tsx +26 -0
- package/frontend/src/components/Stepper.tsx +139 -0
- package/frontend/src/components/ThemeToggle.tsx +58 -0
- package/frontend/src/components/TypeBadge.tsx +20 -0
- package/frontend/src/components/datagrid/DataGrid.tsx +264 -0
- package/frontend/src/components/datagrid/DefaultCellRenderer.tsx +114 -0
- package/frontend/src/components/datagrid/IdCell.tsx +44 -0
- package/frontend/src/components/datagrid/SortableHeader.tsx +74 -0
- package/frontend/src/components/datagrid/cell-editors/BooleanCellEditor.tsx +54 -0
- package/frontend/src/components/datagrid/cell-editors/DateCellEditor.tsx +483 -0
- package/frontend/src/components/datagrid/cell-editors/JsonCellEditor.tsx +362 -0
- package/frontend/src/components/datagrid/cell-editors/TextCellEditor.tsx +38 -0
- package/frontend/src/components/datagrid/cell-editors/index.ts +14 -0
- package/frontend/src/components/datagrid/cell-editors/types.ts +43 -0
- package/frontend/src/components/datagrid/datagridTypes.tsx +72 -0
- package/frontend/src/components/datagrid/index.tsx +20 -0
- package/frontend/src/components/index.ts +39 -0
- package/frontend/src/components/layout/AppHeader.tsx +146 -0
- package/frontend/src/components/layout/AppSidebar.tsx +190 -0
- package/frontend/src/components/layout/CloudLayout.tsx +95 -0
- package/frontend/src/components/layout/Layout.tsx +43 -0
- package/frontend/src/components/radix/Alert.tsx +45 -0
- package/frontend/src/components/radix/AlertDialog.tsx +115 -0
- package/frontend/src/components/radix/Avatar.tsx +45 -0
- package/frontend/src/components/radix/Badge.tsx +33 -0
- package/frontend/src/components/radix/Button.tsx +50 -0
- package/frontend/src/components/radix/Card.tsx +58 -0
- package/frontend/src/components/radix/Dialog.tsx +98 -0
- package/frontend/src/components/radix/DropdownMenu.tsx +185 -0
- package/frontend/src/components/radix/Form.tsx +167 -0
- package/frontend/src/components/radix/Input.tsx +22 -0
- package/frontend/src/components/radix/Label.tsx +19 -0
- package/frontend/src/components/radix/Popover.tsx +29 -0
- package/frontend/src/components/radix/ScrollArea.tsx +44 -0
- package/frontend/src/components/radix/Select.tsx +151 -0
- package/frontend/src/components/radix/Separator.tsx +26 -0
- package/frontend/src/components/radix/Sheet.tsx +119 -0
- package/frontend/src/components/radix/Skeleton.tsx +7 -0
- package/frontend/src/components/radix/Switch.tsx +29 -0
- package/frontend/src/components/radix/Tabs.tsx +50 -0
- package/frontend/src/components/radix/Textarea.tsx +21 -0
- package/frontend/src/components/radix/Tooltip.tsx +28 -0
- package/frontend/src/features/ai/components/AIConfigCard.tsx +154 -0
- package/frontend/src/features/ai/components/AIConfigDialog.tsx +76 -0
- package/frontend/src/features/ai/components/AIConfigForm.tsx +222 -0
- package/frontend/src/features/ai/components/AIEmptyState.tsx +18 -0
- package/frontend/src/features/ai/components/fields/ModalityField.tsx +87 -0
- package/frontend/src/features/ai/components/fields/ModelSelectionField.tsx +134 -0
- package/frontend/src/features/ai/components/fields/SystemPromptField.tsx +33 -0
- package/frontend/src/features/ai/helpers.ts +155 -0
- package/frontend/src/features/ai/hooks/useAIConfigs.ts +221 -0
- package/frontend/src/features/ai/hooks/useAIUsage.ts +77 -0
- package/frontend/src/features/ai/page/AIPage.tsx +178 -0
- package/frontend/src/features/ai/services/ai.service.ts +148 -0
- package/frontend/src/features/auth/components/AddOAuthDialog.tsx +106 -0
- package/frontend/src/features/auth/components/AuthMethodTab.tsx +238 -0
- package/frontend/src/features/auth/components/OAuthConfigDialog.tsx +303 -0
- package/frontend/src/features/auth/components/OAuthEmptyState.tsx +15 -0
- package/frontend/src/features/auth/components/UserFormDialog.tsx +248 -0
- package/frontend/src/features/auth/components/UsersDataGrid.tsx +183 -0
- package/frontend/src/features/auth/components/UsersTab.tsx +114 -0
- package/frontend/src/features/auth/hooks/useOAuthConfig.ts +129 -0
- package/frontend/src/features/auth/hooks/useUsers.ts +57 -0
- package/frontend/src/features/auth/index.ts +9 -0
- package/frontend/src/features/auth/page/AuthenticationPage.tsx +169 -0
- package/frontend/src/features/auth/services/auth.service.ts +112 -0
- package/frontend/src/features/auth/services/oauth.service.ts +49 -0
- package/frontend/src/features/dashboard/page/DashboardPage.tsx +194 -0
- package/frontend/src/features/database/components/ColumnTypeSelect.tsx +64 -0
- package/frontend/src/features/database/components/DatabaseDataGrid.tsx +282 -0
- package/frontend/src/features/database/components/ForeignKeyCell.tsx +187 -0
- package/frontend/src/features/database/components/ForeignKeyPopover.tsx +378 -0
- package/frontend/src/features/database/components/LinkRecordModal.tsx +288 -0
- package/frontend/src/features/database/components/RecordFormDialog.tsx +164 -0
- package/frontend/src/features/database/components/RecordFormField.tsx +568 -0
- package/frontend/src/features/database/components/TableEmptyState.tsx +21 -0
- package/frontend/src/features/database/components/TableForm.tsx +656 -0
- package/frontend/src/features/database/components/TableFormColumn.tsx +137 -0
- package/frontend/src/features/database/components/TableListSkeleton.tsx +9 -0
- package/frontend/src/features/database/components/TableSidebar.tsx +47 -0
- package/frontend/src/features/database/constants.ts +26 -0
- package/frontend/src/features/database/helpers.ts +125 -0
- package/frontend/src/features/database/hooks/UseLinkModal.tsx +78 -0
- package/frontend/src/features/database/index.ts +12 -0
- package/frontend/src/features/database/page/DatabasePage.tsx +626 -0
- package/frontend/src/features/database/schema.ts +25 -0
- package/frontend/src/features/database/services/database.service.ts +216 -0
- package/frontend/src/features/functions/components/FunctionEmptyState.tsx +15 -0
- package/frontend/src/features/functions/components/FunctionRow.tsx +71 -0
- package/frontend/src/features/functions/components/FunctionViewer.tsx +46 -0
- package/frontend/src/features/functions/components/FunctionsContent.tsx +88 -0
- package/frontend/src/features/functions/components/FunctionsSidebar.tsx +56 -0
- package/frontend/src/features/functions/components/SecretEmptyState.tsx +23 -0
- package/frontend/src/features/functions/components/SecretRow.tsx +68 -0
- package/frontend/src/features/functions/components/SecretsContent.tsx +120 -0
- package/frontend/src/features/functions/hooks/useFunctions.ts +106 -0
- package/frontend/src/features/functions/page/FunctionsPage.tsx +28 -0
- package/frontend/src/features/functions/services/functions.service.ts +48 -0
- package/frontend/src/features/login/components/AuthErrorBoundary.tsx +87 -0
- package/frontend/src/features/login/components/PrivateRoute.tsx +24 -0
- package/frontend/src/features/login/page/CloudLoginPage.tsx +93 -0
- package/frontend/src/features/login/page/LoginPage.tsx +174 -0
- package/frontend/src/features/logs/components/AnalyticsLogsTable.tsx +313 -0
- package/frontend/src/features/logs/components/LogsTable.tsx +199 -0
- package/frontend/src/features/logs/hooks/useAuditLogs.ts +39 -0
- package/frontend/src/features/logs/index.ts +5 -0
- package/frontend/src/features/logs/page/AnalyticsLogsPage.tsx +530 -0
- package/frontend/src/features/logs/page/AuditsPage.tsx +192 -0
- package/frontend/src/features/logs/services/log.service.ts +171 -0
- package/frontend/src/features/metadata/hooks/useMetadata.ts +53 -0
- package/frontend/src/features/metadata/index.ts +0 -0
- package/frontend/src/features/metadata/page/MetadataPage.tsx +136 -0
- package/frontend/src/features/metadata/services/metadata.service.ts +17 -0
- package/frontend/src/features/onboard/components/CompletionCard.tsx +41 -0
- package/frontend/src/features/onboard/components/OnboardButton.tsx +84 -0
- package/frontend/src/features/onboard/components/StepContent.tsx +91 -0
- package/frontend/src/features/onboard/components/TestConnectionStep.tsx +53 -0
- package/frontend/src/features/onboard/components/mcp/CursorDeeplinkGenerator.tsx +35 -0
- package/frontend/src/features/onboard/components/mcp/McpInstallation.tsx +144 -0
- package/frontend/src/features/onboard/components/mcp/index.ts +4 -0
- package/frontend/src/features/onboard/components/mcp/mcp-helper.tsx +98 -0
- package/frontend/src/features/onboard/index.ts +3 -0
- package/frontend/src/features/onboard/page/OnBoardPage.tsx +104 -0
- package/frontend/src/features/onboard/types.ts +8 -0
- package/frontend/src/features/secrets/hooks/useSecrets.ts +139 -0
- package/frontend/src/features/secrets/services/secrets.service.ts +57 -0
- package/frontend/src/features/storage/components/BucketEmptyState.tsx +19 -0
- package/frontend/src/features/storage/components/BucketFormDialog.tsx +194 -0
- package/frontend/src/features/storage/components/BucketListSkeleton.tsx +17 -0
- package/frontend/src/features/storage/components/FilePreviewDialog.tsx +287 -0
- package/frontend/src/features/storage/components/StorageDataGrid.tsx +239 -0
- package/frontend/src/features/storage/components/StorageManager.tsx +236 -0
- package/frontend/src/features/storage/components/StorageSidebar.tsx +44 -0
- package/frontend/src/features/storage/components/UploadToast.tsx +46 -0
- package/frontend/src/features/storage/index.ts +3 -0
- package/frontend/src/features/storage/page/StoragePage.tsx +553 -0
- package/frontend/src/features/storage/services/storage.service.ts +144 -0
- package/frontend/src/features/visualizer/components/AuthNode.tsx +107 -0
- package/frontend/src/features/visualizer/components/BucketNode.tsx +34 -0
- package/frontend/src/features/visualizer/components/SchemaVisualizer.tsx +359 -0
- package/frontend/src/features/visualizer/components/TableNode.tsx +152 -0
- package/frontend/src/features/visualizer/components/VisualizerSkeleton.tsx +24 -0
- package/frontend/src/features/visualizer/components/index.ts +5 -0
- package/frontend/src/features/visualizer/page/VisualizerPage.tsx +127 -0
- package/frontend/src/index.css +248 -0
- package/frontend/src/lib/api/client.ts +163 -0
- package/frontend/src/lib/contexts/AuthContext.tsx +157 -0
- package/frontend/src/lib/contexts/OnboardStepContext.tsx +68 -0
- package/frontend/src/lib/contexts/SocketContext.tsx +303 -0
- package/frontend/src/lib/contexts/ThemeContext.tsx +125 -0
- package/frontend/src/lib/hooks/useAuth.ts +4 -0
- package/frontend/src/lib/hooks/useConfirm.ts +55 -0
- package/frontend/src/lib/hooks/useInterval.ts +27 -0
- package/frontend/src/lib/hooks/useMediaQuery.ts +59 -0
- package/frontend/src/lib/hooks/useOnboardingCompletion.ts +29 -0
- package/frontend/src/lib/hooks/usePagination.ts +27 -0
- package/frontend/src/lib/hooks/useTimeout.ts +27 -0
- package/frontend/src/lib/hooks/useToast.tsx +229 -0
- package/frontend/src/lib/utils/constants.ts +38 -0
- package/frontend/src/lib/utils/utils.ts +165 -0
- package/frontend/src/lib/utils/validation-schemas.ts +126 -0
- package/frontend/src/main.tsx +16 -0
- package/frontend/src/rdg.css +194 -0
- package/frontend/src/vite-env.d.ts +12 -0
- package/frontend/tailwind.config.js +97 -0
- package/frontend/tsconfig.json +26 -0
- package/frontend/tsconfig.node.json +10 -0
- package/frontend/vite.config.ts +37 -0
- package/frontend/vitest.config.ts +36 -0
- package/functions/deno.json +25 -0
- package/functions/server.ts +290 -0
- package/functions/worker-template.js +126 -0
- package/openapi/ai.yaml +689 -0
- package/openapi/auth.yaml +563 -0
- package/openapi/functions.yaml +476 -0
- package/openapi/health.yaml +30 -0
- package/openapi/logs.yaml +224 -0
- package/openapi/metadata.yaml +178 -0
- package/openapi/records.yaml +382 -0
- package/openapi/secrets.yaml +371 -0
- package/openapi/storage.yaml +876 -0
- package/openapi/tables.yaml +464 -0
- package/package.json +88 -0
- package/shared-schemas/package.json +31 -0
- package/shared-schemas/src/ai-api.schema.ts +167 -0
- package/shared-schemas/src/ai.schema.ts +54 -0
- package/shared-schemas/src/auth-api.schema.ts +193 -0
- package/shared-schemas/src/auth.schema.ts +94 -0
- package/shared-schemas/src/database-api.schema.ts +259 -0
- package/shared-schemas/src/database.schema.ts +69 -0
- package/shared-schemas/src/functions-api.schema.ts +25 -0
- package/shared-schemas/src/functions.schema.ts +16 -0
- package/shared-schemas/src/index.ts +13 -0
- package/shared-schemas/src/logs-api.schema.ts +49 -0
- package/shared-schemas/src/logs.schema.ts +14 -0
- package/shared-schemas/src/metadata.schema.ts +56 -0
- package/shared-schemas/src/storage-api.schema.ts +65 -0
- package/shared-schemas/src/storage.schema.ts +19 -0
- package/shared-schemas/tsconfig.json +21 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
import { Pool } from 'pg';
|
|
2
|
+
import { DatabaseManager } from '@/core/database/manager.js';
|
|
3
|
+
import { SecretsService } from '@/core/secrets/secrets.js';
|
|
4
|
+
import { AppError } from '@/api/middleware/error.js';
|
|
5
|
+
import { ERROR_CODES } from '@/types/error-constants.js';
|
|
6
|
+
import logger from '@/utils/logger.js';
|
|
7
|
+
import { OAuthConfigSchema } from '@insforge/shared-schemas';
|
|
8
|
+
|
|
9
|
+
export interface CreateOAuthConfigInput {
|
|
10
|
+
provider: string;
|
|
11
|
+
clientId?: string;
|
|
12
|
+
clientSecret?: string;
|
|
13
|
+
redirectUri?: string;
|
|
14
|
+
scopes?: string[];
|
|
15
|
+
useSharedKey?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface UpdateOAuthConfigInput {
|
|
19
|
+
clientId?: string;
|
|
20
|
+
clientSecret?: string;
|
|
21
|
+
redirectUri?: string;
|
|
22
|
+
scopes?: string[];
|
|
23
|
+
useSharedKey?: boolean;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export class OAuthConfigService {
|
|
27
|
+
private static instance: OAuthConfigService;
|
|
28
|
+
private pool: Pool | null = null;
|
|
29
|
+
private secretsService: SecretsService;
|
|
30
|
+
|
|
31
|
+
private constructor() {
|
|
32
|
+
this.secretsService = new SecretsService();
|
|
33
|
+
logger.info('OAuthService initialized');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public static getInstance(): OAuthConfigService {
|
|
37
|
+
if (!OAuthConfigService.instance) {
|
|
38
|
+
OAuthConfigService.instance = new OAuthConfigService();
|
|
39
|
+
}
|
|
40
|
+
return OAuthConfigService.instance;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private getPool(): Pool {
|
|
44
|
+
if (!this.pool) {
|
|
45
|
+
this.pool = DatabaseManager.getInstance().getPool();
|
|
46
|
+
}
|
|
47
|
+
return this.pool;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Get all OAuth configurations
|
|
52
|
+
*/
|
|
53
|
+
async getAllConfigs(): Promise<OAuthConfigSchema[]> {
|
|
54
|
+
const client = await this.getPool().connect();
|
|
55
|
+
try {
|
|
56
|
+
const result = await client.query(
|
|
57
|
+
`SELECT
|
|
58
|
+
provider,
|
|
59
|
+
client_id as "clientId",
|
|
60
|
+
redirect_uri as "redirectUri",
|
|
61
|
+
scopes,
|
|
62
|
+
use_shared_key as "useSharedKey"
|
|
63
|
+
FROM _oauth_configs
|
|
64
|
+
ORDER BY provider ASC`
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
return result.rows;
|
|
68
|
+
} catch (error) {
|
|
69
|
+
logger.error('Failed to get OAuth configs', { error });
|
|
70
|
+
throw new AppError('Failed to get OAuth configurations', 500, ERROR_CODES.INTERNAL_ERROR);
|
|
71
|
+
} finally {
|
|
72
|
+
client.release();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Get OAuth configuration by provider name
|
|
78
|
+
*/
|
|
79
|
+
async getConfigByProvider(provider: string): Promise<OAuthConfigSchema | null> {
|
|
80
|
+
const client = await this.getPool().connect();
|
|
81
|
+
try {
|
|
82
|
+
const result = await client.query(
|
|
83
|
+
`SELECT
|
|
84
|
+
provider,
|
|
85
|
+
client_id as "clientId",
|
|
86
|
+
redirect_uri as "redirectUri",
|
|
87
|
+
scopes,
|
|
88
|
+
use_shared_key as "useSharedKey"
|
|
89
|
+
FROM _oauth_configs
|
|
90
|
+
WHERE LOWER(provider) = LOWER($1)
|
|
91
|
+
LIMIT 1`,
|
|
92
|
+
[provider]
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
if (result.rows.length === 0) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return result.rows[0];
|
|
100
|
+
} catch (error) {
|
|
101
|
+
logger.error('Failed to get OAuth config by provider', { error, provider });
|
|
102
|
+
throw new AppError('Failed to get OAuth configuration', 500, ERROR_CODES.INTERNAL_ERROR);
|
|
103
|
+
} finally {
|
|
104
|
+
client.release();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Get OAuth provider secret
|
|
110
|
+
*/
|
|
111
|
+
async getClientSecretByProvider(provider: string): Promise<string | null> {
|
|
112
|
+
const client = await this.getPool().connect();
|
|
113
|
+
try {
|
|
114
|
+
const result = await client.query(
|
|
115
|
+
`SELECT
|
|
116
|
+
secret_id as "secretId"
|
|
117
|
+
FROM _oauth_configs
|
|
118
|
+
WHERE LOWER(provider) = LOWER($1)
|
|
119
|
+
LIMIT 1`,
|
|
120
|
+
[provider]
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
if (result.rows.length === 0) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const config = result.rows[0];
|
|
128
|
+
const clientSecret = await this.secretsService.getSecretById(config.secretId);
|
|
129
|
+
if (!clientSecret) {
|
|
130
|
+
logger.warn('OAuth config exists but secret not found', { provider });
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return clientSecret;
|
|
135
|
+
} catch (error) {
|
|
136
|
+
logger.error('Failed to get OAuth config with secret', { error, provider });
|
|
137
|
+
throw new AppError('Failed to get OAuth configuration', 500, ERROR_CODES.INTERNAL_ERROR);
|
|
138
|
+
} finally {
|
|
139
|
+
client.release();
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Create OAuth configuration
|
|
145
|
+
*/
|
|
146
|
+
async createConfig(input: CreateOAuthConfigInput): Promise<OAuthConfigSchema> {
|
|
147
|
+
const client = await this.getPool().connect();
|
|
148
|
+
try {
|
|
149
|
+
await client.query('BEGIN');
|
|
150
|
+
|
|
151
|
+
// Check if config already exists for this provider
|
|
152
|
+
const existingConfig = await client.query(
|
|
153
|
+
'SELECT id FROM _oauth_configs WHERE LOWER(provider) = LOWER($1)',
|
|
154
|
+
[input.provider]
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
if (existingConfig.rows.length > 0) {
|
|
158
|
+
throw new AppError(
|
|
159
|
+
`OAuth configuration for ${input.provider} already exists`,
|
|
160
|
+
409,
|
|
161
|
+
ERROR_CODES.ALREADY_EXISTS
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
let secretId: string | null = null;
|
|
166
|
+
|
|
167
|
+
// Only create secret if clientSecret is provided and not using shared key
|
|
168
|
+
if (input.clientSecret && !input.useSharedKey) {
|
|
169
|
+
// Create new secret
|
|
170
|
+
const secret = await this.secretsService.createSecret({
|
|
171
|
+
key: `${input.provider.toUpperCase()}_CLIENT_SECRET`,
|
|
172
|
+
value: input.clientSecret,
|
|
173
|
+
});
|
|
174
|
+
secretId = secret.id;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Set default scopes if not provided
|
|
178
|
+
let scopes = input.scopes;
|
|
179
|
+
if (!scopes) {
|
|
180
|
+
const provider = input.provider.toLowerCase();
|
|
181
|
+
if (provider === 'google') {
|
|
182
|
+
scopes = ['openid', 'email', 'profile'];
|
|
183
|
+
} else if (provider === 'github') {
|
|
184
|
+
scopes = ['user:email'];
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Create new OAuth config
|
|
189
|
+
const result = await client.query(
|
|
190
|
+
`INSERT INTO _oauth_configs (provider, client_id, secret_id, redirect_uri, scopes, use_shared_key)
|
|
191
|
+
VALUES ($1, $2, $3, $4, $5, $6)
|
|
192
|
+
RETURNING
|
|
193
|
+
provider,
|
|
194
|
+
client_id as "clientId",
|
|
195
|
+
redirect_uri as "redirectUri",
|
|
196
|
+
scopes,
|
|
197
|
+
use_shared_key as "useSharedKey"`,
|
|
198
|
+
[
|
|
199
|
+
input.provider.toLowerCase(),
|
|
200
|
+
input.clientId || null,
|
|
201
|
+
secretId,
|
|
202
|
+
null, // Deprecating redirect_uri
|
|
203
|
+
scopes,
|
|
204
|
+
input.useSharedKey || false,
|
|
205
|
+
]
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
await client.query('COMMIT');
|
|
209
|
+
logger.info('OAuth config created', { provider: input.provider });
|
|
210
|
+
|
|
211
|
+
return result.rows[0];
|
|
212
|
+
} catch (error) {
|
|
213
|
+
await client.query('ROLLBACK');
|
|
214
|
+
logger.error('Failed to create OAuth config', { error, provider: input.provider });
|
|
215
|
+
if (error instanceof AppError) {
|
|
216
|
+
throw error;
|
|
217
|
+
}
|
|
218
|
+
throw new AppError('Failed to create OAuth configuration', 500, ERROR_CODES.INTERNAL_ERROR);
|
|
219
|
+
} finally {
|
|
220
|
+
client.release();
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Update OAuth configuration
|
|
226
|
+
*/
|
|
227
|
+
async updateConfig(provider: string, input: UpdateOAuthConfigInput): Promise<OAuthConfigSchema> {
|
|
228
|
+
const client = await this.getPool().connect();
|
|
229
|
+
try {
|
|
230
|
+
await client.query('BEGIN');
|
|
231
|
+
|
|
232
|
+
// Get existing config with secret_id
|
|
233
|
+
const existingResult = await client.query(
|
|
234
|
+
`SELECT id, secret_id as "secretId" FROM _oauth_configs WHERE LOWER(provider) = LOWER($1)`,
|
|
235
|
+
[provider]
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
if (existingResult.rows.length === 0) {
|
|
239
|
+
throw new AppError('OAuth configuration not found', 404, ERROR_CODES.NOT_FOUND);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const existingConfig = existingResult.rows[0];
|
|
243
|
+
|
|
244
|
+
// Update or create secret if provided
|
|
245
|
+
if (input.clientSecret !== undefined) {
|
|
246
|
+
if (existingConfig.secretId) {
|
|
247
|
+
// Update existing secret
|
|
248
|
+
await this.secretsService.updateSecret(existingConfig.secretId, {
|
|
249
|
+
value: input.clientSecret,
|
|
250
|
+
});
|
|
251
|
+
} else {
|
|
252
|
+
// Create new secret if it doesn't exist
|
|
253
|
+
const secret = await this.secretsService.createSecret({
|
|
254
|
+
key: `${provider.toUpperCase()}_CLIENT_SECRET`,
|
|
255
|
+
value: input.clientSecret,
|
|
256
|
+
});
|
|
257
|
+
// Add secret_id to the update query
|
|
258
|
+
await client.query(`UPDATE _oauth_configs SET secret_id = $1 WHERE id = $2`, [
|
|
259
|
+
secret.id,
|
|
260
|
+
existingConfig.id,
|
|
261
|
+
]);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Build update query
|
|
266
|
+
const updates: string[] = [];
|
|
267
|
+
const values: (string | string[] | boolean | null)[] = [];
|
|
268
|
+
let paramCount = 1;
|
|
269
|
+
|
|
270
|
+
if (input.clientId !== undefined) {
|
|
271
|
+
updates.push(`client_id = $${paramCount++}`);
|
|
272
|
+
values.push(input.clientId);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (input.redirectUri !== undefined) {
|
|
276
|
+
updates.push(`redirect_uri = $${paramCount++}`);
|
|
277
|
+
values.push(input.redirectUri);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (input.scopes !== undefined) {
|
|
281
|
+
updates.push(`scopes = $${paramCount++}`);
|
|
282
|
+
values.push(input.scopes);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (input.useSharedKey !== undefined) {
|
|
286
|
+
updates.push(`use_shared_key = $${paramCount++}`);
|
|
287
|
+
values.push(input.useSharedKey);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (updates.length === 0 && input.clientSecret === undefined) {
|
|
291
|
+
await client.query('COMMIT');
|
|
292
|
+
// Return the config in the correct format
|
|
293
|
+
const config = await this.getConfigByProvider(provider);
|
|
294
|
+
if (!config) {
|
|
295
|
+
throw new AppError('Failed to retrieve configuration', 500, ERROR_CODES.INTERNAL_ERROR);
|
|
296
|
+
}
|
|
297
|
+
return config;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (updates.length > 0) {
|
|
301
|
+
updates.push('updated_at = NOW()');
|
|
302
|
+
values.push(provider.toLowerCase());
|
|
303
|
+
|
|
304
|
+
const result = await client.query(
|
|
305
|
+
`UPDATE _oauth_configs
|
|
306
|
+
SET ${updates.join(', ')}
|
|
307
|
+
WHERE LOWER(provider) = $${paramCount}
|
|
308
|
+
RETURNING
|
|
309
|
+
provider,
|
|
310
|
+
client_id as "clientId",
|
|
311
|
+
redirect_uri as "redirectUri",
|
|
312
|
+
scopes,
|
|
313
|
+
use_shared_key as "useSharedKey"`,
|
|
314
|
+
values
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
await client.query('COMMIT');
|
|
318
|
+
logger.info('OAuth config updated', { provider });
|
|
319
|
+
return result.rows[0];
|
|
320
|
+
} else {
|
|
321
|
+
// Only secret was updated
|
|
322
|
+
await client.query('COMMIT');
|
|
323
|
+
const updatedConfig = await this.getConfigByProvider(provider);
|
|
324
|
+
if (!updatedConfig) {
|
|
325
|
+
throw new AppError(
|
|
326
|
+
'Failed to retrieve updated configuration',
|
|
327
|
+
500,
|
|
328
|
+
ERROR_CODES.INTERNAL_ERROR
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
return updatedConfig;
|
|
332
|
+
}
|
|
333
|
+
} catch (error) {
|
|
334
|
+
await client.query('ROLLBACK');
|
|
335
|
+
logger.error('Failed to update OAuth config', { error, provider });
|
|
336
|
+
if (error instanceof AppError) {
|
|
337
|
+
throw error;
|
|
338
|
+
}
|
|
339
|
+
throw new AppError('Failed to update OAuth configuration', 500, ERROR_CODES.INTERNAL_ERROR);
|
|
340
|
+
} finally {
|
|
341
|
+
client.release();
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Delete OAuth configuration
|
|
347
|
+
*/
|
|
348
|
+
async deleteConfig(provider: string): Promise<boolean> {
|
|
349
|
+
const client = await this.getPool().connect();
|
|
350
|
+
try {
|
|
351
|
+
await client.query('BEGIN');
|
|
352
|
+
|
|
353
|
+
// Get existing config with secret_id
|
|
354
|
+
const existingResult = await client.query(
|
|
355
|
+
`SELECT id, secret_id as "secretId" FROM _oauth_configs WHERE LOWER(provider) = LOWER($1)`,
|
|
356
|
+
[provider]
|
|
357
|
+
);
|
|
358
|
+
|
|
359
|
+
if (existingResult.rows.length === 0) {
|
|
360
|
+
await client.query('ROLLBACK');
|
|
361
|
+
return false;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
const existingConfig = existingResult.rows[0];
|
|
365
|
+
|
|
366
|
+
// Delete OAuth config (secret will be restricted due to foreign key)
|
|
367
|
+
const result = await client.query(
|
|
368
|
+
'DELETE FROM _oauth_configs WHERE LOWER(provider) = LOWER($1)',
|
|
369
|
+
[provider]
|
|
370
|
+
);
|
|
371
|
+
|
|
372
|
+
// Try to delete the associated secret (will fail if still referenced)
|
|
373
|
+
try {
|
|
374
|
+
await client.query('DELETE FROM _secrets WHERE id = $1', [existingConfig.secretId]);
|
|
375
|
+
logger.info('Associated secret deleted', { secretId: existingConfig.secretId });
|
|
376
|
+
} catch {
|
|
377
|
+
logger.warn('Could not delete associated secret, it may be in use elsewhere', {
|
|
378
|
+
provider,
|
|
379
|
+
secretId: existingConfig.secretId,
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
await client.query('COMMIT');
|
|
384
|
+
|
|
385
|
+
const success = (result.rowCount ?? 0) > 0;
|
|
386
|
+
if (success) {
|
|
387
|
+
logger.info('OAuth config deleted', { provider });
|
|
388
|
+
}
|
|
389
|
+
return success;
|
|
390
|
+
} catch (error) {
|
|
391
|
+
await client.query('ROLLBACK');
|
|
392
|
+
logger.error('Failed to delete OAuth config', { error, provider });
|
|
393
|
+
throw new AppError('Failed to delete OAuth configuration', 500, ERROR_CODES.INTERNAL_ERROR);
|
|
394
|
+
} finally {
|
|
395
|
+
client.release();
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|