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
@@ -0,0 +1,326 @@
1
+ import { describe, test, expect } from 'vitest';
2
+ import { DatabaseAdvanceService } from '../../src/services/database/database-advance.service';
3
+ import { AppError } from '../../src/api/middlewares/error';
4
+ import { ERROR_CODES } from '../../src/types/error-constants';
5
+
6
+ describe('DatabaseAdvanceService - sanitizeQuery', () => {
7
+ const service = DatabaseAdvanceService.getInstance();
8
+
9
+ describe('auth schema blocking', () => {
10
+ test('blocks DELETE FROM auth.users', () => {
11
+ const query = "DELETE FROM auth.users WHERE id = '00000000-0000-0000-0000-000000000001'";
12
+ expect(() => service.sanitizeQuery(query)).toThrow(AppError);
13
+ expect(() => service.sanitizeQuery(query)).toThrow(/auth schema/i);
14
+ });
15
+
16
+ test('blocks DELETE FROM quoted auth schema', () => {
17
+ const query = 'DELETE FROM "auth"."users" WHERE id = $1';
18
+ expect(() => service.sanitizeQuery(query)).toThrow(AppError);
19
+ });
20
+
21
+ test('blocks TRUNCATE auth.users', () => {
22
+ const query = 'TRUNCATE TABLE auth.users';
23
+ expect(() => service.sanitizeQuery(query)).toThrow(AppError);
24
+ });
25
+
26
+ test('blocks TRUNCATE without TABLE keyword', () => {
27
+ const query = 'TRUNCATE auth.users';
28
+ expect(() => service.sanitizeQuery(query)).toThrow(AppError);
29
+ });
30
+
31
+ test('blocks DROP TABLE auth.users', () => {
32
+ const query = 'DROP TABLE auth.users';
33
+ expect(() => service.sanitizeQuery(query)).toThrow(AppError);
34
+ });
35
+
36
+ test('blocks DROP TABLE with IF EXISTS', () => {
37
+ const query = 'DROP TABLE IF EXISTS auth.users';
38
+ expect(() => service.sanitizeQuery(query)).toThrow(AppError);
39
+ });
40
+
41
+ test('blocks DROP INDEX on auth schema', () => {
42
+ const query = 'DROP INDEX auth.users_email_idx';
43
+ expect(() => service.sanitizeQuery(query)).toThrow(AppError);
44
+ });
45
+
46
+ test('blocks DROP TRIGGER on auth schema tables', () => {
47
+ const queries = [
48
+ 'DROP TRIGGER user_created_trigger ON auth.users',
49
+ 'DROP TRIGGER IF EXISTS user_created_trigger ON auth.users',
50
+ 'DROP TRIGGER trigger_name ON "auth"."users"',
51
+ ];
52
+
53
+ queries.forEach((query) => {
54
+ expect(() => service.sanitizeQuery(query)).toThrow(AppError);
55
+ });
56
+ });
57
+
58
+ test('blocks DROP FUNCTION on auth schema', () => {
59
+ const query = 'DROP FUNCTION auth.create_user_profile()';
60
+ expect(() => service.sanitizeQuery(query)).toThrow(AppError);
61
+ });
62
+
63
+ test('blocks DROP VIEW on auth schema', () => {
64
+ const query = 'DROP VIEW auth.user_summary';
65
+ expect(() => service.sanitizeQuery(query)).toThrow(AppError);
66
+ });
67
+
68
+ test('blocks DROP SCHEMA auth (no dot after auth)', () => {
69
+ const queries = [
70
+ 'DROP SCHEMA auth',
71
+ 'DROP SCHEMA auth CASCADE',
72
+ 'DROP SCHEMA IF EXISTS auth',
73
+ 'DROP SCHEMA "auth" CASCADE',
74
+ ];
75
+
76
+ queries.forEach((query) => {
77
+ expect(() => service.sanitizeQuery(query)).toThrow(AppError);
78
+ });
79
+ });
80
+
81
+ test('allows SELECT FROM auth.users (read-only)', () => {
82
+ const query = 'SELECT * FROM auth.users LIMIT 1';
83
+ expect(() => service.sanitizeQuery(query)).not.toThrow();
84
+ });
85
+
86
+ test('blocks case-insensitive AUTH.users', () => {
87
+ const query = 'DELETE FROM AUTH.users WHERE id = $1';
88
+ expect(() => service.sanitizeQuery(query)).toThrow(AppError);
89
+ });
90
+
91
+ test('blocks mixed case Auth.Users', () => {
92
+ const query = 'DELETE FROM Auth.Users WHERE id = $1';
93
+ expect(() => service.sanitizeQuery(query)).toThrow(AppError);
94
+ });
95
+
96
+ test('blocks auth schema with quoted table name', () => {
97
+ const query = 'DELETE FROM auth."users" WHERE id = $1';
98
+ expect(() => service.sanitizeQuery(query)).toThrow(AppError);
99
+ });
100
+
101
+ test('blocks DELETE with whitespace before dot in auth schema', () => {
102
+ const queries = [
103
+ 'DELETE FROM auth . users WHERE id = $1',
104
+ 'DELETE FROM auth .users WHERE id = $1',
105
+ 'DELETE FROM auth\t.users WHERE id = $1',
106
+ ];
107
+
108
+ queries.forEach((query) => {
109
+ expect(() => service.sanitizeQuery(query)).toThrow(AppError);
110
+ });
111
+ });
112
+
113
+ test('allows UPDATE on auth schema (not blocked)', () => {
114
+ // UPDATE is allowed on auth schema
115
+ const queries = [
116
+ 'UPDATE auth.users SET email = $1 WHERE id = $2',
117
+ 'UPDATE auth.user_providers SET provider = $1 WHERE id = $2',
118
+ ];
119
+
120
+ queries.forEach((query) => {
121
+ expect(() => service.sanitizeQuery(query)).not.toThrow();
122
+ });
123
+ });
124
+
125
+ test('blocks DELETE on other auth schema tables', () => {
126
+ const queries = [
127
+ 'DELETE FROM auth.user_providers WHERE id = $1',
128
+ 'DELETE FROM auth.configs WHERE id = $1',
129
+ 'DELETE FROM auth.oauth_configs WHERE id = $1',
130
+ ];
131
+
132
+ queries.forEach((query) => {
133
+ expect(() => service.sanitizeQuery(query)).toThrow(AppError);
134
+ });
135
+ });
136
+
137
+ test('blocks TRUNCATE on other auth schema tables', () => {
138
+ const queries = ['TRUNCATE TABLE auth.user_providers', 'TRUNCATE auth.configs'];
139
+
140
+ queries.forEach((query) => {
141
+ expect(() => service.sanitizeQuery(query)).toThrow(AppError);
142
+ });
143
+ });
144
+
145
+ test('blocks DROP operations on other auth schema tables', () => {
146
+ const queries = [
147
+ 'DROP TABLE auth.user_providers',
148
+ 'DROP INDEX auth.configs_key_idx',
149
+ 'DROP FUNCTION auth.some_function()',
150
+ 'DROP VIEW auth.user_view',
151
+ 'DROP SEQUENCE auth.user_id_seq',
152
+ 'DROP POLICY auth_policy ON auth.users',
153
+ 'DROP TYPE auth.user_type',
154
+ 'DROP DOMAIN auth.email_domain',
155
+ ];
156
+
157
+ queries.forEach((query) => {
158
+ expect(() => service.sanitizeQuery(query)).toThrow(AppError);
159
+ });
160
+ });
161
+
162
+ test('allows SELECT on other auth schema tables', () => {
163
+ const queries = [
164
+ 'SELECT * FROM auth.email_otps',
165
+ 'SELECT * FROM auth.user_providers',
166
+ 'SELECT * FROM auth.configs',
167
+ ];
168
+
169
+ queries.forEach((query) => {
170
+ expect(() => service.sanitizeQuery(query)).not.toThrow();
171
+ });
172
+ });
173
+
174
+ test('allows INSERT into auth schema (for test users)', () => {
175
+ const queries = [
176
+ "INSERT INTO auth.users (email, password) VALUES ('test@example.com', 'hashed')",
177
+ 'INSERT INTO auth.user_providers (user_id, provider) VALUES ($1, $2)',
178
+ ];
179
+
180
+ queries.forEach((query) => {
181
+ expect(() => service.sanitizeQuery(query)).not.toThrow();
182
+ });
183
+ });
184
+
185
+ test('allows CREATE TRIGGER on auth schema', () => {
186
+ const query =
187
+ 'CREATE TRIGGER user_profile_trigger AFTER INSERT ON auth.users FOR EACH ROW EXECUTE FUNCTION create_user_profile()';
188
+ expect(() => service.sanitizeQuery(query)).not.toThrow();
189
+ });
190
+
191
+ test('allows ALTER TABLE on auth schema (for indexes, constraints)', () => {
192
+ const queries = [
193
+ 'ALTER TABLE auth.users ADD CONSTRAINT email_unique UNIQUE (email)',
194
+ 'CREATE INDEX idx_auth_users_email ON auth.users(email)',
195
+ ];
196
+
197
+ queries.forEach((query) => {
198
+ expect(() => service.sanitizeQuery(query)).not.toThrow();
199
+ });
200
+ });
201
+
202
+ test('throws AppError with FORBIDDEN error code', () => {
203
+ const query = 'DELETE FROM auth.users WHERE id = $1';
204
+ try {
205
+ service.sanitizeQuery(query);
206
+ expect.fail('Should have thrown an error');
207
+ } catch (error) {
208
+ expect(error).toBeInstanceOf(AppError);
209
+ if (error instanceof AppError) {
210
+ expect(error.statusCode).toBe(403);
211
+ expect(error.code).toBe(ERROR_CODES.FORBIDDEN);
212
+ expect(error.message).toContain('auth schema');
213
+ }
214
+ }
215
+ });
216
+ });
217
+
218
+ describe('allowed queries', () => {
219
+ test('allows DELETE from other tables even when auth is referenced in subquery', () => {
220
+ const queries = [
221
+ 'DELETE FROM orders WHERE user_id NOT IN (SELECT id FROM auth.users)',
222
+ 'DELETE FROM user_profiles WHERE id IN (SELECT user_id FROM auth.sessions WHERE expired = true)',
223
+ 'DELETE FROM public.users WHERE email IN (SELECT email FROM auth.users WHERE verified = false)',
224
+ ];
225
+
226
+ queries.forEach((query) => {
227
+ expect(() => service.sanitizeQuery(query)).not.toThrow();
228
+ });
229
+ });
230
+
231
+ test('allows queries with auth schema in string literals or comments', () => {
232
+ const queries = [
233
+ "SELECT 'DELETE FROM auth.users' AS example_query",
234
+ '/* DELETE FROM auth.users */ SELECT * FROM public.users',
235
+ "SELECT 'DROP TABLE auth.users' AS test",
236
+ ];
237
+
238
+ queries.forEach((query) => {
239
+ expect(() => service.sanitizeQuery(query)).not.toThrow();
240
+ });
241
+ });
242
+
243
+ test('blocks DELETE FROM auth even when previous line has a comment', () => {
244
+ const queries = [
245
+ 'SELECT 1; -- some comment\nDELETE FROM auth.users WHERE id = 1',
246
+ '-- previous comment\nDELETE FROM auth.users',
247
+ '/* block comment */\nDELETE FROM auth.users WHERE id = 1',
248
+ ];
249
+
250
+ queries.forEach((query) => {
251
+ expect(() => service.sanitizeQuery(query)).toThrow(AppError);
252
+ });
253
+ });
254
+
255
+ test('allows SELECT from public schema', () => {
256
+ const query = 'SELECT 1 as test';
257
+ expect(() => service.sanitizeQuery(query)).not.toThrow();
258
+ });
259
+
260
+ test('allows auth.uid() function calls', () => {
261
+ const queries = [
262
+ 'SELECT auth.uid()',
263
+ 'SELECT * FROM users WHERE id = auth.uid()',
264
+ 'CREATE POLICY test ON users FOR SELECT USING (id = auth.uid())',
265
+ ];
266
+
267
+ queries.forEach((query) => {
268
+ expect(() => service.sanitizeQuery(query)).not.toThrow();
269
+ });
270
+ });
271
+
272
+ test('allows auth.role() and auth.email() function calls', () => {
273
+ const queries = [
274
+ 'SELECT auth.role()',
275
+ 'SELECT auth.email()',
276
+ 'SELECT * FROM users WHERE email = auth.email()',
277
+ ];
278
+
279
+ queries.forEach((query) => {
280
+ expect(() => service.sanitizeQuery(query)).not.toThrow();
281
+ });
282
+ });
283
+
284
+ test('allows DELETE from public schema tables', () => {
285
+ const query = 'DELETE FROM users WHERE id = $1';
286
+ expect(() => service.sanitizeQuery(query)).not.toThrow();
287
+ });
288
+
289
+ test('allows INSERT into public schema tables', () => {
290
+ const query = "INSERT INTO products (name) VALUES ('test')";
291
+ expect(() => service.sanitizeQuery(query)).not.toThrow();
292
+ });
293
+
294
+ test('allows UPDATE public schema tables', () => {
295
+ const query = 'UPDATE products SET price = 100 WHERE id = $1';
296
+ expect(() => service.sanitizeQuery(query)).not.toThrow();
297
+ });
298
+
299
+ test('allows CREATE TABLE in public schema', () => {
300
+ const query = 'CREATE TABLE test_table (id UUID PRIMARY KEY)';
301
+ expect(() => service.sanitizeQuery(query)).not.toThrow();
302
+ });
303
+ });
304
+
305
+ describe('other blocked operations', () => {
306
+ test('blocks DROP DATABASE', () => {
307
+ const query = 'DROP DATABASE testdb';
308
+ expect(() => service.sanitizeQuery(query)).toThrow(AppError);
309
+ });
310
+
311
+ test('blocks CREATE DATABASE', () => {
312
+ const query = 'CREATE DATABASE testdb';
313
+ expect(() => service.sanitizeQuery(query)).toThrow(AppError);
314
+ });
315
+
316
+ test('blocks ALTER DATABASE', () => {
317
+ const query = 'ALTER DATABASE testdb SET connection_limit = 100';
318
+ expect(() => service.sanitizeQuery(query)).toThrow(AppError);
319
+ });
320
+
321
+ test('blocks pg_catalog access', () => {
322
+ const query = 'SELECT * FROM pg_catalog.pg_tables';
323
+ expect(() => service.sanitizeQuery(query)).toThrow(AppError);
324
+ });
325
+ });
326
+ });
@@ -57,7 +57,7 @@ describe('convertSqlTypeToColumnType', () => {
57
57
  });
