insforge 0.3.1

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 (395) hide show
  1. package/.dockerignore +58 -0
  2. package/.env.example +49 -0
  3. package/.github/ISSUE_TEMPLATE/bug_report.yml +83 -0
  4. package/.github/ISSUE_TEMPLATE/config.yml +11 -0
  5. package/.github/ISSUE_TEMPLATE/feature_request.yml +79 -0
  6. package/.github/copilot-instructions.md +147 -0
  7. package/.github/workflows/build-image.yml +65 -0
  8. package/.github/workflows/ci-premerge-check.yml +24 -0
  9. package/.github/workflows/deploy-aws.yml +130 -0
  10. package/.github/workflows/lint-and-format.yml +33 -0
  11. package/.prettierignore +65 -0
  12. package/.prettierrc +9 -0
  13. package/CHANGELOG.md +3 -0
  14. package/CONTRIBUTING.md +126 -0
  15. package/Dockerfile +27 -0
  16. package/GITHUB_OAUTH_SETUP.md +49 -0
  17. package/GOOGLE_OAUTH_SETUP.md +148 -0
  18. package/LICENSE +201 -0
  19. package/README.md +134 -0
  20. package/assets/Dark.svg +23 -0
  21. package/assets/archDiagram.png +0 -0
  22. package/assets/banner.png +0 -0
  23. package/assets/mcpInstallv2.png +0 -0
  24. package/assets/sampleResponse.png +0 -0
  25. package/assets/signin.png +0 -0
  26. package/assets/userflow.png +0 -0
  27. package/backend/migrations/000_create-base-tables.sql +142 -0
  28. package/backend/migrations/001_create-helper-functions.sql +41 -0
  29. package/backend/migrations/002_rename-auth-tables.sql +30 -0
  30. package/backend/migrations/003_create-users-table.sql +56 -0
  31. package/backend/migrations/004_add-reload-postgrest-func.sql +24 -0
  32. package/backend/migrations/005_enable-project-admin-modify-users.sql +30 -0
  33. package/backend/migrations/006_modify-ai-usage-table.sql +25 -0
  34. package/backend/migrations/007_drop-metadata-table.sql +2 -0
  35. package/backend/migrations/008_add-system-tables.sql +77 -0
  36. package/backend/migrations/009_add-function-secrets.sql +24 -0
  37. package/backend/migrations/010_modify-ai-config-modalities.sql +93 -0
  38. package/backend/migrations/011_refactor-secrets-table.sql +15 -0
  39. package/backend/migrations/012_add-storage-uploaded-by.sql +8 -0
  40. package/backend/package.json +75 -0
  41. package/backend/src/api/middleware/auth.ts +240 -0
  42. package/backend/src/api/middleware/error.ts +231 -0
  43. package/backend/src/api/middleware/upload.ts +59 -0
  44. package/backend/src/api/routes/agent.ts +29 -0
  45. package/backend/src/api/routes/ai.ts +472 -0
  46. package/backend/src/api/routes/auth.oauth.ts +482 -0
  47. package/backend/src/api/routes/auth.ts +386 -0
  48. package/backend/src/api/routes/database.advance.ts +275 -0
  49. package/backend/src/api/routes/database.records.ts +246 -0
  50. package/backend/src/api/routes/database.tables.ts +161 -0
  51. package/backend/src/api/routes/docs.ts +66 -0
  52. package/backend/src/api/routes/functions.ts +183 -0
  53. package/backend/src/api/routes/logs.ts +150 -0
  54. package/backend/src/api/routes/metadata.ts +160 -0
  55. package/backend/src/api/routes/openapi.ts +82 -0
  56. package/backend/src/api/routes/secrets.ts +199 -0
  57. package/backend/src/api/routes/storage.ts +547 -0
  58. package/backend/src/api/routes/usage.ts +96 -0
  59. package/backend/src/core/ai/chat.ts +207 -0
  60. package/backend/src/core/ai/client.ts +242 -0
  61. package/backend/src/core/ai/config.ts +187 -0
  62. package/backend/src/core/ai/image.ts +156 -0
  63. package/backend/src/core/ai/model.ts +117 -0
  64. package/backend/src/core/ai/usage.ts +290 -0
  65. package/backend/src/core/auth/auth.ts +781 -0
  66. package/backend/src/core/auth/oauth.ts +398 -0
  67. package/backend/src/core/database/advance.ts +1074 -0
  68. package/backend/src/core/database/manager.ts +178 -0
  69. package/backend/src/core/database/table.ts +772 -0
  70. package/backend/src/core/documentation/agent.ts +689 -0
  71. package/backend/src/core/documentation/openapi.ts +856 -0
  72. package/backend/src/core/functions/functions.ts +310 -0
  73. package/backend/src/core/logs/analytics.ts +76 -0
  74. package/backend/src/core/logs/audit.ts +255 -0
  75. package/backend/src/core/logs/providers/base.provider.ts +83 -0
  76. package/backend/src/core/logs/providers/cloudwatch.provider.ts +510 -0
  77. package/backend/src/core/logs/providers/localdb.provider.ts +246 -0
  78. package/backend/src/core/secrets/encryption.ts +58 -0
  79. package/backend/src/core/secrets/secrets.ts +410 -0
  80. package/backend/src/core/socket/socket.ts +388 -0
  81. package/backend/src/core/socket/types.ts +79 -0
  82. package/backend/src/core/storage/storage.ts +923 -0
  83. package/backend/src/server.ts +288 -0
  84. package/backend/src/types/ai.ts +46 -0
  85. package/backend/src/types/auth.ts +90 -0
  86. package/backend/src/types/database.ts +136 -0
  87. package/backend/src/types/error-constants.ts +86 -0
  88. package/backend/src/types/logs.ts +47 -0
  89. package/backend/src/types/profile.ts +55 -0
  90. package/backend/src/types/storage.ts +23 -0
  91. package/backend/src/utils/cloud-token.ts +39 -0
  92. package/backend/src/utils/constants.ts +1 -0
  93. package/backend/src/utils/environment.ts +35 -0
  94. package/backend/src/utils/helpers.ts +49 -0
  95. package/backend/src/utils/logger.ts +13 -0
  96. package/backend/src/utils/response.ts +62 -0
  97. package/backend/src/utils/seed.ts +205 -0
  98. package/backend/src/utils/sql-parser.ts +63 -0
  99. package/backend/src/utils/uuid.ts +9 -0
  100. package/backend/src/utils/validations.ts +129 -0
  101. package/backend/tests/README.md +134 -0
  102. package/backend/tests/cleanup-all-test-data.sh +231 -0
  103. package/backend/tests/cloud/test-s3-multitenant.sh +132 -0
  104. package/backend/tests/local/comprehensive-curl-tests.sh +156 -0
  105. package/backend/tests/local/test-auth-router.sh +144 -0
  106. package/backend/tests/local/test-database-router.sh +222 -0
  107. package/backend/tests/local/test-e2e.sh +241 -0
  108. package/backend/tests/local/test-fk-errors.sh +97 -0
  109. package/backend/tests/local/test-id-field.sh +201 -0
  110. package/backend/tests/local/test-public-bucket.sh +265 -0
  111. package/backend/tests/local/test-secrets.sh +248 -0
  112. package/backend/tests/local/test-serverless-functions.sh.disabled +325 -0
  113. package/backend/tests/local/test-traditional-rest.sh +209 -0
  114. package/backend/tests/manual/README.md +51 -0
  115. package/backend/tests/manual/create-large-table-simple.sql +11 -0
  116. package/backend/tests/manual/seed-large-table.sql +101 -0
  117. package/backend/tests/manual/setup-large-table-extras.sql +34 -0
  118. package/backend/tests/manual/test-better-auth.sh +303 -0
  119. package/backend/tests/manual/test-bulk-upsert.sh +410 -0
  120. package/backend/tests/manual/test-database-advance.sh +297 -0
  121. package/backend/tests/manual/test-postgrest-stability.sh +192 -0
  122. package/backend/tests/manual/test-rawsql-export-import.sh +412 -0
  123. package/backend/tests/manual/test-universal-storage.sh +264 -0
  124. package/backend/tests/manual/test-users.sql +18 -0
  125. package/backend/tests/run-all-tests.sh +140 -0
  126. package/backend/tests/setup.ts +22 -0
  127. package/backend/tests/test-config.sh +303 -0
  128. package/backend/tsconfig.json +23 -0
  129. package/backend/tsup.config.ts +18 -0
  130. package/backend/vitest.config.ts +22 -0
  131. package/docker-compose.prod.yml +145 -0
  132. package/docker-compose.yml +167 -0
  133. package/docker-init/db/db-init.sql +125 -0
  134. package/docker-init/db/jwt.sql +5 -0
  135. package/docker-init/db/logs.sql +9 -0
  136. package/docker-init/db/postgresql.conf +17 -0
  137. package/docs/deprecated/insforge-auth-api.md +215 -0
  138. package/docs/deprecated/insforge-auth-sdk.md +100 -0
  139. package/docs/deprecated/insforge-db-api.md +359 -0
  140. package/docs/deprecated/insforge-db-sdk.md +140 -0
  141. package/docs/deprecated/insforge-debug-sdk.md +157 -0
  142. package/docs/deprecated/insforge-debug.md +65 -0
  143. package/docs/deprecated/insforge-instructions.md +124 -0
  144. package/docs/deprecated/insforge-project.md +118 -0
  145. package/docs/deprecated/insforge-storage-api.md +279 -0
  146. package/docs/deprecated/insforge-storage-sdk.md +159 -0
  147. package/docs/insforge-instructions-sdk.md +407 -0
  148. package/eslint.config.js +317 -0
  149. package/examples/oauth/frontend-oauth-example.html +251 -0
  150. package/examples/response-examples.md +444 -0
  151. package/frontend/README.md +112 -0
  152. package/frontend/components.json +17 -0
  153. package/frontend/index.html +13 -0
  154. package/frontend/package.json +63 -0
  155. package/frontend/public/favicon.ico +0 -0
  156. package/frontend/src/App.tsx +106 -0
  157. package/frontend/src/assets/icons/checkbox_checked.svg +6 -0
  158. package/frontend/src/assets/icons/checkbox_undetermined.svg +6 -0
  159. package/frontend/src/assets/icons/checked.svg +3 -0
  160. package/frontend/src/assets/icons/error.svg +3 -0
  161. package/frontend/src/assets/icons/pencil.svg +4 -0
  162. package/frontend/src/assets/icons/refresh.svg +4 -0
  163. package/frontend/src/assets/icons/step_active.svg +3 -0
  164. package/frontend/src/assets/icons/step_inactive.svg +11 -0
  165. package/frontend/src/assets/icons/warning.svg +3 -0
  166. package/frontend/src/assets/logos/amazon.svg +1 -0
  167. package/frontend/src/assets/logos/claude_code.svg +3 -0
  168. package/frontend/src/assets/logos/cline.svg +6 -0
  169. package/frontend/src/assets/logos/cursor.svg +20 -0
  170. package/frontend/src/assets/logos/discord.svg +9 -0
  171. package/frontend/src/assets/logos/gemini.svg +19 -0
  172. package/frontend/src/assets/logos/github.svg +5 -0
  173. package/frontend/src/assets/logos/google.svg +13 -0
  174. package/frontend/src/assets/logos/grok.svg +10 -0
  175. package/frontend/src/assets/logos/insforge_dark.svg +15 -0
  176. package/frontend/src/assets/logos/insforge_light.svg +15 -0
  177. package/frontend/src/assets/logos/openai.svg +10 -0
  178. package/frontend/src/assets/logos/roo_code.svg +9 -0
  179. package/frontend/src/assets/logos/trae.svg +3 -0
  180. package/frontend/src/assets/logos/windsurf.svg +10 -0
  181. package/frontend/src/components/ButtonWithLoading.tsx +27 -0
  182. package/frontend/src/components/Checkbox.tsx +61 -0
  183. package/frontend/src/components/CodeBlock.tsx +32 -0
  184. package/frontend/src/components/ConfirmDialog.tsx +96 -0
  185. package/frontend/src/components/CopyButton.tsx +69 -0
  186. package/frontend/src/components/DeleteActionButton.tsx +42 -0
  187. package/frontend/src/components/EmptyState.tsx +41 -0
  188. package/frontend/src/components/ErrorState.tsx +35 -0
  189. package/frontend/src/components/FeatureSidebar.tsx +126 -0
  190. package/frontend/src/components/FeatureSidebarItem.tsx +101 -0
  191. package/frontend/src/components/JsonHighlight.tsx +61 -0
  192. package/frontend/src/components/LoadingState.tsx +16 -0
  193. package/frontend/src/components/PaginationControls.tsx +54 -0
  194. package/frontend/src/components/PromptDialog.tsx +68 -0
  195. package/frontend/src/components/SearchInput.tsx +90 -0
  196. package/frontend/src/components/SelectionClearButton.tsx +26 -0
  197. package/frontend/src/components/Stepper.tsx +139 -0
  198. package/frontend/src/components/ThemeToggle.tsx +58 -0
  199. package/frontend/src/components/TypeBadge.tsx +20 -0
  200. package/frontend/src/components/datagrid/DataGrid.tsx +264 -0
  201. package/frontend/src/components/datagrid/DefaultCellRenderer.tsx +114 -0
  202. package/frontend/src/components/datagrid/IdCell.tsx +44 -0
  203. package/frontend/src/components/datagrid/SortableHeader.tsx +74 -0
  204. package/frontend/src/components/datagrid/cell-editors/BooleanCellEditor.tsx +54 -0
  205. package/frontend/src/components/datagrid/cell-editors/DateCellEditor.tsx +483 -0
  206. package/frontend/src/components/datagrid/cell-editors/JsonCellEditor.tsx +362 -0
  207. package/frontend/src/components/datagrid/cell-editors/TextCellEditor.tsx +38 -0
  208. package/frontend/src/components/datagrid/cell-editors/index.ts +14 -0
  209. package/frontend/src/components/datagrid/cell-editors/types.ts +43 -0
  210. package/frontend/src/components/datagrid/datagridTypes.tsx +72 -0
  211. package/frontend/src/components/datagrid/index.tsx +20 -0
  212. package/frontend/src/components/index.ts +39 -0
  213. package/frontend/src/components/layout/AppHeader.tsx +146 -0
  214. package/frontend/src/components/layout/AppSidebar.tsx +190 -0
  215. package/frontend/src/components/layout/CloudLayout.tsx +95 -0
  216. package/frontend/src/components/layout/Layout.tsx +43 -0
  217. package/frontend/src/components/radix/Alert.tsx +45 -0
  218. package/frontend/src/components/radix/AlertDialog.tsx +115 -0
  219. package/frontend/src/components/radix/Avatar.tsx +45 -0
  220. package/frontend/src/components/radix/Badge.tsx +33 -0
  221. package/frontend/src/components/radix/Button.tsx +50 -0
  222. package/frontend/src/components/radix/Card.tsx +58 -0
  223. package/frontend/src/components/radix/Dialog.tsx +98 -0
  224. package/frontend/src/components/radix/DropdownMenu.tsx +185 -0
  225. package/frontend/src/components/radix/Form.tsx +167 -0
  226. package/frontend/src/components/radix/Input.tsx +22 -0
  227. package/frontend/src/components/radix/Label.tsx +19 -0
  228. package/frontend/src/components/radix/Popover.tsx +29 -0
  229. package/frontend/src/components/radix/ScrollArea.tsx +44 -0
  230. package/frontend/src/components/radix/Select.tsx +151 -0
  231. package/frontend/src/components/radix/Separator.tsx +26 -0
  232. package/frontend/src/components/radix/Sheet.tsx +119 -0
  233. package/frontend/src/components/radix/Skeleton.tsx +7 -0
  234. package/frontend/src/components/radix/Switch.tsx +29 -0
  235. package/frontend/src/components/radix/Tabs.tsx +50 -0
  236. package/frontend/src/components/radix/Textarea.tsx +21 -0
  237. package/frontend/src/components/radix/Tooltip.tsx +28 -0
  238. package/frontend/src/features/ai/components/AIConfigCard.tsx +154 -0
  239. package/frontend/src/features/ai/components/AIConfigDialog.tsx +76 -0
  240. package/frontend/src/features/ai/components/AIConfigForm.tsx +222 -0
  241. package/frontend/src/features/ai/components/AIEmptyState.tsx +18 -0
  242. package/frontend/src/features/ai/components/fields/ModalityField.tsx +87 -0
  243. package/frontend/src/features/ai/components/fields/ModelSelectionField.tsx +134 -0
  244. package/frontend/src/features/ai/components/fields/SystemPromptField.tsx +33 -0
  245. package/frontend/src/features/ai/helpers.ts +155 -0
  246. package/frontend/src/features/ai/hooks/useAIConfigs.ts +221 -0
  247. package/frontend/src/features/ai/hooks/useAIUsage.ts +77 -0
  248. package/frontend/src/features/ai/page/AIPage.tsx +178 -0
  249. package/frontend/src/features/ai/services/ai.service.ts +148 -0
  250. package/frontend/src/features/auth/components/AddOAuthDialog.tsx +106 -0
  251. package/frontend/src/features/auth/components/AuthMethodTab.tsx +238 -0
  252. package/frontend/src/features/auth/components/OAuthConfigDialog.tsx +303 -0
  253. package/frontend/src/features/auth/components/OAuthEmptyState.tsx +15 -0
  254. package/frontend/src/features/auth/components/UserFormDialog.tsx +248 -0
  255. package/frontend/src/features/auth/components/UsersDataGrid.tsx +183 -0
  256. package/frontend/src/features/auth/components/UsersTab.tsx +114 -0
  257. package/frontend/src/features/auth/hooks/useOAuthConfig.ts +129 -0
  258. package/frontend/src/features/auth/hooks/useUsers.ts +57 -0
  259. package/frontend/src/features/auth/index.ts +9 -0
  260. package/frontend/src/features/auth/page/AuthenticationPage.tsx +169 -0
  261. package/frontend/src/features/auth/services/auth.service.ts +112 -0
  262. package/frontend/src/features/auth/services/oauth.service.ts +49 -0
  263. package/frontend/src/features/dashboard/page/DashboardPage.tsx +194 -0
  264. package/frontend/src/features/database/components/ColumnTypeSelect.tsx +64 -0
  265. package/frontend/src/features/database/components/DatabaseDataGrid.tsx +282 -0
  266. package/frontend/src/features/database/components/ForeignKeyCell.tsx +187 -0
  267. package/frontend/src/features/database/components/ForeignKeyPopover.tsx +378 -0
  268. package/frontend/src/features/database/components/LinkRecordModal.tsx +288 -0
  269. package/frontend/src/features/database/components/RecordFormDialog.tsx +164 -0
  270. package/frontend/src/features/database/components/RecordFormField.tsx +568 -0
  271. package/frontend/src/features/database/components/TableEmptyState.tsx +21 -0
  272. package/frontend/src/features/database/components/TableForm.tsx +656 -0
  273. package/frontend/src/features/database/components/TableFormColumn.tsx +137 -0
  274. package/frontend/src/features/database/components/TableListSkeleton.tsx +9 -0
  275. package/frontend/src/features/database/components/TableSidebar.tsx +47 -0
  276. package/frontend/src/features/database/constants.ts +26 -0
  277. package/frontend/src/features/database/helpers.ts +125 -0
  278. package/frontend/src/features/database/hooks/UseLinkModal.tsx +78 -0
  279. package/frontend/src/features/database/index.ts +12 -0
  280. package/frontend/src/features/database/page/DatabasePage.tsx +626 -0
  281. package/frontend/src/features/database/schema.ts +25 -0
  282. package/frontend/src/features/database/services/database.service.ts +216 -0
  283. package/frontend/src/features/functions/components/FunctionEmptyState.tsx +15 -0
  284. package/frontend/src/features/functions/components/FunctionRow.tsx +71 -0
  285. package/frontend/src/features/functions/components/FunctionViewer.tsx +46 -0
  286. package/frontend/src/features/functions/components/FunctionsContent.tsx +88 -0
  287. package/frontend/src/features/functions/components/FunctionsSidebar.tsx +56 -0
  288. package/frontend/src/features/functions/components/SecretEmptyState.tsx +23 -0
  289. package/frontend/src/features/functions/components/SecretRow.tsx +68 -0
  290. package/frontend/src/features/functions/components/SecretsContent.tsx +120 -0
  291. package/frontend/src/features/functions/hooks/useFunctions.ts +106 -0
  292. package/frontend/src/features/functions/page/FunctionsPage.tsx +28 -0
  293. package/frontend/src/features/functions/services/functions.service.ts +48 -0
  294. package/frontend/src/features/login/components/AuthErrorBoundary.tsx +87 -0
  295. package/frontend/src/features/login/components/PrivateRoute.tsx +24 -0
  296. package/frontend/src/features/login/page/CloudLoginPage.tsx +93 -0
  297. package/frontend/src/features/login/page/LoginPage.tsx +174 -0
  298. package/frontend/src/features/logs/components/AnalyticsLogsTable.tsx +313 -0
  299. package/frontend/src/features/logs/components/LogsTable.tsx +199 -0
  300. package/frontend/src/features/logs/hooks/useAuditLogs.ts +39 -0
  301. package/frontend/src/features/logs/index.ts +5 -0
  302. package/frontend/src/features/logs/page/AnalyticsLogsPage.tsx +530 -0
  303. package/frontend/src/features/logs/page/AuditsPage.tsx +192 -0
  304. package/frontend/src/features/logs/services/log.service.ts +171 -0
  305. package/frontend/src/features/metadata/hooks/useMetadata.ts +53 -0
  306. package/frontend/src/features/metadata/index.ts +0 -0
  307. package/frontend/src/features/metadata/page/MetadataPage.tsx +136 -0
  308. package/frontend/src/features/metadata/services/metadata.service.ts +17 -0
  309. package/frontend/src/features/onboard/components/CompletionCard.tsx +41 -0
  310. package/frontend/src/features/onboard/components/OnboardButton.tsx +84 -0
  311. package/frontend/src/features/onboard/components/StepContent.tsx +91 -0
  312. package/frontend/src/features/onboard/components/TestConnectionStep.tsx +53 -0
  313. package/frontend/src/features/onboard/components/mcp/CursorDeeplinkGenerator.tsx +35 -0
  314. package/frontend/src/features/onboard/components/mcp/McpInstallation.tsx +144 -0
  315. package/frontend/src/features/onboard/components/mcp/index.ts +4 -0
  316. package/frontend/src/features/onboard/components/mcp/mcp-helper.tsx +98 -0
  317. package/frontend/src/features/onboard/index.ts +3 -0
  318. package/frontend/src/features/onboard/page/OnBoardPage.tsx +104 -0
  319. package/frontend/src/features/onboard/types.ts +8 -0
  320. package/frontend/src/features/secrets/hooks/useSecrets.ts +139 -0
  321. package/frontend/src/features/secrets/services/secrets.service.ts +57 -0
  322. package/frontend/src/features/storage/components/BucketEmptyState.tsx +19 -0
  323. package/frontend/src/features/storage/components/BucketFormDialog.tsx +194 -0
  324. package/frontend/src/features/storage/components/BucketListSkeleton.tsx +17 -0
  325. package/frontend/src/features/storage/components/FilePreviewDialog.tsx +287 -0
  326. package/frontend/src/features/storage/components/StorageDataGrid.tsx +239 -0
  327. package/frontend/src/features/storage/components/StorageManager.tsx +236 -0
  328. package/frontend/src/features/storage/components/StorageSidebar.tsx +44 -0
  329. package/frontend/src/features/storage/components/UploadToast.tsx +46 -0
  330. package/frontend/src/features/storage/index.ts +3 -0
  331. package/frontend/src/features/storage/page/StoragePage.tsx +553 -0
  332. package/frontend/src/features/storage/services/storage.service.ts +144 -0
  333. package/frontend/src/features/visualizer/components/AuthNode.tsx +107 -0
  334. package/frontend/src/features/visualizer/components/BucketNode.tsx +34 -0
  335. package/frontend/src/features/visualizer/components/SchemaVisualizer.tsx +359 -0
  336. package/frontend/src/features/visualizer/components/TableNode.tsx +152 -0
  337. package/frontend/src/features/visualizer/components/VisualizerSkeleton.tsx +24 -0
  338. package/frontend/src/features/visualizer/components/index.ts +5 -0
  339. package/frontend/src/features/visualizer/page/VisualizerPage.tsx +127 -0
  340. package/frontend/src/index.css +248 -0
  341. package/frontend/src/lib/api/client.ts +163 -0
  342. package/frontend/src/lib/contexts/AuthContext.tsx +157 -0
  343. package/frontend/src/lib/contexts/OnboardStepContext.tsx +68 -0
  344. package/frontend/src/lib/contexts/SocketContext.tsx +303 -0
  345. package/frontend/src/lib/contexts/ThemeContext.tsx +125 -0
  346. package/frontend/src/lib/hooks/useAuth.ts +4 -0
  347. package/frontend/src/lib/hooks/useConfirm.ts +55 -0
  348. package/frontend/src/lib/hooks/useInterval.ts +27 -0
  349. package/frontend/src/lib/hooks/useMediaQuery.ts +59 -0
  350. package/frontend/src/lib/hooks/useOnboardingCompletion.ts +29 -0
  351. package/frontend/src/lib/hooks/usePagination.ts +27 -0
  352. package/frontend/src/lib/hooks/useTimeout.ts +27 -0
  353. package/frontend/src/lib/hooks/useToast.tsx +229 -0
  354. package/frontend/src/lib/utils/constants.ts +38 -0
  355. package/frontend/src/lib/utils/utils.ts +165 -0
  356. package/frontend/src/lib/utils/validation-schemas.ts +126 -0
  357. package/frontend/src/main.tsx +16 -0
  358. package/frontend/src/rdg.css +194 -0
  359. package/frontend/src/vite-env.d.ts +12 -0
  360. package/frontend/tailwind.config.js +97 -0
  361. package/frontend/tsconfig.json +26 -0
  362. package/frontend/tsconfig.node.json +10 -0
  363. package/frontend/vite.config.ts +37 -0
  364. package/frontend/vitest.config.ts +36 -0
  365. package/functions/deno.json +25 -0
  366. package/functions/server.ts +290 -0
  367. package/functions/worker-template.js +126 -0
  368. package/openapi/ai.yaml +689 -0
  369. package/openapi/auth.yaml +563 -0
  370. package/openapi/functions.yaml +476 -0
  371. package/openapi/health.yaml +30 -0
  372. package/openapi/logs.yaml +224 -0
  373. package/openapi/metadata.yaml +178 -0
  374. package/openapi/records.yaml +382 -0
  375. package/openapi/secrets.yaml +371 -0
  376. package/openapi/storage.yaml +876 -0
  377. package/openapi/tables.yaml +464 -0
  378. package/package.json +88 -0
  379. package/shared-schemas/package.json +31 -0
  380. package/shared-schemas/src/ai-api.schema.ts +167 -0
  381. package/shared-schemas/src/ai.schema.ts +54 -0
  382. package/shared-schemas/src/auth-api.schema.ts +193 -0
  383. package/shared-schemas/src/auth.schema.ts +94 -0
  384. package/shared-schemas/src/database-api.schema.ts +259 -0
  385. package/shared-schemas/src/database.schema.ts +69 -0
  386. package/shared-schemas/src/functions-api.schema.ts +25 -0
  387. package/shared-schemas/src/functions.schema.ts +16 -0
  388. package/shared-schemas/src/index.ts +13 -0
  389. package/shared-schemas/src/logs-api.schema.ts +49 -0
  390. package/shared-schemas/src/logs.schema.ts +14 -0
  391. package/shared-schemas/src/metadata.schema.ts +56 -0
  392. package/shared-schemas/src/storage-api.schema.ts +65 -0
  393. package/shared-schemas/src/storage.schema.ts +19 -0
  394. package/shared-schemas/tsconfig.json +21 -0
  395. package/tsconfig.json +8 -0
