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
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
# [1.4.0](https://github.com/InsForge/InsForge/compare/v1.3.1-e2e.2...v1.4.0) (2025-12-19)
|
|
4
|
+
|
|
3
5
|
## [1.2.8](https://github.com/InsForge/InsForge/compare/v1.2.6...v1.2.8) (2025-12-05)
|
|
4
6
|
|
|
5
7
|
## [1.2.6](https://github.com/InsForge/InsForge/compare/v1.2.4...v1.2.6) (2025-11-22)
|
package/auth/package.json
CHANGED
|
@@ -10,11 +10,13 @@
|
|
|
10
10
|
"preview": "vite preview"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@insforge/react": "
|
|
14
|
-
"@insforge/
|
|
13
|
+
"@insforge/react": "1.1.2",
|
|
14
|
+
"@insforge/sdk": "1.1.0",
|
|
15
|
+
"clsx": "^2.1.1",
|
|
15
16
|
"react": "^19.2.1",
|
|
16
17
|
"react-dom": "^19.2.1",
|
|
17
|
-
"react-router-dom": "^7.7.0"
|
|
18
|
+
"react-router-dom": "^7.7.0",
|
|
19
|
+
"tailwind-merge": "^3.4.0"
|
|
18
20
|
},
|
|
19
21
|
"devDependencies": {
|
|
20
22
|
"@tailwindcss/vite": "^4.1.11",
|
|
@@ -1,117 +1,115 @@
|
|
|
1
|
-
// TODO: Rewrite this broadcast service file to implement PKCE in future
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
private
|
|
21
|
-
private
|
|
22
|
-
|
|
23
|
-
private
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const broadcastService = new BroadcastService();
|
|
117
|
-
export default broadcastService;
|
|
1
|
+
// TODO: Rewrite this broadcast service file to implement PKCE in future
|
|
2
|
+
import { VerifyEmailResponse } from '@insforge/shared-schemas';
|
|
3
|
+
|
|
4
|
+
export enum BroadcastEventType {
|
|
5
|
+
EMAIL_VERIFIED_SUCCESS = 'EMAIL_VERIFIED_SUCCESS',
|
|
6
|
+
PASSWORD_RESET_SUCCESS = 'PASSWORD_RESET_SUCCESS',
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface BroadcastEvent {
|
|
10
|
+
type: BroadcastEventType;
|
|
11
|
+
timestamp: number;
|
|
12
|
+
data?: VerifyEmailResponse;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type BroadcastEventHandler = (event: BroadcastEvent) => void;
|
|
16
|
+
|
|
17
|
+
class BroadcastService {
|
|
18
|
+
private channel: BroadcastChannel | null = null;
|
|
19
|
+
private readonly CHANNEL_NAME = 'insforge-auth-channel';
|
|
20
|
+
private handlers: Map<BroadcastEventType, Set<BroadcastEventHandler>> = new Map();
|
|
21
|
+
private isInitialized = false;
|
|
22
|
+
|
|
23
|
+
private isSupported(): boolean {
|
|
24
|
+
return typeof window !== 'undefined' && 'BroadcastChannel' in window;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
init(): void {
|
|
28
|
+
if (this.isInitialized) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (!this.isSupported()) {
|
|
33
|
+
console.warn('BroadcastChannel API is not supported in this browser');
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
this.channel = new BroadcastChannel(this.CHANNEL_NAME);
|
|
39
|
+
this.channel.onmessage = (messageEvent: MessageEvent<BroadcastEvent>) => {
|
|
40
|
+
const event = messageEvent.data;
|
|
41
|
+
this.handleIncomingEvent(event);
|
|
42
|
+
};
|
|
43
|
+
this.isInitialized = true;
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error('Failed to initialize BroadcastService:', error);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
private handleIncomingEvent(event: BroadcastEvent): void {
|
|
50
|
+
const handlers = this.handlers.get(event.type);
|
|
51
|
+
if (handlers) {
|
|
52
|
+
handlers.forEach((handler) => {
|
|
53
|
+
try {
|
|
54
|
+
handler(event);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
console.error('Error handling broadcast event:', error);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
subscribe(eventType: BroadcastEventType, handler: BroadcastEventHandler): () => void {
|
|
63
|
+
if (!this.isInitialized) {
|
|
64
|
+
this.init();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!this.handlers.has(eventType)) {
|
|
68
|
+
this.handlers.set(eventType, new Set());
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
this.handlers.get(eventType)?.add(handler);
|
|
72
|
+
|
|
73
|
+
return () => {
|
|
74
|
+
const handlers = this.handlers.get(eventType);
|
|
75
|
+
if (handlers) {
|
|
76
|
+
handlers.delete(handler);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
broadcast(eventType: BroadcastEventType, data?: BroadcastEvent['data']): void {
|
|
82
|
+
if (!this.isInitialized) {
|
|
83
|
+
this.init();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (!this.channel) {
|
|
87
|
+
console.warn('BroadcastChannel not available, cannot broadcast event');
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const event: BroadcastEvent = {
|
|
92
|
+
type: eventType,
|
|
93
|
+
timestamp: Date.now(),
|
|
94
|
+
data,
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
this.channel.postMessage(event);
|
|
99
|
+
} catch (error) {
|
|
100
|
+
console.error('Failed to broadcast event:', error);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
close(): void {
|
|
105
|
+
if (this.channel) {
|
|
106
|
+
this.channel.close();
|
|
107
|
+
this.channel = null;
|
|
108
|
+
}
|
|
109
|
+
this.handlers.clear();
|
|
110
|
+
this.isInitialized = false;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const broadcastService = new BroadcastService();
|
|
115
|
+
export default broadcastService;
|
package/auth/src/main.tsx
CHANGED
|
@@ -4,16 +4,14 @@ import { BrowserRouter } from 'react-router-dom';
|
|
|
4
4
|
import { InsforgeProvider } from '@insforge/react';
|
|
5
5
|
import './index.css';
|
|
6
6
|
import App from './App';
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
const backendUrl = getBackendUrl();
|
|
7
|
+
import { insforge } from './lib/insforge';
|
|
10
8
|
|
|
11
9
|
const rootElement = document.getElementById('root');
|
|
12
10
|
if (rootElement) {
|
|
13
11
|
createRoot(rootElement).render(
|
|
14
12
|
<StrictMode>
|
|
15
13
|
<BrowserRouter>
|
|
16
|
-
<InsforgeProvider
|
|
14
|
+
<InsforgeProvider client={insforge}>
|
|
17
15
|
<App />
|
|
18
16
|
</InsforgeProvider>
|
|
19
17
|
</BrowserRouter>
|
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
import { useCallback, useEffect } from 'react';
|
|
2
|
-
import { useSearchParams } from 'react-router-dom';
|
|
3
|
-
import { SignIn } from '@insforge/react';
|
|
4
|
-
import broadcastService, { BroadcastEventType, BroadcastEvent } from '../lib/broadcastService';
|
|
5
|
-
import { ErrorCard } from '../components/ErrorCard';
|
|
6
|
-
|
|
7
|
-
export function SignInPage() {
|
|
8
|
-
const [searchParams] = useSearchParams();
|
|
9
|
-
const redirectUrl = searchParams.get('redirect');
|
|
10
|
-
|
|
11
|
-
// Listen for email verification success from other tabs
|
|
12
|
-
useEffect(() => {
|
|
13
|
-
if (!redirectUrl) {
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const unsubscribeVerified = broadcastService.subscribe(
|
|
18
|
-
BroadcastEventType.EMAIL_VERIFIED_SUCCESS,
|
|
19
|
-
(event: BroadcastEvent) => {
|
|
20
|
-
const { accessToken, user, csrfToken } = event.data || {};
|
|
21
|
-
if (accessToken && user) {
|
|
22
|
-
// Email verified in another tab, redirect with token
|
|
23
|
-
try {
|
|
24
|
-
const finalUrl = new URL(redirectUrl, window.location.origin);
|
|
25
|
-
const params = new URLSearchParams();
|
|
26
|
-
params.set('access_token', accessToken);
|
|
27
|
-
params.set('user_id', user.id);
|
|
28
|
-
params.set('email', user.email);
|
|
29
|
-
params.set('name', user.name);
|
|
30
|
-
if (csrfToken) {
|
|
31
|
-
params.set('csrf_token', csrfToken);
|
|
32
|
-
}
|
|
33
|
-
finalUrl.search = params.toString();
|
|
34
|
-
window.location.href = finalUrl.toString();
|
|
35
|
-
} catch {
|
|
36
|
-
console.error('Failed to redirect to final URL');
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
return () => {
|
|
43
|
-
unsubscribeVerified();
|
|
44
|
-
};
|
|
45
|
-
}, [redirectUrl]);
|
|
46
|
-
|
|
47
|
-
const handleError = useCallback((error: Error) => {
|
|
48
|
-
console.error('Sign in failed:', error);
|
|
49
|
-
}, []);
|
|
50
|
-
|
|
51
|
-
if (!redirectUrl) {
|
|
52
|
-
return (
|
|
53
|
-
<ErrorCard title="Missing Redirect URL">
|
|
54
|
-
<p>No redirect URL provided. Please check the URL and try again.</p>
|
|
55
|
-
</ErrorCard>
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return <SignIn onError={handleError} />;
|
|
60
|
-
}
|
|
1
|
+
import { useCallback, useEffect } from 'react';
|
|
2
|
+
import { useSearchParams } from 'react-router-dom';
|
|
3
|
+
import { SignIn } from '@insforge/react';
|
|
4
|
+
import broadcastService, { BroadcastEventType, BroadcastEvent } from '../lib/broadcastService';
|
|
5
|
+
import { ErrorCard } from '../components/ErrorCard';
|
|
6
|
+
|
|
7
|
+
export function SignInPage() {
|
|
8
|
+
const [searchParams] = useSearchParams();
|
|
9
|
+
const redirectUrl = searchParams.get('redirect');
|
|
10
|
+
|
|
11
|
+
// Listen for email verification success from other tabs
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (!redirectUrl) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const unsubscribeVerified = broadcastService.subscribe(
|
|
18
|
+
BroadcastEventType.EMAIL_VERIFIED_SUCCESS,
|
|
19
|
+
(event: BroadcastEvent) => {
|
|
20
|
+
const { accessToken, user, csrfToken } = event.data || {};
|
|
21
|
+
if (accessToken && user) {
|
|
22
|
+
// Email verified in another tab, redirect with token
|
|
23
|
+
try {
|
|
24
|
+
const finalUrl = new URL(redirectUrl, window.location.origin);
|
|
25
|
+
const params = new URLSearchParams();
|
|
26
|
+
params.set('access_token', accessToken);
|
|
27
|
+
params.set('user_id', user.id);
|
|
28
|
+
params.set('email', user.email);
|
|
29
|
+
params.set('name', String(user.profile?.name));
|
|
30
|
+
if (csrfToken) {
|
|
31
|
+
params.set('csrf_token', csrfToken);
|
|
32
|
+
}
|
|
33
|
+
finalUrl.search = params.toString();
|
|
34
|
+
window.location.href = finalUrl.toString();
|
|
35
|
+
} catch {
|
|
36
|
+
console.error('Failed to redirect to final URL');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
return () => {
|
|
43
|
+
unsubscribeVerified();
|
|
44
|
+
};
|
|
45
|
+
}, [redirectUrl]);
|
|
46
|
+
|
|
47
|
+
const handleError = useCallback((error: Error) => {
|
|
48
|
+
console.error('Sign in failed:', error);
|
|
49
|
+
}, []);
|
|
50
|
+
|
|
51
|
+
if (!redirectUrl) {
|
|
52
|
+
return (
|
|
53
|
+
<ErrorCard title="Missing Redirect URL">
|
|
54
|
+
<p>No redirect URL provided. Please check the URL and try again.</p>
|
|
55
|
+
</ErrorCard>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return <SignIn onError={handleError} />;
|
|
60
|
+
}
|
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
import { useCallback, useEffect } from 'react';
|
|
2
|
-
import { useSearchParams } from 'react-router-dom';
|
|
3
|
-
import { SignUp } from '@insforge/react';
|
|
4
|
-
import broadcastService, { BroadcastEventType, BroadcastEvent } from '../lib/broadcastService';
|
|
5
|
-
import { ErrorCard } from '../components/ErrorCard';
|
|
6
|
-
|
|
7
|
-
export function SignUpPage() {
|
|
8
|
-
const [searchParams] = useSearchParams();
|
|
9
|
-
const redirectUrl = searchParams.get('redirect');
|
|
10
|
-
|
|
11
|
-
// Listen for email verification success from other tabs
|
|
12
|
-
useEffect(() => {
|
|
13
|
-
if (!redirectUrl) {
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const unsubscribeVerified = broadcastService.subscribe(
|
|
18
|
-
BroadcastEventType.EMAIL_VERIFIED_SUCCESS,
|
|
19
|
-
(event: BroadcastEvent) => {
|
|
20
|
-
const { accessToken, user, csrfToken } = event.data || {};
|
|
21
|
-
if (accessToken && user) {
|
|
22
|
-
// Email verified in another tab, redirect with token
|
|
23
|
-
try {
|
|
24
|
-
const finalUrl = new URL(redirectUrl, window.location.origin);
|
|
25
|
-
const params = new URLSearchParams();
|
|
26
|
-
params.set('access_token', accessToken);
|
|
27
|
-
params.set('user_id', user.id);
|
|
28
|
-
params.set('email', user.email);
|
|
29
|
-
params.set('name', user.name);
|
|
30
|
-
if (csrfToken) {
|
|
31
|
-
params.set('csrf_token', csrfToken);
|
|
32
|
-
}
|
|
33
|
-
finalUrl.search = params.toString();
|
|
34
|
-
window.location.href = finalUrl.toString();
|
|
35
|
-
} catch {
|
|
36
|
-
console.error('Failed to redirect to final URL');
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
return () => {
|
|
43
|
-
unsubscribeVerified();
|
|
44
|
-
};
|
|
45
|
-
}, [redirectUrl]);
|
|
46
|
-
|
|
47
|
-
const handleError = useCallback((error: Error) => {
|
|
48
|
-
console.error('Sign up failed:', error);
|
|
49
|
-
}, []);
|
|
50
|
-
|
|
51
|
-
if (!redirectUrl) {
|
|
52
|
-
return (
|
|
53
|
-
<ErrorCard title="Missing Redirect URL">
|
|
54
|
-
<p>No redirect URL provided. Please check the URL and try again.</p>
|
|
55
|
-
</ErrorCard>
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return <SignUp onError={handleError} />;
|
|
60
|
-
}
|
|
1
|
+
import { useCallback, useEffect } from 'react';
|
|
2
|
+
import { useSearchParams } from 'react-router-dom';
|
|
3
|
+
import { SignUp } from '@insforge/react';
|
|
4
|
+
import broadcastService, { BroadcastEventType, BroadcastEvent } from '../lib/broadcastService';
|
|
5
|
+
import { ErrorCard } from '../components/ErrorCard';
|
|
6
|
+
|
|
7
|
+
export function SignUpPage() {
|
|
8
|
+
const [searchParams] = useSearchParams();
|
|
9
|
+
const redirectUrl = searchParams.get('redirect');
|
|
10
|
+
|
|
11
|
+
// Listen for email verification success from other tabs
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (!redirectUrl) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const unsubscribeVerified = broadcastService.subscribe(
|
|
18
|
+
BroadcastEventType.EMAIL_VERIFIED_SUCCESS,
|
|
19
|
+
(event: BroadcastEvent) => {
|
|
20
|
+
const { accessToken, user, csrfToken } = event.data || {};
|
|
21
|
+
if (accessToken && user) {
|
|
22
|
+
// Email verified in another tab, redirect with token
|
|
23
|
+
try {
|
|
24
|
+
const finalUrl = new URL(redirectUrl, window.location.origin);
|
|
25
|
+
const params = new URLSearchParams();
|
|
26
|
+
params.set('access_token', accessToken);
|
|
27
|
+
params.set('user_id', user.id);
|
|
28
|
+
params.set('email', user.email);
|
|
29
|
+
params.set('name', String(user.profile?.name));
|
|
30
|
+
if (csrfToken) {
|
|
31
|
+
params.set('csrf_token', csrfToken);
|
|
32
|
+
}
|
|
33
|
+
finalUrl.search = params.toString();
|
|
34
|
+
window.location.href = finalUrl.toString();
|
|
35
|
+
} catch {
|
|
36
|
+
console.error('Failed to redirect to final URL');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
return () => {
|
|
43
|
+
unsubscribeVerified();
|
|
44
|
+
};
|
|
45
|
+
}, [redirectUrl]);
|
|
46
|
+
|
|
47
|
+
const handleError = useCallback((error: Error) => {
|
|
48
|
+
console.error('Sign up failed:', error);
|
|
49
|
+
}, []);
|
|
50
|
+
|
|
51
|
+
if (!redirectUrl) {
|
|
52
|
+
return (
|
|
53
|
+
<ErrorCard title="Missing Redirect URL">
|
|
54
|
+
<p>No redirect URL provided. Please check the URL and try again.</p>
|
|
55
|
+
</ErrorCard>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return <SignUp onError={handleError} />;
|
|
60
|
+
}
|
|
@@ -5,12 +5,30 @@ import broadcastService, { BroadcastEventType } from '../lib/broadcastService';
|
|
|
5
5
|
export function VerifyEmailPage() {
|
|
6
6
|
const [searchParams] = useSearchParams();
|
|
7
7
|
const token = searchParams.get('token');
|
|
8
|
+
const redirectTo = searchParams.get('redirectTo');
|
|
8
9
|
|
|
9
10
|
return (
|
|
10
11
|
<VerifyEmail
|
|
11
12
|
token={token || ''}
|
|
12
13
|
onSuccess={(data) => {
|
|
13
14
|
broadcastService.broadcast(BroadcastEventType.EMAIL_VERIFIED_SUCCESS, data);
|
|
15
|
+
// Redirect to custom URL if provided
|
|
16
|
+
if (redirectTo) {
|
|
17
|
+
const { accessToken, user, csrfToken } = data;
|
|
18
|
+
if (accessToken && user) {
|
|
19
|
+
const finalUrl = new URL(redirectTo, window.location.origin);
|
|
20
|
+
const params = new URLSearchParams();
|
|
21
|
+
params.set('access_token', accessToken);
|
|
22
|
+
params.set('user_id', user.id);
|
|
23
|
+
params.set('email', user.email);
|
|
24
|
+
params.set('name', String(user.profile?.name));
|
|
25
|
+
if (csrfToken) {
|
|
26
|
+
params.set('csrf_token', csrfToken);
|
|
27
|
+
}
|
|
28
|
+
finalUrl.search = params.toString();
|
|
29
|
+
window.location.href = finalUrl.toString();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
14
32
|
}}
|
|
15
33
|
onError={(error) => {
|
|
16
34
|
console.error('Email verification failed:', error);
|
package/auth/tsconfig.json
CHANGED
package/backend/package.json
CHANGED
|
@@ -15,13 +15,15 @@
|
|
|
15
15
|
"test:watch": "vitest",
|
|
16
16
|
"test:coverage": "vitest run --coverage",
|
|
17
17
|
"test:ui": "vitest --ui",
|
|
18
|
+
"test:bootstrap-import": "tsx tests/verify-bootstrap-import.js",
|
|
18
19
|
"test:e2e": "./tests/run-all-tests.sh",
|
|
19
|
-
"migrate:
|
|
20
|
-
"migrate:
|
|
21
|
-
"migrate:
|
|
22
|
-
"migrate:
|
|
23
|
-
"migrate:
|
|
24
|
-
"migrate:
|
|
20
|
+
"migrate:bootstrap": "tsx src/infra/database/migrations/bootstrap/bootstrap-migrations.js",
|
|
21
|
+
"migrate:up": "npm run migrate:bootstrap && node-pg-migrate up --migrations-dir src/infra/database/migrations --migrations-schema system --migrations-table migrations",
|
|
22
|
+
"migrate:down": "node-pg-migrate down --migrations-dir src/infra/database/migrations --migrations-schema system --migrations-table migrations",
|
|
23
|
+
"migrate:create": "node-pg-migrate create --migrations-dir src/infra/database/migrations --migrations-schema system --migrations-table migrations",
|
|
24
|
+
"migrate:redo": "npm run migrate:bootstrap && node-pg-migrate redo --migrations-dir src/infra/database/migrations --migrations-schema system --migrations-table migrations",
|
|
25
|
+
"migrate:up:local": "dotenv -e ../.env -- npm run migrate:bootstrap && dotenv -e ../.env -- node-pg-migrate up --migrations-dir src/infra/database/migrations --migrations-schema system --migrations-table migrations",
|
|
26
|
+
"migrate:down:local": "dotenv -e ../.env -- node-pg-migrate down --migrations-dir src/infra/database/migrations --migrations-schema system --migrations-table migrations"
|
|
25
27
|
},
|
|
26
28
|
"keywords": [
|
|
27
29
|
"backend-as-a-service",
|
|
@@ -39,6 +41,7 @@
|
|
|
39
41
|
"@databases/sql": "^3.3.0",
|
|
40
42
|
"@types/multer": "^1.4.13",
|
|
41
43
|
"@types/pg": "^8.15.4",
|
|
44
|
+
"adm-zip": "^0.5.16",
|
|
42
45
|
"axios": "^1.11.0",
|
|
43
46
|
"bcryptjs": "^3.0.2",
|
|
44
47
|
"cookie-parser": "^1.4.7",
|
|
@@ -62,6 +65,7 @@
|
|
|
62
65
|
"zod": "^3.23.8"
|
|
63
66
|
},
|
|
64
67
|
"devDependencies": {
|
|
68
|
+
"@types/adm-zip": "^0.5.7",
|
|
65
69
|
"@types/cookie-parser": "^1.4.8",
|
|
66
70
|
"@types/cors": "^2.8.17",
|
|
67
71
|
"@types/express": "^4.17.21",
|