58
58
  });
59
59
 
60
- it('returns first 5 chars for unknown types', () => {
61
- expect(convertSqlTypeToColumnType('customtype')).toBe('custo');
60
+ it('returns first 8 chars for unknown types', () => {
61
+ expect(convertSqlTypeToColumnType('customtype')).toBe('customty');
62
62
  });
63
63
  });
@@ -15,8 +15,8 @@ Expert patterns for designing PostgreSQL schemas optimized for InsForge's PostgR
15
15
  ```sql
16
16
  CREATE TABLE follows (
17
17
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
18
- follower_id UUID REFERENCES users(id) ON DELETE CASCADE,
19
- following_id UUID REFERENCES users(id) ON DELETE CASCADE,
18
+ follower_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
19
+ following_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
20
20
  created_at TIMESTAMPTZ DEFAULT NOW(),
21
21
  UNIQUE(follower_id, following_id)
22
22
  );
@@ -44,16 +44,16 @@ CREATE POLICY "Users can unfollow" ON follows
44
44
 
45
45
  **Query with InsForge SDK:**
46
46
  ```javascript
47
- // Get users I follow with their profiles
47
+ // Get users I follow
48
48
  const { data: following } = await client.database
49
49
  .from('follows')
50
- .select('*, following:following_id(id, nickname, avatar_url, bio)')
50
+ .select()
51
51
  .eq('follower_id', currentUserId);