@@ -0,0 +1,156 @@
1
+ import OpenAI from 'openai';
2
+
3
+ import { AIUsageService } from './usage';
4
+ import { AIConfigService } from './config';
5
+ import { AIClientService } from './client';
6
+ import type {
7
+ AIConfigurationSchema,
8
+ ImageGenerationRequest,
9
+ ImageGenerationResponse,
10
+ } from '@insforge/shared-schemas';
11
+ import logger from '@/utils/logger.js';
12
+ import { OpenRouterImageMessage } from '@/types/ai';
13
+
14
+ export class ImageService {
15
+ private static aiUsageService = new AIUsageService();
16
+ private static aiConfigService = new AIConfigService();
17
+ private static aiCredentialsService = AIClientService.getInstance();
18
+
19
+ /**
20
+ * Validate model and get config
21
+ */
22
+ private static async validateAndGetConfig(
23
+ modelId: string
24
+ ): Promise<AIConfigurationSchema | null> {
25
+ const aiConfig = await ImageService.aiConfigService.findByModelId(modelId);
26
+ if (!aiConfig) {
27
+ throw new Error(
28
+ `Model ${modelId} is not enabled. Please contact your administrator to enable this model.`
29
+ );
30
+ }
31
+ return aiConfig;
32
+ }
33
+
34
+ /**
35
+ * Generate images using the specified model
36
+ * @param options - Image generation options
37
+ */
38
+ static async generate(options: ImageGenerationRequest): Promise<ImageGenerationResponse> {
39
+ // Get the client (handles validation and initialization automatically)
40
+ const client = await this.aiCredentialsService.getClient();
41
+
42
+ // Validate model and get config
43
+ const aiConfig = await ImageService.validateAndGetConfig(options.model);
44
+
45
+ const model = options.model;
46
+
47
+ try {
48
+ // Concatenate system prompt with user prompt if it exists
49
+ // This is because OpenRouter image models don't properly handle system messages
50
+ let finalPrompt = options.prompt;
51
+ if (aiConfig?.systemPrompt) {
52
+ finalPrompt = `${aiConfig.systemPrompt}\n\n${options.prompt}`;
53
+ }
54
+
55
+ // Build content for the message
56
+ const userContent = options.images?.length
57
+ ? [
58
+ { type: 'text', text: finalPrompt },
59
+ ...options.images.map((image) => ({
60
+ type: 'image_url',
61
+ image_url: { url: image.url },
62
+ })),
63
+ ]
64
+ : finalPrompt;
65
+
66
+ // Build the request - OpenRouter extends OpenAI's API with additional fields
67
+ const request = {
68
+ model,
69
+ messages: [
70
+ {
71
+ role: 'user',
72
+ content: userContent,
73
+ },
74
+ ],
75
+ stream: false, // Explicitly disable streaming
76
+ // OpenRouter-specific field for image generation
77
+ modalities: ['text', 'image'],
78
+ };
79
+
80
+ // Use OpenRouter's standard chat completions API
81
+ // Cast the extended request to the base OpenAI type for the SDK call
82
+ const response = (await client.chat.completions.create(
83
+ request as OpenAI.Chat.ChatCompletionCreateParamsNonStreaming
84
+ )) as OpenAI.Chat.ChatCompletion;
85
+
86
+ // Initialize the result
87
+ const result: ImageGenerationResponse = {
88
+ images: [],
89
+ metadata: {
90
+ model: model,
91
+ usage: response.usage
92
+ ? {
93
+ promptTokens: response.usage.prompt_tokens || 0,
94
+ completionTokens: response.usage.completion_tokens || 0,
95
+ totalTokens: response.usage.total_tokens || 0,
96
+ }
97
+ : undefined,
98
+ },
99
+ };
100
+
101
+ // Process the OpenAI-compatible response
102
+ if (response.choices && response.choices.length > 0) {
103
+ for (const choice of response.choices) {
104
+ const message = choice.message;
105
+
106
+ // Extract text content if present (for multimodal responses)
107
+ if (message.content) {
108
+ result.text = message.content;
109
+ // Use text as revised prompt if available
110
+ }
111
+
112
+ // OpenRouter adds an 'images' field to the assistant message for image generation
113
+ // Cast the message to include the extended OpenRouter fields
114
+ const extendedMessage = message as typeof message & {
115
+ images?: OpenRouterImageMessage[];
116
+ };
117
+
118
+ // Check for images in the OpenRouter format
119
+ if (extendedMessage.images && Array.isArray(extendedMessage.images)) {
120
+ for (const image of extendedMessage.images) {
121
+ if (image.type === 'image_url' && image.image_url?.url) {
122
+ result.images.push({
123
+ type: 'imageUrl',
124
+ imageUrl: image.image_url?.url,
125
+ });
126
+ }
127
+ }
128
+ }
129
+ }
130
+ }
131
+
132
+ // Track usage if config is available
133
+ if (aiConfig?.id) {
134
+ // Pass token usage information if available
135
+ const inputTokens = result.metadata?.usage?.promptTokens;
136
+ const outputTokens = result.metadata?.usage?.completionTokens;
137
+
138
+ await ImageService.aiUsageService.trackImageGenerationUsage(
139
+ aiConfig.id,
140
+ result.images.length,
141
+ undefined, // image resolution not available from OpenRouter
142
+ inputTokens,
143
+ outputTokens,
144
+ options.model
145
+ );
146
+ }
147
+
148
+ return result;
149
+ } catch (error) {
150
+ logger.error('Image generation error', { error });
151
+ throw new Error(
152
+ `Failed to generate image: ${error instanceof Error ? error.message : String(error)}`
153
+ );
154
+ }
155
+ }
156
+ }
@@ -0,0 +1,117 @@
1
+ import { isCloudEnvironment } from '@/utils/environment';
2
+ import { AIClientService } from './client';
3
+ import type { RawOpenRouterModel } from '@/types/ai';
4
+ import type { OpenRouterModel } from '@insforge/shared-schemas';
5
+
6
+ export interface ModelProviderInfo {
7
+ provider: string;
8
+ configured: boolean;
9
+ models: OpenRouterModel[];
10
+ }
11
+
12
+ export interface ListModelsResponse {
13
+ text: ModelProviderInfo[];
14
+ image: ModelProviderInfo[];
15
+ }
16
+
17
+ export class AIModelService {
18
+ /**
19
+ * Get all available AI models
20
+ * Fetches from cloud API if in cloud environment, otherwise from OpenRouter directly
21
+ */
22
+ static async getModels(): Promise<ListModelsResponse> {
23
+ const credentialsService = AIClientService.getInstance();
24
+ const configured = credentialsService.isConfigured();
25
+
26
+ if (!configured) {
27
+ return {
28
+ text: [
29
+ {
30
+ provider: 'openrouter',
31
+ configured: false,
32
+ models: [],
33
+ },
34
+ ],
35
+ image: [
36
+ {
37
+ provider: 'openrouter',
38
+ configured: false,
39
+ models: [],
40
+ },
41
+ ],
42
+ };
43
+ }
44
+
45
+ // Get API key from credentials service
46
+ const apiKey = await credentialsService.getApiKey();
47
+
48
+ // Determine the API endpoint based on environment
49
+ const apiUrl = isCloudEnvironment()
50
+ ? 'https://api.insforge.dev/ai/v1/models'
51
+ : 'https://openrouter.ai/api/v1/models/user';
52
+
53
+ // Fetch models from the appropriate endpoint
54
+ const response = await fetch(apiUrl, {
55
+ headers: {
56
+ Authorization: `Bearer ${apiKey}`,
57
+ },
58
+ });
59
+
60
+ if (!response.ok) {
61
+ throw new Error(`Failed to fetch models: ${response.statusText}`);
62
+ }
63
+
64
+ const data = (await response.json()) as { data: RawOpenRouterModel[] };
65
+ const models = data.data || [];
66
+
67
+ const textModels: OpenRouterModel[] = [];
68
+ const imageModels: OpenRouterModel[] = [];
69
+
70
+ for (const model of models) {
71
+ // Classify based on output modality
72
+ const transformedModel: OpenRouterModel = {
73
+ ...model,
74
+ architecture: model.architecture
75
+ ? {
76
+ inputModalities: model.architecture.input_modalities || [],
77
+ outputModalities: model.architecture.output_modalities || [],
78
+ tokenizer: model.architecture.tokenizer || '',
79
+ instructType: model.architecture.instruct_type || '',
80
+ }
81
+ : undefined,
82
+ topProvider: model.topProvider
83
+ ? {
84
+ isModerated: model.topProvider.is_moderated,
85
+ contextLength: model.topProvider.context_length,
86
+ maxCompletionTokens: model.topProvider.max_completion_tokens,
87
+ }
88
+ : undefined,
89
+ };
90
+
91
+ if (model.architecture?.output_modalities?.includes('image')) {
92
+ imageModels.push(transformedModel);
93
+ }
94
+
95
+ if (model.architecture?.output_modalities?.includes('text')) {
96
+ textModels.push(transformedModel);
97
+ }
98
+ }
99
+
100
+ return {
101
+ text: [
102
+ {
103
+ provider: 'openrouter',
104
+ configured: true,
105
+ models: textModels,
106
+ },
107
+ ],
108
+ image: [
109
+ {
110
+ provider: 'openrouter',
111
+ configured: true,
112
+ models: imageModels,
113
+ },
114
+ ],
115
+ };
116
+ }
117
+ }
@@ -0,0 +1,290 @@
1
+ import { Pool } from 'pg';
2
+ import { DatabaseManager } from '@/core/database/manager.js';
3
+ import logger from '@/utils/logger.js';
4
+ import type {
5
+ AIUsageDataSchema,
6
+ AIUsageRecordSchema,
7
+ AIUsageSummarySchema,
8
+ ListAIUsageResponse,
9
+ } from '@insforge/shared-schemas';
10
+
11
+ export class AIUsageService {
12
+ private pool: Pool | null = null;
13
+
14
+ private getPool(): Pool {
15
+ if (!this.pool) {
16
+ this.pool = DatabaseManager.getInstance().getPool();
17
+ }
18
+ return this.pool;
19
+ }
20
+
21
+ async trackUsage(data: AIUsageDataSchema): Promise<{ id: string }> {
22
+ const client = await this.getPool().connect();
23
+ try {
24
+ const result = await client.query(
25
+ `INSERT INTO _ai_usage (config_id, input_tokens, output_tokens, image_count, image_resolution)
26
+ VALUES ($1, $2, $3, $4, $5)
27
+ RETURNING id`,
28
+ [
29
+ data.configId,
30
+ data.inputTokens || null,
31
+ data.outputTokens || null,
32
+ data.imageCount || null,
33
+ data.imageResolution || null,
34
+ ]
35
+ );
36
+
37
+ logger.info('AI usage tracked', {
38
+ id: result.rows[0].id,
39
+ configId: data.configId,
40
+ inputTokens: data.inputTokens,
41
+ outputTokens: data.outputTokens,
42
+ imageCount: data.imageCount,
43
+ });
44
+
45
+ return { id: result.rows[0].id };
46
+ } catch (error) {
47
+ logger.error('Failed to track AI usage', { error, data });
48
+ throw new Error('Failed to track AI usage');
49
+ } finally {
50
+ client.release();
51
+ }
52
+ }
53
+
54
+ async trackChatUsage(
55
+ configId: string,
56
+ inputTokens?: number,
57
+ outputTokens?: number,
58
+ modelId?: string
59
+ ): Promise<{ id: string }> {
60
+ const totalTokens = (inputTokens || 0) + (outputTokens || 0);
61
+
62
+ const client = await this.getPool().connect();
63
+ try {
64
+ const usageResult = await client.query(
65
+ `INSERT INTO _ai_usage (config_id, input_tokens, output_tokens, model_id)
66
+ VALUES ($1, $2, $3, $4)
67
+ RETURNING id`,
68
+ [configId, inputTokens || null, outputTokens || null, modelId || null]
69
+ );
70
+
71
+ logger.info('Chat usage tracked', {
72
+ id: usageResult.rows[0].id,
73
+ configId,
74
+ inputTokens,
75
+ outputTokens,
76
+ totalTokens,
77
+ modelId,
78
+ });
79
+
80
+ return { id: usageResult.rows[0].id };
81
+ } catch (error) {
82
+ logger.error('Failed to track chat usage', { error, configId });
83
+ throw new Error('Failed to track chat usage');
84
+ } finally {
85
+ client.release();
86
+ }
87
+ }
88
+
89
+ async trackImageGenerationUsage(
90
+ configId: string,
91
+ imageCount: number,
92
+ imageResolution?: string,
93
+ inputTokens?: number,
94
+ outputTokens?: number,
95
+ modelId?: string
96
+ ): Promise<{ id: string }> {
97
+ const client = await this.getPool().connect();
98
+ try {
99
+ const usageResult = await client.query(
100
+ `INSERT INTO _ai_usage (config_id, image_count, image_resolution, input_tokens, output_tokens, model_id)
101
+ VALUES ($1, $2, $3, $4, $5, $6)
102
+ RETURNING id`,
103
+ [
104
+ configId,
105
+ imageCount,
106
+ imageResolution || null,
107
+ inputTokens || null,
108
+ outputTokens || null,
109
+ modelId || null,
110
+ ]
111
+ );
112
+
113
+ logger.info('Image usage tracked', {
114
+ id: usageResult.rows[0].id,
115
+ configId,
116
+ imageCount,
117
+ imageResolution,
118
+ inputTokens,
119
+ outputTokens,
120
+ modelId,
121
+ });
122
+
123
+ return { id: usageResult.rows[0].id };
124
+ } catch (error) {
125
+ logger.error('Failed to track image usage', { error, configId });
126
+ throw new Error('Failed to track image usage');
127
+ } finally {
128
+ client.release();
129
+ }
130
+ }
131
+
132
+ async getUsageByConfig(
133
+ configId: string,
134
+ startDate?: Date,
135
+ endDate?: Date
136
+ ): Promise<AIUsageRecordSchema[]> {
137
+ const client = await this.getPool().connect();
138
+ try {
139
+ let query = `
140
+ SELECT id, config_id as "configId", input_tokens as "inputTokens",
141
+ output_tokens as "outputTokens", image_count as "imageCount",
142
+ image_resolution as "imageResolution", created_at as "createdAt"
143
+ FROM _ai_usage
144
+ WHERE config_id = $1
145
+ `;
146
+
147
+ const params: (string | Date)[] = [configId];
148
+
149
+ if (startDate) {
150
+ params.push(startDate);
151
+ query += ` AND created_at >= $${params.length}`;
152
+ }
153
+
154
+ if (endDate) {
155
+ params.push(endDate);
156
+ query += ` AND created_at <= $${params.length}`;
157
+ }
158
+
159
+ query += ' ORDER BY created_at DESC';
160
+
161
+ const result = await client.query(query, params);
162
+
163
+ return result.rows;
164
+ } catch (error) {
165
+ logger.error('Failed to fetch usage by config', { error, configId });
166
+ throw new Error('Failed to fetch usage records');
167
+ } finally {
168
+ client.release();
169
+ }
170
+ }
171
+
172
+ async getUsageSummary(
173
+ configId?: string,
174
+ startDate?: Date,
175
+ endDate?: Date
176
+ ): Promise<AIUsageSummarySchema> {
177
+ const client = await this.getPool().connect();
178
+ try {
179
+ let query = `
180
+ SELECT
181
+ COALESCE(SUM(input_tokens), 0) as "totalInputTokens",
182
+ COALESCE(SUM(output_tokens), 0) as "totalOutputTokens",
183
+ COALESCE(SUM(COALESCE(input_tokens, 0) + COALESCE(output_tokens, 0)), 0) as "totalTokens",
184
+ COALESCE(SUM(image_count), 0) as "totalImageCount",
185
+ COUNT(*) as "totalRequests"
186
+ FROM _ai_usage
187
+ WHERE 1=1
188
+ `;
189
+
190
+ const params: (string | Date)[] = [];
191
+
192
+ if (configId) {
193
+ params.push(configId);
194
+ query += ` AND config_id = $${params.length}`;
195
+ }
196
+
197
+ if (startDate) {
198
+ params.push(startDate);
199
+ query += ` AND created_at >= $${params.length}`;
200
+ }
201
+
202
+ if (endDate) {
203
+ params.push(endDate);
204
+ query += ` AND created_at <= $${params.length}`;
205
+ }
206
+
207
+ const result = await client.query(query, params);
208
+
209
+ return {
210
+ totalInputTokens: parseInt(result.rows[0].totalInputTokens),
211
+ totalOutputTokens: parseInt(result.rows[0].totalOutputTokens),
212
+ totalTokens: parseInt(result.rows[0].totalTokens),
213
+ totalImageCount: parseInt(result.rows[0].totalImageCount),
214
+ totalRequests: parseInt(result.rows[0].totalRequests),
215
+ };
216
+ } catch (error) {
217
+ logger.error('Failed to fetch usage summary', { error, configId });
218
+ throw new Error('Failed to fetch usage summary');
219
+ } finally {
220
+ client.release();
221
+ }
222
+ }
223
+
224
+ async getAllUsage(
225
+ startDate?: Date,
226
+ endDate?: Date,
227
+ limit?: number,
228
+ offset?: number
229
+ ): Promise<ListAIUsageResponse> {
230
+ const client = await this.getPool().connect();
231
+ try {
232
+ let query = `
233
+ SELECT
234
+ u.id,
235
+ u.config_id as "configId",
236
+ u.input_tokens as "inputTokens",
237
+ u.output_tokens as "outputTokens",
238
+ u.image_count as "imageCount",
239
+ u.image_resolution as "imageResolution",
240
+ u.created_at as "createdAt",
241
+ u.model_id as "modelId",
242
+ COALESCE(u.model_id, c.model_id) as "model",
243
+ c.provider,
244
+ c.modality
245
+ FROM _ai_usage u
246
+ LEFT JOIN _ai_configs c ON u.config_id = c.id
247
+ WHERE 1=1
248
+ `;
249
+
250
+ const params: (string | Date | number)[] = [];
251
+
252
+ if (startDate) {
253
+ params.push(startDate);
254
+ query += ` AND u.created_at >= $${params.length}`;
255
+ }
256
+
257
+ if (endDate) {
258
+ params.push(endDate);
259
+ query += ` AND u.created_at <= $${params.length}`;
260
+ }
261
+
262
+ const countQuery = `SELECT COUNT(*) as total FROM (${query}) as subquery`;
263
+ const countResult = await client.query(countQuery, params);
264
+
265
+ query += ' ORDER BY u.created_at DESC';
266
+
267
+ if (limit) {
268
+ params.push(limit);
269
+ query += ` LIMIT $${params.length}`;
270
+ }
271
+
272
+ if (offset) {
273
+ params.push(offset);
274
+ query += ` OFFSET $${params.length}`;
275
+ }
276
+
277
+ const result = await client.query(query, params);
278
+
279
+ return {
280
+ records: result.rows,
281
+ total: parseInt(countResult.rows[0].total),
282
+ };
283
+ } catch (error) {
284
+ logger.error('Failed to fetch all usage records', { error });
285
+ throw new Error('Failed to fetch usage records');
286
+ } finally {
287
+ client.release();
288
+ }
289
+ }
290
+ }