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,856 @@
1
+ import {
2
+ OpenAPIRegistry,
3
+ OpenApiGeneratorV3,
4
+ extendZodWithOpenApi,
5
+ } from '@asteasolutions/zod-to-openapi';
6
+ import { z } from 'zod';
7
+ import { TableSchema, ColumnSchema, ColumnType } from '@insforge/shared-schemas';
8
+ import logger from '@/utils/logger.js';
9
+ import { DatabaseTableService } from '../database/table';
10
+ import { DatabaseManager } from '../database/manager';
11
+
12
+ // Extend Zod with OpenAPI functionality
13
+ extendZodWithOpenApi(z);
14
+
15
+ export class OpenAPIService {
16
+ private static instance: OpenAPIService;
17
+
18
+ private constructor() {}
19
+
20
+ static getInstance(): OpenAPIService {
21
+ if (!OpenAPIService.instance) {
22
+ OpenAPIService.instance = new OpenAPIService();
23
+ }
24
+ return OpenAPIService.instance;
25
+ }
26
+
27
+ /**
28
+ * Convert column type to Zod schema
29
+ */
30
+ private columnToZodType(column: ColumnSchema): z.ZodTypeAny {
31
+ let baseType: z.ZodTypeAny;
32
+
33
+ switch (column.type) {
34
+ case ColumnType.STRING:
35
+ baseType = z.string();
36
+ break;
37
+ case ColumnType.INTEGER:
38
+ baseType = z.number().int();
39
+ break;
40
+ case ColumnType.FLOAT:
41
+ baseType = z.number();
42
+ break;
43
+ case ColumnType.BOOLEAN:
44
+ baseType = z.boolean();
45
+ break;
46
+ case ColumnType.DATE:
47
+ baseType = z.string().date();
48
+ break;
49
+ case ColumnType.DATETIME:
50
+ baseType = z.string().datetime();
51
+ break;
52
+ case ColumnType.UUID:
53
+ baseType = z.string().uuid();
54
+ break;
55
+ case ColumnType.JSON:
56
+ baseType = z.record(z.unknown());
57
+ break;
58
+ default:
59
+ baseType = z.unknown();
60
+ }
61
+
62
+ // Apply nullable/optional modifiers
63
+ if (column.isNullable) {
64
+ baseType = baseType.nullable();
65
+ }
66
+
67
+ // Apply default values
68
+ if (column.defaultValue !== undefined) {
69
+ baseType = baseType.optional();
70
+ }
71
+
72
+ return baseType;
73
+ }
74
+
75
+ /**
76
+ * Generate Zod schema for a table
77
+ */
78
+ private generateTableSchema(table: TableSchema): z.ZodObject<Record<string, z.ZodTypeAny>> {
79
+ const schemaFields: Record<string, z.ZodTypeAny> = {};
80
+
81
+ for (const column of table.columns) {
82
+ schemaFields[column.columnName] = this.columnToZodType(column);
83
+ }
84
+
85
+ return z.object(schemaFields);
86
+ }
87
+
88
+ /**
89
+ * Generate filter schema for query parameters
90
+ */
91
+ private generateFilterSchema(table: TableSchema): z.ZodObject<Record<string, z.ZodTypeAny>> {
92
+ const filterFields: Record<string, z.ZodTypeAny> = {};
93
+
94
+ // Standard PostgREST query parameters
95
+ filterFields['select'] = z.string().optional().describe('Columns to select');
96
+ filterFields['order'] = z.string().optional().describe('Column to order by');
97
+ filterFields['limit'] = z.string().optional().describe('Maximum number of rows to return');
98
+ filterFields['offset'] = z.string().optional().describe('Number of rows to skip');
99
+
100
+ // Add column-specific filters
101
+ for (const column of table.columns) {
102
+ const columnName = column.columnName;
103
+
104
+ // Basic equality filter
105
+ filterFields[columnName] = z.string().optional().describe(`Filter by ${columnName}`);
106
+
107
+ // PostgREST operators
108
+ filterFields[`${columnName}.eq`] = z.string().optional().describe(`${columnName} equals`);
109
+ filterFields[`${columnName}.neq`] = z
110
+ .string()
111
+ .optional()
112
+ .describe(`${columnName} not equals`);
113
+ filterFields[`${columnName}.gt`] = z
114
+ .string()
115
+ .optional()
116
+ .describe(`${columnName} greater than`);
117
+ filterFields[`${columnName}.gte`] = z
118
+ .string()
119
+ .optional()
120
+ .describe(`${columnName} greater than or equal`);
121
+ filterFields[`${columnName}.lt`] = z.string().optional().describe(`${columnName} less than`);
122
+ filterFields[`${columnName}.lte`] = z
123
+ .string()
124
+ .optional()
125
+ .describe(`${columnName} less than or equal`);
126
+ filterFields[`${columnName}.like`] = z
127
+ .string()
128
+ .optional()
129
+ .describe(`${columnName} LIKE pattern`);
130
+ filterFields[`${columnName}.ilike`] = z
131
+ .string()
132
+ .optional()
133
+ .describe(`${columnName} ILIKE pattern (case insensitive)`);
134
+ filterFields[`${columnName}.is`] = z
135
+ .string()
136
+ .optional()
137
+ .describe(`${columnName} IS (for null checks)`);
138
+ filterFields[`${columnName}.in`] = z.string().optional().describe(`${columnName} IN list`);
139
+ }
140
+
141
+ return z.object(filterFields);
142
+ }
143
+
144
+ /**
145
+ * Register authentication endpoints
146
+ */
147
+ private registerAuthenticationEndpoints(registry: OpenAPIRegistry) {
148
+ // User registration endpoint
149
+ registry.registerPath({
150
+ method: 'post',
151
+ path: '/api/auth/users',
152
+ summary: 'Register new user',
153
+ description: 'Create a new user account',
154
+ tags: ['Authentication'],
155
+ request: {
156
+ body: {
157
+ content: {
158
+ 'application/json': {
159
+ schema: z
160
+ .object({
161
+ email: z.string().email().describe('Valid email address'),
162
+ password: z.string().min(8).describe('User password (min 8 characters)'),
163
+ name: z.string().optional().describe('User display name'),
164
+ })
165
+ .openapi('UserRegistration'),
166
+ },
167
+ },
168
+ },
169
+ },
170
+ responses: {
171
+ 200: {
172
+ description: 'User registered successfully',
173
+ content: {
174
+ 'application/json': {
175
+ schema: z
176
+ .object({
177
+ user: z.object({
178
+ id: z.string(),
179
+ email: z.string(),
180
+ name: z.string().nullable(),
181
+ }),
182
+ accessToken: z.string().describe('JWT token for authentication'),
183
+ })
184
+ .openapi('AuthResponse'),
185
+ },
186
+ },
187
+ },
188
+ 400: {
189
+ description: 'Invalid request',
190
+ },
191
+ 409: {
192
+ description: 'User already exists',
193
+ },
194
+ },
195
+ });
196
+
197
+ // User login endpoint
198
+ registry.registerPath({
199
+ method: 'post',
200
+ path: '/api/auth/sessions',
201
+ summary: 'User login',
202
+ description: 'Authenticate user and create session',
203
+ tags: ['Authentication'],
204
+ request: {
205
+ body: {
206
+ content: {
207
+ 'application/json': {
208
+ schema: z
209
+ .object({
210
+ email: z.string().email().describe('User email address'),
211
+ password: z.string().describe('User password'),
212
+ })
213
+ .openapi('UserLogin'),
214
+ },
215
+ },
216
+ },
217
+ },
218
+ responses: {
219
+ 200: {
220
+ description: 'Login successful',
221
+ content: {
222
+ 'application/json': {
223
+ schema: z
224
+ .object({
225
+ user: z.object({
226
+ id: z.string(),
227
+ email: z.string(),
228
+ name: z.string().nullable(),
229
+ }),
230
+ accessToken: z.string().describe('JWT token for authentication'),
231
+ })
232
+ .openapi('AuthResponse'),
233
+ },
234
+ },
235
+ },
236
+ 401: {
237
+ description: 'Invalid credentials',
238
+ },
239
+ 400: {
240
+ description: 'Invalid request',
241
+ },
242
+ },
243
+ });
244
+
245
+ // Get current user endpoint
246
+ registry.registerPath({
247
+ method: 'get',
248
+ path: '/api/auth/sessions/current',
249
+ summary: 'Get current user',
250
+ description: 'Get information about the currently authenticated user',
251
+ tags: ['Authentication'],
252
+ security: [{ BearerAuth: [] }],
253
+ responses: {
254
+ 200: {
255
+ description: 'Current user information',
256
+ content: {
257
+ 'application/json': {
258
+ schema: z
259
+ .object({
260
+ user: z.object({
261
+ id: z.string(),
262
+ email: z.string(),
263
+ role: z.string(),
264
+ }),
265
+ })
266
+ .openapi('CurrentUserResponse'),
267
+ },
268
+ },
269
+ },
270
+ 401: {
271
+ description: 'Unauthorized',
272
+ },
273
+ },
274
+ });
275
+
276
+ // Google OAuth endpoint
277
+ registry.registerPath({
278
+ method: 'get',
279
+ path: '/api/auth/oauth/google',
280
+ summary: 'Google OAuth',
281
+ description: 'Initiate Google OAuth authentication',
282
+ tags: ['Authentication'],
283
+ request: {
284
+ query: z
285
+ .object({
286
+ redirect_uri: z.string().optional().describe('URL to redirect after OAuth completion'),
287
+ })
288
+ .openapi('OAuthRequest'),
289
+ },
290
+ responses: {
291
+ 200: {
292
+ description: 'OAuth URL generated',
293
+ content: {
294
+ 'application/json': {
295
+ schema: z
296
+ .object({
297
+ authUrl: z.string().describe('Google OAuth authorization URL'),
298
+ })
299
+ .openapi('OAuthUrlResponse'),
300
+ },
301
+ },
302
+ },
303
+ 500: {
304
+ description: 'Internal server error',
305
+ },
306
+ },
307
+ });
308
+
309
+ // GitHub OAuth endpoint
310
+ registry.registerPath({
311
+ method: 'get',
312
+ path: '/api/auth/oauth/github',
313
+ summary: 'GitHub OAuth',
314
+ description: 'Initiate GitHub OAuth authentication',
315
+ tags: ['Authentication'],
316
+ request: {
317
+ query: z
318
+ .object({
319
+ redirect_uri: z.string().optional().describe('URL to redirect after OAuth completion'),
320
+ })
321
+ .openapi('OAuthRequest'),
322
+ },
323
+ responses: {
324
+ 200: {
325
+ description: 'OAuth URL generated',
326
+ content: {
327
+ 'application/json': {
328
+ schema: z
329
+ .object({
330
+ authUrl: z.string().describe('GitHub OAuth authorization URL'),
331
+ })
332
+ .openapi('OAuthUrlResponse'),
333
+ },
334
+ },
335
+ },
336
+ 500: {
337
+ description: 'Internal server error',
338
+ },
339
+ },
340
+ });
341
+
342
+ // OAuth callback endpoint
343
+ registry.registerPath({
344
+ method: 'get',
345
+ path: '/api/auth/oauth/{provider}/callback',
346
+ summary: 'OAuth callback',
347
+ description: 'OAuth callback endpoint - handled automatically by OAuth flow',
348
+ tags: ['Authentication'],
349
+ request: {
350
+ params: z
351
+ .object({
352
+ provider: z.enum(['google', 'github']).describe('OAuth provider'),
353
+ })
354
+ .openapi('OAuthProvider'),
355
+ query: z
356
+ .object({
357
+ code: z.string().describe('Authorization code from OAuth provider'),
358
+ state: z.string().describe('State parameter for security'),
359
+ token: z.string().optional().describe('ID token for some flows'),
360
+ })
361
+ .openapi('OAuthCallback'),
362
+ },
363
+ responses: {
364
+ 302: {
365
+ description: 'Redirects to redirect_uri with authentication details or error',
366
+ },
367
+ },
368
+ });
369
+ }
370
+
371
+ /**
372
+ * Register storage endpoints
373
+ */
374
+ private registerStorageEndpoints(registry: OpenAPIRegistry) {
375
+ // Upload object with specific key
376
+ registry.registerPath({
377
+ method: 'put',
378
+ path: '/api/storage/buckets/{bucketName}/objects/{objectKey}',
379
+ summary: 'Upload object',
380
+ description: 'Upload a file to storage with a specific key',
381
+ tags: ['Storage'],
382
+ security: [{ BearerAuth: [] }],
383
+ request: {
384
+ params: z
385
+ .object({
386
+ bucketName: z.string().describe('Name of the bucket'),
387
+ objectKey: z.string().describe('Full object key/path (e.g., "images/photo.jpg")'),
388
+ })
389
+ .openapi('StorageParams'),
390
+ body: {
391
+ content: {
392
+ 'multipart/form-data': {
393
+ schema: z
394
+ .object({
395
+ file: z.instanceof(File).describe('File to upload'),
396
+ })
397
+ .openapi('FileUpload'),
398
+ },
399
+ },
400
+ },
401
+ },
402
+ responses: {
403
+ 201: {
404
+ description: 'File uploaded successfully',
405
+ content: {
406
+ 'application/json': {
407
+ schema: z
408
+ .object({
409
+ key: z.string(),
410
+ bucket: z.string(),
411
+ size: z.number(),
412
+ mimeType: z.string().optional(),
413
+ uploadedAt: z.string(),
414
+ url: z.string(),
415
+ })
416
+ .openapi('StorageFile'),
417
+ },
418
+ },
419
+ },
420
+ 400: {
421
+ description: 'Bad request',
422
+ },
423
+ 401: {
424
+ description: 'Unauthorized',
425
+ },
426
+ 409: {
427
+ description: 'Conflict - file already exists',
428
+ },
429
+ },
430
+ });
431
+
432
+ // Upload object with auto-generated key
433
+ registry.registerPath({
434
+ method: 'post',
435
+ path: '/api/storage/buckets/{bucketName}/objects',
436
+ summary: 'Upload object with auto-key',
437
+ description: 'Upload a file to storage with an auto-generated key',
438
+ tags: ['Storage'],
439
+ security: [{ BearerAuth: [] }],
440
+ request: {
441
+ params: z
442
+ .object({
443
+ bucketName: z.string().describe('Name of the bucket'),
444
+ })
445
+ .openapi('BucketParam'),
446
+ body: {
447
+ content: {
448
+ 'multipart/form-data': {
449
+ schema: z
450
+ .object({
451
+ file: z.instanceof(File).describe('File to upload'),
452
+ })
453
+ .openapi('FileUpload'),
454
+ },
455
+ },
456
+ },
457
+ },
458
+ responses: {
459
+ 201: {
460
+ description: 'File uploaded successfully',
461
+ content: {
462
+ 'application/json': {
463
+ schema: z
464
+ .object({
465
+ key: z.string(),
466
+ bucket: z.string(),
467
+ size: z.number(),
468
+ mimeType: z.string().optional(),
469
+ uploadedAt: z.string(),
470
+ url: z.string(),
471
+ })
472
+ .openapi('StorageFile'),
473
+ },
474
+ },
475
+ },
476
+ 400: {
477
+ description: 'Bad request',
478
+ },
479
+ 401: {
480
+ description: 'Unauthorized',
481
+ },
482
+ 404: {
483
+ description: 'Bucket not found',
484
+ },
485
+ },
486
+ });
487
+
488
+ // Download object
489
+ registry.registerPath({
490
+ method: 'get',
491
+ path: '/api/storage/buckets/{bucketName}/objects/{objectKey}',
492
+ summary: 'Download object',
493
+ description: 'Download a file from storage',
494
+ tags: ['Storage'],
495
+ request: {
496
+ params: z
497
+ .object({
498
+ bucketName: z.string().describe('Name of the bucket'),
499
+ objectKey: z.string().describe('Full object key/path'),
500
+ })
501
+ .openapi('StorageParams'),
502
+ },
503
+ responses: {
504
+ 200: {
505
+ description: 'File content',
506
+ content: {
507
+ 'application/octet-stream': {
508
+ schema: z.instanceof(Buffer).describe('Binary file data'),
509
+ },
510
+ },
511
+ },
512
+ 404: {
513
+ description: 'File not found',
514
+ },
515
+ 401: {
516
+ description: 'Unauthorized (for private buckets)',
517
+ },
518
+ },
519
+ });
520
+
521
+ // Delete object
522
+ registry.registerPath({
523
+ method: 'delete',
524
+ path: '/api/storage/buckets/{bucketName}/objects/{objectKey}',
525
+ summary: 'Delete object',
526
+ description: 'Delete a file from storage',
527
+ tags: ['Storage'],
528
+ security: [{ BearerAuth: [] }],
529
+ request: {
530
+ params: z
531
+ .object({
532
+ bucketName: z.string().describe('Name of the bucket'),
533
+ objectKey: z.string().describe('Full object key/path'),
534
+ })
535
+ .openapi('StorageParams'),
536
+ },
537
+ responses: {
538
+ 200: {
539
+ description: 'File deleted successfully',
540
+ content: {
541
+ 'application/json': {
542
+ schema: z
543
+ .object({
544
+ message: z.string(),
545
+ })
546
+ .openapi('DeleteResponse'),
547
+ },
548
+ },
549
+ },
550
+ 404: {
551
+ description: 'File not found',
552
+ },
553
+ 401: {
554
+ description: 'Unauthorized',
555
+ },
556
+ },
557
+ });
558
+ }
559
+
560
+ /**
561
+ * Register CRUD endpoints for a table
562
+ */
563
+ private registerTableEndpoints(registry: OpenAPIRegistry, table: TableSchema) {
564
+ const tableName = table.tableName;
565
+ const recordSchema = this.generateTableSchema(table);
566
+ const filterSchema = this.generateFilterSchema(table);
567
+
568
+ // Create schemas with OpenAPI metadata
569
+ const singleRecordSchema = recordSchema.openapi(`${tableName}Record`);
570
+ const recordArraySchema = z.array(recordSchema).openapi(`${tableName}RecordArray`);
571
+ const createRecordSchema = recordSchema.partial().openapi(`Create${tableName}Record`);
572
+ const updateRecordSchema = recordSchema.partial().openapi(`Update${tableName}Record`);
573
+
574
+ // GET /api/database/records/{tableName} - List records
575
+ registry.registerPath({
576
+ method: 'get',
577
+ path: `/api/database/records/${tableName}`,
578
+ summary: `List ${tableName} records`,
579
+ description: `Retrieve a list of records from the ${tableName} table with optional filtering`,
580
+ tags: [tableName],
581
+ request: {
582
+ query: filterSchema,
583
+ },
584
+ responses: {
585
+ 200: {
586
+ description: `List of ${tableName} records`,
587
+ content: {
588
+ 'application/json': {
589
+ schema: recordArraySchema,
590
+ },
591
+ },
592
+ },
593
+ 400: {
594
+ description: 'Bad request',
595
+ },
596
+ 401: {
597
+ description: 'Unauthorized',
598
+ },
599
+ },
600
+ });
601
+
602
+ // POST /api/database/records/{tableName} - Create record
603
+ registry.registerPath({
604
+ method: 'post',
605
+ path: `/api/database/records/${tableName}`,
606
+ summary: `Create ${tableName} record`,
607
+ description: `Create a new record in the ${tableName} table`,
608
+ tags: [tableName],
609
+ request: {
610
+ body: {
611
+ content: {
612
+ 'application/json': {
613
+ schema: createRecordSchema,
614
+ },
615
+ },
616
+ },
617
+ },
618
+ responses: {
619
+ 201: {
620
+ description: `Created ${tableName} record`,
621
+ content: {
622
+ 'application/json': {
623
+ schema: singleRecordSchema,
624
+ },
625
+ },
626
+ },
627
+ 400: {
628
+ description: 'Bad request',
629
+ },
630
+ 401: {
631
+ description: 'Unauthorized',
632
+ },
633
+ },
634
+ });
635
+
636
+ // GET /api/database/records/{tableName}/{id} - Get single record
637
+ const primaryKeyColumn = table.columns.find((col) => col.isPrimaryKey);
638
+ if (primaryKeyColumn) {
639
+ registry.registerPath({
640
+ method: 'get',
641
+ path: `/api/database/records/${tableName}/{id}`,
642
+ summary: `Get ${tableName} record by ID`,
643
+ description: `Retrieve a single record from the ${tableName} table by its primary key`,
644
+ tags: [tableName],
645
+ request: {
646
+ params: z.object({
647
+ id: z.string().describe(`Primary key value`),
648
+ }),
649
+ },
650
+ responses: {
651
+ 200: {
652
+ description: `${tableName} record`,
653
+ content: {
654
+ 'application/json': {
655
+ schema: singleRecordSchema,
656
+ },
657
+ },
658
+ },
659
+ 404: {
660
+ description: 'Record not found',
661
+ },
662
+ 401: {
663
+ description: 'Unauthorized',
664
+ },
665
+ },
666
+ });
667
+
668
+ // PATCH /api/database/records/{tableName}/{id} - Update record
669
+ registry.registerPath({
670
+ method: 'patch',
671
+ path: `/api/database/records/${tableName}/{id}`,
672
+ summary: `Update ${tableName} record`,
673
+ description: `Update a record in the ${tableName} table`,
674
+ tags: [tableName],
675
+ request: {
676
+ params: z.object({
677
+ id: z.string().describe(`Primary key value`),
678
+ }),
679
+ body: {
680
+ content: {
681
+ 'application/json': {
682
+ schema: updateRecordSchema,
683
+ },
684
+ },
685
+ },
686
+ },
687
+ responses: {
688
+ 200: {
689
+ description: `Updated ${tableName} record`,
690
+ content: {
691
+ 'application/json': {
692
+ schema: singleRecordSchema,
693
+ },
694
+ },
695
+ },
696
+ 404: {
697
+ description: 'Record not found',
698
+ },
699
+ 401: {
700
+ description: 'Unauthorized',
701
+ },
702
+ },
703
+ });
704
+
705
+ // DELETE /api/database/records/{tableName}/{id} - Delete record
706
+ registry.registerPath({
707
+ method: 'delete',
708
+ path: `/api/database/records/${tableName}/{id}`,
709
+ summary: `Delete ${tableName} record`,
710
+ description: `Delete a record from the ${tableName} table`,
711
+ tags: [tableName],
712
+ request: {
713
+ params: z.object({
714
+ id: z.string().describe(`Primary key value`),
715
+ }),
716
+ },
717
+ responses: {
718
+ 204: {
719
+ description: 'Record deleted successfully',
720
+ },
721
+ 404: {
722
+ description: 'Record not found',
723
+ },
724
+ 401: {
725
+ description: 'Unauthorized',
726
+ },
727
+ },
728
+ });
729
+ }
730
+
731
+ // PATCH /api/database/records/{tableName} - Bulk update
732
+ registry.registerPath({
733
+ method: 'patch',
734
+ path: `/api/database/records/${tableName}`,
735
+ summary: `Bulk update ${tableName} records`,
736
+ description: `Update multiple records in the ${tableName} table based on filters`,
737
+ tags: [tableName],
738
+ request: {
739
+ query: filterSchema,
740
+ body: {
741
+ content: {
742
+ 'application/json': {
743
+ schema: updateRecordSchema,
744
+ },
745
+ },
746
+ },
747
+ },
748
+ responses: {
749
+ 200: {
750
+ description: `Updated ${tableName} records`,
751
+ content: {
752
+ 'application/json': {
753
+ schema: recordArraySchema,
754
+ },
755
+ },
756
+ },
757
+ 400: {
758
+ description: 'Bad request',
759
+ },
760
+ 401: {
761
+ description: 'Unauthorized',
762
+ },
763
+ },
764
+ });
765
+
766
+ // DELETE /api/database/records/{tableName} - Bulk delete
767
+ registry.registerPath({
768
+ method: 'delete',
769
+ path: `/api/database/records/${tableName}`,
770
+ summary: `Bulk delete ${tableName} records`,
771
+ description: `Delete multiple records from the ${tableName} table based on filters`,
772
+ tags: [tableName],
773
+ request: {
774
+ query: filterSchema,
775
+ },
776
+ responses: {
777
+ 204: {
778
+ description: 'Records deleted successfully',
779
+ },
780
+ 400: {
781
+ description: 'Bad request',
782
+ },
783
+ 401: {
784
+ description: 'Unauthorized',
785
+ },
786
+ },
787
+ });
788
+ }
789
+
790
+ /**
791
+ * Generate OpenAPI document
792
+ */
793
+ async generateOpenAPIDocument() {
794
+ try {
795
+ // Create new registry
796
+ const registry = new OpenAPIRegistry();
797
+
798
+ // Register security scheme
799
+ registry.registerComponent('securitySchemes', 'ApiKeyAuth', {
800
+ type: 'apiKey',
801
+ in: 'header',
802
+ name: 'x-api-key',
803
+ description: 'API key for authentication',
804
+ });
805
+
806
+ registry.registerComponent('securitySchemes', 'BearerAuth', {
807
+ type: 'http',
808
+ scheme: 'bearer',
809
+ bearerFormat: 'JWT',
810
+ description: 'JWT token for authentication',
811
+ });
812
+
813
+ // Register authentication endpoints
814
+ this.registerAuthenticationEndpoints(registry);
815
+
816
+ // Register storage endpoints
817
+ this.registerStorageEndpoints(registry);
818
+
819
+ const tableService = new DatabaseTableService();
820
+ const dbManager = DatabaseManager.getInstance();
821
+ const allTables = await dbManager.getUserTables();
822
+
823
+ // Register endpoints for each table
824
+ for (const table of allTables) {
825
+ const tableSchema = await tableService.getTableSchema(table);
826
+ this.registerTableEndpoints(registry, tableSchema);
827
+ }
828
+
829
+ // Generate OpenAPI document
830
+ const generator = new OpenApiGeneratorV3(registry.definitions);
831
+ const document = generator.generateDocument({
832
+ openapi: '3.0.0',
833
+ info: {
834
+ title: 'InsForge Dynamic API',
835
+ version: process.env.npm_package_version || '1.0.0',
836
+ description: 'Automatically generated API documentation for InsForge database tables',
837
+ },
838
+ servers: [
839
+ {
840
+ url: process.env.API_BASE_URL || 'http://localhost:7130',
841
+ description: 'API server',
842
+ },
843
+ ],
844
+ security: [{ ApiKeyAuth: [] }, { BearerAuth: [] }],
845
+ });
846
+
847
+ return document;
848
+ } catch (error) {
849
+ logger.error('Failed to generate OpenAPI document', {
850
+ error: error instanceof Error ? error.message : String(error),
851
+ });
852
+ console.error(error);
853
+ throw error;
854
+ }
855
+ }
856
+ }