52
52
 
53
53
  // Get my followers
54
54
  const { data: followers } = await client.database
55
55
  .from('follows')
56
- .select('*, follower:follower_id(id, nickname, avatar_url, bio)')
56
+ .select()
57
57
  .eq('following_id', currentUserId);
58
58
 
59
59
  // Check if user1 follows user2
@@ -80,7 +80,7 @@ await client.database
80
80
  ```sql
81
81
  CREATE TABLE likes (
82
82
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
83
- user_id UUID REFERENCES users(id) ON DELETE CASCADE,
83
+ user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
84
84
  post_id UUID REFERENCES posts(id) ON DELETE CASCADE,
85
85
  created_at TIMESTAMPTZ DEFAULT NOW(),
86
86
  UNIQUE(user_id, post_id) -- Prevent duplicate likes
@@ -143,7 +143,7 @@ await client.database
143
143
  CREATE TABLE comments (
144
144
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
145
145
  post_id UUID REFERENCES posts(id) ON DELETE CASCADE,
146
- user_id UUID REFERENCES users(id) ON DELETE CASCADE,
146
+ user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
147
147
  parent_comment_id UUID REFERENCES comments(id) ON DELETE CASCADE,
148
148
  content TEXT NOT NULL,
149
149
  created_at TIMESTAMPTZ DEFAULT NOW(),
@@ -178,17 +178,20 @@ CREATE POLICY "Users can delete their comments" ON comments
178
178
  **Query with InsForge SDK:**
179
179
  ```javascript
