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,196 +1,196 @@
1
- import { ColumnType } from '@insforge/shared-schemas';
2
- import { type ClassValue, clsx } from 'clsx';
3
- import { twMerge } from 'tailwind-merge';
4
- import { z } from 'zod';
5
- import { format, parse, isValid, parseISO } from 'date-fns';
6
- import {
7
- uuidSchema,
8
- integerSchema,
9
- floatSchema,
10
- booleanSchema,
11
- dateSchema,
12
- dateTimeSchema,
13
- jsonSchema,
14
- stringSchema,
15
- } from './schemaValidations';
16
- import { v4 as uuidv4 } from 'uuid';
17
- import type { ConvertedValue, DisplayValue, ValueConversionResult } from '@/components/datagrid';
18
-
19
- export function cn(...inputs: ClassValue[]) {
20
- return twMerge(clsx(inputs));
21
- }
22
-
23
- /**
24
- * Convert and validate a string value based on the specified ColumnType
25
- */
26
- export function convertValueForColumn(
27
- type: ColumnType | string,
28
- value: string | null | undefined
29
- ): ValueConversionResult {
30
- try {
31
- let convertedValue;
32
-
33
- switch (type) {
34
- case ColumnType.UUID:
35
- convertedValue = uuidSchema.parse(value);
36
- break;
37
- case ColumnType.INTEGER:
38
- convertedValue = integerSchema.parse(value);
39
- break;
40
- case ColumnType.FLOAT:
41
- convertedValue = floatSchema.parse(value);
42
- break;
43
- case ColumnType.BOOLEAN:
44
- convertedValue = booleanSchema.parse(value);
45
- break;
46
- case ColumnType.DATE:
47
- convertedValue = dateSchema.parse(value);
48
- break;
49
- case ColumnType.DATETIME:
50
- convertedValue = dateTimeSchema.parse(value);
51
- break;
52
- case ColumnType.JSON:
53
- convertedValue = jsonSchema.parse(value);
54
- break;
55
- case ColumnType.STRING:
56
- convertedValue = stringSchema.parse(value);
57
- break;
58
- default:
59
- return {
60
- success: false,
61
- error: `Unsupported column type: ${type}`,
62
- };
63
- }
64
-
65
- return {
66
- success: true,
67
- value: convertedValue,
68
- };
69
- } catch (error) {
70
- if (error instanceof z.ZodError) {
71
- return {
72
- success: false,
73
- error: error.errors[0]?.message || 'Validation failed',
74
- };
75
- }
76
- return {
77
- success: false,
78
- error: error instanceof Error ? error.message : 'Unknown conversion error',
79
- };
80
- }
81
- }
82
-
83
- /**
84
- * Generate a UUID v4 using the uuid library
85
- * Works in all browsers and contexts (secure and non-secure)
86
- * Uses crypto.getRandomValues when available, falls back to Math.random
87
- */
88
- export function generateUUID(): string {
89
- return uuidv4();
90
- }
91
-
92
- /**
93
- * Centralized value formatter that handles all data types consistently
94
- * Converts database values to formatted display strings for UI components
95
- */
96
- export function formatValueForDisplay(value: ConvertedValue, type?: ColumnType): DisplayValue {
97
- // Handle null/undefined values
98
- if (isEmptyValue(value)) {
99
- return 'null';
100
- }
101
-
102
- // Handle different column types
103
- switch (type) {
104
- case ColumnType.BOOLEAN:
105
- return value ? 'True' : 'False';
106
-
107
- case ColumnType.DATE: {
108
- const date = parse(String(value), 'yyyy-MM-dd', new Date());
109
- if (!isValid(date)) {
110
- return String(value);
111
- }
112
- const displayValue = format(date, 'MMM dd, yyyy');
113
- return displayValue;
114
- }
115
-
116
- case ColumnType.DATETIME: {
117
- const date = parseISO(String(value));
118
- if (!isValid(date)) {
119
- return String(value);
120
- }
121
- const displayValue = format(date, 'MMM dd, yyyy, hh:mm a');
122
- return displayValue;
123
- }
124
-
125
- case ColumnType.JSON: {
126
- try {
127
- const parsed = typeof value === 'string' ? JSON.parse(value) : value;
128
- const formatted =
129
- parsed && typeof parsed === 'object' ? JSON.stringify(parsed) : String(parsed);
130
-
131
- return formatted;
132
- } catch {
133
- return 'Invalid JSON';
134
- }
135
- }
136
-
137
- case ColumnType.INTEGER:
138
- case ColumnType.FLOAT: {
139
- return String(value);
140
- }
141
-
142
- case ColumnType.UUID:
143
- case ColumnType.STRING:
144
- default: {
145
- // Convert to string and optionally truncate
146
- return String(value);
147
- }
148
- }
149
- }
150
-
151
- /**
152
- * Check if a value is considered empty for database purposes
153
- */
154
- export function isEmptyValue(value: unknown): boolean {
155
- return value === null || value === undefined || value === '';
156
- }
157
-
158
- export const isInsForgeCloudProject = () => {
159
- return window.location.hostname.endsWith('.insforge.app');
160
- };
161
-
162
- export const getBackendUrl = () => {
163
- const isHttp = window.location.protocol === 'http:';
164
- return isHttp ? 'http://localhost:7130' : window.location.origin;
165
- };
166
-
167
- export const isIframe = () => {
168
- return window.self !== window.top;
169
- };
170
-
171
- /**
172
- * Formats a timestamp string to a human-readable format with time
173
- * Used consistently across the application for displaying timestamps
174
- * @param timestamp - ISO timestamp string
175
- * @returns Formatted date string (e.g., "Jan 15, 2025, 03:30 PM")
176
- */
177
- export function formatTime(timestamp: string): string {
178
- const date = parseISO(timestamp);
179
- if (!isValid(date)) {
180
- return timestamp; // Return original if invalid
181
- }
182
- return format(date, 'MMM dd, yyyy, hh:mm a');
183
- }
184
-
185
- /**
186
- * Formats a timestamp string to a date-only format
187
- * @param timestamp - ISO timestamp string
188
- * @returns Formatted date string (e.g., "Jan 15, 2025")
189
- */
190
- export function formatDate(timestamp: string): string {
191
- const date = parseISO(timestamp);
192
- if (!isValid(date)) {
193
- return timestamp; // Return original if invalid
194
- }
195
- return format(date, 'MMM dd, yyyy');
196
- }
1
+ import { ColumnType } from '@insforge/shared-schemas';
2
+ import { type ClassValue, clsx } from 'clsx';
3
+ import { twMerge } from 'tailwind-merge';
4
+ import { z } from 'zod';
5
+ import { format, parse, isValid, parseISO } from 'date-fns';
6
+ import {
7
+ uuidSchema,
8
+ integerSchema,
9
+ floatSchema,
10
+ booleanSchema,
11
+ dateSchema,
12
+ dateTimeSchema,
13
+ jsonSchema,
14
+ stringSchema,
15
+ } from './schemaValidations';
16
+ import { v4 as uuidv4 } from 'uuid';
17
+ import type { ConvertedValue, DisplayValue, ValueConversionResult } from '@/components/datagrid';
18
+
19
+ export function cn(...inputs: ClassValue[]) {
20
+ return twMerge(clsx(inputs));
21
+ }
22
+
23
+ /**
24
+ * Convert and validate a string value based on the specified ColumnType
25
+ */
26
+ export function convertValueForColumn(
27
+ type: ColumnType | string,
28
+ value: string | null | undefined
29
+ ): ValueConversionResult {
30
+ try {
31
+ let convertedValue;
32
+
33
+ switch (type) {
34
+ case ColumnType.UUID:
35
+ convertedValue = uuidSchema.parse(value);
36
+ break;
37
+ case ColumnType.INTEGER:
38
+ convertedValue = integerSchema.parse(value);
39
+ break;
40
+ case ColumnType.FLOAT:
41
+ convertedValue = floatSchema.parse(value);
42
+ break;
43
+ case ColumnType.BOOLEAN:
44
+ convertedValue = booleanSchema.parse(value);
45
+ break;
46
+ case ColumnType.DATE:
47
+ convertedValue = dateSchema.parse(value);
48
+ break;
49
+ case ColumnType.DATETIME:
50
+ convertedValue = dateTimeSchema.parse(value);
51
+ break;
52
+ case ColumnType.JSON:
53
+ convertedValue = jsonSchema.parse(value);
54
+ break;
55
+ case ColumnType.STRING:
56
+ convertedValue = stringSchema.parse(value);
57
+ break;
58
+ default:
59
+ return {
60
+ success: false,
61
+ error: `Unsupported column type: ${type}`,
62
+ };
63
+ }
64
+
65
+ return {
66
+ success: true,
67
+ value: convertedValue,
68
+ };
69
+ } catch (error) {
70
+ if (error instanceof z.ZodError) {
71
+ return {
72
+ success: false,
73
+ error: error.errors[0]?.message || 'Validation failed',
74
+ };
75
+ }
76
+ return {
77
+ success: false,
78
+ error: error instanceof Error ? error.message : 'Unknown conversion error',
79
+ };
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Generate a UUID v4 using the uuid library
85
+ * Works in all browsers and contexts (secure and non-secure)
86
+ * Uses crypto.getRandomValues when available, falls back to Math.random
87
+ */
88
+ export function generateUUID(): string {
89
+ return uuidv4();
90
+ }
91
+
92
+ /**
93
+ * Centralized value formatter that handles all data types consistently
94
+ * Converts database values to formatted display strings for UI components
95
+ */
96
+ export function formatValueForDisplay(value: ConvertedValue, type?: ColumnType): DisplayValue {
97
+ // Handle null/undefined values
98
+ if (isEmptyValue(value)) {
99
+ return 'null';
100
+ }
101
+
102
+ // Handle different column types
103
+ switch (type) {
104
+ case ColumnType.BOOLEAN:
105
+ return value ? 'True' : 'False';
106
+
107
+ case ColumnType.DATE: {
108
+ const date = parse(String(value), 'yyyy-MM-dd', new Date());
109
+ if (!isValid(date)) {
110
+ return String(value);
111
+ }
112
+ const displayValue = format(date, 'MMM dd, yyyy');
113
+ return displayValue;
114
+ }
115
+
116
+ case ColumnType.DATETIME: {
117
+ const date = parseISO(String(value));
118
+ if (!isValid(date)) {
119
+ return String(value);
120
+ }
121
+ const displayValue = format(date, 'MMM dd, yyyy, hh:mm a');
122
+ return displayValue;
123
+ }
124
+
125
+ case ColumnType.JSON: {
126
+ try {
127
+ const parsed = typeof value === 'string' ? JSON.parse(value) : value;
128
+ const formatted =
129
+ parsed && typeof parsed === 'object' ? JSON.stringify(parsed) : String(parsed);
130
+
131
+ return formatted;
132
+ } catch {
133
+ return 'Invalid JSON';
134
+ }
135
+ }
136
+
137
+ case ColumnType.INTEGER:
138
+ case ColumnType.FLOAT: {
139
+ return String(value);
140
+ }
141
+
142
+ case ColumnType.UUID:
143
+ case ColumnType.STRING:
144
+ default: {
145
+ // Convert to string and optionally truncate
146
+ return String(value);
147
+ }
148
+ }
149
+ }
150
+
151
+ /**
152
+ * Check if a value is considered empty for database purposes
153
+ */
154
+ export function isEmptyValue(value: unknown): boolean {
155
+ return value === null || value === undefined || value === '';
156
+ }
157
+
158
+ export const isInsForgeCloudProject = () => {
159
+ return window.location.hostname.endsWith('.insforge.app');
160
+ };
161
+
162
+ export const getBackendUrl = () => {
163
+ const isHttp = window.location.protocol === 'http:';
164
+ return isHttp ? 'http://localhost:7130' : window.location.origin;
165
+ };
166
+
167
+ export const isIframe = () => {
168
+ return window.self !== window.top;
169
+ };
170
+
171
+ /**
172
+ * Formats a timestamp string to a human-readable format with time
173
+ * Used consistently across the application for displaying timestamps
174
+ * @param timestamp - ISO timestamp string
175
+ * @returns Formatted date string (e.g., "Jan 15, 2025, 03:30 PM")
176
+ */
177
+ export function formatTime(timestamp: string): string {
178
+ const date = parseISO(timestamp);
179
+ if (!isValid(date)) {
180
+ return timestamp; // Return original if invalid
181
+ }
182
+ return format(date, 'MMM dd, yyyy, hh:mm a');
183
+ }
184
+
185
+ /**
186
+ * Formats a timestamp string to a date-only format
187
+ * @param timestamp - ISO timestamp string
188
+ * @returns Formatted date string (e.g., "Jan 15, 2025")
189
+ */
190
+ export function formatDate(timestamp: string): string {
191
+ const date = parseISO(timestamp);
192
+ if (!isValid(date)) {
193
+ return timestamp; // Return original if invalid
194
+ }
195
+ return format(date, 'MMM dd, yyyy');
196
+ }