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.
Files changed (269) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/auth/package.json +5 -3
  3. package/auth/src/lib/broadcastService.ts +115 -117
  4. package/auth/src/lib/insforge.ts +8 -0
  5. package/auth/src/main.tsx +2 -4
  6. package/auth/src/pages/SignInPage.tsx +60 -60
  7. package/auth/src/pages/SignUpPage.tsx +60 -60
  8. package/auth/src/pages/VerifyEmailPage.tsx +18 -0
  9. package/auth/tsconfig.json +2 -1
  10. package/backend/package.json +10 -6
  11. package/backend/src/api/middlewares/rate-limiters.ts +127 -127
  12. package/backend/src/api/routes/ai/index.routes.ts +475 -468
  13. package/backend/src/api/routes/auth/index.routes.ts +85 -32
  14. package/backend/src/api/routes/auth/oauth.routes.ts +11 -6
  15. package/backend/src/api/routes/database/index.routes.ts +2 -0
  16. package/backend/src/api/routes/database/records.routes.ts +39 -175
  17. package/backend/src/api/routes/database/rpc.routes.ts +69 -0
  18. package/backend/src/api/routes/deployments/index.routes.ts +192 -0
  19. package/backend/src/api/routes/docs/index.routes.ts +3 -2
  20. package/backend/src/api/routes/email/index.routes.ts +35 -35
  21. package/backend/src/api/routes/functions/index.routes.ts +3 -3
  22. package/backend/src/api/routes/metadata/index.routes.ts +26 -0
  23. package/backend/src/api/routes/webhooks/index.routes.ts +109 -0
  24. package/backend/src/infra/database/database.manager.ts +0 -10
  25. package/backend/src/infra/database/migrations/018_schema-rework.sql +441 -0
  26. package/backend/src/infra/database/migrations/019_create-deployments-table.sql +36 -0
  27. package/backend/src/infra/database/migrations/020_add-audio-modality.sql +11 -0
  28. package/backend/src/infra/database/migrations/bootstrap/bootstrap-migrations.js +103 -0
  29. package/backend/src/infra/security/token.manager.ts +1 -4
  30. package/backend/src/providers/ai/openrouter.provider.ts +12 -3
  31. package/backend/src/providers/database/base.provider.ts +39 -0
  32. package/backend/src/providers/database/cloud.provider.ts +159 -0
  33. package/backend/src/providers/deployments/vercel.provider.ts +516 -0
  34. package/backend/src/server.ts +19 -7
  35. package/backend/src/services/ai/ai-config.service.ts +6 -6
  36. package/backend/src/services/ai/ai-model.service.ts +60 -60
  37. package/backend/src/services/ai/ai-usage.service.ts +7 -7
  38. package/backend/src/services/ai/chat-completion.service.ts +415 -220
  39. package/backend/src/services/ai/helpers.ts +64 -64
  40. package/backend/src/services/ai/index.ts +13 -13
  41. package/backend/src/services/auth/auth-config.service.ts +4 -4
  42. package/backend/src/services/auth/auth-otp.service.ts +6 -6
  43. package/backend/src/services/auth/auth.service.ts +134 -74
  44. package/backend/src/services/auth/index.ts +4 -4
  45. package/backend/src/services/auth/oauth-config.service.ts +12 -12
  46. package/backend/src/services/database/database-advance.service.ts +19 -55
  47. package/backend/src/services/database/database-table.service.ts +38 -85
  48. package/backend/src/services/database/postgrest-proxy.service.ts +165 -0
  49. package/backend/src/services/deployments/deployment.service.ts +693 -0
  50. package/backend/src/services/functions/function.service.ts +61 -41
  51. package/backend/src/services/logs/audit.service.ts +10 -10
  52. package/backend/src/services/secrets/secret.service.ts +101 -27
  53. package/backend/src/services/storage/storage.service.ts +30 -30
  54. package/backend/src/services/usage/usage.service.ts +6 -6
  55. package/backend/src/types/ai.ts +8 -0
  56. package/backend/src/types/auth.ts +5 -1
  57. package/backend/src/types/database.ts +2 -0
  58. package/backend/src/types/deployments.ts +33 -0
  59. package/backend/src/types/storage.ts +1 -1
  60. package/backend/src/types/webhooks.ts +45 -0
  61. package/backend/src/utils/cookies.ts +34 -35
  62. package/backend/src/utils/environment.ts +0 -14
  63. package/backend/src/utils/s3-config-loader.ts +64 -64
  64. package/backend/src/utils/seed.ts +334 -301
  65. package/backend/src/utils/sql-parser.ts +126 -0
  66. package/backend/src/utils/utils.ts +114 -114
  67. package/backend/src/utils/validations.ts +10 -10
  68. package/backend/tests/local/test-rpc.sh +141 -0
  69. package/backend/tests/local/test-secrets.sh +1 -1
  70. package/backend/tests/manual/test-ai-model-plugins.sh +258 -0
  71. package/backend/tests/manual/test-rawsql-modes.sh +24 -24
  72. package/backend/tests/unit/database-advance.test.ts +326 -0
  73. package/backend/tests/unit/helpers.test.ts +2 -2
  74. package/claude-plugin/skills/insforge-schema-patterns/SKILL.md +13 -10
  75. package/docker-compose.prod.yml +1 -1
  76. package/docker-compose.yml +1 -1
  77. package/docs/agent-docs/deployment.md +79 -0
  78. package/docs/changelog.mdx +165 -72
  79. package/docs/core-concepts/ai/architecture.mdx +1 -23
  80. package/docs/core-concepts/ai/sdk.mdx +26 -1
  81. package/docs/core-concepts/authentication/architecture.mdx +6 -8
  82. package/docs/core-concepts/authentication/sdk.mdx +387 -91
  83. package/docs/core-concepts/authentication/ui-components/customization.mdx +460 -256
  84. package/docs/core-concepts/authentication/ui-components/nextjs.mdx +50 -24
  85. package/docs/core-concepts/authentication/ui-components/react-router.mdx +18 -19
  86. package/docs/core-concepts/authentication/ui-components/react.mdx +26 -19
  87. package/docs/core-concepts/database/architecture.mdx +58 -21
  88. package/docs/core-concepts/database/pgvector.mdx +138 -0
  89. package/docs/core-concepts/database/sdk.mdx +17 -17
  90. package/docs/core-concepts/deployments/architecture.mdx +152 -0
  91. package/docs/core-concepts/email/architecture.mdx +4 -2
  92. package/docs/core-concepts/functions/architecture.mdx +1 -1
  93. package/docs/core-concepts/functions/sdk.mdx +0 -1
  94. package/docs/core-concepts/realtime/architecture.mdx +1 -1
  95. package/docs/core-concepts/storage/architecture.mdx +1 -1
  96. package/docs/core-concepts/storage/sdk.mdx +25 -25
  97. package/docs/docs.json +14 -6
  98. package/docs/favicon.png +0 -0
  99. package/docs/favicon.svg +3 -18
  100. package/docs/images/changelog/dec-2025/apple-oauth.mp4 +0 -0
  101. package/docs/images/changelog/dec-2025/moreModels.png +0 -0
  102. package/docs/images/changelog/dec-2025/multi-region.webp +0 -0
  103. package/docs/images/changelog/dec-2025/postgres-connection.webp +0 -0
  104. package/docs/images/changelog/dec-2025/realtime2.png +0 -0
  105. package/docs/images/mcp-setup/CC-MCP-1.mp4 +0 -0
  106. package/docs/images/mcp-setup/CC-MCP-2.mp4 +0 -0
  107. package/docs/images/mcp-setup/Cursor-MCP-1.mp4 +0 -0
  108. package/docs/images/mcp-setup/Cursor-MCP-2.mp4 +0 -0
  109. package/docs/images/mcp-setup/Cursor-MCP-3.mp4 +0 -0
  110. package/docs/images/mcp-setup/claude-code-connect.png +0 -0
  111. package/docs/images/mcp-setup/cline-1.png +0 -0
  112. package/docs/images/mcp-setup/cline-2.png +0 -0
  113. package/docs/images/mcp-setup/cline-3.png +0 -0
  114. package/docs/images/mcp-setup/connect-project.png +0 -0
  115. package/docs/images/mcp-setup/copilot-1.png +0 -0
  116. package/docs/images/mcp-setup/copilot-2.png +0 -0
  117. package/docs/images/mcp-setup/copilot-3.png +0 -0
  118. package/docs/images/mcp-setup/mcp-json-1.png +0 -0
  119. package/docs/images/mcp-setup/mcp-json-2.png +0 -0
  120. package/docs/images/mcp-setup/qoder-1.png +0 -0
  121. package/docs/images/mcp-setup/qoder-2.png +0 -0
  122. package/docs/images/mcp-setup/roocode-1.png +0 -0
  123. package/docs/images/mcp-setup/roocode-2.png +0 -0
  124. package/docs/images/mcp-setup/trae-1.png +0 -0
  125. package/docs/images/mcp-setup/trae-2.png +0 -0
  126. package/docs/images/mcp-setup/trae-3.png +0 -0
  127. package/docs/images/mcp-setup/trae-4.png +0 -0
  128. package/docs/images/mcp-setup/trae-5.png +0 -0
  129. package/docs/images/mcp-setup/windsurf-1.png +0 -0
  130. package/docs/images/mcp-setup/windsurf-2.png +0 -0
  131. package/docs/insforge-instructions-sdk.md +7 -3
  132. package/docs/introduction.mdx +9 -8
  133. package/docs/mcp-setup.mdx +332 -0
  134. package/docs/oauth-server.mdx +563 -0
  135. package/docs/partnership.mdx +79 -10
  136. package/docs/quickstart.mdx +1 -1
  137. package/docs/vscode-extension.mdx +74 -0
  138. package/eslint.config.js +1 -0
  139. package/examples/response-examples.md +1 -1
  140. package/frontend/package.json +1 -1
  141. package/frontend/src/App.tsx +8 -3
  142. package/frontend/src/assets/logos/antigravity.svg +1 -0
  143. package/frontend/src/assets/logos/copilot.svg +10 -0
  144. package/frontend/src/assets/logos/deepseek.svg +139 -0
  145. package/frontend/src/assets/logos/kiro.svg +9 -0
  146. package/frontend/src/assets/logos/qoder.svg +4 -0
  147. package/frontend/src/assets/logos/qwen.svg +15 -0
  148. package/frontend/src/components/CodeBlock.tsx +2 -2
  149. package/frontend/src/components/ConnectCTA.tsx +3 -2
  150. package/frontend/src/components/datagrid/DataGrid.tsx +90 -62
  151. package/frontend/src/components/datagrid/datagridTypes.tsx +2 -1
  152. package/frontend/src/components/datagrid/index.ts +1 -1
  153. package/frontend/src/components/index.ts +0 -1
  154. package/frontend/src/components/layout/AppHeader.tsx +4 -27
  155. package/frontend/src/components/layout/AppSidebar.tsx +85 -100
  156. package/frontend/src/components/layout/Layout.tsx +34 -32
  157. package/frontend/src/components/layout/PrimaryMenu.tsx +12 -4
  158. package/frontend/src/components/radix/Select.tsx +151 -151
  159. package/frontend/src/features/ai/components/AIConfigCard.tsx +200 -200
  160. package/frontend/src/features/ai/components/AIEmptyState.tsx +23 -23
  161. package/frontend/src/features/ai/components/ModalityFilterSidebar.tsx +102 -101
  162. package/frontend/src/features/ai/components/ModelSelectionDialog.tsx +135 -135
  163. package/frontend/src/features/ai/components/ModelSelectionGrid.tsx +51 -51
  164. package/frontend/src/features/ai/components/SystemPromptDialog.tsx +118 -118
  165. package/frontend/src/features/ai/components/index.ts +6 -6
  166. package/frontend/src/features/ai/helpers.ts +147 -141
  167. package/frontend/src/features/ai/pages/AIPage.tsx +166 -166
  168. package/frontend/src/features/auth/components/AuthPreview.tsx +96 -96
  169. package/frontend/src/features/auth/components/UsersDataGrid.tsx +55 -31
  170. package/frontend/src/features/auth/components/index.ts +5 -5
  171. package/frontend/src/features/auth/pages/AuthMethodsPage.tsx +275 -275
  172. package/frontend/src/features/dashboard/pages/DashboardPage.tsx +1 -1
  173. package/frontend/src/features/database/components/DatabaseDataGrid.tsx +0 -2
  174. package/frontend/src/features/database/components/ForeignKeyCell.tsx +38 -11
  175. package/frontend/src/features/database/components/ForeignKeyPopover.tsx +18 -8
  176. package/frontend/src/features/database/components/LinkRecordModal.tsx +61 -13
  177. package/frontend/src/features/database/components/RecordFormField.tsx +1 -1
  178. package/frontend/src/features/database/components/TableSidebar.tsx +0 -3
  179. package/frontend/src/features/database/components/TablesEmptyState.tsx +1 -1
  180. package/frontend/src/features/database/components/TemplatePreview.tsx +1 -2
  181. package/frontend/src/features/database/constants.ts +16 -28
  182. package/frontend/src/features/database/hooks/useCSVImport.ts +3 -2
  183. package/frontend/src/features/database/hooks/useRawSQL.ts +3 -2
  184. package/frontend/src/features/database/hooks/useTables.ts +5 -7
  185. package/frontend/src/features/database/pages/FunctionsPage.tsx +0 -5
  186. package/frontend/src/features/database/pages/IndexesPage.tsx +0 -5
  187. package/frontend/src/features/database/pages/PoliciesPage.tsx +0 -5
  188. package/frontend/src/features/database/pages/SQLEditorPage.tsx +2 -2
  189. package/frontend/src/features/database/pages/TriggersPage.tsx +0 -5
  190. package/frontend/src/features/database/services/advance.service.ts +1 -15
  191. package/frontend/src/features/database/services/record.service.ts +4 -20
  192. package/frontend/src/features/database/services/table.service.ts +1 -4
  193. package/frontend/src/features/database/templates/ai-chatbot.ts +6 -6
  194. package/frontend/src/features/database/templates/ecommerce-platform.ts +2 -2
  195. package/frontend/src/features/database/templates/instagram-clone.ts +10 -10
  196. package/frontend/src/features/database/templates/notion-clone.ts +8 -8
  197. package/frontend/src/features/database/templates/reddit-clone.ts +10 -10
  198. package/frontend/src/features/deployments/components/DeploymentRow.tsx +93 -0
  199. package/frontend/src/features/deployments/components/DeploymentsEmptyState.tsx +15 -0
  200. package/frontend/src/features/deployments/hooks/useDeployments.ts +157 -0
  201. package/frontend/src/features/deployments/pages/DeploymentsPage.tsx +318 -0
  202. package/frontend/src/features/deployments/services/deployments.service.ts +63 -0
  203. package/frontend/src/features/functions/components/FunctionRow.tsx +72 -72
  204. package/frontend/src/features/functions/components/FunctionsSidebar.tsx +56 -56
  205. package/frontend/src/features/functions/components/SecretRow.tsx +3 -3
  206. package/frontend/src/features/functions/components/index.ts +5 -5
  207. package/frontend/src/features/functions/hooks/useFunctions.ts +5 -4
  208. package/frontend/src/features/functions/hooks/useSecrets.ts +6 -9
  209. package/frontend/src/features/functions/pages/SecretsPage.tsx +118 -118
  210. package/frontend/src/features/functions/services/function.service.ts +8 -25
  211. package/frontend/src/features/functions/services/secret.service.ts +23 -41
  212. package/frontend/src/features/login/pages/CloudLoginPage.tsx +125 -118
  213. package/frontend/src/features/logs/components/LogDetailPanel.tsx +41 -0
  214. package/frontend/src/features/logs/components/LogsDataGrid.tsx +32 -1
  215. package/frontend/src/features/logs/components/index.ts +1 -0
  216. package/frontend/src/features/logs/pages/LogsPage.tsx +36 -6
  217. package/frontend/src/features/onboard/components/ApiCredentialsSection.tsx +59 -0
  218. package/frontend/src/features/onboard/components/ConnectionStringSection.tsx +180 -0
  219. package/frontend/src/features/onboard/components/McpConnectionSection.tsx +159 -0
  220. package/frontend/src/features/onboard/components/OnboardingController.tsx +68 -0
  221. package/frontend/src/features/onboard/components/OnboardingModal.tsx +121 -267
  222. package/frontend/src/features/onboard/components/ShowPasswordButton.tsx +21 -0
  223. package/frontend/src/features/onboard/components/index.ts +9 -4
  224. package/frontend/src/features/onboard/components/mcp/CursorDeeplinkGenerator.tsx +1 -1
  225. package/frontend/src/features/onboard/components/mcp/QoderDeeplinkGenerator.tsx +36 -0
  226. package/frontend/src/features/onboard/components/mcp/helpers.tsx +123 -98
  227. package/frontend/src/features/onboard/components/mcp/index.ts +4 -3
  228. package/frontend/src/features/onboard/index.ts +17 -13
  229. package/frontend/src/features/settings/pages/SettingsPage.tsx +349 -0
  230. package/frontend/src/features/visualizer/components/AuthNode.tsx +4 -4
  231. package/frontend/src/features/visualizer/components/SchemaVisualizer.tsx +21 -8
  232. package/frontend/src/features/visualizer/pages/VisualizerPage.tsx +10 -1
  233. package/frontend/src/index.css +249 -249
  234. package/frontend/src/lib/contexts/ModalContext.tsx +35 -0
  235. package/frontend/src/lib/hooks/useMetadata.ts +45 -1
  236. package/frontend/src/lib/hooks/useModal.tsx +2 -0
  237. package/frontend/src/lib/routing/AppRoutes.tsx +103 -99
  238. package/frontend/src/lib/services/metadata.service.ts +20 -3
  239. package/frontend/src/lib/utils/menuItems.ts +223 -207
  240. package/frontend/src/lib/utils/utils.ts +196 -196
  241. package/functions/server.ts +315 -315
  242. package/functions/worker-template.js +1 -1
  243. package/openapi/ai.yaml +115 -5
  244. package/openapi/auth.yaml +97 -17
  245. package/openapi/logs.yaml +0 -2
  246. package/openapi/metadata.yaml +0 -2
  247. package/openapi/records.yaml +21 -21
  248. package/openapi/tables.yaml +1 -2
  249. package/package.json +1 -1
  250. package/shared-schemas/package.json +1 -1
  251. package/shared-schemas/src/ai-api.schema.ts +251 -143
  252. package/shared-schemas/src/ai.schema.ts +63 -63
  253. package/shared-schemas/src/auth-api.schema.ts +34 -6
  254. package/shared-schemas/src/auth.schema.ts +17 -10
  255. package/shared-schemas/src/cloud-events.schema.ts +26 -0
  256. package/shared-schemas/src/deployments-api.schema.ts +55 -0
  257. package/shared-schemas/src/deployments.schema.ts +30 -0
  258. package/shared-schemas/src/docs.schema.ts +8 -2
  259. package/shared-schemas/src/email-api.schema.ts +30 -30
  260. package/shared-schemas/src/functions-api.schema.ts +13 -4
  261. package/shared-schemas/src/functions.schema.ts +1 -1
  262. package/shared-schemas/src/index.ts +22 -18
  263. package/shared-schemas/src/metadata.schema.ts +30 -4
  264. package/shared-schemas/src/secrets-api.schema.ts +44 -0
  265. package/shared-schemas/src/secrets.schema.ts +15 -0
  266. package/zeabur/README.md +13 -0
  267. package/zeabur/template.yml +20 -51
  268. package/backend/src/types/profile.ts +0 -55
  269. 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": "^1.0.3",