180
180
  // Get top-level comments with author info
181
+ // Note: profile is a JSONB column containing { name, avatar_url, bio, birthday }
181
182
  const { data: comments } = await client.database
182
183
  .from('comments')
183
- .select('*, author:user_id(nickname, avatar_url)')
184
+ .select('*, author:user_id(id, profile)')
184
185
  .eq('post_id', postId)
185
186
  .is('parent_comment_id', null)
186
187
  .order('created_at', { ascending: false });
187
188
 
189
+ // Access author info: comment.author.profile.name, comment.author.profile.avatar_url
190
+
188
191
  // Get replies to a comment
189
192
  const { data: replies } = await client.database
190
193
  .from('comments')
191
- .select('*, author:user_id(nickname, avatar_url)')
194
+ .select('*, author:user_id(id, profile)')
192
195
  .eq('parent_comment_id', commentId)
193
196
  .order('created_at', { ascending: true });
194
197
  ```
@@ -209,7 +212,7 @@ CREATE TABLE organizations (
209
212
 
210
213
  CREATE TABLE organization_members (
211
214
  organization_id UUID REFERENCES organizations(id) ON DELETE CASCADE,
212
- user_id UUID REFERENCES users(id) ON DELETE CASCADE,
215
+ user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
213
216
  role TEXT NOT NULL CHECK (role IN ('owner', 'admin', 'member')),
214
217
  joined_at TIMESTAMPTZ DEFAULT NOW(),
215
218
  PRIMARY KEY (organization_id, user_id)
@@ -1,6 +1,6 @@
1
1
  services:
2
2
  postgres:
3
- image: postgres:15.13
3
+ image: ghcr.io/insforge/postgres:v15.13.1
4
4
  container_name: insforge-postgres
5
5
  command: postgres -c config_file=/etc/postgresql/postgresql.conf
6
6
  environment:
@@ -2,7 +2,7 @@ version: '3.8'
2
2
 
3
3
  services:
4
4
  postgres:
5
- image: postgres:15.13
5
+ image: ghcr.io/insforge/postgres:v15.13.1
6
6
  container_name: insforge-postgres
7
7
  command: postgres -c config_file=/etc/postgresql/postgresql.conf
8
8
  environment:
@@ -0,0 +1,79 @@
1
+ # InsForge Deployment - Agent Documentation
2
+
3
+ ## Overview
4
+
5
+ Deploy frontend applications to InsForge using the `create-deployment` MCP tool. The tool handles uploading source files, building, and deploying automatically.
6
+
7
+ ## Deploy with MCP Tool
8
+
9
+ Use the `create-deployment` tool with these parameters:
10
+
11
+ | Parameter | Required | Description |
12
+ |-----------|----------|-------------|
13
+ | `sourceDirectory` | Yes | **Absolute path** to source directory (e.g., `/Users/me/project/frontend`). Relative paths do not work. |
14
+ | `projectSettings.buildCommand` | No | Build command (default: auto-detected) |
15
+ | `projectSettings.outputDirectory` | No | Build output directory (default: auto-detected) |
16
+ | `projectSettings.installCommand` | No | Install command (default: `npm install`) |
17
+ | `projectSettings.rootDirectory` | No | Root directory within source |
18
+ | `envVars` | No | Array of `{key, value}` objects |
19
+ | `meta` | No | Custom metadata key-value pairs |
20
+
21
+ ### Example
22
+
23
+ ```json
24
+ {
25
+ "sourceDirectory": "/Users/me/project/frontend",
26
+ "projectSettings": {
27
+ "buildCommand": "npm run build",
28
+ "outputDirectory": "dist"
29
+ },
30
+ "envVars": [
31
+ { "key": "VITE_INSFORGE_BASE_URL", "value": "https://your-project.insforge.app" },
32
+ { "key": "VITE_INSFORGE_ANON_KEY", "value": "your-anon-key" }
33
+ ]
34
+ }
35
+ ```
36
+
37
+ **Important**:
38
+ - `sourceDirectory` must be an **absolute path** (relative paths don't work on Windows)
39
+ - Pass the source directory, NOT pre-built static files
40
+ - Include all required environment variables (e.g., `VITE_*` for Vite apps)
41
+
42
+ ## Check Deployment Status
43
+
44
+ After creating a deployment, query the status using `run-raw-sql`:
45
+
46
+ ```sql
47
+ SELECT id, status, url, created_at
48
+ FROM system.deployments
49
+ ORDER BY created_at DESC
50
+ LIMIT 1;
51
+ ```
52
+
53
+ ### Status Values
54
+
55
+ | Status | Description |
56
+ |--------|-------------|
57
+ | `WAITING` | Waiting for source upload |
58
+ | `UPLOADING` | Uploading to build server |
59
+ | `QUEUED` | Queued for build |
60
+ | `BUILDING` | Building (typically ~1 min) |
61
+ | `READY` | Deployment complete, URL available |
62
+ | `ERROR` | Build or deployment failed |
63
+ | `CANCELED` | Deployment was cancelled |
64
+
65
+ ### Get Deployment URL
66
+
67
+ Once status is `READY`, the `url` column contains the live deployment URL.
68
+
69
+ ```sql
70
+ SELECT url FROM system.deployments WHERE id = '<deployment-id>';
71
+ ```
72
+
73
+ ## Quick Reference
74
+
75
+ | Task | Tool | Command |
76
+ |------|------|---------|
77
+ | Deploy app | `create-deployment` | Provide `sourceDirectory` and `envVars` |
78
+ | Check status | `run-raw-sql` | `SELECT status FROM system.deployments WHERE id = '...'` |
79
+ | List deployments | `run-raw-sql` | `SELECT * FROM system.deployments ORDER BY created_at DESC` |