insforge 1.3.0 → 1.4.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (269) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/auth/package.json +5 -3
  3. package/auth/src/lib/broadcastService.ts +115 -117
  4. package/auth/src/lib/insforge.ts +8 -0
  5. package/auth/src/main.tsx +2 -4
  6. package/auth/src/pages/SignInPage.tsx +60 -60
  7. package/auth/src/pages/SignUpPage.tsx +60 -60
  8. package/auth/src/pages/VerifyEmailPage.tsx +18 -0
  9. package/auth/tsconfig.json +2 -1
  10. package/backend/package.json +10 -6
  11. package/backend/src/api/middlewares/rate-limiters.ts +127 -127
  12. package/backend/src/api/routes/ai/index.routes.ts +475 -468
  13. package/backend/src/api/routes/auth/index.routes.ts +85 -32
  14. package/backend/src/api/routes/auth/oauth.routes.ts +11 -6
  15. package/backend/src/api/routes/database/index.routes.ts +2 -0
  16. package/backend/src/api/routes/database/records.routes.ts +39 -175
  17. package/backend/src/api/routes/database/rpc.routes.ts +69 -0
  18. package/backend/src/api/routes/deployments/index.routes.ts +192 -0
  19. package/backend/src/api/routes/docs/index.routes.ts +3 -2
  20. package/backend/src/api/routes/email/index.routes.ts +35 -35
  21. package/backend/src/api/routes/functions/index.routes.ts +3 -3
  22. package/backend/src/api/routes/metadata/index.routes.ts +26 -0
  23. package/backend/src/api/routes/webhooks/index.routes.ts +109 -0
  24. package/backend/src/infra/database/database.manager.ts +0 -10
  25. package/backend/src/infra/database/migrations/018_schema-rework.sql +441 -0
  26. package/backend/src/infra/database/migrations/019_create-deployments-table.sql +36 -0
  27. package/backend/src/infra/database/migrations/020_add-audio-modality.sql +11 -0
  28. package/backend/src/infra/database/migrations/bootstrap/bootstrap-migrations.js +103 -0
  29. package/backend/src/infra/security/token.manager.ts +1 -4
  30. package/backend/src/providers/ai/openrouter.provider.ts +12 -3
  31. package/backend/src/providers/database/base.provider.ts +39 -0
  32. package/backend/src/providers/database/cloud.provider.ts +159 -0
  33. package/backend/src/providers/deployments/vercel.provider.ts +516 -0
  34. package/backend/src/server.ts +19 -7
  35. package/backend/src/services/ai/ai-config.service.ts +6 -6
  36. package/backend/src/services/ai/ai-model.service.ts +60 -60
  37. package/backend/src/services/ai/ai-usage.service.ts +7 -7
  38. package/backend/src/services/ai/chat-completion.service.ts +415 -220
  39. package/backend/src/services/ai/helpers.ts +64 -64
  40. package/backend/src/services/ai/index.ts +13 -13
  41. package/backend/src/services/auth/auth-config.service.ts +4 -4
  42. package/backend/src/services/auth/auth-otp.service.ts +6 -6
  43. package/backend/src/services/auth/auth.service.ts +134 -74
  44. package/backend/src/services/auth/index.ts +4 -4
  45. package/backend/src/services/auth/oauth-config.service.ts +12 -12
  46. package/backend/src/services/database/database-advance.service.ts +19 -55
  47. package/backend/src/services/database/database-table.service.ts +38 -85
  48. package/backend/src/services/database/postgrest-proxy.service.ts +165 -0
  49. package/backend/src/services/deployments/deployment.service.ts +693 -0
  50. package/backend/src/services/functions/function.service.ts +61 -41
  51. package/backend/src/services/logs/audit.service.ts +10 -10
  52. package/backend/src/services/secrets/secret.service.ts +101 -27
  53. package/backend/src/services/storage/storage.service.ts +30 -30
  54. package/backend/src/services/usage/usage.service.ts +6 -6
  55. package/backend/src/types/ai.ts +8 -0
  56. package/backend/src/types/auth.ts +5 -1
  57. package/backend/src/types/database.ts +2 -0
  58. package/backend/src/types/deployments.ts +33 -0
  59. package/backend/src/types/storage.ts +1 -1
  60. package/backend/src/types/webhooks.ts +45 -0
  61. package/backend/src/utils/cookies.ts +34 -35
  62. package/backend/src/utils/environment.ts +0 -14
  63. package/backend/src/utils/s3-config-loader.ts +64 -64
  64. package/backend/src/utils/seed.ts +334 -301
  65. package/backend/src/utils/sql-parser.ts +126 -0
  66. package/backend/src/utils/utils.ts +114 -114
  67. package/backend/src/utils/validations.ts +10 -10
  68. package/backend/tests/local/test-rpc.sh +141 -0
  69. package/backend/tests/local/test-secrets.sh +1 -1
  70. package/backend/tests/manual/test-ai-model-plugins.sh +258 -0
  71. package/backend/tests/manual/test-rawsql-modes.sh +24 -24
  72. package/backend/tests/unit/database-advance.test.ts +326 -0
  73. package/backend/tests/unit/helpers.test.ts +2 -2
  74. package/claude-plugin/skills/insforge-schema-patterns/SKILL.md +13 -10
  75. package/docker-compose.prod.yml +1 -1
  76. package/docker-compose.yml +1 -1
  77. package/docs/agent-docs/deployment.md +79 -0
  78. package/docs/changelog.mdx +165 -72
  79. package/docs/core-concepts/ai/architecture.mdx +1 -23
  80. package/docs/core-concepts/ai/sdk.mdx +26 -1
  81. package/docs/core-concepts/authentication/architecture.mdx +6 -8
  82. package/docs/core-concepts/authentication/sdk.mdx +387 -91
  83. package/docs/core-concepts/authentication/ui-components/customization.mdx +460 -256
  84. package/docs/core-concepts/authentication/ui-components/nextjs.mdx +50 -24
  85. package/docs/core-concepts/authentication/ui-components/react-router.mdx +18 -19
  86. package/docs/core-concepts/authentication/ui-components/react.mdx +26 -19
  87. package/docs/core-concepts/database/architecture.mdx +58 -21
  88. package/docs/core-concepts/database/pgvector.mdx +138 -0
  89. package/docs/core-concepts/database/sdk.mdx +17 -17
  90. package/docs/core-concepts/deployments/architecture.mdx +152 -0
  91. package/docs/core-concepts/email/architecture.mdx +4 -2
  92. package/docs/core-concepts/functions/architecture.mdx +1 -1
  93. package/docs/core-concepts/functions/sdk.mdx +0 -1
  94. package/docs/core-concepts/realtime/architecture.mdx +1 -1
  95. package/docs/core-concepts/storage/architecture.mdx +1 -1
  96. package/docs/core-concepts/storage/sdk.mdx +25 -25
  97. package/docs/docs.json +14 -6
  98. package/docs/favicon.png +0 -0
  99. package/docs/favicon.svg +3 -18
  100. package/docs/images/changelog/dec-2025/apple-oauth.mp4 +0 -0
  101. package/docs/images/changelog/dec-2025/moreModels.png +0 -0
  102. package/docs/images/changelog/dec-2025/multi-region.webp +0 -0
  103. package/docs/images/changelog/dec-2025/postgres-connection.webp +0 -0
  104. package/docs/images/changelog/dec-2025/realtime2.png +0 -0
  105. package/docs/images/mcp-setup/CC-MCP-1.mp4 +0 -0
  106. package/docs/images/mcp-setup/CC-MCP-2.mp4 +0 -0
  107. package/docs/images/mcp-setup/Cursor-MCP-1.mp4 +0 -0
  108. package/docs/images/mcp-setup/Cursor-MCP-2.mp4 +0 -0
  109. package/docs/images/mcp-setup/Cursor-MCP-3.mp4 +0 -0
  110. package/docs/images/mcp-setup/claude-code-connect.png +0 -0
  111. package/docs/images/mcp-setup/cline-1.png +0 -0
  112. package/docs/images/mcp-setup/cline-2.png +0 -0
  113. package/docs/images/mcp-setup/cline-3.png +0 -0
  114. package/docs/images/mcp-setup/connect-project.png +0 -0
  115. package/docs/images/mcp-setup/copilot-1.png +0 -0
  116. package/docs/images/mcp-setup/copilot-2.png +0 -0
  117. package/docs/images/mcp-setup/copilot-3.png +0 -0
  118. package/docs/images/mcp-setup/mcp-json-1.png +0 -0
  119. package/docs/images/mcp-setup/mcp-json-2.png +0 -0
  120. package/docs/images/mcp-setup/qoder-1.png +0 -0
  121. package/docs/images/mcp-setup/qoder-2.png +0 -0
  122. package/docs/images/mcp-setup/roocode-1.png +0 -0
  123. package/docs/images/mcp-setup/roocode-2.png +0 -0
  124. package/docs/images/mcp-setup/trae-1.png +0 -0
  125. package/docs/images/mcp-setup/trae-2.png +0 -0
  126. package/docs/images/mcp-setup/trae-3.png +0 -0
  127. package/docs/images/mcp-setup/trae-4.png +0 -0
  128. package/docs/images/mcp-setup/trae-5.png +0 -0
  129. package/docs/images/mcp-setup/windsurf-1.png +0 -0
  130. package/docs/images/mcp-setup/windsurf-2.png +0 -0
  131. package/docs/insforge-instructions-sdk.md +7 -3
  132. package/docs/introduction.mdx +9 -8
  133. package/docs/mcp-setup.mdx +332 -0
  134. package/docs/oauth-server.mdx +563 -0
  135. package/docs/partnership.mdx +79 -10
  136. package/docs/quickstart.mdx +1 -1
  137. package/docs/vscode-extension.mdx +74 -0
  138. package/eslint.config.js +1 -0
  139. package/examples/response-examples.md +1 -1
  140. package/frontend/package.json +1 -1
  141. package/frontend/src/App.tsx +8 -3
  142. package/frontend/src/assets/logos/antigravity.svg +1 -0
  143. package/frontend/src/assets/logos/copilot.svg +10 -0
  144. package/frontend/src/assets/logos/deepseek.svg +139 -0
  145. package/frontend/src/assets/logos/kiro.svg +9 -0
  146. package/frontend/src/assets/logos/qoder.svg +4 -0
  147. package/frontend/src/assets/logos/qwen.svg +15 -0
  148. package/frontend/src/components/CodeBlock.tsx +2 -2
  149. package/frontend/src/components/ConnectCTA.tsx +3 -2
  150. package/frontend/src/components/datagrid/DataGrid.tsx +90 -62
  151. package/frontend/src/components/datagrid/datagridTypes.tsx +2 -1
  152. package/frontend/src/components/datagrid/index.ts +1 -1
  153. package/frontend/src/components/index.ts +0 -1
  154. package/frontend/src/components/layout/AppHeader.tsx +4 -27
  155. package/frontend/src/components/layout/AppSidebar.tsx +85 -100
  156. package/frontend/src/components/layout/Layout.tsx +34 -32
  157. package/frontend/src/components/layout/PrimaryMenu.tsx +12 -4
  158. package/frontend/src/components/radix/Select.tsx +151 -151
  159. package/frontend/src/features/ai/components/AIConfigCard.tsx +200 -200
  160. package/frontend/src/features/ai/components/AIEmptyState.tsx +23 -23
  161. package/frontend/src/features/ai/components/ModalityFilterSidebar.tsx +102 -101
  162. package/frontend/src/features/ai/components/ModelSelectionDialog.tsx +135 -135
  163. package/frontend/src/features/ai/components/ModelSelectionGrid.tsx +51 -51
  164. package/frontend/src/features/ai/components/SystemPromptDialog.tsx +118 -118
  165. package/frontend/src/features/ai/components/index.ts +6 -6
  166. package/frontend/src/features/ai/helpers.ts +147 -141
  167. package/frontend/src/features/ai/pages/AIPage.tsx +166 -166
  168. package/frontend/src/features/auth/components/AuthPreview.tsx +96 -96
  169. package/frontend/src/features/auth/components/UsersDataGrid.tsx +55 -31
  170. package/frontend/src/features/auth/components/index.ts +5 -5
  171. package/frontend/src/features/auth/pages/AuthMethodsPage.tsx +275 -275
  172. package/frontend/src/features/dashboard/pages/DashboardPage.tsx +1 -1
  173. package/frontend/src/features/database/components/DatabaseDataGrid.tsx +0 -2
  174. package/frontend/src/features/database/components/ForeignKeyCell.tsx +38 -11
  175. package/frontend/src/features/database/components/ForeignKeyPopover.tsx +18 -8
  176. package/frontend/src/features/database/components/LinkRecordModal.tsx +61 -13
  177. package/frontend/src/features/database/components/RecordFormField.tsx +1 -1
  178. package/frontend/src/features/database/components/TableSidebar.tsx +0 -3
  179. package/frontend/src/features/database/components/TablesEmptyState.tsx +1 -1
  180. package/frontend/src/features/database/components/TemplatePreview.tsx +1 -2
  181. package/frontend/src/features/database/constants.ts +16 -28
  182. package/frontend/src/features/database/hooks/useCSVImport.ts +3 -2
  183. package/frontend/src/features/database/hooks/useRawSQL.ts +3 -2
  184. package/frontend/src/features/database/hooks/useTables.ts +5 -7
  185. package/frontend/src/features/database/pages/FunctionsPage.tsx +0 -5
  186. package/frontend/src/features/database/pages/IndexesPage.tsx +0 -5
  187. package/frontend/src/features/database/pages/PoliciesPage.tsx +0 -5
  188. package/frontend/src/features/database/pages/SQLEditorPage.tsx +2 -2
  189. package/frontend/src/features/database/pages/TriggersPage.tsx +0 -5
  190. package/frontend/src/features/database/services/advance.service.ts +1 -15
  191. package/frontend/src/features/database/services/record.service.ts +4 -20
  192. package/frontend/src/features/database/services/table.service.ts +1 -4
  193. package/frontend/src/features/database/templates/ai-chatbot.ts +6 -6
  194. package/frontend/src/features/database/templates/ecommerce-platform.ts +2 -2
  195. package/frontend/src/features/database/templates/instagram-clone.ts +10 -10
  196. package/frontend/src/features/database/templates/notion-clone.ts +8 -8
  197. package/frontend/src/features/database/templates/reddit-clone.ts +10 -10
  198. package/frontend/src/features/deployments/components/DeploymentRow.tsx +93 -0
  199. package/frontend/src/features/deployments/components/DeploymentsEmptyState.tsx +15 -0
  200. package/frontend/src/features/deployments/hooks/useDeployments.ts +157 -0
  201. package/frontend/src/features/deployments/pages/DeploymentsPage.tsx +318 -0
  202. package/frontend/src/features/deployments/services/deployments.service.ts +63 -0
  203. package/frontend/src/features/functions/components/FunctionRow.tsx +72 -72
  204. package/frontend/src/features/functions/components/FunctionsSidebar.tsx +56 -56
  205. package/frontend/src/features/functions/components/SecretRow.tsx +3 -3
  206. package/frontend/src/features/functions/components/index.ts +5 -5
  207. package/frontend/src/features/functions/hooks/useFunctions.ts +5 -4
  208. package/frontend/src/features/functions/hooks/useSecrets.ts +6 -9
  209. package/frontend/src/features/functions/pages/SecretsPage.tsx +118 -118
  210. package/frontend/src/features/functions/services/function.service.ts +8 -25
  211. package/frontend/src/features/functions/services/secret.service.ts +23 -41
  212. package/frontend/src/features/login/pages/CloudLoginPage.tsx +125 -118
  213. package/frontend/src/features/logs/components/LogDetailPanel.tsx +41 -0
  214. package/frontend/src/features/logs/components/LogsDataGrid.tsx +32 -1
  215. package/frontend/src/features/logs/components/index.ts +1 -0
  216. package/frontend/src/features/logs/pages/LogsPage.tsx +36 -6
  217. package/frontend/src/features/onboard/components/ApiCredentialsSection.tsx +59 -0
  218. package/frontend/src/features/onboard/components/ConnectionStringSection.tsx +180 -0
  219. package/frontend/src/features/onboard/components/McpConnectionSection.tsx +159 -0
  220. package/frontend/src/features/onboard/components/OnboardingController.tsx +68 -0
  221. package/frontend/src/features/onboard/components/OnboardingModal.tsx +121 -267
  222. package/frontend/src/features/onboard/components/ShowPasswordButton.tsx +21 -0
  223. package/frontend/src/features/onboard/components/index.ts +9 -4
  224. package/frontend/src/features/onboard/components/mcp/CursorDeeplinkGenerator.tsx +1 -1
  225. package/frontend/src/features/onboard/components/mcp/QoderDeeplinkGenerator.tsx +36 -0
  226. package/frontend/src/features/onboard/components/mcp/helpers.tsx +123 -98
  227. package/frontend/src/features/onboard/components/mcp/index.ts +4 -3
  228. package/frontend/src/features/onboard/index.ts +17 -13
  229. package/frontend/src/features/settings/pages/SettingsPage.tsx +349 -0
  230. package/frontend/src/features/visualizer/components/AuthNode.tsx +4 -4
  231. package/frontend/src/features/visualizer/components/SchemaVisualizer.tsx +21 -8
  232. package/frontend/src/features/visualizer/pages/VisualizerPage.tsx +10 -1
  233. package/frontend/src/index.css +249 -249
  234. package/frontend/src/lib/contexts/ModalContext.tsx +35 -0
  235. package/frontend/src/lib/hooks/useMetadata.ts +45 -1
  236. package/frontend/src/lib/hooks/useModal.tsx +2 -0
  237. package/frontend/src/lib/routing/AppRoutes.tsx +103 -99
  238. package/frontend/src/lib/services/metadata.service.ts +20 -3
  239. package/frontend/src/lib/utils/menuItems.ts +223 -207
  240. package/frontend/src/lib/utils/utils.ts +196 -196
  241. package/functions/server.ts +315 -315
  242. package/functions/worker-template.js +1 -1
  243. package/openapi/ai.yaml +115 -5
  244. package/openapi/auth.yaml +97 -17
  245. package/openapi/logs.yaml +0 -2
  246. package/openapi/metadata.yaml +0 -2
  247. package/openapi/records.yaml +21 -21
  248. package/openapi/tables.yaml +1 -2
  249. package/package.json +1 -1
  250. package/shared-schemas/package.json +1 -1
  251. package/shared-schemas/src/ai-api.schema.ts +251 -143
  252. package/shared-schemas/src/ai.schema.ts +63 -63
  253. package/shared-schemas/src/auth-api.schema.ts +34 -6
  254. package/shared-schemas/src/auth.schema.ts +17 -10
  255. package/shared-schemas/src/cloud-events.schema.ts +26 -0
  256. package/shared-schemas/src/deployments-api.schema.ts +55 -0
  257. package/shared-schemas/src/deployments.schema.ts +30 -0
  258. package/shared-schemas/src/docs.schema.ts +8 -2
  259. package/shared-schemas/src/email-api.schema.ts +30 -30
  260. package/shared-schemas/src/functions-api.schema.ts +13 -4
  261. package/shared-schemas/src/functions.schema.ts +1 -1
  262. package/shared-schemas/src/index.ts +22 -18
  263. package/shared-schemas/src/metadata.schema.ts +30 -4
  264. package/shared-schemas/src/secrets-api.schema.ts +44 -0
  265. package/shared-schemas/src/secrets.schema.ts +15 -0
  266. package/zeabur/README.md +13 -0
  267. package/zeabur/template.yml +20 -51
  268. package/backend/src/types/profile.ts +0 -55
  269. package/frontend/src/components/ProjectInfoModal.tsx +0 -128
