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
@@ -109,7 +109,7 @@ export class StorageService {
109
109
  // This query finds all files matching the pattern and extracts the counter number
110
110
  const result = await this.getPool().query(
111
111
  `
112
- SELECT key FROM _storage
112
+ SELECT key FROM storage.objects
113
113
  WHERE bucket = $1
114
114
  AND (key = $2 OR key LIKE $3)
115
115
  `,
@@ -169,7 +169,7 @@ export class StorageService {
169
169
  // Save metadata to database and return the timestamp in one operation
170
170
  const result = await client.query(
171
171
  `
172
- INSERT INTO _storage (bucket, key, size, mime_type, uploaded_by)
172
+ INSERT INTO storage.objects (bucket, key, size, mime_type, uploaded_by)
173
173
  VALUES ($1, $2, $3, $4, $5)
174
174
  RETURNING uploaded_at as "uploadedAt"
175
175
  `,
@@ -207,7 +207,7 @@ export class StorageService {
207
207
  this.validateKey(key);
208
208
 
209
209
  const result = await this.getPool().query(
210
- 'SELECT * FROM _storage WHERE bucket = $1 AND key = $2',
210
+ 'SELECT * FROM storage.objects WHERE bucket = $1 AND key = $2',
211
211
  [bucket, key]
212
212
  );
213
213
 
@@ -249,7 +249,7 @@ export class StorageService {
249
249
  // Check permissions
250
250
  if (!isAdmin) {
251
251
  const fileResult = await client.query(
252
- 'SELECT uploaded_by FROM _storage WHERE bucket = $1 AND key = $2',
252
+ 'SELECT uploaded_by FROM storage.objects WHERE bucket = $1 AND key = $2',
253
253
  [bucket, key]
254
254
  );
255
255
 
@@ -273,10 +273,10 @@ export class StorageService {
273
273
  await this.provider.deleteObject(bucket, key);
274
274
 
275
275
  // Delete from database
276
- const result = await client.query('DELETE FROM _storage WHERE bucket = $1 AND key = $2', [
277
- bucket,
278
- key,
279
- ]);
276
+ const result = await client.query(
277
+ 'DELETE FROM storage.objects WHERE bucket = $1 AND key = $2',
278
+ [bucket, key]
279
+ );
280
280
 
281
281
  return result.rowCount !== null && result.rowCount > 0;
282
282
  } finally {
@@ -295,8 +295,8 @@ export class StorageService {
295
295
 
296
296
  const client = await this.getPool().connect();
297
297
  try {
298
- let query = 'SELECT * FROM _storage WHERE bucket = $1';
299
- let countQuery = 'SELECT COUNT(*) as count FROM _storage WHERE bucket = $1';
298
+ let query = 'SELECT * FROM storage.objects WHERE bucket = $1';
299
+ let countQuery = 'SELECT COUNT(*) as count FROM storage.objects WHERE bucket = $1';
300
300
  const params: (string | number)[] = [bucket];
301
301
  let paramIndex = 2;
302
302
 
@@ -338,7 +338,7 @@ export class StorageService {
338
338
 
339
339
  async isBucketPublic(bucket: string): Promise<boolean> {
340
340
  const result = await this.getPool().query(
341
- 'SELECT public FROM _storage_buckets WHERE name = $1',
341
+ 'SELECT public FROM storage.buckets WHERE name = $1',
342
342
  [bucket]
343
343
  );
344
344
  return result.rows[0]?.public || false;
@@ -348,7 +348,7 @@ export class StorageService {
348
348
  const client = await this.getPool().connect();
349
349
  try {
350
350
  // Check if bucket exists
351
- const bucketResult = await client.query('SELECT name FROM _storage_buckets WHERE name = $1', [
351
+ const bucketResult = await client.query('SELECT name FROM storage.buckets WHERE name = $1', [
352
352
  bucket,
353
353
  ]);
354
354
 
@@ -356,9 +356,9 @@ export class StorageService {
356
356
  throw new Error(`Bucket "${bucket}" does not exist`);
357
357
  }
358
358
 
359
- // Update bucket visibility in _storage_buckets table
359
+ // Update bucket visibility in storage.buckets table
360
360
  await client.query(
361
- 'UPDATE _storage_buckets SET public = $1, updated_at = CURRENT_TIMESTAMP WHERE name = $2',
361
+ 'UPDATE storage.buckets SET public = $1, updated_at = CURRENT_TIMESTAMP WHERE name = $2',
362
362
  [isPublic, bucket]
363
363
  );
364
364
 
@@ -370,9 +370,9 @@ export class StorageService {
370
370
  }
371
371
 
372
372
  async listBuckets(): Promise<StorageBucketSchema[]> {
373
- // Get all buckets with their metadata from _storage_buckets table
373
+ // Get all buckets with their metadata from storage.buckets table
374
374
  const result = await this.getPool().query(
375
- 'SELECT name, public, created_at as "createdAt" FROM _storage_buckets ORDER BY name'
375
+ 'SELECT name, public, created_at as "createdAt" FROM storage.buckets ORDER BY name'
376
376
  );
377
377
 
378
378
  return result.rows as StorageBucketSchema[];
@@ -384,7 +384,7 @@ export class StorageService {
384
384
  const client = await this.getPool().connect();
385
385
  try {
386
386
  // Check if bucket already exists
387
- const existing = await client.query('SELECT name FROM _storage_buckets WHERE name = $1', [
387
+ const existing = await client.query('SELECT name FROM storage.buckets WHERE name = $1', [
388
388
  bucket,
389
389
  ]);
390
390
 
@@ -392,8 +392,8 @@ export class StorageService {
392
392
  throw new Error(`Bucket "${bucket}" already exists`);
393
393
  }
394
394
 
395
- // Insert bucket into _storage_buckets table
396
- await client.query('INSERT INTO _storage_buckets (name, public) VALUES ($1, $2)', [
395
+ // Insert bucket into storage.buckets table
396
+ await client.query('INSERT INTO storage.buckets (name, public) VALUES ($1, $2)', [
397
397
  bucket,
398
398
  isPublic,
399
399
  ]);
@@ -414,7 +414,7 @@ export class StorageService {
414
414
  const client = await this.getPool().connect();
415
415
  try {
416
416
  // Check if bucket exists
417
- const bucketResult = await client.query('SELECT name FROM _storage_buckets WHERE name = $1', [
417
+ const bucketResult = await client.query('SELECT name FROM storage.buckets WHERE name = $1', [
418
418
  bucket,
419
419
  ]);
420
420
 
@@ -425,8 +425,8 @@ export class StorageService {
425
425
  // Delete bucket using backend (handles all files)
426
426
  await this.provider.deleteBucket(bucket);
427
427
 
428
- // Delete from storage table (cascade will handle _storage entries)
429
- await client.query('DELETE FROM _storage_buckets WHERE name = $1', [bucket]);
428
+ // Delete from storage table (cascade will handle storage.objects entries)
429
+ await client.query('DELETE FROM storage.buckets WHERE name = $1', [bucket]);
430
430
 
431
431
  // Update storage metadata
432
432
  // Metadata is now updated on-demand
@@ -451,7 +451,7 @@ export class StorageService {
451
451
  const client = await this.getPool().connect();
452
452
  try {
453
453
  // Check if bucket exists
454
- const bucketResult = await client.query('SELECT name FROM _storage_buckets WHERE name = $1', [
454
+ const bucketResult = await client.query('SELECT name FROM storage.buckets WHERE name = $1', [
455
455
  bucket,
456
456
  ]);
457
457
 
@@ -503,7 +503,7 @@ export class StorageService {
503
503
  try {
504
504
  // Check if already confirmed
505
505
  const existingResult = await client.query(
506
- 'SELECT key FROM _storage WHERE bucket = $1 AND key = $2',
506
+ 'SELECT key FROM storage.objects WHERE bucket = $1 AND key = $2',
507
507
  [bucket, key]
508
508
  );
509
509
 
@@ -514,7 +514,7 @@ export class StorageService {
514
514
  // Save metadata to database and return the timestamp in one operation
515
515
  const result = await client.query(
516
516
  `
517
- INSERT INTO _storage (bucket, key, size, mime_type, uploaded_by)
517
+ INSERT INTO storage.objects (bucket, key, size, mime_type, uploaded_by)
518
518
  VALUES ($1, $2, $3, $4, $5)
519
519
  RETURNING uploaded_at as "uploadedAt"
520
520
  `,
@@ -548,9 +548,9 @@ export class StorageService {
548
548
  * Get storage metadata
549
549
  */
550
550
  async getMetadata(): Promise<StorageMetadataSchema> {
551
- // Get storage buckets from _storage_buckets table
551
+ // Get storage buckets from storage.buckets table
552
552
  const result = await this.getPool().query(
553
- 'SELECT name, public, created_at as "createdAt" FROM _storage_buckets ORDER BY name'
553
+ 'SELECT name, public, created_at as "createdAt" FROM storage.buckets ORDER BY name'
554
554
  );
555
555
 
556
556
  const storageBuckets = result.rows as StorageBucketSchema[];
@@ -572,7 +572,7 @@ export class StorageService {
572
572
  try {
573
573
  // Query to get object count for each bucket
574
574
  const result = await this.getPool().query(
575
- 'SELECT bucket, COUNT(*) as count FROM _storage GROUP BY bucket'
575
+ 'SELECT bucket, COUNT(*) as count FROM storage.objects GROUP BY bucket'
576
576
  );
577
577
 
578
578
  const bucketCounts = result.rows as { bucket: string; count: string }[];
@@ -595,11 +595,11 @@ export class StorageService {
595
595
 
596
596
  private async getStorageSizeInGB(): Promise<number> {
597
597
  try {
598
- // Query the _storage table to sum all file sizes
598
+ // Query the storage.objects table to sum all file sizes
599
599
  const result = await this.getPool().query(
600
600
  `
601
601
  SELECT COALESCE(SUM(size), 0) as total_size
602
- FROM _storage
602
+ FROM storage.objects
603
603
  `
604
604
  );
605
605
 
@@ -54,7 +54,7 @@ export class UsageService {
54
54
  async recordMCPUsage(toolName: string, success: boolean = true): Promise<{ created_at: string }> {
55
55
  try {
56
56
  const result = await this.getPool().query(
57
- `INSERT INTO _mcp_usage (tool_name, success)
57
+ `INSERT INTO system.mcp_usage (tool_name, success)
58
58
  VALUES ($1, $2)
59
59
  RETURNING created_at`,
60
60
  [toolName, success]
@@ -75,7 +75,7 @@ export class UsageService {
75
75
  try {
76
76
  const result = await this.getPool().query(
77
77
  `SELECT tool_name, success, created_at
78
- FROM _mcp_usage
78
+ FROM system.mcp_usage
79
79
  WHERE success = $1
80
80
  ORDER BY created_at DESC
81
81
  LIMIT $2`,
@@ -98,7 +98,7 @@ export class UsageService {
98
98
  // Get MCP tool usage count
99
99
  const mcpResult = await this.getPool().query(
100
100
  `SELECT COUNT(*) as count
101
- FROM _mcp_usage
101
+ FROM system.mcp_usage
102
102
  WHERE success = true
103
103
  AND created_at >= $1
104
104
  AND created_at < $2`,
@@ -112,7 +112,7 @@ export class UsageService {
112
112
 
113
113
  // Get total storage size
114
114
  const storageResult = await this.getPool().query(
115
- `SELECT COALESCE(SUM(size), 0) as total_size FROM _storage`
115
+ `SELECT COALESCE(SUM(size), 0) as total_size FROM storage.objects`
116
116
  );
117
117
 
118
118
  // Get AI usage breakdown by model (only billable metrics)
@@ -122,8 +122,8 @@ export class UsageService {
122
122
  COALESCE(SUM(u.input_tokens), 0) as total_input_tokens,
123
123
  COALESCE(SUM(u.output_tokens), 0) as total_output_tokens,
124
124
  COALESCE(SUM(u.image_count), 0) as total_images
125
- FROM _ai_usage u
126
- LEFT JOIN _ai_configs c ON u.config_id = c.id
125
+ FROM ai.usage u
126
+ LEFT JOIN ai.configs c ON u.config_id = c.id
127
127
  WHERE u.created_at >= $1 AND u.created_at < $2
128
128
  GROUP BY COALESCE(u.model_id, c.model_id)
129
129
  ORDER BY (COALESCE(SUM(u.input_tokens), 0) + COALESCE(SUM(u.output_tokens), 0)) DESC`,
@@ -11,6 +11,14 @@ export interface OpenRouterImageMessage {
11
11
  };
12
12
  }
13
13
 
14
+ export interface OpenRouterAudioMessage {
15
+ type: 'input_audio';
16
+ input_audio: {
17
+ data: string; // Base64-encoded audio data
18
+ format: string; // wav, mp3, aiff, aac, ogg, flac, m4a
19
+ };
20
+ }
21
+
14
22
  // ============= OpenRouter API Types =============
15
23
 
16
24
  export interface RawOpenRouterModel {
@@ -1,9 +1,13 @@
1
1
  // Type definitions for database user records
2
+
2
3
  export interface UserRecord {
3
4
  id: string;
4
5
  email: string;
5
- name: string;
6
+ profile: Record<string, unknown> | null;
7
+ metadata: Record<string, unknown> | null;
6
8
  email_verified: boolean;
9
+ is_project_admin: boolean;
10
+ is_anonymous: boolean;
7
11
  created_at: string;
8
12
  updated_at: string;
9
13
  password?: string;
@@ -102,6 +102,7 @@ export type ForeignKeyInfo = ForeignKeySchema & {
102
102
  export interface ForeignKeyRow {
103
103
  constraint_name: string;
104
104
  from_column: string;
105
+ foreign_schema: string;
105
106
  foreign_table: string;
106
107
  foreign_column: string;
107
108
  on_delete: string;
@@ -112,6 +113,7 @@ export interface ForeignKeyRow {
112
113
  export interface ColumnInfo {
113
114
  column_name: string;
114
115
  data_type: string;
116
+ udt_name: string;
115
117
  is_nullable: string;
116
118
  column_default: string | null;
117
119
  character_maximum_length: number | null;
@@ -0,0 +1,33 @@
1
+ // Backend-only types for deployments
2
+
3
+ /**
4
+ * Deployment status constants
5
+ * WAITING -> UPLOADING -> (Vercel statuses: QUEUED/BUILDING/READY/ERROR/CANCELED)
6
+ */
7
+ export const DeploymentStatus = {
8
+ // InsForge internal statuses
9
+ WAITING: 'WAITING', // Record created, waiting for client to upload zip to S3
10
+ UPLOADING: 'UPLOADING', // Server is downloading from S3 and uploading to Vercel
11
+ // Vercel statuses (stored directly)
12
+ QUEUED: 'QUEUED',
13
+ BUILDING: 'BUILDING',
14
+ READY: 'READY',
15
+ ERROR: 'ERROR',
16
+ CANCELED: 'CANCELED',
17
+ } as const;
18
+
19
+ export type DeploymentStatusType = (typeof DeploymentStatus)[keyof typeof DeploymentStatus];
20
+
21
+ /**
22
+ * Internal deployment record with Date objects (database returns Date, not string)
23
+ */
24
+ export interface DeploymentRecord {
25
+ id: string;
26
+ providerDeploymentId: string | null; // Provider's deployment ID, null until deployment starts
27
+ provider: string;
28
+ status: DeploymentStatusType;
29
+ url: string | null;
30
+ metadata: Record<string, unknown> | null;
31
+ createdAt: Date;
32
+ updatedAt: Date;
33
+ }
@@ -10,7 +10,7 @@ export interface StorageRecord {
10
10
  uploaded_at: string;
11
11
  }
12
12
 
13
- // Bucket record from _storage_buckets table
13
+ // Bucket record from storage.buckets table
14
14
  export type BucketRecord = Omit<StorageBucketSchema, 'created_at'>;
15
15
 
16
16
  // Form field types for file uploads
@@ -0,0 +1,45 @@
1
+ // Webhook types for external integrations
2
+
3
+ // ============================================================================
4
+ // Vercel Webhooks
5
+ // ============================================================================
6
+
7
+ /**
8
+ * Vercel webhook event types we handle for deployments
9
+ */
10
+ export type VercelDeploymentEventType =
11
+ | 'deployment.created'
12
+ | 'deployment.succeeded'
13
+ | 'deployment.error'
14
+ | 'deployment.canceled';
15
+
16
+ /**
17
+ * Map Vercel webhook event types to our deployment status
18
+ */
19
+ export const VERCEL_EVENT_TO_STATUS: Record<VercelDeploymentEventType, string> = {
20
+ 'deployment.created': 'BUILDING',
21
+ 'deployment.succeeded': 'READY',
22
+ 'deployment.error': 'ERROR',
23
+ 'deployment.canceled': 'CANCELED',
24
+ };
25
+
26
+ /**
27
+ * Vercel webhook payload structure for deployment events
28
+ */
29
+ export interface VercelWebhookPayload {
30
+ type: string;
31
+ id: string;
32
+ createdAt: string;
33
+ payload: {
34
+ team?: { id: string };
35
+ user?: { id: string };
36
+ deployment: {
37
+ id: string;
38
+ url: string;
39
+ name: string;
40
+ meta?: Record<string, unknown>;
41
+ };
42
+ target?: string;
43
+ project?: { id: string };
44
+ };
45
+ }
@@ -1,35 +1,34 @@
1
- import { Response } from 'express';
2
- import { isProduction } from './environment';
3
-
4
- /**
5
- * Cookie names
6
- */
7
- export const REFRESH_TOKEN_COOKIE_NAME = 'insforge_refresh_token';
8
-
9
- /**
10
- * Set an auth cookie on response
11
- * @param name - Cookie name
12
- * @param value - Cookie value
13
- */
14
- export function setAuthCookie(res: Response, name: string, value: string): void {
15
- res.cookie(name, value, {
16
- httpOnly: true,
17
- secure: isProduction(),
18
- sameSite: 'none',
19
- path: '/api/auth',
20
- maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days
21
- });
22
- }
23
-
24
- /**
25
- * Clear an auth cookie on response
26
- * IMPORTANT: Must use the same options (especially path) as when setting the cookie
27
- */
28
- export function clearAuthCookie(res: Response, name: string): void {
29
- res.clearCookie(name, {
30
- httpOnly: true,
31
- secure: isProduction(),
32
- sameSite: 'none',
33
- path: '/api/auth',
34
- });
35
- }
1
+ import { Request, Response } from 'express';
2
+
3
+ /**
4
+ * Cookie names
5
+ */
6
+ export const REFRESH_TOKEN_COOKIE_NAME = 'insforge_refresh_token';
7
+
8
+ /**
9
+ * Set an auth cookie on response
10
+ * @param name - Cookie name
11
+ * @param value - Cookie value
12
+ */
13
+ export function setAuthCookie(req: Request, res: Response, name: string, value: string): void {
14
+ res.cookie(name, value, {
15
+ httpOnly: true,
16
+ secure: req.secure,
17
+ sameSite: 'none',
18
+ path: '/api/auth',
19
+ maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days
20
+ });
21
+ }
22
+
23
+ /**
24
+ * Clear an auth cookie on response
25
+ * IMPORTANT: Must use the same options (especially path) as when setting the cookie
26
+ */
27
+ export function clearAuthCookie(req: Request, res: Response, name: string): void {
28
+ res.clearCookie(name, {
29
+ httpOnly: true,
30
+ secure: req.secure,
31
+ sameSite: 'none',
32
+ path: '/api/auth',
33
+ });
34
+ }
@@ -18,20 +18,6 @@ export function isOAuthSharedKeysAvailable(): boolean {
18
18
  return isCloudEnvironment();
19
19
  }
20
20
 
21
- /**
22
- * Check if running in development mode
23
- */
24
- export function isDevelopment(): boolean {
25
- return process.env.NODE_ENV === 'development' || !process.env.NODE_ENV;
26
- }
27
-
28
- /**
29
- * Check if running in production mode
30
- */
31
- export function isProduction(): boolean {
32
- return process.env.NODE_ENV === 'production';
33
- }
34
-
35
21
  /**
36
22
  * Get the API base URL from environment variable or default to localhost
37
23
  * @returns The API base URL
@@ -1,64 +1,64 @@
1
- import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
2
- import logger from '@/utils/logger.js';
3
-
4
- // TODO: make these configurable in env variables in cloud backend
5
- const CONFIG_BUCKET = process.env.AWS_CONFIG_BUCKET || 'insforge-config';
6
- const CONFIG_REGION = process.env.AWS_CONFIG_REGION || 'us-east-2';
7
-
8
- let s3Client: S3Client | null = null;
9
-
10
- /**
11
- * Get or create S3 client for config loading
12
- */
13
- function getS3Client(): S3Client {
14
- if (s3Client) {
15
- return s3Client;
16
- }
17
-
18
- const s3Config: {
19
- region: string;
20
- credentials?: { accessKeyId: string; secretAccessKey: string };
21
- } = {
22
- region: CONFIG_REGION,
23
- };
24
-
25
- // Use explicit credentials if provided, otherwise IAM role
26
- if (process.env.AWS_ACCESS_KEY_ID && process.env.AWS_SECRET_ACCESS_KEY) {
27
- s3Config.credentials = {
28
- accessKeyId: process.env.AWS_ACCESS_KEY_ID,
29
- secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
30
- };
31
- }
32
-
33
- s3Client = new S3Client(s3Config);
34
- return s3Client;
35
- }
36
-
37
- /**
38
- * Fetches a JSON config file from the S3 config bucket
39
- * @param key - The S3 object key (e.g., 'default-ai-models.json')
40
- * @returns Parsed JSON content or null if fetch fails
41
- */
42
- export async function fetchS3Config<T>(key: string): Promise<T | null> {
43
- try {
44
- const command = new GetObjectCommand({
45
- Bucket: CONFIG_BUCKET,
46
- Key: key,
47
- });
48
-
49
- const response = await getS3Client().send(command);
50
- const body = await response.Body?.transformToString();
51
-
52
- if (!body) {
53
- logger.warn(`Empty config file from S3: ${key}`);
54
- return null;
55
- }
56
-
57
- return JSON.parse(body) as T;
58
- } catch (error) {
59
- logger.warn(`Failed to fetch config from S3: ${key}`, {
60
- error: error instanceof Error ? error.message : String(error),
61
- });
62
- return null;
63
- }
64
- }
1
+ import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
2
+ import logger from '@/utils/logger.js';
3
+
4
+ // TODO: make these configurable in env variables in cloud backend
5
+ const CONFIG_BUCKET = process.env.AWS_CONFIG_BUCKET || 'insforge-config';
6
+ const CONFIG_REGION = process.env.AWS_CONFIG_REGION || 'us-east-2';
7
+
8
+ let s3Client: S3Client | null = null;
9
+
10
+ /**
11
+ * Get or create S3 client for config loading
12
+ */
13
+ function getS3Client(): S3Client {
14
+ if (s3Client) {
15
+ return s3Client;
16
+ }
17
+
18
+ const s3Config: {
19
+ region: string;
20
+ credentials?: { accessKeyId: string; secretAccessKey: string };
21
+ } = {
22
+ region: CONFIG_REGION,
23
+ };
24
+
25
+ // Use explicit credentials if provided, otherwise IAM role
26
+ if (process.env.AWS_ACCESS_KEY_ID && process.env.AWS_SECRET_ACCESS_KEY) {
27
+ s3Config.credentials = {
28
+ accessKeyId: process.env.AWS_ACCESS_KEY_ID,
29
+ secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
30
+ };
31
+ }
32
+
33
+ s3Client = new S3Client(s3Config);
34
+ return s3Client;
35
+ }
36
+
37
+ /**
38
+ * Fetches a JSON config file from the S3 config bucket
39
+ * @param key - The S3 object key (e.g., 'default-ai-models.json')
40
+ * @returns Parsed JSON content or null if fetch fails
41
+ */
42
+ export async function fetchS3Config<T>(key: string): Promise<T | null> {
43
+ try {
44
+ const command = new GetObjectCommand({
45
+ Bucket: CONFIG_BUCKET,
46
+ Key: key,
47
+ });
48
+
49
+ const response = await getS3Client().send(command);
50
+ const body = await response.Body?.transformToString();
51
+
52
+ if (!body) {
53
+ logger.warn(`Empty config file from S3: ${key}`);
54
+ return null;
55
+ }
56
+
57
+ return JSON.parse(body) as T;
58
+ } catch (error) {
59
+ logger.warn(`Failed to fetch config from S3: ${key}`, {
60
+ error: error instanceof Error ? error.message : String(error),
61
+ });
62
+ return null;
63
+ }
64
+ }