insforge 1.3.0 → 1.4.8
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/CHANGELOG.md +2 -0
- package/auth/package.json +5 -3
- package/auth/src/lib/broadcastService.ts +115 -117
- package/auth/src/lib/insforge.ts +8 -0
- package/auth/src/main.tsx +2 -4
- package/auth/src/pages/SignInPage.tsx +60 -60
- package/auth/src/pages/SignUpPage.tsx +60 -60
- package/auth/src/pages/VerifyEmailPage.tsx +18 -0
- package/auth/tsconfig.json +2 -1
- package/backend/package.json +10 -6
- package/backend/src/api/middlewares/rate-limiters.ts +127 -127
- package/backend/src/api/routes/ai/index.routes.ts +475 -468
- package/backend/src/api/routes/auth/index.routes.ts +85 -32
- package/backend/src/api/routes/auth/oauth.routes.ts +11 -6
- package/backend/src/api/routes/database/index.routes.ts +2 -0
- package/backend/src/api/routes/database/records.routes.ts +39 -175
- package/backend/src/api/routes/database/rpc.routes.ts +69 -0
- package/backend/src/api/routes/deployments/index.routes.ts +192 -0
- package/backend/src/api/routes/docs/index.routes.ts +3 -2
- package/backend/src/api/routes/email/index.routes.ts +35 -35
- package/backend/src/api/routes/functions/index.routes.ts +3 -3
- package/backend/src/api/routes/metadata/index.routes.ts +26 -0
- package/backend/src/api/routes/webhooks/index.routes.ts +109 -0
- package/backend/src/infra/database/database.manager.ts +0 -10
- package/backend/src/infra/database/migrations/018_schema-rework.sql +441 -0
- package/backend/src/infra/database/migrations/019_create-deployments-table.sql +36 -0
- package/backend/src/infra/database/migrations/020_add-audio-modality.sql +11 -0
- package/backend/src/infra/database/migrations/bootstrap/bootstrap-migrations.js +103 -0
- package/backend/src/infra/security/token.manager.ts +1 -4
- package/backend/src/providers/ai/openrouter.provider.ts +12 -3
- package/backend/src/providers/database/base.provider.ts +39 -0
- package/backend/src/providers/database/cloud.provider.ts +159 -0
- package/backend/src/providers/deployments/vercel.provider.ts +516 -0
- package/backend/src/server.ts +19 -7
- package/backend/src/services/ai/ai-config.service.ts +6 -6
- package/backend/src/services/ai/ai-model.service.ts +60 -60
- package/backend/src/services/ai/ai-usage.service.ts +7 -7
- package/backend/src/services/ai/chat-completion.service.ts +415 -220
- package/backend/src/services/ai/helpers.ts +64 -64
- package/backend/src/services/ai/index.ts +13 -13
- package/backend/src/services/auth/auth-config.service.ts +4 -4
- package/backend/src/services/auth/auth-otp.service.ts +6 -6
- package/backend/src/services/auth/auth.service.ts +134 -74
- package/backend/src/services/auth/index.ts +4 -4
- package/backend/src/services/auth/oauth-config.service.ts +12 -12
- package/backend/src/services/database/database-advance.service.ts +19 -55
- package/backend/src/services/database/database-table.service.ts +38 -85
- package/backend/src/services/database/postgrest-proxy.service.ts +165 -0
- package/backend/src/services/deployments/deployment.service.ts +693 -0
- package/backend/src/services/functions/function.service.ts +61 -41
- package/backend/src/services/logs/audit.service.ts +10 -10
- package/backend/src/services/secrets/secret.service.ts +101 -27
- package/backend/src/services/storage/storage.service.ts +30 -30
- package/backend/src/services/usage/usage.service.ts +6 -6
- package/backend/src/types/ai.ts +8 -0
- package/backend/src/types/auth.ts +5 -1
- package/backend/src/types/database.ts +2 -0
- package/backend/src/types/deployments.ts +33 -0
- package/backend/src/types/storage.ts +1 -1
- package/backend/src/types/webhooks.ts +45 -0
- package/backend/src/utils/cookies.ts +34 -35
- package/backend/src/utils/environment.ts +0 -14
- package/backend/src/utils/s3-config-loader.ts +64 -64
- package/backend/src/utils/seed.ts +334 -301
- package/backend/src/utils/sql-parser.ts +126 -0
- package/backend/src/utils/utils.ts +114 -114
- package/backend/src/utils/validations.ts +10 -10
- package/backend/tests/local/test-rpc.sh +141 -0
- package/backend/tests/local/test-secrets.sh +1 -1
- package/backend/tests/manual/test-ai-model-plugins.sh +258 -0
- package/backend/tests/manual/test-rawsql-modes.sh +24 -24
- package/backend/tests/unit/database-advance.test.ts +326 -0
- package/backend/tests/unit/helpers.test.ts +2 -2
- package/claude-plugin/skills/insforge-schema-patterns/SKILL.md +13 -10
- package/docker-compose.prod.yml +1 -1
- package/docker-compose.yml +1 -1
- package/docs/agent-docs/deployment.md +79 -0
- package/docs/changelog.mdx +165 -72
- package/docs/core-concepts/ai/architecture.mdx +1 -23
- package/docs/core-concepts/ai/sdk.mdx +26 -1
- package/docs/core-concepts/authentication/architecture.mdx +6 -8
- package/docs/core-concepts/authentication/sdk.mdx +387 -91
- package/docs/core-concepts/authentication/ui-components/customization.mdx +460 -256
- package/docs/core-concepts/authentication/ui-components/nextjs.mdx +50 -24
- package/docs/core-concepts/authentication/ui-components/react-router.mdx +18 -19
- package/docs/core-concepts/authentication/ui-components/react.mdx +26 -19
- package/docs/core-concepts/database/architecture.mdx +58 -21
- package/docs/core-concepts/database/pgvector.mdx +138 -0
- package/docs/core-concepts/database/sdk.mdx +17 -17
- package/docs/core-concepts/deployments/architecture.mdx +152 -0
- package/docs/core-concepts/email/architecture.mdx +4 -2
- package/docs/core-concepts/functions/architecture.mdx +1 -1
- package/docs/core-concepts/functions/sdk.mdx +0 -1
- package/docs/core-concepts/realtime/architecture.mdx +1 -1
- package/docs/core-concepts/storage/architecture.mdx +1 -1
- package/docs/core-concepts/storage/sdk.mdx +25 -25
- package/docs/docs.json +14 -6
- package/docs/favicon.png +0 -0
- package/docs/favicon.svg +3 -18
- package/docs/images/changelog/dec-2025/apple-oauth.mp4 +0 -0
- package/docs/images/changelog/dec-2025/moreModels.png +0 -0
- package/docs/images/changelog/dec-2025/multi-region.webp +0 -0
- package/docs/images/changelog/dec-2025/postgres-connection.webp +0 -0
- package/docs/images/changelog/dec-2025/realtime2.png +0 -0
- package/docs/images/mcp-setup/CC-MCP-1.mp4 +0 -0
- package/docs/images/mcp-setup/CC-MCP-2.mp4 +0 -0
- package/docs/images/mcp-setup/Cursor-MCP-1.mp4 +0 -0
- package/docs/images/mcp-setup/Cursor-MCP-2.mp4 +0 -0
- package/docs/images/mcp-setup/Cursor-MCP-3.mp4 +0 -0
- package/docs/images/mcp-setup/claude-code-connect.png +0 -0
- package/docs/images/mcp-setup/cline-1.png +0 -0
- package/docs/images/mcp-setup/cline-2.png +0 -0
- package/docs/images/mcp-setup/cline-3.png +0 -0
- package/docs/images/mcp-setup/connect-project.png +0 -0
- package/docs/images/mcp-setup/copilot-1.png +0 -0
- package/docs/images/mcp-setup/copilot-2.png +0 -0
- package/docs/images/mcp-setup/copilot-3.png +0 -0
- package/docs/images/mcp-setup/mcp-json-1.png +0 -0
- package/docs/images/mcp-setup/mcp-json-2.png +0 -0
- package/docs/images/mcp-setup/qoder-1.png +0 -0
- package/docs/images/mcp-setup/qoder-2.png +0 -0
- package/docs/images/mcp-setup/roocode-1.png +0 -0
- package/docs/images/mcp-setup/roocode-2.png +0 -0
- package/docs/images/mcp-setup/trae-1.png +0 -0
- package/docs/images/mcp-setup/trae-2.png +0 -0
- package/docs/images/mcp-setup/trae-3.png +0 -0
- package/docs/images/mcp-setup/trae-4.png +0 -0
- package/docs/images/mcp-setup/trae-5.png +0 -0
- package/docs/images/mcp-setup/windsurf-1.png +0 -0
- package/docs/images/mcp-setup/windsurf-2.png +0 -0
- package/docs/insforge-instructions-sdk.md +7 -3
- package/docs/introduction.mdx +9 -8
- package/docs/mcp-setup.mdx +332 -0
- package/docs/oauth-server.mdx +563 -0
- package/docs/partnership.mdx +79 -10
- package/docs/quickstart.mdx +1 -1
- package/docs/vscode-extension.mdx +74 -0
- package/eslint.config.js +1 -0
- package/examples/response-examples.md +1 -1
- package/frontend/package.json +1 -1
- package/frontend/src/App.tsx +8 -3
- package/frontend/src/assets/logos/antigravity.svg +1 -0
- package/frontend/src/assets/logos/copilot.svg +10 -0
- package/frontend/src/assets/logos/deepseek.svg +139 -0
- package/frontend/src/assets/logos/kiro.svg +9 -0
- package/frontend/src/assets/logos/qoder.svg +4 -0
- package/frontend/src/assets/logos/qwen.svg +15 -0
- package/frontend/src/components/CodeBlock.tsx +2 -2
- package/frontend/src/components/ConnectCTA.tsx +3 -2
- package/frontend/src/components/datagrid/DataGrid.tsx +90 -62
- package/frontend/src/components/datagrid/datagridTypes.tsx +2 -1
- package/frontend/src/components/datagrid/index.ts +1 -1
- package/frontend/src/components/index.ts +0 -1
- package/frontend/src/components/layout/AppHeader.tsx +4 -27
- package/frontend/src/components/layout/AppSidebar.tsx +85 -100
- package/frontend/src/components/layout/Layout.tsx +34 -32
- package/frontend/src/components/layout/PrimaryMenu.tsx +12 -4
- package/frontend/src/components/radix/Select.tsx +151 -151
- package/frontend/src/features/ai/components/AIConfigCard.tsx +200 -200
- package/frontend/src/features/ai/components/AIEmptyState.tsx +23 -23
- package/frontend/src/features/ai/components/ModalityFilterSidebar.tsx +102 -101
- package/frontend/src/features/ai/components/ModelSelectionDialog.tsx +135 -135
- package/frontend/src/features/ai/components/ModelSelectionGrid.tsx +51 -51
- package/frontend/src/features/ai/components/SystemPromptDialog.tsx +118 -118
- package/frontend/src/features/ai/components/index.ts +6 -6
- package/frontend/src/features/ai/helpers.ts +147 -141
- package/frontend/src/features/ai/pages/AIPage.tsx +166 -166
- package/frontend/src/features/auth/components/AuthPreview.tsx +96 -96
- package/frontend/src/features/auth/components/UsersDataGrid.tsx +55 -31
- package/frontend/src/features/auth/components/index.ts +5 -5
- package/frontend/src/features/auth/pages/AuthMethodsPage.tsx +275 -275
- package/frontend/src/features/dashboard/pages/DashboardPage.tsx +1 -1
- package/frontend/src/features/database/components/DatabaseDataGrid.tsx +0 -2
- package/frontend/src/features/database/components/ForeignKeyCell.tsx +38 -11
- package/frontend/src/features/database/components/ForeignKeyPopover.tsx +18 -8
- package/frontend/src/features/database/components/LinkRecordModal.tsx +61 -13
- package/frontend/src/features/database/components/RecordFormField.tsx +1 -1
- package/frontend/src/features/database/components/TableSidebar.tsx +0 -3
- package/frontend/src/features/database/components/TablesEmptyState.tsx +1 -1
- package/frontend/src/features/database/components/TemplatePreview.tsx +1 -2
- package/frontend/src/features/database/constants.ts +16 -28
- package/frontend/src/features/database/hooks/useCSVImport.ts +3 -2
- package/frontend/src/features/database/hooks/useRawSQL.ts +3 -2
- package/frontend/src/features/database/hooks/useTables.ts +5 -7
- package/frontend/src/features/database/pages/FunctionsPage.tsx +0 -5
- package/frontend/src/features/database/pages/IndexesPage.tsx +0 -5
- package/frontend/src/features/database/pages/PoliciesPage.tsx +0 -5
- package/frontend/src/features/database/pages/SQLEditorPage.tsx +2 -2
- package/frontend/src/features/database/pages/TriggersPage.tsx +0 -5
- package/frontend/src/features/database/services/advance.service.ts +1 -15
- package/frontend/src/features/database/services/record.service.ts +4 -20
- package/frontend/src/features/database/services/table.service.ts +1 -4
- package/frontend/src/features/database/templates/ai-chatbot.ts +6 -6
- package/frontend/src/features/database/templates/ecommerce-platform.ts +2 -2
- package/frontend/src/features/database/templates/instagram-clone.ts +10 -10
- package/frontend/src/features/database/templates/notion-clone.ts +8 -8
- package/frontend/src/features/database/templates/reddit-clone.ts +10 -10
- package/frontend/src/features/deployments/components/DeploymentRow.tsx +93 -0
- package/frontend/src/features/deployments/components/DeploymentsEmptyState.tsx +15 -0
- package/frontend/src/features/deployments/hooks/useDeployments.ts +157 -0
- package/frontend/src/features/deployments/pages/DeploymentsPage.tsx +318 -0
- package/frontend/src/features/deployments/services/deployments.service.ts +63 -0
- package/frontend/src/features/functions/components/FunctionRow.tsx +72 -72
- package/frontend/src/features/functions/components/FunctionsSidebar.tsx +56 -56
- package/frontend/src/features/functions/components/SecretRow.tsx +3 -3
- package/frontend/src/features/functions/components/index.ts +5 -5
- package/frontend/src/features/functions/hooks/useFunctions.ts +5 -4
- package/frontend/src/features/functions/hooks/useSecrets.ts +6 -9
- package/frontend/src/features/functions/pages/SecretsPage.tsx +118 -118
- package/frontend/src/features/functions/services/function.service.ts +8 -25
- package/frontend/src/features/functions/services/secret.service.ts +23 -41
- package/frontend/src/features/login/pages/CloudLoginPage.tsx +125 -118
- package/frontend/src/features/logs/components/LogDetailPanel.tsx +41 -0
- package/frontend/src/features/logs/components/LogsDataGrid.tsx +32 -1
- package/frontend/src/features/logs/components/index.ts +1 -0
- package/frontend/src/features/logs/pages/LogsPage.tsx +36 -6
- package/frontend/src/features/onboard/components/ApiCredentialsSection.tsx +59 -0
- package/frontend/src/features/onboard/components/ConnectionStringSection.tsx +180 -0
- package/frontend/src/features/onboard/components/McpConnectionSection.tsx +159 -0
- package/frontend/src/features/onboard/components/OnboardingController.tsx +68 -0
- package/frontend/src/features/onboard/components/OnboardingModal.tsx +121 -267
- package/frontend/src/features/onboard/components/ShowPasswordButton.tsx +21 -0
- package/frontend/src/features/onboard/components/index.ts +9 -4
- package/frontend/src/features/onboard/components/mcp/CursorDeeplinkGenerator.tsx +1 -1
- package/frontend/src/features/onboard/components/mcp/QoderDeeplinkGenerator.tsx +36 -0
- package/frontend/src/features/onboard/components/mcp/helpers.tsx +123 -98
- package/frontend/src/features/onboard/components/mcp/index.ts +4 -3
- package/frontend/src/features/onboard/index.ts +17 -13
- package/frontend/src/features/settings/pages/SettingsPage.tsx +349 -0
- package/frontend/src/features/visualizer/components/AuthNode.tsx +4 -4
- package/frontend/src/features/visualizer/components/SchemaVisualizer.tsx +21 -8
- package/frontend/src/features/visualizer/pages/VisualizerPage.tsx +10 -1
- package/frontend/src/index.css +249 -249
- package/frontend/src/lib/contexts/ModalContext.tsx +35 -0
- package/frontend/src/lib/hooks/useMetadata.ts +45 -1
- package/frontend/src/lib/hooks/useModal.tsx +2 -0
- package/frontend/src/lib/routing/AppRoutes.tsx +103 -99
- package/frontend/src/lib/services/metadata.service.ts +20 -3
- package/frontend/src/lib/utils/menuItems.ts +223 -207
- package/frontend/src/lib/utils/utils.ts +196 -196
- package/functions/server.ts +315 -315
- package/functions/worker-template.js +1 -1
- package/openapi/ai.yaml +115 -5
- package/openapi/auth.yaml +97 -17
- package/openapi/logs.yaml +0 -2
- package/openapi/metadata.yaml +0 -2
- package/openapi/records.yaml +21 -21
- package/openapi/tables.yaml +1 -2
- package/package.json +1 -1
- package/shared-schemas/package.json +1 -1
- package/shared-schemas/src/ai-api.schema.ts +251 -143
- package/shared-schemas/src/ai.schema.ts +63 -63
- package/shared-schemas/src/auth-api.schema.ts +34 -6
- package/shared-schemas/src/auth.schema.ts +17 -10
- package/shared-schemas/src/cloud-events.schema.ts +26 -0
- package/shared-schemas/src/deployments-api.schema.ts +55 -0
- package/shared-schemas/src/deployments.schema.ts +30 -0
- package/shared-schemas/src/docs.schema.ts +8 -2
- package/shared-schemas/src/email-api.schema.ts +30 -30
- package/shared-schemas/src/functions-api.schema.ts +13 -4
- package/shared-schemas/src/functions.schema.ts +1 -1
- package/shared-schemas/src/index.ts +22 -18
- package/shared-schemas/src/metadata.schema.ts +30 -4
- package/shared-schemas/src/secrets-api.schema.ts +44 -0
- package/shared-schemas/src/secrets.schema.ts +15 -0
- package/zeabur/README.md +13 -0
- package/zeabur/template.yml +20 -51
- package/backend/src/types/profile.ts +0 -55
- package/frontend/src/components/ProjectInfoModal.tsx +0 -128
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
-- Migration: 018 - Create system and auth schemas, move and rename system tables
|
|
2
|
+
-- This migration creates dedicated schemas for internal system and auth tables,
|
|
3
|
+
-- moves tables into them, and removes the underscore prefix from table names.
|
|
4
|
+
|
|
5
|
+
-- ============================================================================
|
|
6
|
+
-- PART 1: SYSTEM SCHEMA (secrets, audit_logs, mcp_usage)
|
|
7
|
+
-- Note: migrations table is handled by bootstrap/bootstrap-migrations.js before this runs
|
|
8
|
+
-- ============================================================================
|
|
9
|
+
|
|
10
|
+
-- 1.1 Create the system schema (may already exist from bootstrap)
|
|
11
|
+
CREATE SCHEMA IF NOT EXISTS system;
|
|
12
|
+
|
|
13
|
+
-- 1.2 Move _secrets table to system schema and rename to 'secrets'
|
|
14
|
+
-- First, drop the foreign key constraint from _oauth_configs that references _secrets
|
|
15
|
+
ALTER TABLE public._oauth_configs
|
|
16
|
+
DROP CONSTRAINT IF EXISTS _oauth_configs_secret_id_fkey;
|
|
17
|
+
|
|
18
|
+
-- Move and rename the _secrets table to system.secrets
|
|
19
|
+
ALTER TABLE public._secrets SET SCHEMA system;
|
|
20
|
+
ALTER TABLE system._secrets RENAME TO secrets;
|
|
21
|
+
|
|
22
|
+
-- Note: We'll recreate the FK constraint after moving _oauth_configs to auth schema
|
|
23
|
+
|
|
24
|
+
-- 1.3 Move _audit_logs table to system schema and rename to 'audit_logs'
|
|
25
|
+
ALTER TABLE public._audit_logs SET SCHEMA system;
|
|
26
|
+
ALTER TABLE system._audit_logs RENAME TO audit_logs;
|
|
27
|
+
|
|
28
|
+
-- 1.4 Move _mcp_usage table to system schema and rename to 'mcp_usage'
|
|
29
|
+
ALTER TABLE public._mcp_usage SET SCHEMA system;
|
|
30
|
+
ALTER TABLE system._mcp_usage RENAME TO mcp_usage;
|
|
31
|
+
|
|
32
|
+
-- Note: system schema is internal and should NOT be exposed to PUBLIC.
|
|
33
|
+
-- Access is controlled through the application's database connection.
|
|
34
|
+
|
|
35
|
+
-- ============================================================================
|
|
36
|
+
-- PART 2: AUTH SCHEMA (users, user_providers, configs, oauth_configs, email_otps)
|
|
37
|
+
-- ============================================================================
|
|
38
|
+
|
|
39
|
+
-- 2.1 Create the auth schema
|
|
40
|
+
CREATE SCHEMA IF NOT EXISTS auth;
|
|
41
|
+
|
|
42
|
+
-- 2.2 Drop all foreign key constraints that reference tables being moved
|
|
43
|
+
-- FK: _account_providers.user_id -> _accounts(id)
|
|
44
|
+
ALTER TABLE public._account_providers
|
|
45
|
+
DROP CONSTRAINT IF EXISTS _account_providers_user_id_fkey;
|
|
46
|
+
|
|
47
|
+
-- FK: users.id -> _accounts(id) (public users table references _accounts)
|
|
48
|
+
ALTER TABLE public.users
|
|
49
|
+
DROP CONSTRAINT IF EXISTS users_id_fkey;
|
|
50
|
+
|
|
51
|
+
-- FK: _storage.uploaded_by -> _accounts(id)
|
|
52
|
+
ALTER TABLE public._storage
|
|
53
|
+
DROP CONSTRAINT IF EXISTS _storage_uploaded_by_fkey;
|
|
54
|
+
|
|
55
|
+
-- 2.3 Move _accounts table to auth schema and rename to 'users'
|
|
56
|
+
ALTER TABLE public._accounts SET SCHEMA auth;
|
|
57
|
+
ALTER TABLE auth._accounts RENAME TO users;
|
|
58
|
+
|
|
59
|
+
-- 2.4 Move _account_providers table to auth schema and rename to 'user_providers'
|
|
60
|
+
ALTER TABLE public._account_providers SET SCHEMA auth;
|
|
61
|
+
ALTER TABLE auth._account_providers RENAME TO user_providers;
|
|
62
|
+
|
|
63
|
+
-- 2.5 Recreate FK: auth.user_providers.user_id -> auth.users(id)
|
|
64
|
+
ALTER TABLE auth.user_providers
|
|
65
|
+
ADD CONSTRAINT user_providers_user_id_fkey
|
|
66
|
+
FOREIGN KEY (user_id) REFERENCES auth.users(id) ON DELETE CASCADE;
|
|
67
|
+
|
|
68
|
+
-- 2.6 Add profile and metadata JSONB columns to auth.users BEFORE migrating data
|
|
69
|
+
-- profile: stores user profile data (name, avatar_url, bio, etc.)
|
|
70
|
+
-- metadata: reserved for system use (device ID, login IP, etc.)
|
|
71
|
+
ALTER TABLE auth.users ADD COLUMN IF NOT EXISTS profile JSONB DEFAULT '{}'::jsonb;
|
|
72
|
+
ALTER TABLE auth.users ADD COLUMN IF NOT EXISTS metadata JSONB DEFAULT '{}'::jsonb;
|
|
73
|
+
|
|
74
|
+
-- 2.7 Migrate data from public.users into auth.users.profile
|
|
75
|
+
-- Priority for name: public.users.nickname first, then auth.users.name as fallback
|
|
76
|
+
-- Also migrate: avatar_url, bio, birthday from public.users
|
|
77
|
+
UPDATE auth.users AS au
|
|
78
|
+
SET profile = jsonb_strip_nulls(jsonb_build_object(
|
|
79
|
+
'name', COALESCE(pu.nickname, au.name),
|
|
80
|
+
'avatar_url', pu.avatar_url,
|
|
81
|
+
'bio', pu.bio,
|
|
82
|
+
'birthday', pu.birthday
|
|
83
|
+
))
|
|
84
|
+
FROM public.users AS pu
|
|
85
|
+
WHERE au.id = pu.id;
|
|
86
|
+
|
|
87
|
+
-- 2.8 For users without a public.users row, migrate auth.users.name to profile
|
|
88
|
+
UPDATE auth.users
|
|
89
|
+
SET profile = jsonb_build_object('name', name)
|
|
90
|
+
WHERE name IS NOT NULL
|
|
91
|
+
AND (profile IS NULL OR profile = '{}'::jsonb)
|
|
92
|
+
AND id NOT IN (SELECT id FROM public.users);
|
|
93
|
+
|
|
94
|
+
-- 2.9 Update all foreign key constraints that reference public.users to use auth.users instead
|
|
95
|
+
-- This handles any custom tables developers may have created that reference public.users
|
|
96
|
+
DO $$
|
|
97
|
+
DECLARE
|
|
98
|
+
fk_record RECORD;
|
|
99
|
+
drop_sql TEXT;
|
|
100
|
+
create_sql TEXT;
|
|
101
|
+
BEGIN
|
|
102
|
+
-- Find all foreign keys that reference public.users
|
|
103
|
+
FOR fk_record IN
|
|
104
|
+
SELECT
|
|
105
|
+
tc.table_schema,
|
|
106
|
+
tc.table_name,
|
|
107
|
+
tc.constraint_name,
|
|
108
|
+
kcu.column_name,
|
|
109
|
+
rc.delete_rule,
|
|
110
|
+
rc.update_rule
|
|
111
|
+
FROM information_schema.table_constraints tc
|
|
112
|
+
JOIN information_schema.key_column_usage kcu
|
|
113
|
+
ON tc.constraint_name = kcu.constraint_name
|
|
114
|
+
AND tc.table_schema = kcu.table_schema
|
|
115
|
+
JOIN information_schema.referential_constraints rc
|
|
116
|
+
ON tc.constraint_name = rc.constraint_name
|
|
117
|
+
AND tc.table_schema = rc.constraint_schema
|
|
118
|
+
JOIN information_schema.constraint_column_usage ccu
|
|
119
|
+
ON rc.unique_constraint_name = ccu.constraint_name
|
|
120
|
+
AND rc.unique_constraint_schema = ccu.constraint_schema
|
|
121
|
+
WHERE tc.constraint_type = 'FOREIGN KEY'
|
|
122
|
+
AND ccu.table_schema = 'public'
|
|
123
|
+
AND ccu.table_name = 'users'
|
|
124
|
+
LOOP
|
|
125
|
+
-- Drop the old foreign key
|
|
126
|
+
drop_sql := format(
|
|
127
|
+
'ALTER TABLE %I.%I DROP CONSTRAINT IF EXISTS %I',
|
|
128
|
+
fk_record.table_schema,
|
|
129
|
+
fk_record.table_name,
|
|
130
|
+
fk_record.constraint_name
|
|
131
|
+
);
|
|
132
|
+
EXECUTE drop_sql;
|
|
133
|
+
|
|
134
|
+
-- Recreate with reference to auth.users
|
|
135
|
+
create_sql := format(
|
|
136
|
+
'ALTER TABLE %I.%I ADD CONSTRAINT %I FOREIGN KEY (%I) REFERENCES auth.users(id) ON DELETE %s ON UPDATE %s',
|
|
137
|
+
fk_record.table_schema,
|
|
138
|
+
fk_record.table_name,
|
|
139
|
+
fk_record.constraint_name,
|
|
140
|
+
fk_record.column_name,
|
|
141
|
+
fk_record.delete_rule,
|
|
142
|
+
fk_record.update_rule
|
|
143
|
+
);
|
|
144
|
+
EXECUTE create_sql;
|
|
145
|
+
|
|
146
|
+
RAISE NOTICE 'Updated FK constraint % on %.% to reference auth.users',
|
|
147
|
+
fk_record.constraint_name, fk_record.table_schema, fk_record.table_name;
|
|
148
|
+
END LOOP;
|
|
149
|
+
END $$;
|
|
150
|
+
|
|
151
|
+
-- 2.10 Drop public.users table (profile data now stored in auth.users.profile)
|
|
152
|
+
-- First drop RLS policies
|
|
153
|
+
DROP POLICY IF EXISTS "Enable read access for all users" ON public.users;
|
|
154
|
+
DROP POLICY IF EXISTS "Disable delete for users" ON public.users;
|
|
155
|
+
DROP POLICY IF EXISTS "Enable update for users based on user_id" ON public.users;
|
|
156
|
+
-- Drop the table (CASCADE will handle any remaining dependencies)
|
|
157
|
+
DROP TABLE IF EXISTS public.users CASCADE;
|
|
158
|
+
|
|
159
|
+
-- 2.11 Drop the name column from auth.users (data already migrated to profile)
|
|
160
|
+
ALTER TABLE auth.users DROP COLUMN IF EXISTS name;
|
|
161
|
+
|
|
162
|
+
-- Note: _storage.uploaded_by FK is handled in Part 4 when moving to storage schema
|
|
163
|
+
|
|
164
|
+
-- 2.12 Add is_project_admin and is_anonymous columns to auth.users
|
|
165
|
+
ALTER TABLE auth.users ADD COLUMN IF NOT EXISTS is_project_admin BOOLEAN NOT NULL DEFAULT false;
|
|
166
|
+
ALTER TABLE auth.users ADD COLUMN IF NOT EXISTS is_anonymous BOOLEAN NOT NULL DEFAULT false;
|
|
167
|
+
|
|
168
|
+
-- 2.13 Move _auth_configs table to auth schema and rename to 'configs'
|
|
169
|
+
ALTER TABLE public._auth_configs SET SCHEMA auth;
|
|
170
|
+
ALTER TABLE auth._auth_configs RENAME TO configs;
|
|
171
|
+
|
|
172
|
+
-- 2.14 Move _oauth_configs table to auth schema and rename to 'oauth_configs'
|
|
173
|
+
ALTER TABLE public._oauth_configs SET SCHEMA auth;
|
|
174
|
+
ALTER TABLE auth._oauth_configs RENAME TO oauth_configs;
|
|
175
|
+
|
|
176
|
+
-- 2.15 Recreate FK: auth.oauth_configs.secret_id -> system.secrets(id)
|
|
177
|
+
ALTER TABLE auth.oauth_configs
|
|
178
|
+
ADD CONSTRAINT oauth_configs_secret_id_fkey
|
|
179
|
+
FOREIGN KEY (secret_id) REFERENCES system.secrets(id) ON DELETE RESTRICT;
|
|
180
|
+
|
|
181
|
+
-- 2.16 Move _email_otps table to auth schema and rename to 'email_otps'
|
|
182
|
+
ALTER TABLE public._email_otps SET SCHEMA auth;
|
|
183
|
+
ALTER TABLE auth._email_otps RENAME TO email_otps;
|
|
184
|
+
|
|
185
|
+
-- Note: auth schema is internal and should NOT be exposed to PUBLIC.
|
|
186
|
+
-- However, we grant limited access to auth.users for public profile info.
|
|
187
|
+
|
|
188
|
+
-- 2.17 Grant limited public access to auth.users (only safe columns)
|
|
189
|
+
GRANT USAGE ON SCHEMA auth TO PUBLIC;
|
|
190
|
+
|
|
191
|
+
-- Grant SELECT on specific columns only (public profile info)
|
|
192
|
+
GRANT SELECT (id, profile, created_at) ON auth.users TO PUBLIC;
|
|
193
|
+
|
|
194
|
+
-- Grant UPDATE on profile column only (users can update their own profile)
|
|
195
|
+
GRANT UPDATE (profile) ON auth.users TO PUBLIC;
|
|
196
|
+
|
|
197
|
+
-- 2.18 Enable RLS on auth.users for row-level access control
|
|
198
|
+
-- Note: auth.uid() function already exists from migration 013
|
|
199
|
+
ALTER TABLE auth.users ENABLE ROW LEVEL SECURITY;
|
|
200
|
+
|
|
201
|
+
-- Policy: Everyone can SELECT public columns (id, profile, created_at)
|
|
202
|
+
-- Column-level GRANT above already restricts which columns can be read
|
|
203
|
+
CREATE POLICY "Public can view user profiles" ON auth.users
|
|
204
|
+
FOR SELECT
|
|
205
|
+
USING (true);
|
|
206
|
+
|
|
207
|
+
-- Policy: Users can only UPDATE their own row
|
|
208
|
+
CREATE POLICY "Users can update own profile" ON auth.users
|
|
209
|
+
FOR UPDATE
|
|
210
|
+
USING (id = auth.uid())
|
|
211
|
+
WITH CHECK (id = auth.uid());
|
|
212
|
+
|
|
213
|
+
-- 2.19 Drop obsolete public schema helper functions (migrated to auth schema)
|
|
214
|
+
-- NOTE: CASCADE intentionally used to force migration from public.uid() to auth.uid()
|
|
215
|
+
-- Any dependent objects (policies, views, functions, defaults) will be dropped.
|
|
216
|
+
-- Users must recreate them using auth.uid(), auth.role(), auth.email() instead.
|
|
217
|
+
DROP FUNCTION IF EXISTS public.uid() CASCADE;
|
|
218
|
+
DROP FUNCTION IF EXISTS public.role() CASCADE;
|
|
219
|
+
DROP FUNCTION IF EXISTS public.email() CASCADE;
|
|
220
|
+
|
|
221
|
+
-- ============================================================================
|
|
222
|
+
-- PART 3: AI SCHEMA (configs, usage)
|
|
223
|
+
-- ============================================================================
|
|
224
|
+
|
|
225
|
+
-- 3.1 Create the ai schema
|
|
226
|
+
CREATE SCHEMA IF NOT EXISTS ai;
|
|
227
|
+
|
|
228
|
+
-- 3.2 Drop FK constraint from _ai_usage to _ai_configs before moving
|
|
229
|
+
ALTER TABLE public._ai_usage
|
|
230
|
+
DROP CONSTRAINT IF EXISTS _ai_usage_config_id_fkey;
|
|
231
|
+
|
|
232
|
+
-- 3.3 Move _ai_configs table to ai schema and rename to 'configs'
|
|
233
|
+
ALTER TABLE public._ai_configs SET SCHEMA ai;
|
|
234
|
+
ALTER TABLE ai._ai_configs RENAME TO configs;
|
|
235
|
+
|
|
236
|
+
-- 3.4 Move _ai_usage table to ai schema and rename to 'usage'
|
|
237
|
+
ALTER TABLE public._ai_usage SET SCHEMA ai;
|
|
238
|
+
ALTER TABLE ai._ai_usage RENAME TO usage;
|
|
239
|
+
|
|
240
|
+
-- 3.5 Recreate FK: ai.usage.config_id -> ai.configs(id)
|
|
241
|
+
ALTER TABLE ai.usage
|
|
242
|
+
ADD CONSTRAINT usage_config_id_fkey
|
|
243
|
+
FOREIGN KEY (config_id) REFERENCES ai.configs(id) ON DELETE NO ACTION;
|
|
244
|
+
|
|
245
|
+
-- Note: ai schema is internal and should NOT be exposed to PUBLIC.
|
|
246
|
+
-- Access is controlled through the application's database connection.
|
|
247
|
+
|
|
248
|
+
-- ============================================================================
|
|
249
|
+
-- PART 4: STORAGE SCHEMA (buckets, objects)
|
|
250
|
+
-- ============================================================================
|
|
251
|
+
|
|
252
|
+
-- 4.1 Create the storage schema
|
|
253
|
+
CREATE SCHEMA IF NOT EXISTS storage;
|
|
254
|
+
|
|
255
|
+
-- 4.2 Drop FK constraints from _storage before moving
|
|
256
|
+
ALTER TABLE public._storage
|
|
257
|
+
DROP CONSTRAINT IF EXISTS _storage_bucket_fkey;
|
|
258
|
+
|
|
259
|
+
ALTER TABLE public._storage
|
|
260
|
+
DROP CONSTRAINT IF EXISTS _storage_uploaded_by_fkey;
|
|
261
|
+
|
|
262
|
+
-- 4.3 Move _storage_buckets table to storage schema and rename to 'buckets'
|
|
263
|
+
ALTER TABLE public._storage_buckets SET SCHEMA storage;
|
|
264
|
+
ALTER TABLE storage._storage_buckets RENAME TO buckets;
|
|
265
|
+
|
|
266
|
+
-- 4.4 Move _storage table to storage schema and rename to 'objects'
|
|
267
|
+
ALTER TABLE public._storage SET SCHEMA storage;
|
|
268
|
+
ALTER TABLE storage._storage RENAME TO objects;
|
|
269
|
+
|
|
270
|
+
-- 4.5 Recreate FK: storage.objects.bucket -> storage.buckets(name)
|
|
271
|
+
ALTER TABLE storage.objects
|
|
272
|
+
ADD CONSTRAINT objects_bucket_fkey
|
|
273
|
+
FOREIGN KEY (bucket) REFERENCES storage.buckets(name) ON DELETE CASCADE;
|
|
274
|
+
|
|
275
|
+
-- 4.6 Recreate FK: storage.objects.uploaded_by -> auth.users(id)
|
|
276
|
+
ALTER TABLE storage.objects
|
|
277
|
+
ADD CONSTRAINT objects_uploaded_by_fkey
|
|
278
|
+
FOREIGN KEY (uploaded_by) REFERENCES auth.users(id) ON DELETE SET NULL;
|
|
279
|
+
|
|
280
|
+
-- Note: storage schema is internal and should NOT be exposed to PUBLIC.
|
|
281
|
+
-- Access is controlled through the application's database connection.
|
|
282
|
+
|
|
283
|
+
-- ============================================================================
|
|
284
|
+
-- PART 5: FUNCTIONS SCHEMA (definitions)
|
|
285
|
+
-- ============================================================================
|
|
286
|
+
|
|
287
|
+
-- 5.1 Create the functions schema
|
|
288
|
+
CREATE SCHEMA IF NOT EXISTS functions;
|
|
289
|
+
|
|
290
|
+
-- 5.2 Move _functions table to functions schema and rename to 'definitions'
|
|
291
|
+
ALTER TABLE public._functions SET SCHEMA functions;
|
|
292
|
+
ALTER TABLE functions._functions RENAME TO definitions;
|
|
293
|
+
|
|
294
|
+
-- Note: functions schema is internal and should NOT be exposed to PUBLIC.
|
|
295
|
+
-- Access is controlled through the application's database connection.
|
|
296
|
+
|
|
297
|
+
-- ============================================================================
|
|
298
|
+
-- PART 6: UTILITY FUNCTIONS CLEANUP
|
|
299
|
+
-- ============================================================================
|
|
300
|
+
|
|
301
|
+
-- 6.1 Create system.update_updated_at() function (replaces public.update_updated_at_column)
|
|
302
|
+
CREATE OR REPLACE FUNCTION system.update_updated_at()
|
|
303
|
+
RETURNS trigger AS $$
|
|
304
|
+
BEGIN
|
|
305
|
+
NEW.updated_at = NOW();
|
|
306
|
+
RETURN NEW;
|
|
307
|
+
END;
|
|
308
|
+
$$ LANGUAGE plpgsql;
|
|
309
|
+
|
|
310
|
+
-- 6.2 Update all triggers to use system.update_updated_at() and rename (remove double underscore)
|
|
311
|
+
|
|
312
|
+
-- system.secrets: update__secrets_updated_at -> update_secrets_updated_at
|
|
313
|
+
DROP TRIGGER IF EXISTS update__secrets_updated_at ON system.secrets;
|
|
314
|
+
CREATE TRIGGER update_secrets_updated_at
|
|
315
|
+
BEFORE UPDATE ON system.secrets
|
|
316
|
+
FOR EACH ROW EXECUTE FUNCTION system.update_updated_at();
|
|
317
|
+
|
|
318
|
+
-- system.audit_logs: update__audit_logs_updated_at -> update_audit_logs_updated_at
|
|
319
|
+
DROP TRIGGER IF EXISTS update__audit_logs_updated_at ON system.audit_logs;
|
|
320
|
+
CREATE TRIGGER update_audit_logs_updated_at
|
|
321
|
+
BEFORE UPDATE ON system.audit_logs
|
|
322
|
+
FOR EACH ROW EXECUTE FUNCTION system.update_updated_at();
|
|
323
|
+
|
|
324
|
+
-- auth.configs: update__auth_configs_updated_at -> update_configs_updated_at
|
|
325
|
+
DROP TRIGGER IF EXISTS update__auth_configs_updated_at ON auth.configs;
|
|
326
|
+
CREATE TRIGGER update_configs_updated_at
|
|
327
|
+
BEFORE UPDATE ON auth.configs
|
|
328
|
+
FOR EACH ROW EXECUTE FUNCTION system.update_updated_at();
|
|
329
|
+
|
|
330
|
+
-- auth.oauth_configs: update__oauth_configs_updated_at -> update_oauth_configs_updated_at
|
|
331
|
+
DROP TRIGGER IF EXISTS update__oauth_configs_updated_at ON auth.oauth_configs;
|
|
332
|
+
CREATE TRIGGER update_oauth_configs_updated_at
|
|
333
|
+
BEFORE UPDATE ON auth.oauth_configs
|
|
334
|
+
FOR EACH ROW EXECUTE FUNCTION system.update_updated_at();
|
|
335
|
+
|
|
336
|
+
-- auth.email_otps: update__email_otps_updated_at -> update_email_otps_updated_at
|
|
337
|
+
DROP TRIGGER IF EXISTS update__email_otps_updated_at ON auth.email_otps;
|
|
338
|
+
CREATE TRIGGER update_email_otps_updated_at
|
|
339
|
+
BEFORE UPDATE ON auth.email_otps
|
|
340
|
+
FOR EACH ROW EXECUTE FUNCTION system.update_updated_at();
|
|
341
|
+
|
|
342
|
+
-- functions.definitions: update__edge_functions_updated_at -> update_definitions_updated_at
|
|
343
|
+
DROP TRIGGER IF EXISTS update__edge_functions_updated_at ON functions.definitions;
|
|
344
|
+
CREATE TRIGGER update_definitions_updated_at
|
|
345
|
+
BEFORE UPDATE ON functions.definitions
|
|
346
|
+
FOR EACH ROW EXECUTE FUNCTION system.update_updated_at();
|
|
347
|
+
|
|
348
|
+
-- realtime.channels: trg_channels_updated_at -> update_channels_updated_at
|
|
349
|
+
DROP TRIGGER IF EXISTS trg_channels_updated_at ON realtime.channels;
|
|
350
|
+
CREATE TRIGGER update_channels_updated_at
|
|
351
|
+
BEFORE UPDATE ON realtime.channels
|
|
352
|
+
FOR EACH ROW EXECUTE FUNCTION system.update_updated_at();
|
|
353
|
+
|
|
354
|
+
-- 6.3 Move reload_postgrest_schema to system schema
|
|
355
|
+
-- Recreate in system schema (ALTER FUNCTION SET SCHEMA doesn't work well with search_path)
|
|
356
|
+
CREATE OR REPLACE FUNCTION system.reload_postgrest_schema()
|
|
357
|
+
RETURNS void AS $$
|
|
358
|
+
BEGIN
|
|
359
|
+
NOTIFY pgrst, 'reload schema';
|
|
360
|
+
RAISE NOTICE 'PostgREST schema reload notification sent';
|
|
361
|
+
END
|
|
362
|
+
$$ LANGUAGE plpgsql;
|
|
363
|
+
|
|
364
|
+
-- 6.4 Move event trigger functions to system schema
|
|
365
|
+
-- These functions auto-create project_admin_policy when RLS is enabled on tables
|
|
366
|
+
|
|
367
|
+
-- First, drop the event triggers (they reference the old functions)
|
|
368
|
+
DROP EVENT TRIGGER IF EXISTS create_policies_on_table_create;
|
|
369
|
+
DROP EVENT TRIGGER IF EXISTS create_policies_on_rls_enable;
|
|
370
|
+
|
|
371
|
+
-- Recreate functions in system schema
|
|
372
|
+
CREATE OR REPLACE FUNCTION system.create_default_policies()
|
|
373
|
+
RETURNS event_trigger AS $$
|
|
374
|
+
DECLARE
|
|
375
|
+
obj record;
|
|
376
|
+
table_schema text;
|
|
377
|
+
table_name text;
|
|
378
|
+
has_rls boolean;
|
|
379
|
+
BEGIN
|
|
380
|
+
FOR obj IN SELECT * FROM pg_event_trigger_ddl_commands() WHERE command_tag = 'CREATE TABLE'
|
|
381
|
+
LOOP
|
|
382
|
+
SELECT INTO table_schema, table_name
|
|
383
|
+
split_part(obj.object_identity, '.', 1),
|
|
384
|
+
trim(both '"' from split_part(obj.object_identity, '.', 2));
|
|
385
|
+
SELECT INTO has_rls
|
|
386
|
+
rowsecurity
|
|
387
|
+
FROM pg_tables
|
|
388
|
+
WHERE schemaname = table_schema
|
|
389
|
+
AND tablename = table_name;
|
|
390
|
+
IF has_rls THEN
|
|
391
|
+
EXECUTE format('CREATE POLICY "project_admin_policy" ON %s FOR ALL TO project_admin USING (true) WITH CHECK (true)', obj.object_identity);
|
|
392
|
+
END IF;
|
|
393
|
+
END LOOP;
|
|
394
|
+
END;
|
|
395
|
+
$$ LANGUAGE plpgsql;
|
|
396
|
+
|
|
397
|
+
CREATE OR REPLACE FUNCTION system.create_policies_after_rls()
|
|
398
|
+
RETURNS event_trigger AS $$
|
|
399
|
+
DECLARE
|
|
400
|
+
obj record;
|
|
401
|
+
table_schema text;
|
|
402
|
+
table_name text;
|
|
403
|
+
BEGIN
|
|
404
|
+
FOR obj IN SELECT * FROM pg_event_trigger_ddl_commands() WHERE command_tag = 'ALTER TABLE'
|
|
405
|
+
LOOP
|
|
406
|
+
SELECT INTO table_schema, table_name
|
|
407
|
+
split_part(obj.object_identity, '.', 1),
|
|
408
|
+
trim(both '"' from split_part(obj.object_identity, '.', 2));
|
|
409
|
+
IF EXISTS (
|
|
410
|
+
SELECT 1 FROM pg_tables
|
|
411
|
+
WHERE schemaname = table_schema
|
|
412
|
+
AND tablename = table_name
|
|
413
|
+
AND rowsecurity = true
|
|
414
|
+
) AND NOT EXISTS (
|
|
415
|
+
SELECT 1 FROM pg_policies
|
|
416
|
+
WHERE schemaname = table_schema
|
|
417
|
+
AND tablename = table_name
|
|
418
|
+
) THEN
|
|
419
|
+
EXECUTE format('CREATE POLICY "project_admin_policy" ON %s FOR ALL TO project_admin USING (true) WITH CHECK (true)', obj.object_identity);
|
|
420
|
+
END IF;
|
|
421
|
+
END LOOP;
|
|
422
|
+
END;
|
|
423
|
+
$$ LANGUAGE plpgsql;
|
|
424
|
+
|
|
425
|
+
-- Recreate event triggers pointing to system schema functions
|
|
426
|
+
CREATE EVENT TRIGGER create_policies_on_table_create
|
|
427
|
+
ON ddl_command_end
|
|
428
|
+
WHEN TAG IN ('CREATE TABLE')
|
|
429
|
+
EXECUTE FUNCTION system.create_default_policies();
|
|
430
|
+
|
|
431
|
+
CREATE EVENT TRIGGER create_policies_on_rls_enable
|
|
432
|
+
ON ddl_command_end
|
|
433
|
+
WHEN TAG IN ('ALTER TABLE')
|
|
434
|
+
EXECUTE FUNCTION system.create_policies_after_rls();
|
|
435
|
+
|
|
436
|
+
-- 6.5 Drop obsolete functions
|
|
437
|
+
DROP FUNCTION IF EXISTS public.create_default_policies() CASCADE;
|
|
438
|
+
DROP FUNCTION IF EXISTS public.create_policies_after_rls() CASCADE;
|
|
439
|
+
DROP FUNCTION IF EXISTS public.reload_postgrest_schema() CASCADE;
|
|
440
|
+
DROP FUNCTION IF EXISTS public.update_updated_at_column() CASCADE;
|
|
441
|
+
DROP FUNCTION IF EXISTS realtime.update_updated_at() CASCADE;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
-- Migration: 019 - Create deployments table in system schema
|
|
2
|
+
|
|
3
|
+
-- Create deployments table for tracking deployment requests and their status
|
|
4
|
+
-- Designed to be provider-agnostic (Vercel, Netlify, Cloudflare, etc.)
|
|
5
|
+
--
|
|
6
|
+
-- Status flow:
|
|
7
|
+
-- WAITING -> UPLOADING -> (Vercel statuses: QUEUED/BUILDING/READY/ERROR/CANCELED)
|
|
8
|
+
-- InsForge statuses:
|
|
9
|
+
-- - WAITING: Record created, waiting for client to upload zip to S3
|
|
10
|
+
-- - UPLOADING: Server is downloading from S3 and uploading to Vercel
|
|
11
|
+
-- Vercel statuses (stored directly):
|
|
12
|
+
-- - QUEUED: Deployment queued
|
|
13
|
+
-- - BUILDING: Deployment building
|
|
14
|
+
-- - READY: Deployment ready
|
|
15
|
+
-- - ERROR: Deployment failed
|
|
16
|
+
-- - CANCELED: Deployment canceled
|
|
17
|
+
CREATE TABLE IF NOT EXISTS system.deployments (
|
|
18
|
+
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
|
|
19
|
+
provider TEXT NOT NULL DEFAULT 'vercel',
|
|
20
|
+
provider_deployment_id TEXT UNIQUE, -- Provider's deployment ID, null until deployment starts
|
|
21
|
+
status TEXT NOT NULL DEFAULT 'WAITING',
|
|
22
|
+
url TEXT,
|
|
23
|
+
metadata JSONB,
|
|
24
|
+
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
25
|
+
updated_at TIMESTAMPTZ DEFAULT NOW()
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
-- Create indexes for better query performance
|
|
29
|
+
CREATE INDEX IF NOT EXISTS idx_deployments_status ON system.deployments(status);
|
|
30
|
+
CREATE INDEX IF NOT EXISTS idx_deployments_provider ON system.deployments(provider);
|
|
31
|
+
CREATE INDEX IF NOT EXISTS idx_deployments_created_at ON system.deployments(created_at DESC);
|
|
32
|
+
|
|
33
|
+
-- Add trigger for updated_at
|
|
34
|
+
DROP TRIGGER IF EXISTS update_system_deployments_updated_at ON system.deployments;
|
|
35
|
+
CREATE TRIGGER update_system_deployments_updated_at BEFORE UPDATE ON system.deployments
|
|
36
|
+
FOR EACH ROW EXECUTE FUNCTION system.update_updated_at();
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
-- Migration: 020 - Expand modality constraints to all OpenRouter modalities
|
|
2
|
+
-- Supports: text, image, audio, video, file
|
|
3
|
+
-- Filtering is handled in application layer (shared-schemas + helpers.ts)
|
|
4
|
+
|
|
5
|
+
ALTER TABLE ai.configs DROP CONSTRAINT IF EXISTS check_input_modality_valid;
|
|
6
|
+
ALTER TABLE ai.configs ADD CONSTRAINT check_input_modality_valid
|
|
7
|
+
CHECK (input_modality <@ '{text,image,audio,video,file}'::TEXT[]);
|
|
8
|
+
|
|
9
|
+
ALTER TABLE ai.configs DROP CONSTRAINT IF EXISTS check_output_modality_valid;
|
|
10
|
+
ALTER TABLE ai.configs ADD CONSTRAINT check_output_modality_valid
|
|
11
|
+
CHECK (output_modality <@ '{text,image,audio,video,file}'::TEXT[]);
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bootstrap script for migrations table migration
|
|
3
|
+
*
|
|
4
|
+
* This script handles the one-time migration of the node-pg-migrate tracking table
|
|
5
|
+
* from `public._migrations` to `system.migrations`.
|
|
6
|
+
*
|
|
7
|
+
* Why this is needed:
|
|
8
|
+
* - node-pg-migrate checks for the migrations table BEFORE running any migrations
|
|
9
|
+
* - If we try to move the table inside a migration file, node-pg-migrate will have
|
|
10
|
+
* already looked for `system.migrations`, not found it, and created an empty one
|
|
11
|
+
* - This would cause all migrations to appear as "pending" and fail
|
|
12
|
+
*
|
|
13
|
+
* This script runs BEFORE node-pg-migrate and handles the table move gracefully.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import pg from 'pg';
|
|
17
|
+
// Note: This imports a TypeScript file. This works because the script is run with `tsx`
|
|
18
|
+
// (see package.json migrate:bootstrap script), which can handle TypeScript imports.
|
|
19
|
+
// The relative path goes up 4 levels: bootstrap -> migrations -> database -> infra -> src, then into utils.
|
|
20
|
+
import logger from '@/utils/logger.js';
|
|
21
|
+
|
|
22
|
+
const { Pool } = pg;
|
|
23
|
+
|
|
24
|
+
async function bootstrapMigrations() {
|
|
25
|
+
// Use DATABASE_URL from environment (set by dotenv-cli in npm scripts)
|
|
26
|
+
const connectionString = process.env.DATABASE_URL;
|
|
27
|
+
|
|
28
|
+
if (!connectionString) {
|
|
29
|
+
logger.error('DATABASE_URL environment variable is not set');
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const pool = new Pool({ connectionString });
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
const client = await pool.connect();
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
// Check if old _migrations table exists in public schema
|
|
40
|
+
const oldTableExists = await client.query(`
|
|
41
|
+
SELECT EXISTS (
|
|
42
|
+
SELECT 1 FROM information_schema.tables
|
|
43
|
+
WHERE table_schema = 'public' AND table_name = '_migrations'
|
|
44
|
+
) as exists
|
|
45
|
+
`);
|
|
46
|
+
|
|
47
|
+
// Check if new system.migrations table already exists
|
|
48
|
+
const newTableExists = await client.query(`
|
|
49
|
+
SELECT EXISTS (
|
|
50
|
+
SELECT 1 FROM information_schema.tables
|
|
51
|
+
WHERE table_schema = 'system' AND table_name = 'migrations'
|
|
52
|
+
) as exists
|
|
53
|
+
`);
|
|
54
|
+
|
|
55
|
+
if (oldTableExists.rows[0].exists && !newTableExists.rows[0].exists) {
|
|
56
|
+
logger.info('Bootstrap: Moving _migrations table to system.migrations...');
|
|
57
|
+
|
|
58
|
+
// Create system schema if it doesn't exist
|
|
59
|
+
await client.query('CREATE SCHEMA IF NOT EXISTS system');
|
|
60
|
+
|
|
61
|
+
// Move the table in a transaction to avoid partial state
|
|
62
|
+
await client.query('BEGIN');
|
|
63
|
+
try {
|
|
64
|
+
await client.query('ALTER TABLE public._migrations SET SCHEMA system');
|
|
65
|
+
await client.query('ALTER TABLE system._migrations RENAME TO migrations');
|
|
66
|
+
await client.query('COMMIT');
|
|
67
|
+
} catch (error) {
|
|
68
|
+
await client.query('ROLLBACK');
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
logger.info('Bootstrap: Successfully moved _migrations to system.migrations');
|
|
73
|
+
} else if (newTableExists.rows[0].exists) {
|
|
74
|
+
// Already migrated, nothing to do
|
|
75
|
+
logger.info('Bootstrap: system.migrations already exists, skipping');
|
|
76
|
+
} else if (!oldTableExists.rows[0].exists && !newTableExists.rows[0].exists) {
|
|
77
|
+
// Fresh install - create system schema so node-pg-migrate can create its table there
|
|
78
|
+
logger.info('Bootstrap: No existing migrations table, fresh install');
|
|
79
|
+
await client.query('CREATE SCHEMA IF NOT EXISTS system');
|
|
80
|
+
logger.info('Bootstrap: Created system schema for migrations');
|
|
81
|
+
}
|
|
82
|
+
} finally {
|
|
83
|
+
client.release();
|
|
84
|
+
}
|
|
85
|
+
} catch (error) {
|
|
86
|
+
logger.error('Bootstrap migration failed', {
|
|
87
|
+
error: error instanceof Error ? error.message : String(error),
|
|
88
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
89
|
+
});
|
|
90
|
+
process.exitCode = 1;
|
|
91
|
+
} finally {
|
|
92
|
+
await pool.end();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
bootstrapMigrations().catch((error) => {
|
|
97
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
98
|
+
logger.error('Bootstrap migration failed', {
|
|
99
|
+
error: message,
|
|
100
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
101
|
+
});
|
|
102
|
+
process.exitCode = 1;
|
|
103
|
+
});
|
|
@@ -195,10 +195,7 @@ export class TokenManager {
|
|
|
195
195
|
* Generate CSRF token derived from refresh token using HMAC
|
|
196
196
|
*/
|
|
197
197
|
generateCsrfToken(refreshToken: string): string {
|
|
198
|
-
return crypto
|
|
199
|
-
.createHmac('sha256', JWT_SECRET)
|
|
200
|
-
.update(refreshToken)
|
|
201
|
-
.digest('hex');
|
|
198
|
+
return crypto.createHmac('sha256', JWT_SECRET).update(refreshToken).digest('hex');
|
|
202
199
|
}
|
|
203
200
|
|
|
204
201
|
/**
|
|
@@ -185,7 +185,10 @@ export class OpenRouterProvider {
|
|
|
185
185
|
};
|
|
186
186
|
}
|
|
187
187
|
} catch (error) {
|
|
188
|
-
|
|
188
|
+
logger.error('Failed to fetch remaining credits', {
|
|
189
|
+
error: error instanceof Error ? error.message : String(error),
|
|
190
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
191
|
+
});
|
|
189
192
|
throw error;
|
|
190
193
|
}
|
|
191
194
|
}
|
|
@@ -243,7 +246,10 @@ export class OpenRouterProvider {
|
|
|
243
246
|
|
|
244
247
|
return data.openrouter.api_key;
|
|
245
248
|
} catch (error) {
|
|
246
|
-
|
|
249
|
+
logger.error('Failed to fetch cloud API key', {
|
|
250
|
+
error: error instanceof Error ? error.message : String(error),
|
|
251
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
252
|
+
});
|
|
247
253
|
throw error;
|
|
248
254
|
} finally {
|
|
249
255
|
// Clear the promise after completion (success or failure)
|
|
@@ -317,7 +323,10 @@ export class OpenRouterProvider {
|
|
|
317
323
|
|
|
318
324
|
return data.openrouter.api_key;
|
|
319
325
|
} catch (error) {
|
|
320
|
-
|
|
326
|
+
logger.error('Failed to renew cloud API key', {
|
|
327
|
+
error: error instanceof Error ? error.message : String(error),
|
|
328
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
329
|
+
});
|
|
321
330
|
throw error;
|
|
322
331
|
} finally {
|
|
323
332
|
// Clear the promise after completion (success or failure)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database connection information
|
|
3
|
+
*/
|
|
4
|
+
export interface DatabaseConnectionInfo {
|
|
5
|
+
connectionURL: string;
|
|
6
|
+
parameters: {
|
|
7
|
+
host: string;
|
|
8
|
+
port: number;
|
|
9
|
+
database: string;
|
|
10
|
+
user: string;
|
|
11
|
+
password: string;
|
|
12
|
+
sslmode: string;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Database password information
|
|
18
|
+
*/
|
|
19
|
+
export interface DatabasePasswordInfo {
|
|
20
|
+
databasePassword: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Database provider interface
|
|
25
|
+
* Defines the contract for fetching database connection information
|
|
26
|
+
*/
|
|
27
|
+
export interface DatabaseProvider {
|
|
28
|
+
/**
|
|
29
|
+
* Get database connection string
|
|
30
|
+
* @returns Database connection info with masked password
|
|
31
|
+
*/
|
|
32
|
+
getDatabaseConnectionString(): Promise<DatabaseConnectionInfo>;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Get database password
|
|
36
|
+
* @returns Database password (unmasked)
|
|
37
|
+
*/
|
|
38
|
+
getDatabasePassword(): Promise<DatabasePasswordInfo>;
|
|
39
|
+
}
|