@@ -1,12 +1,13 @@
1
1
  import { useState, useCallback, useMemo } from 'react';
2
2
  import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
3
- import { functionService, type EdgeFunction } from '../services/function.service';
3
+ import { functionService } from '../services/function.service';
4
+ import { FunctionSchema } from '@insforge/shared-schemas';
4
5
  import { useToast } from '@/lib/hooks/useToast';
5
6
 
6
7
  export function useFunctions() {
7
8
  const queryClient = useQueryClient();
8
9
  const { showToast } = useToast();
9
- const [selectedFunction, setSelectedFunction] = useState<EdgeFunction | null>(null);
10
+ const [selectedFunction, setSelectedFunction] = useState<FunctionSchema | null>(null);
10
11
 
11
12
  // Query to fetch all functions
12
13
  const {
@@ -26,7 +27,7 @@ export function useFunctions() {
26
27
 
27
28
  // Function to fetch and set selected function details
28
29
  const selectFunction = useCallback(
29
- async (func: EdgeFunction) => {
30
+ async (func: FunctionSchema) => {
30
31
  try {
31
32
  const data = await functionService.getFunctionBySlug(func.slug);
32
33
  setSelectedFunction(data);
@@ -97,7 +98,7 @@ export function useFunctions() {
97
98
 
98
99
  // Helpers
99
100
  getFunctionBySlug: useCallback(
100
- (slug: string): EdgeFunction | undefined => {
101
+ (slug: string): FunctionSchema | undefined => {
101
102
  return displayFunctions.find((func) => func.slug === slug);
102
103
  },
103
104
  [displayFunctions]
@@ -1,10 +1,7 @@
1
1
  import { useState, useCallback } from 'react';
2
2
  import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
3
- import {
4
- secretService,
5
- type Secret,
6
- type CreateSecretInput,
7
- } from '@/features/functions/services/secret.service';
3
+ import { secretService } from '@/features/functions/services/secret.service';
4
+ import type { SecretSchema, CreateSecretRequest } from '@insforge/shared-schemas';
8
5
  import { useToast } from '@/lib/hooks/useToast';
9
6
  import { useConfirm } from '@/lib/hooks/useConfirm';
10
7
 
@@ -27,11 +24,11 @@ export function useSecrets() {
27
24
  });
28
25
 
29
26
  // Filter out inactive secrets
30
- const secrets = allSecrets.filter((secret: Secret) => secret.isActive);
27
+ const secrets = allSecrets.filter((secret: SecretSchema) => secret.isActive);
31
28
 
32
29
  // Create secret mutation
33
30
  const createSecretMutation = useMutation({
34
- mutationFn: (input: CreateSecretInput) => secretService.createSecret(input),
31
+ mutationFn: (input: CreateSecretRequest) => secretService.createSecret(input),
35
32
  onSuccess: () => {
36
33
  void queryClient.invalidateQueries({ queryKey: ['secrets'] });
37
34
  showToast('Secret created successfully', 'success');
@@ -80,7 +77,7 @@ export function useSecrets() {
80
77
 
81
78
  // Delete secret with confirmation
82
79
  const deleteSecret = useCallback(
83
- async (secret: Secret) => {
80
+ async (secret: SecretSchema) => {
84
81
  if (secret.isReserved) {
85
82
  showToast('Cannot delete reserved secrets', 'error');
86
83
  return false;
@@ -108,7 +105,7 @@ export function useSecrets() {
108
105
  );
109
106
 
110
107
  // Filter secrets based on search query
111
- const filteredSecrets = secrets.filter((secret: Secret) =>
108
+ const filteredSecrets = secrets.filter((secret: SecretSchema) =>
112
109
  secret.key.toLowerCase().includes(searchQuery.toLowerCase())
113
110
  );
114
111
 
@@ -1,118 +1,118 @@
1
- import { useState } from 'react';
2
- import { Button, Input, Skeleton, SearchInput, ConfirmDialog } from '@/components';
3
- import { SecretRow } from '../components/SecretRow';
4
- import SecretEmptyState from '../components/SecretEmptyState';
5
- import { useSecrets } from '@/features/functions/hooks/useSecrets';
6
-
7
- export default function SecretsPage() {
8
- const [newSecretKey, setNewSecretKey] = useState('');
9
- const [newSecretValue, setNewSecretValue] = useState('');
10
-
11
- const {
12
- filteredSecrets,
13
- searchQuery,
14
- setSearchQuery,
15
- isLoading: loading,
16
- createSecret,
17
- deleteSecret,
18
- confirmDialogProps,
19
- } = useSecrets();
20
-
21
- const handleSaveNewSecret = async () => {
22
- const success = await createSecret(newSecretKey, newSecretValue);
23
- if (success) {
24
- setNewSecretKey('');
25
- setNewSecretValue('');
26
- }
27
- };
28
-
29
- return (
30
- <div className="h-full flex flex-col overflow-hidden">
31
- <div className="flex flex-col gap-6 p-4">
32
- {/* Header */}
33
- <p className="h-7 text-xl text-zinc-950 dark:text-white">Secrets</p>
34
-
35
- {/* Add New Secret Portal */}
36
- <div className="bg-white dark:bg-[#333333] rounded-[8px]">
37
- <div className="p-6 border-b border-gray-200 dark:border-neutral-700">
38
- <p className="text-base text-zinc-950 dark:text-white">Add New Secret</p>
39
- </div>
40
- <div className="p-6 flex gap-6 items-end">
41
- <div className="flex-1">
42
- <label className="block text-sm text-zinc-950 dark:text-neutral-50 mb-2">Key</label>
43
- <Input
44
- placeholder="e.g CLIENT_KEY"
45
- value={newSecretKey}
46
- onChange={(e) => setNewSecretKey(e.target.value)}
47
- className="shadow-none w-full dark:bg-neutral-900 dark:text-white dark:placeholder:text-neutral-400 dark:border-neutral-700"
48
- />
49
- </div>
50
- <div className="flex-1">
51
- <label className="block text-sm text-zinc-950 dark:text-neutral-50 mb-2">Value</label>
52
- <Input
53
- placeholder="e.g 1234567890"
54
- type="text"
55
- value={newSecretValue}
56
- onChange={(e) => setNewSecretValue(e.target.value)}
57
- className="shadow-none w-full dark:bg-neutral-900 dark:text-white dark:placeholder:text-neutral-400 dark:border-neutral-700"
58
- />
59
- </div>
60
- <Button
61
- onClick={() => void handleSaveNewSecret()}
62
- className="bg-black hover:bg-zinc-800 dark:bg-emerald-300 dark:hover:bg-emerald-400 dark:text-black text-white px-3 py-2 w-20 h-9 rounded"
63
- disabled={!newSecretKey.trim() || !newSecretValue.trim()}
64
- >
65
- Save
66
- </Button>
67
- </div>
68
- </div>
69
-
70
- {/* Search Bar */}
71
- <SearchInput
72
- placeholder="Search secret"
73
- value={searchQuery}
74
- onChange={setSearchQuery}
75
- className="max-w-70 dark:bg-neutral-900 dark:border-neutral-700"
76
- />
77
-
78
- {/* Secrets Table Header */}
79
- <div className="grid grid-cols-12 px-3 text-sm text-muted-foreground dark:text-neutral-400">
80
- <div className="col-span-8 py-1 px-3">Name</div>
81
- {/* <div className="col-span-5 py-1 px-3">Digest</div> */}
82
- <div className="col-span-3 py-1 px-3">Updated at</div>
83
- <div className="col-span-1 py-1 px-3" />
84
- </div>
85
- </div>
86
-
87
- {/* Scrollable Table Body */}
88
- <div className="flex-1 min-h-0 overflow-y-auto px-4 pb-4">
89
- <div className="flex flex-col gap-2">
90
- {loading ? (
91
- <>
92
- {[...Array(4)].map((_, i) => (
93
- <Skeleton key={i} className="h-14 rounded-[8px] cols-span-full" />
94
- ))}
95
- </>
96
- ) : filteredSecrets.length >= 1 ? (
97
- <>
98
- {filteredSecrets.map((secret) => (
99
- <SecretRow
100
- key={secret.id}
101
- secret={secret}
102
- onDelete={() => void deleteSecret(secret)}
103
- className="cols-span-full"
104
- />
105
- ))}
106
- </>
107
- ) : (
108
- <div className="cols-span-full">
109
- <SecretEmptyState searchQuery={searchQuery} />
110
- </div>
111
- )}
112
- </div>
113
- </div>
114
-
115
- <ConfirmDialog {...confirmDialogProps} />
116
- </div>
117
- );
118
- }
1
+ import { useState } from 'react';
2
+ import { Button, Input, Skeleton, SearchInput, ConfirmDialog } from '@/components';
3
+ import { SecretRow } from '../components/SecretRow';
4
+ import SecretEmptyState from '../components/SecretEmptyState';
5
+ import { useSecrets } from '@/features/functions/hooks/useSecrets';
6
+
7
+ export default function SecretsPage() {
8
+ const [newSecretKey, setNewSecretKey] = useState('');
9
+ const [newSecretValue, setNewSecretValue] = useState('');
10
+
11
+ const {
12
+ filteredSecrets,
13
+ searchQuery,
14
+ setSearchQuery,
15
+ isLoading: loading,
16
+ createSecret,
17
+ deleteSecret,
18
+ confirmDialogProps,
19
+ } = useSecrets();
20
+
21
+ const handleSaveNewSecret = async () => {
22
+ const success = await createSecret(newSecretKey, newSecretValue);
23
+ if (success) {
24
+ setNewSecretKey('');
25
+ setNewSecretValue('');
26
+ }
27
+ };
28
+
29
+ return (
30
+ <div className="h-full flex flex-col overflow-hidden">
31
+ <div className="flex flex-col gap-6 p-4">
32
+ {/* Header */}
33
+ <p className="h-7 text-xl text-zinc-950 dark:text-white">Secrets</p>
34
+
35
+ {/* Add New Secret Portal */}
36
+ <div className="bg-white dark:bg-[#333333] rounded-[8px]">
37
+ <div className="p-6 border-b border-gray-200 dark:border-neutral-700">
38
+ <p className="text-base text-zinc-950 dark:text-white">Add New Secret</p>
39
+ </div>
40
+ <div className="p-6 flex gap-6 items-end">
41
+ <div className="flex-1">
42
+ <label className="block text-sm text-zinc-950 dark:text-neutral-50 mb-2">Key</label>
43
+ <Input
44
+ placeholder="e.g CLIENT_KEY"
45
+ value={newSecretKey}
46
+ onChange={(e) => setNewSecretKey(e.target.value)}
47
+ className="shadow-none w-full dark:bg-neutral-900 dark:text-white dark:placeholder:text-neutral-400 dark:border-neutral-700"
48
+ />
49
+ </div>
50
+ <div className="flex-1">
51
+ <label className="block text-sm text-zinc-950 dark:text-neutral-50 mb-2">Value</label>
52
+ <Input
53
+ placeholder="e.g 1234567890"
54
+ type="text"
55
+ value={newSecretValue}
56
+ onChange={(e) => setNewSecretValue(e.target.value)}
57
+ className="shadow-none w-full dark:bg-neutral-900 dark:text-white dark:placeholder:text-neutral-400 dark:border-neutral-700"
58
+ />
59
+ </div>
60
+ <Button
61
+ onClick={() => void handleSaveNewSecret()}
62
+ className="bg-black hover:bg-zinc-800 dark:bg-emerald-300 dark:hover:bg-emerald-400 dark:text-black text-white px-3 py-2 w-20 h-9 rounded"
63
+ disabled={!newSecretKey.trim() || !newSecretValue.trim()}
64
+ >
65
+ Save
66
+ </Button>
67
+ </div>
68
+ </div>
69
+
70
+ {/* Search Bar */}
71
+ <SearchInput
72
+ placeholder="Search secret"
73
+ value={searchQuery}
74
+ onChange={setSearchQuery}
75
+ className="max-w-70 dark:bg-neutral-900 dark:border-neutral-700"
76
+ />
77
+
78
+ {/* Secrets Table Header */}
79
+ <div className="grid grid-cols-12 px-3 text-sm text-muted-foreground dark:text-neutral-400">
80
+ <div className="col-span-8 py-1 px-3">Name</div>
81
+ {/* <div className="col-span-5 py-1 px-3">Digest</div> */}
82
+ <div className="col-span-3 py-1 px-3">Updated at</div>
83
+ <div className="col-span-1 py-1 px-3" />
84
+ </div>
85
+ </div>
86
+
87
+ {/* Scrollable Table Body */}
88
+ <div className="flex-1 min-h-0 overflow-y-auto px-4 pb-4">
89
+ <div className="flex flex-col gap-2">
90
+ {loading ? (
91
+ <>
92
+ {[...Array(4)].map((_, i) => (
93
+ <Skeleton key={i} className="h-14 rounded-[8px] cols-span-full" />
94
+ ))}
95
+ </>
96
+ ) : filteredSecrets.length >= 1 ? (
97
+ <>
98
+ {filteredSecrets.map((secret) => (
99
+ <SecretRow
100
+ key={secret.id}
101
+ secret={secret}
102
+ onDelete={() => void deleteSecret(secret)}
103
+ className="cols-span-full"
104
+ />
105
+ ))}
106
+ </>
107
+ ) : (
108
+ <div className="cols-span-full">
109
+ <SecretEmptyState searchQuery={searchQuery} />
110
+ </div>
111
+ )}
112
+ </div>
113
+ </div>
114
+
115
+ <ConfirmDialog {...confirmDialogProps} />
116
+ </div>
117
+ );
118
+ }
@@ -1,40 +1,23 @@
1
1
  import { apiClient } from '@/lib/api/client';
2
-
3
- export interface EdgeFunction {
4
- id: string;
5
- slug: string;
6
- name: string;
7
- description?: string;
8
- code?: string;
9
- status: 'draft' | 'active' | 'error';
10
- created_at: string;
11
- updated_at: string;
12
- deployed_at?: string;
13
- }
14
-
15
- export interface FunctionsResponse {
16
- functions: EdgeFunction[];
17
- runtime: {
18
- status: 'running' | 'unavailable';
19
- };
20
- }
2
+ import { FunctionSchema, ListFunctionsResponse } from '@insforge/shared-schemas';
21
3
 
22
4
  export class FunctionService {
23
- async listFunctions(): Promise<FunctionsResponse> {
24
- const data = await apiClient.request('/functions', {
5
+ async listFunctions(): Promise<ListFunctionsResponse> {
6
+ const response: ListFunctionsResponse = await apiClient.request('/functions', {
25
7
  headers: apiClient.withAccessToken(),
26
8
  });
27
9
 
28
10
  return {
29
- functions: Array.isArray(data.functions) ? data.functions : [],
30
- runtime: data.runtime || { status: 'unavailable' },
11
+ functions: Array.isArray(response.functions) ? response.functions : [],
12
+ runtime: response.runtime || { status: 'unavailable' },
31
13
  };
32
14
  }
33
15
 
34
- async getFunctionBySlug(slug: string): Promise<EdgeFunction> {
35
- return apiClient.request(`/functions/${slug}`, {
16
+ async getFunctionBySlug(slug: string): Promise<FunctionSchema> {
17
+ const response: FunctionSchema = await apiClient.request(`/functions/${slug}`, {
36
18
  headers: apiClient.withAccessToken(),
37
19
  });
20
+ return response;
38
21
  }
39
22
 
40
23
  async deleteFunction(slug: string): Promise<void> {
@@ -1,56 +1,38 @@
1
1
  import { apiClient } from '@/lib/api/client';
2
-
3
- export interface Secret {
4
- id: string;
5
- key: string;
6
- isActive: boolean;
7
- isReserved: boolean;
8
- lastUsedAt: string | null;
9
- expiresAt: string | null;
10
- createdAt: string;
11
- updatedAt: string;
12
- }
13
-
14
- export interface CreateSecretInput {
15
- key: string;
16
- value: string;
17
- }
18
-
19
- export interface SecretsListResponse {
20
- secrets: Secret[];
21
- }
22
-
23
- export interface SecretValueResponse {
24
- key: string;
25
- value: string;
26
- }
2
+ import {
3
+ SecretSchema,
4
+ CreateSecretRequest,
5
+ CreateSecretResponse,
6
+ ListSecretsResponse,
7
+ DeleteSecretResponse,
8
+ } from '@insforge/shared-schemas';
27
9
 
28
10
  export class SecretService {
29
- async listSecrets(): Promise<Secret[]> {
11
+ async listSecrets(): Promise<SecretSchema[]> {
30
12
  const data = (await apiClient.request('/secrets', {
31
13
  headers: apiClient.withAccessToken(),
32
- })) as SecretsListResponse;
33
- return data.secrets || [];
14
+ })) as ListSecretsResponse;
15
+ return data.secrets as SecretSchema[];
34
16
  }
35
17
 
36
- async createSecret(
37
- input: CreateSecretInput
38
- ): Promise<{ success: boolean; message: string; id?: string }> {
39
- return apiClient.request('/secrets', {
18
+ async createSecret(input: CreateSecretRequest): Promise<CreateSecretResponse> {
19
+ const response: CreateSecretResponse = await apiClient.request('/secrets', {
40
20
  method: 'POST',
41
- headers: {
42
- 'Content-Type': 'application/json',
43
- ...apiClient.withAccessToken(),
44
- },
21
+ headers: apiClient.withAccessToken(),
45
22
  body: JSON.stringify(input),
46
23
  });
24
+ return response;
47
25
  }
48
26
 
49
- async deleteSecret(key: string): Promise<{ success: boolean; message: string }> {
50
- return apiClient.request(`/secrets/${encodeURIComponent(key)}`, {
51
- method: 'DELETE',
52
- headers: apiClient.withAccessToken(),
53
- });
27
+ async deleteSecret(key: string): Promise<DeleteSecretResponse> {
28
+ const response: DeleteSecretResponse = await apiClient.request(
29
+ `/secrets/${encodeURIComponent(key)}`,
30
+ {
31
+ method: 'DELETE',
32
+ headers: apiClient.withAccessToken(),
33
+ }
34
+ );
35
+ return response;
54
36
  }
55
37
  }
56
38