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,248 @@
1
+ #!/bin/bash
2
+
3
+ # Test secrets API endpoints (refactored to use _secrets table)
4
+ # Tests CRUD operations for secrets and edge function integration
5
+
6
+ set -e # Exit on error
7
+
8
+ # Get the directory where this script is located
9
+ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
10
+ source "$SCRIPT_DIR/../test-config.sh"
11
+
12
+ # API base URL
13
+ API_BASE="${TEST_API_BASE:-http://localhost:7130/api}"
14
+ DENO_BASE="${DENO_BASE:-http://localhost:7133}"
15
+
16
+ print_blue "🔐 Testing Secrets API (refactored)..."
17
+
18
+ # 1. Test authentication requirement
19
+ print_info "1. Testing authentication requirement for secrets"
20
+ response=$(curl -s -o /dev/null -w "%{http_code}" "$API_BASE/secrets")
21
+ if [ "$response" = "401" ]; then
22
+ print_success "Unauthorized without auth"
23
+ else
24
+ print_fail "Expected 401, got $response"
25
+ track_test_failure
26
+ fi
27
+
28
+ # Get admin token
29
+ print_info "2. Logging in as admin"
30
+ ADMIN_TOKEN=$(get_admin_token)
31
+ if [ -z "$ADMIN_TOKEN" ]; then
32
+ print_fail "Failed to get admin token"
33
+ exit 1
34
+ fi
35
+ print_success "Admin logged in"
36
+
37
+ # 3. List initial secrets (should include BACKEND_INTERNAL_URL)
38
+ print_info "3. Listing initial secrets"
39
+ response=$(curl -s "$API_BASE/secrets" \
40
+ -H "Authorization: Bearer $ADMIN_TOKEN")
41
+
42
+ if echo "$response" | jq -e '.secrets | map(select(.key == "INSFORGE_INTERNAL_URL")) | length == 1' >/dev/null 2>&1; then
43
+ print_success "System secret INSFORGE_INTERNAL_URL exists"
44
+ else
45
+ print_fail "Expected INSFORGE_INTERNAL_URL secret to exist"
46
+ echo "Response: $response"
47
+ track_test_failure
48
+ fi
49
+
50
+ # 4. Create a test secret
51
+ print_info "4. Creating a test secret"
52
+ TEST_KEY="TEST_SECRET_$(date +%s)"
53
+ TEST_VALUE="test_value_12345"
54
+
55
+ response=$(curl -s "$API_BASE/secrets" \
56
+ -X POST \
57
+ -H "Authorization: Bearer $ADMIN_TOKEN" \
58
+ -H "Content-Type: application/json" \
59
+ -d "{\"key\": \"$TEST_KEY\", \"value\": \"$TEST_VALUE\"}")
60
+
61
+ if echo "$response" | grep -q "success.*true"; then
62
+ print_success "Secret created successfully"
63
+ SECRET_ID=$(echo "$response" | jq -r '.id')
64
+ else
65
+ print_fail "Failed to create secret"
66
+ echo "Response: $response"
67
+ track_test_failure
68
+ fi
69
+
70
+ # 5. Get the secret value
71
+ print_info "5. Getting the test secret value"
72
+ response=$(curl -s "$API_BASE/secrets/$TEST_KEY" \
73
+ -H "Authorization: Bearer $ADMIN_TOKEN")
74
+
75
+ if echo "$response" | jq -e ".value == \"$TEST_VALUE\"" >/dev/null 2>&1; then
76
+ print_success "Secret value retrieved correctly"
77
+ else
78
+ print_fail "Failed to retrieve secret value"
79
+ echo "Response: $response"
80
+ track_test_failure
81
+ fi
82
+
83
+ # 6. Update the secret
84
+ print_info "6. Updating the test secret"
85
+ UPDATE_VALUE="updated_value_67890"
86
+
87
+ response=$(curl -s "$API_BASE/secrets/$TEST_KEY" \
88
+ -X PUT \
89
+ -H "Authorization: Bearer $ADMIN_TOKEN" \
90
+ -H "Content-Type: application/json" \
91
+ -d "{\"value\": \"$UPDATE_VALUE\"}")
92
+
93
+ if echo "$response" | grep -q "success.*true"; then
94
+ print_success "Secret updated successfully"
95
+ else
96
+ print_fail "Failed to update secret"
97
+ echo "Response: $response"
98
+ track_test_failure
99
+ fi
100
+
101
+ # 7. Verify update
102
+ print_info "7. Verifying secret update"
103
+ response=$(curl -s "$API_BASE/secrets/$TEST_KEY" \
104
+ -H "Authorization: Bearer $ADMIN_TOKEN")
105
+
106
+ if echo "$response" | jq -e ".value == \"$UPDATE_VALUE\"" >/dev/null 2>&1; then
107
+ print_success "Secret value updated correctly"
108
+ else
109
+ print_fail "Secret value not updated"
110
+ echo "Response: $response"
111
+ track_test_failure
112
+ fi
113
+
114
+ # 8. List secrets and verify our test secret exists
115
+ print_info "8. Verifying secret exists in list"
116
+ response=$(curl -s "$API_BASE/secrets" \
117
+ -H "Authorization: Bearer $ADMIN_TOKEN")
118
+
119
+ if echo "$response" | jq -e ".secrets[] | select(.key == \"$TEST_KEY\")" >/dev/null 2>&1; then
120
+ print_success "Test secret found in list"
121
+ IS_ACTIVE=$(echo "$response" | jq -r ".secrets[] | select(.key == \"$TEST_KEY\") | .isActive")
122
+ if [ "$IS_ACTIVE" = "true" ]; then
123
+ print_success "Secret is active"
124
+ else
125
+ print_fail "Secret is not active"
126
+ track_test_failure
127
+ fi
128
+ else
129
+ print_fail "Test secret not found in list"
130
+ echo "Response: $response"
131
+ track_test_failure
132
+ fi
133
+
134
+ # 9. Test edge function with secret
135
+ print_info "9. Creating edge function to test secret access"
136
+
137
+ # Create a simple function that returns the secret
138
+ cat > /tmp/test-secrets-function.js << EOF
139
+ module.exports = async function(request) {
140
+ const testSecret = Deno.env.get('$TEST_KEY');
141
+ const systemSecret = Deno.env.get('INSFORGE_INTERNAL_URL');
142
+
143
+ return new Response(JSON.stringify({
144
+ testSecretFound: !!testSecret,
145
+ testSecretValue: testSecret === '$UPDATE_VALUE',
146
+ systemSecretFound: !!systemSecret,
147
+ denoEnvWorks: typeof Deno.env.get === 'function'
148
+ }), {
149
+ headers: { 'Content-Type': 'application/json' }
150
+ });
151
+ };
152
+ EOF
153
+
154
+ # Create the function
155
+ FUNCTION_SLUG="test-secrets-fn-$(date +%s)"
156
+ response=$(curl -s -X POST "$API_BASE/functions" \
157
+ -H "Authorization: Bearer $ADMIN_TOKEN" \
158
+ -H "Content-Type: application/json" \
159
+ -d "{
160
+ \"slug\": \"$FUNCTION_SLUG\",
161
+ \"name\": \"Test Secrets Function\",
162
+ \"code\": $(jq -Rs . < /tmp/test-secrets-function.js),
163
+ \"status\": \"active\"
164
+ }")
165
+
166
+ if echo "$response" | grep -q "id"; then
167
+ print_success "Edge function created"
168
+
169
+ # Restart Deno to pick up new secrets
170
+ docker compose restart deno >/dev/null 2>&1
171
+ sleep 3
172
+
173
+ # Test the function
174
+ print_info "10. Testing edge function secret access"
175
+ response=$(curl -s "$DENO_BASE/$FUNCTION_SLUG")
176
+
177
+ if echo "$response" | jq -e '.testSecretValue == true and .systemSecretFound == true' >/dev/null 2>&1; then
178
+ print_success "Edge function can access secrets"
179
+ else
180
+ print_fail "Edge function cannot access secrets properly"
181
+ echo "Response: $response"
182
+ track_test_failure
183
+ fi
184
+
185
+ # Clean up function
186
+ curl -s -X DELETE "$API_BASE/functions/$FUNCTION_SLUG" \
187
+ -H "Authorization: Bearer $ADMIN_TOKEN" >/dev/null 2>&1
188
+ else
189
+ print_fail "Failed to create edge function"
190
+ echo "Response: $response"
191
+ track_test_failure
192
+ fi
193
+
194
+ # 11. Test soft delete (mark as inactive)
195
+ print_info "11. Deleting test secret (soft delete)"
196
+ response=$(curl -s -X DELETE "$API_BASE/secrets/$TEST_KEY" \
197
+ -H "Authorization: Bearer $ADMIN_TOKEN")
198
+
199
+ if echo "$response" | grep -q "success.*true\|deleted"; then
200
+ print_success "Secret deleted successfully"
201
+ else
202
+ print_fail "Failed to delete secret"
203
+ echo "Response: $response"
204
+ track_test_failure
205
+ fi
206
+
207
+ # 12. Verify secret is marked as inactive
208
+ print_info "12. Verifying secret is marked as inactive"
209
+ response=$(curl -s "$API_BASE/secrets" \
210
+ -H "Authorization: Bearer $ADMIN_TOKEN")
211
+
212
+ if echo "$response" | jq -e ".secrets[] | select(.key == \"$TEST_KEY\")" >/dev/null 2>&1; then
213
+ IS_ACTIVE=$(echo "$response" | jq -r ".secrets[] | select(.key == \"$TEST_KEY\") | .isActive")
214
+ if [ "$IS_ACTIVE" = "false" ]; then
215
+ print_success "Secret is marked as inactive (soft delete)"
216
+ else
217
+ print_fail "Secret is still active after deletion"
218
+ echo "isActive: $IS_ACTIVE"
219
+ track_test_failure
220
+ fi
221
+ else
222
+ # Secret might be completely hidden after deletion, which is also fine
223
+ print_success "Secret no longer visible after deletion"
224
+ fi
225
+
226
+ # 13. Test that deleted secret returns 404
227
+ print_info "13. Testing that deleted secret returns 404"
228
+ response_code=$(curl -s -o /dev/null -w "%{http_code}" "$API_BASE/secrets/$TEST_KEY" \
229
+ -H "Authorization: Bearer $ADMIN_TOKEN")
230
+
231
+ if [ "$response_code" = "404" ]; then
232
+ print_success "Deleted secret returns 404"
233
+ else
234
+ print_fail "Expected 404 for deleted secret, got $response_code"
235
+ track_test_failure
236
+ fi
237
+
238
+
239
+ # Clean up
240
+ rm -f /tmp/test-secrets-function.js
241
+
242
+ # Summary
243
+ echo ""
244
+ print_blue "=========================================="
245
+ print_blue "Secrets API Test Complete"
246
+ print_blue "=========================================="
247
+
248
+ exit $TEST_FAILED
@@ -0,0 +1,325 @@
1
+ #!/bin/bash
2
+
3
+ # Fixed Test Script for InsForge Serverless Functions
4
+
5
+ # Get the directory where this script is located
6
+ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
7
+
8
+ # Source the test configuration
9
+ source "$SCRIPT_DIR/../test-config.sh"
10
+
11
+ echo "🧪 InsForge Serverless Functions Test Suite"
12
+ echo "========================================"
13
+ echo ""
14
+
15
+ # Use configuration from test-config.sh
16
+ API_BASE="$TEST_API_BASE"
17
+ # Base URL without /api prefix for function execution
18
+ BASE_URL="${TEST_API_BASE%/api}"
19
+
20
+ # Helper function for section headers
21
+ function section() {
22
+ echo -e "\n${BLUE}▶ $1${NC}"
23
+ echo "----------------------------------------"
24
+ }
25
+
26
+ # Start tests
27
+ section "1. Authentication"
28
+
29
+ TOKEN=$(get_admin_token)
30
+
31
+ if [ -n "$TOKEN" ]; then
32
+ print_success "Admin login"
33
+ else
34
+ print_fail "Admin login - Could not obtain admin token"
35
+ exit 1
36
+ fi
37
+
38
+ section "2. Function CRUD Operations"
39
+
40
+ # Use unique names with timestamp
41
+ TIMESTAMP=$(date +%s)
42
+ FUNC_NAME="test-func-$TIMESTAMP"
43
+ FUNC_SLUG="test-func-$TIMESTAMP" # slug matches name
44
+
45
+ # Create function
46
+ CREATE_RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "$API_BASE/functions" \
47
+ -H "Content-Type: application/json" \
48
+ -H "Authorization: Bearer $TOKEN" \
49
+ -d "{
50
+ \"name\": \"$FUNC_NAME\",
51
+ \"slug\": \"$FUNC_SLUG\",
52
+ \"code\": \"module.exports = async function(req) { return new Response('Hello World'); }\",
53
+ \"status\": \"active\"
54
+ }")
55
+
56
+ HTTP_CODE=$(echo "$CREATE_RESPONSE" | tail -n1)
57
+ if [ "$HTTP_CODE" = "201" ]; then
58
+ print_success "Create function"
59
+ else
60
+ print_fail "Create function - Status: $HTTP_CODE"
61
+ BODY=$(echo "$CREATE_RESPONSE" | sed '$d')
62
+ echo " Response: $BODY"
63
+ fi
64
+
65
+ # Get function
66
+ GET_RESPONSE=$(curl -s -w "\n%{http_code}" -X GET "$API_BASE/functions/$FUNC_SLUG" \
67
+ -H "Authorization: Bearer $TOKEN")
68
+
69
+ HTTP_CODE=$(echo "$GET_RESPONSE" | tail -n1)
70
+ BODY=$(echo "$GET_RESPONSE" | sed '$d')
71
+ if [ "$HTTP_CODE" = "200" ] && echo "$BODY" | grep -q '"code"'; then
72
+ print_success "Get function"
73
+ else
74
+ print_fail "Get function - Status: $HTTP_CODE"
75
+ fi
76
+
77
+ # Update function
78
+ UPDATE_RESPONSE=$(curl -s -w "\n%{http_code}" -X PUT "$API_BASE/functions/$FUNC_SLUG" \
79
+ -H "Content-Type: application/json" \
80
+ -H "Authorization: Bearer $TOKEN" \
81
+ -d '{"code": "module.exports = async function(req) { return new Response(\"Updated!\"); }"}')
82
+
83
+ HTTP_CODE=$(echo "$UPDATE_RESPONSE" | tail -n1)
84
+ if [ "$HTTP_CODE" = "200" ]; then
85
+ print_success "Update function"
86
+ else
87
+ print_fail "Update function - Status: $HTTP_CODE"
88
+ fi
89
+
90
+ # List functions
91
+ LIST_RESPONSE=$(curl -s -w "\n%{http_code}" -X GET "$API_BASE/functions" \
92
+ -H "Authorization: Bearer $TOKEN")
93
+
94
+ HTTP_CODE=$(echo "$LIST_RESPONSE" | tail -n1)
95
+ BODY=$(echo "$LIST_RESPONSE" | sed '$d')
96
+ if [ "$HTTP_CODE" = "200" ] && echo "$BODY" | grep -q "$FUNC_SLUG"; then
97
+ print_success "List functions"
98
+ else
99
+ print_fail "List functions - Status: $HTTP_CODE or missing function"
100
+ fi
101
+
102
+ section "3. Function Execution"
103
+
104
+ # Execute updated function
105
+ EXEC_RESPONSE=$(curl -s -w "\n%{http_code}" "$BASE_URL/functions/$FUNC_SLUG")
106
+ HTTP_CODE=$(echo "$EXEC_RESPONSE" | tail -n1)
107
+ BODY=$(echo "$EXEC_RESPONSE" | sed '$d')
108
+ if [ "$HTTP_CODE" = "200" ] && echo "$BODY" | grep -q "Updated!"; then
109
+ print_success "Execute function"
110
+ else
111
+ print_fail "Execute function - Status: $HTTP_CODE, Body: $BODY"
112
+ fi
113
+
114
+ # Create POST function
115
+ POST_FUNC="post-func-$TIMESTAMP"
116
+ POST_CREATE=$(curl -s -w "\n%{http_code}" -X POST "$API_BASE/functions" \
117
+ -H "Content-Type: application/json" \
118
+ -H "Authorization: Bearer $TOKEN" \
119
+ -d "{
120
+ \"name\": \"$POST_FUNC\",
121
+ \"slug\": \"$POST_FUNC\",
122
+ \"code\": \"module.exports = async function(req) { if (req.method !== 'POST') return new Response('Method Not Allowed', { status: 405 }); const data = await req.json(); return new Response(JSON.stringify({ result: data.value * 2 }), { headers: { 'Content-Type': 'application/json' } }); }\",
123
+ \"status\": \"active\"
124
+ }")
125
+
126
+ HTTP_CODE=$(echo "$POST_CREATE" | tail -n1)
127
+ if [ "$HTTP_CODE" = "201" ]; then
128
+ print_success "Create POST function"
129
+ else
130
+ print_fail "Create POST function - Status: $HTTP_CODE"
131
+ fi
132
+
133
+ # Test POST execution
134
+ POST_EXEC=$(curl -s -w "\n%{http_code}" -X POST "$BASE_URL/functions/$POST_FUNC" \
135
+ -H "Content-Type: application/json" \
136
+ -d '{"value": 21}')
137
+
138
+ HTTP_CODE=$(echo "$POST_EXEC" | tail -n1)
139
+ BODY=$(echo "$POST_EXEC" | sed '$d')
140
+ if [ "$HTTP_CODE" = "200" ] && echo "$BODY" | grep -q '"result":42'; then
141
+ print_success "POST execution"
142
+ else
143
+ print_fail "POST execution - Status: $HTTP_CODE, Body: $BODY"
144
+ fi
145
+
146
+ section "4. Error Status Code Preservation"
147
+
148
+ # Create function that returns 403 Forbidden
149
+ FORBIDDEN_FUNC="forbidden-func-$TIMESTAMP"
150
+ FORBIDDEN_CREATE=$(curl -s -w "\n%{http_code}" -X POST "$API_BASE/functions" \
151
+ -H "Content-Type: application/json" \
152
+ -H "Authorization: Bearer $TOKEN" \
153
+ -d "{
154
+ \"name\": \"$FORBIDDEN_FUNC\",
155
+ \"slug\": \"$FORBIDDEN_FUNC\",
156
+ \"code\": \"module.exports = async function(req) { return new Response(JSON.stringify({ error: 'Access Forbidden' }), { status: 403, headers: { 'Content-Type': 'application/json' } }); }\",
157
+ \"status\": \"active\"
158
+ }")
159
+
160
+ HTTP_CODE=$(echo "$FORBIDDEN_CREATE" | tail -n1)
161
+ if [ "$HTTP_CODE" = "201" ]; then
162
+ # Test execution returns 403
163
+ EXEC_403=$(curl -s -w "\n%{http_code}" "$BASE_URL/functions/$FORBIDDEN_FUNC")
164
+ HTTP_CODE=$(echo "$EXEC_403" | tail -n1)
165
+ BODY=$(echo "$EXEC_403" | sed '$d')
166
+ if [ "$HTTP_CODE" = "403" ] && echo "$BODY" | grep -q "Access Forbidden"; then
167
+ print_success "403 status preserved"
168
+ else
169
+ print_fail "403 status preserved - Expected 403, got $HTTP_CODE"
170
+ fi
171
+ else
172
+ print_fail "Create 403 function - Status: $HTTP_CODE"
173
+ fi
174
+
175
+ # Create function that throws 401 Unauthorized
176
+ UNAUTH_FUNC="unauth-func-$TIMESTAMP"
177
+ UNAUTH_CREATE=$(curl -s -w "\n%{http_code}" -X POST "$API_BASE/functions" \
178
+ -H "Content-Type: application/json" \
179
+ -H "Authorization: Bearer $TOKEN" \
180
+ -d "{
181
+ \"name\": \"$UNAUTH_FUNC\",
182
+ \"slug\": \"$UNAUTH_FUNC\",
183
+ \"code\": \"module.exports = async function(req) { throw new Response(JSON.stringify({ error: 'Unauthorized' }), { status: 401, headers: { 'Content-Type': 'application/json' } }); }\",
184
+ \"status\": \"active\"
185
+ }")
186
+
187
+ HTTP_CODE=$(echo "$UNAUTH_CREATE" | tail -n1)
188
+ if [ "$HTTP_CODE" = "201" ]; then
189
+ # Test execution returns 401
190
+ EXEC_401=$(curl -s -w "\n%{http_code}" "$BASE_URL/functions/$UNAUTH_FUNC")
191
+ HTTP_CODE=$(echo "$EXEC_401" | tail -n1)
192
+ BODY=$(echo "$EXEC_401" | sed '$d')
193
+ if [ "$HTTP_CODE" = "401" ] && echo "$BODY" | grep -q "Unauthorized"; then
194
+ print_success "401 status preserved (thrown)"
195
+ else
196
+ print_fail "401 status preserved (thrown) - Expected 401, got $HTTP_CODE"
197
+ fi
198
+ else
199
+ print_fail "Create 401 function - Status: $HTTP_CODE"
200
+ fi
201
+
202
+ # Create validation function that returns 400 Bad Request
203
+ VALIDATION_FUNC="validation-func-$TIMESTAMP"
204
+ VALIDATION_CREATE=$(curl -s -w "\n%{http_code}" -X POST "$API_BASE/functions" \
205
+ -H "Content-Type: application/json" \
206
+ -H "Authorization: Bearer $TOKEN" \
207
+ -d "{
208
+ \"name\": \"$VALIDATION_FUNC\",
209
+ \"slug\": \"$VALIDATION_FUNC\",
210
+ \"code\": \"module.exports = async function(req) { const url = new URL(req.url); const name = url.searchParams.get('name'); if (!name) { return new Response(JSON.stringify({ error: 'Name parameter required' }), { status: 400, headers: { 'Content-Type': 'application/json' } }); } return new Response(JSON.stringify({ message: 'Hello ' + name }), { headers: { 'Content-Type': 'application/json' } }); }\",
211
+ \"status\": \"active\"
212
+ }")
213
+
214
+ HTTP_CODE=$(echo "$VALIDATION_CREATE" | tail -n1)
215
+ if [ "$HTTP_CODE" = "201" ]; then
216
+ # Test execution without param returns 400
217
+ EXEC_400=$(curl -s -w "\n%{http_code}" "$BASE_URL/functions/$VALIDATION_FUNC")
218
+ HTTP_CODE=$(echo "$EXEC_400" | tail -n1)
219
+ BODY=$(echo "$EXEC_400" | sed '$d')
220
+ if [ "$HTTP_CODE" = "400" ] && echo "$BODY" | grep -q "Name parameter required"; then
221
+ print_success "400 status preserved"
222
+ else
223
+ print_fail "400 status preserved - Expected 400, got $HTTP_CODE"
224
+ fi
225
+
226
+ # Test with valid param returns 200
227
+ EXEC_200=$(curl -s -w "\n%{http_code}" "$BASE_URL/functions/$VALIDATION_FUNC?name=World")
228
+ HTTP_CODE=$(echo "$EXEC_200" | tail -n1)
229
+ BODY=$(echo "$EXEC_200" | sed '$d')
230
+ if [ "$HTTP_CODE" = "200" ] && echo "$BODY" | grep -q "Hello World"; then
231
+ print_success "Validation success (200)"
232
+ else
233
+ print_fail "Validation success - Expected 200, got $HTTP_CODE"
234
+ fi
235
+ else
236
+ print_fail "Create validation function - Status: $HTTP_CODE"
237
+ fi
238
+
239
+ # Create function with real JavaScript error (should be 500)
240
+ ERROR_FUNC="error-func-$TIMESTAMP"
241
+ ERROR_CREATE=$(curl -s -w "\n%{http_code}" -X POST "$API_BASE/functions" \
242
+ -H "Content-Type: application/json" \
243
+ -H "Authorization: Bearer $TOKEN" \
244
+ -d "{
245
+ \"name\": \"$ERROR_FUNC\",
246
+ \"slug\": \"$ERROR_FUNC\",
247
+ \"code\": \"module.exports = async function(req) { throw new Error('Something went wrong'); }\",
248
+ \"status\": \"active\"
249
+ }")
250
+
251
+ HTTP_CODE=$(echo "$ERROR_CREATE" | tail -n1)
252
+ if [ "$HTTP_CODE" = "201" ]; then
253
+ # Test execution returns 500
254
+ EXEC_500=$(curl -s -w "\n%{http_code}" "$BASE_URL/functions/$ERROR_FUNC")
255
+ HTTP_CODE=$(echo "$EXEC_500" | tail -n1)
256
+ BODY=$(echo "$EXEC_500" | sed '$d')
257
+ if [ "$HTTP_CODE" = "500" ] && echo "$BODY" | grep -q "Something went wrong"; then
258
+ print_success "500 for real errors"
259
+ else
260
+ print_fail "500 for real errors - Expected 500, got $HTTP_CODE"
261
+ fi
262
+ else
263
+ print_fail "Create error function - Status: $HTTP_CODE"
264
+ fi
265
+
266
+ section "5. Error Handling"
267
+
268
+ # Duplicate function
269
+ DUP_RESPONSE=$(curl -s -w "\n%{http_code}" -X POST "$API_BASE/functions" \
270
+ -H "Content-Type: application/json" \
271
+ -H "Authorization: Bearer $TOKEN" \
272
+ -d "{
273
+ \"name\": \"$FUNC_NAME\",
274
+ \"slug\": \"$FUNC_SLUG\",
275
+ \"code\": \"module.exports = async function(req) { return new Response('Dup'); }\"
276
+ }")
277
+
278
+ HTTP_CODE=$(echo "$DUP_RESPONSE" | tail -n1)
279
+ if [ "$HTTP_CODE" = "409" ]; then
280
+ print_success "Duplicate rejection"
281
+ else
282
+ print_fail "Duplicate rejection - Expected 409, got $HTTP_CODE"
283
+ fi
284
+
285
+ # No auth
286
+ NO_AUTH=$(curl -s -w "\n%{http_code}" -X GET "$API_BASE/functions")
287
+ HTTP_CODE=$(echo "$NO_AUTH" | tail -n1)
288
+ if [ "$HTTP_CODE" = "401" ]; then
289
+ print_success "Auth required"
290
+ else
291
+ print_fail "Auth required - Expected 401, got $HTTP_CODE"
292
+ fi
293
+
294
+ # Non-existent function
295
+ NOT_FOUND=$(curl -s -w "\n%{http_code}" "$BASE_URL/functions/does-not-exist-$TIMESTAMP")
296
+ HTTP_CODE=$(echo "$NOT_FOUND" | tail -n1)
297
+ if [ "$HTTP_CODE" = "404" ]; then
298
+ print_success "Function not found"
299
+ else
300
+ print_fail "Function not found - Expected 404, got $HTTP_CODE"
301
+ fi
302
+
303
+ section "6. Cleanup"
304
+
305
+ # Delete all test functions
306
+ for slug in "$FUNC_SLUG" "$POST_FUNC" "$FORBIDDEN_FUNC" "$UNAUTH_FUNC" "$VALIDATION_FUNC" "$ERROR_FUNC"; do
307
+ DELETE_RESPONSE=$(curl -s -w "\n%{http_code}" -X DELETE "$API_BASE/functions/$slug" \
308
+ -H "Authorization: Bearer $TOKEN")
309
+
310
+ HTTP_CODE=$(echo "$DELETE_RESPONSE" | tail -n1)
311
+ if [ "$HTTP_CODE" = "200" ]; then
312
+ echo " Deleted: $slug"
313
+ fi
314
+ done
315
+
316
+ # Verify cleanup
317
+ VERIFY=$(curl -s -w "\n%{http_code}" "$BASE_URL/functions/$FUNC_SLUG")
318
+ HTTP_CODE=$(echo "$VERIFY" | tail -n1)
319
+ if [ "$HTTP_CODE" = "404" ]; then
320
+ print_success "Cleanup verified"
321
+ else
322
+ print_fail "Cleanup verification - Expected 404, got $HTTP_CODE"
323
+ fi
324
+
325
+ # Test summary is handled by test-config.sh cleanup function