14
- "@insforge/shared-schemas": "^1.1.23",
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
- export enum BroadcastEventType {
3
- EMAIL_VERIFIED_SUCCESS = 'EMAIL_VERIFIED_SUCCESS',
4
- PASSWORD_RESET_SUCCESS = 'PASSWORD_RESET_SUCCESS',
5
- }
6
-
7
- export interface BroadcastEvent {
8
- type: BroadcastEventType;
9
- timestamp: number;
10
- data?: {
11
- accessToken?: string;
12
- user?: { id: string; email: string; name: string };
13
- csrfToken?: string;
14
- };
15
- }
16
-
17
- export type BroadcastEventHandler = (event: BroadcastEvent) => void;
18
-
19
- class BroadcastService {
20
- private channel: BroadcastChannel | null = null;
21
- private readonly CHANNEL_NAME = 'insforge-auth-channel';
22
- private handlers: Map<BroadcastEventType, Set<BroadcastEventHandler>> = new Map();
23
- private isInitialized = false;
24
-
25
- private isSupported(): boolean {
26
- return typeof window !== 'undefined' && 'BroadcastChannel' in window;
27
- }
28
-
29
- init(): void {
30
- if (this.isInitialized) {
31
- return;
32
- }
33
-
34
- if (!this.isSupported()) {
35
- console.warn('BroadcastChannel API is not supported in this browser');
36
- return;
37
- }
38
-
39
- try {
40
- this.channel = new BroadcastChannel(this.CHANNEL_NAME);
41
- this.channel.onmessage = (messageEvent: MessageEvent<BroadcastEvent>) => {
42
- const event = messageEvent.data;
43
- this.handleIncomingEvent(event);
44
- };
45
- this.isInitialized = true;
46
- } catch (error) {
47
- console.error('Failed to initialize BroadcastService:', error);
48
- }
49
- }
50
-
51
- private handleIncomingEvent(event: BroadcastEvent): void {
52
- const handlers = this.handlers.get(event.type);
53
- if (handlers) {
54
- handlers.forEach((handler) => {
55
- try {
56
- handler(event);
57
- } catch (error) {
58
- console.error('Error handling broadcast event:', error);
59
- }
60
- });
61
- }
62
- }
63
-
64
- subscribe(eventType: BroadcastEventType, handler: BroadcastEventHandler): () => void {
65
- if (!this.isInitialized) {
66
- this.init();
67
- }
68
-
69
- if (!this.handlers.has(eventType)) {
70
- this.handlers.set(eventType, new Set());
71
- }
72
-
73
- this.handlers.get(eventType)?.add(handler);
74
-
75
- return () => {
76
- const handlers = this.handlers.get(eventType);
77
- if (handlers) {
78
- handlers.delete(handler);
79
- }
80
- };
81
- }
82
-
83
- broadcast(eventType: BroadcastEventType, data?: BroadcastEvent['data']): void {
84
- if (!this.isInitialized) {
85
- this.init();
86
- }
87
-
88
- if (!this.channel) {
89
- console.warn('BroadcastChannel not available, cannot broadcast event');
90
- return;
91
- }
92
-
93
- const event: BroadcastEvent = {
94
- type: eventType,
95
- timestamp: Date.now(),
96
- data,
97
- };
98
-
99
- try {
100
- this.channel.postMessage(event);
101
- } catch (error) {
102
- console.error('Failed to broadcast event:', error);
103
- }
104
- }
105
-
106
- close(): void {
107
- if (this.channel) {
108
- this.channel.close();
109
- this.channel = null;
110
- }
111
- this.handlers.clear();
112
- this.isInitialized = false;
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;
@@ -0,0 +1,8 @@
1
+ import { createClient, type InsForgeClient } from '@insforge/sdk';
2
+ import { getBackendUrl } from './utils';
3
+
4
+ const backendUrl = getBackendUrl();
5
+
6
+ export const insforge: InsForgeClient = createClient({
7
+ baseUrl: backendUrl,
8
+ });
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 { getBackendUrl } from './lib/utils';
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 baseUrl={backendUrl}>
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);
@@ -23,7 +23,8 @@
23
23
  /* Path mapping */
24
24
  "baseUrl": ".",
25
25
  "paths": {
26
- "@/*": ["./src/*"]
26
+ "@/*": ["./src/*"],
27
+ "@insforge/shared-schemas": ["../shared-schemas/src/index.ts"],
27
28
  }
28
29
  },
29
30
  "include": ["src"],
@@ -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:up": "node-pg-migrate up --migrations-dir src/infra/database/migrations --migrations-table _migrations",
20
- "migrate:down": "node-pg-migrate down --migrations-dir src/infra/database/migrations --migrations-table _migrations",
21
- "migrate:create": "node-pg-migrate create --migrations-dir src/infra/database/migrations --migrations-table _migrations",
22
- "migrate:redo": "node-pg-migrate redo --migrations-dir src/infra/database/migrations --migrations-table _migrations",
23
- "migrate:up:local": "dotenv -e ../.env -- node-pg-migrate up --migrations-dir src/infra/database/migrations --migrations-table _migrations",
24
- "migrate:down:local": "dotenv -e ../.env -- node-pg-migrate down --migrations-dir src/infra/database/migrations --migrations-table _migrations"
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",