From 6d7121110e81c34c7cb27e43001862ad3c25cae1 Mon Sep 17 00:00:00 2001 From: Adithya Krishna Date: Sat, 21 Mar 2026 01:16:24 +0530 Subject: [PATCH 1/7] feat(loading) show route specific skeleton UI (#3671) * chore: fix conflicts * chore: updated loading states --- apps/sim/app/(auth)/login/loading.tsx | 24 +++++++ apps/sim/app/(auth)/oauth/consent/loading.tsx | 21 ++++++ .../sim/app/(auth)/reset-password/loading.tsx | 16 +++++ apps/sim/app/(auth)/signup/loading.tsx | 28 ++++++++ apps/sim/app/(auth)/sso/loading.tsx | 16 +++++ apps/sim/app/(auth)/verify/loading.tsx | 12 ++++ .../sim/app/(landing)/blog/[slug]/loading.tsx | 59 +++++++++++++++ .../(landing)/blog/authors/[id]/loading.tsx | 25 +++++++ apps/sim/app/(landing)/blog/loading.tsx | 29 ++++++++ apps/sim/app/(landing)/blog/tags/loading.tsx | 20 ++++++ apps/sim/app/(landing)/privacy/loading.tsx | 59 +++++++++++++++ apps/sim/app/(landing)/terms/loading.tsx | 52 ++++++++++++++ apps/sim/app/changelog/loading.tsx | 38 ++++++++++ apps/sim/app/chat/[identifier]/loading.tsx | 39 ++++++++++ .../credential-account/[token]/loading.tsx | 19 +++++ apps/sim/app/form/[identifier]/loading.tsx | 29 ++++++++ apps/sim/app/invite/[id]/loading.tsx | 13 ++++ .../[workflowId]/[executionId]/loading.tsx | 42 +++++++++++ apps/sim/app/templates/[id]/loading.tsx | 55 ++++++++++++++ apps/sim/app/templates/loading.tsx | 36 ++++++++++ apps/sim/app/unsubscribe/loading.tsx | 13 ++++ .../files/[fileId]/view/loading.tsx | 9 +++ .../workspace/[workspaceId]/files/loading.tsx | 62 ++++++++++++++++ .../workspace/[workspaceId]/home/loading.tsx | 22 ++++++ .../knowledge/[id]/[documentId]/loading.tsx | 67 +++++++++++++++++ .../[workspaceId]/knowledge/[id]/loading.tsx | 69 ++++++++++++++++++ .../[workspaceId]/knowledge/loading.tsx | 63 ++++++++++++++++ .../workspace/[workspaceId]/logs/loading.tsx | 71 +++++++++++++++++++ .../[workspaceId]/scheduled-tasks/loading.tsx | 63 ++++++++++++++++ .../settings/[section]/loading.tsx | 15 ++++ .../tables/[tableId]/loading.tsx | 51 +++++++++++++ .../[workspaceId]/tables/loading.tsx | 61 ++++++++++++++++ .../[workspaceId]/templates/[id]/loading.tsx | 47 ++++++++++++ .../[workspaceId]/templates/loading.tsx | 38 ++++++++++ .../[workspaceId]/w/[workflowId]/loading.tsx | 11 +++ .../app/workspace/[workspaceId]/w/loading.tsx | 11 +++ 36 files changed, 1305 insertions(+) create mode 100644 apps/sim/app/(auth)/login/loading.tsx create mode 100644 apps/sim/app/(auth)/oauth/consent/loading.tsx create mode 100644 apps/sim/app/(auth)/reset-password/loading.tsx create mode 100644 apps/sim/app/(auth)/signup/loading.tsx create mode 100644 apps/sim/app/(auth)/sso/loading.tsx create mode 100644 apps/sim/app/(auth)/verify/loading.tsx create mode 100644 apps/sim/app/(landing)/blog/[slug]/loading.tsx create mode 100644 apps/sim/app/(landing)/blog/authors/[id]/loading.tsx create mode 100644 apps/sim/app/(landing)/blog/loading.tsx create mode 100644 apps/sim/app/(landing)/blog/tags/loading.tsx create mode 100644 apps/sim/app/(landing)/privacy/loading.tsx create mode 100644 apps/sim/app/(landing)/terms/loading.tsx create mode 100644 apps/sim/app/changelog/loading.tsx create mode 100644 apps/sim/app/chat/[identifier]/loading.tsx create mode 100644 apps/sim/app/credential-account/[token]/loading.tsx create mode 100644 apps/sim/app/form/[identifier]/loading.tsx create mode 100644 apps/sim/app/invite/[id]/loading.tsx create mode 100644 apps/sim/app/resume/[workflowId]/[executionId]/loading.tsx create mode 100644 apps/sim/app/templates/[id]/loading.tsx create mode 100644 apps/sim/app/templates/loading.tsx create mode 100644 apps/sim/app/unsubscribe/loading.tsx create mode 100644 apps/sim/app/workspace/[workspaceId]/files/[fileId]/view/loading.tsx create mode 100644 apps/sim/app/workspace/[workspaceId]/files/loading.tsx create mode 100644 apps/sim/app/workspace/[workspaceId]/home/loading.tsx create mode 100644 apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/loading.tsx create mode 100644 apps/sim/app/workspace/[workspaceId]/knowledge/[id]/loading.tsx create mode 100644 apps/sim/app/workspace/[workspaceId]/knowledge/loading.tsx create mode 100644 apps/sim/app/workspace/[workspaceId]/logs/loading.tsx create mode 100644 apps/sim/app/workspace/[workspaceId]/scheduled-tasks/loading.tsx create mode 100644 apps/sim/app/workspace/[workspaceId]/settings/[section]/loading.tsx create mode 100644 apps/sim/app/workspace/[workspaceId]/tables/[tableId]/loading.tsx create mode 100644 apps/sim/app/workspace/[workspaceId]/tables/loading.tsx create mode 100644 apps/sim/app/workspace/[workspaceId]/templates/[id]/loading.tsx create mode 100644 apps/sim/app/workspace/[workspaceId]/templates/loading.tsx create mode 100644 apps/sim/app/workspace/[workspaceId]/w/[workflowId]/loading.tsx create mode 100644 apps/sim/app/workspace/[workspaceId]/w/loading.tsx diff --git a/apps/sim/app/(auth)/login/loading.tsx b/apps/sim/app/(auth)/login/loading.tsx new file mode 100644 index 00000000000..e42fb32e2e2 --- /dev/null +++ b/apps/sim/app/(auth)/login/loading.tsx @@ -0,0 +1,24 @@ +import { Skeleton } from '@/components/emcn' + +export default function LoginLoading() { + return ( +
+ +
+ + +
+
+ + +
+ + +
+ + +
+ +
+ ) +} diff --git a/apps/sim/app/(auth)/oauth/consent/loading.tsx b/apps/sim/app/(auth)/oauth/consent/loading.tsx new file mode 100644 index 00000000000..b6c3e192ced --- /dev/null +++ b/apps/sim/app/(auth)/oauth/consent/loading.tsx @@ -0,0 +1,21 @@ +import { Skeleton } from '@/components/emcn' + +export default function OAuthConsentLoading() { + return ( +
+
+ + + +
+ + + + +
+ + +
+
+ ) +} diff --git a/apps/sim/app/(auth)/reset-password/loading.tsx b/apps/sim/app/(auth)/reset-password/loading.tsx new file mode 100644 index 00000000000..cd6a25a9b4f --- /dev/null +++ b/apps/sim/app/(auth)/reset-password/loading.tsx @@ -0,0 +1,16 @@ +import { Skeleton } from '@/components/emcn' + +export default function ResetPasswordLoading() { + return ( +
+ + +
+ + +
+ + +
+ ) +} diff --git a/apps/sim/app/(auth)/signup/loading.tsx b/apps/sim/app/(auth)/signup/loading.tsx new file mode 100644 index 00000000000..4960851a805 --- /dev/null +++ b/apps/sim/app/(auth)/signup/loading.tsx @@ -0,0 +1,28 @@ +import { Skeleton } from '@/components/emcn' + +export default function SignupLoading() { + return ( +
+ +
+ + +
+
+ + +
+
+ + +
+ + +
+ + +
+ +
+ ) +} diff --git a/apps/sim/app/(auth)/sso/loading.tsx b/apps/sim/app/(auth)/sso/loading.tsx new file mode 100644 index 00000000000..11acf1bec75 --- /dev/null +++ b/apps/sim/app/(auth)/sso/loading.tsx @@ -0,0 +1,16 @@ +import { Skeleton } from '@/components/emcn' + +export default function SSOLoading() { + return ( +
+ + +
+ + +
+ + +
+ ) +} diff --git a/apps/sim/app/(auth)/verify/loading.tsx b/apps/sim/app/(auth)/verify/loading.tsx new file mode 100644 index 00000000000..b41b5784f50 --- /dev/null +++ b/apps/sim/app/(auth)/verify/loading.tsx @@ -0,0 +1,12 @@ +import { Skeleton } from '@/components/emcn' + +export default function VerifyLoading() { + return ( +
+ + + + +
+ ) +} diff --git a/apps/sim/app/(landing)/blog/[slug]/loading.tsx b/apps/sim/app/(landing)/blog/[slug]/loading.tsx new file mode 100644 index 00000000000..40352cabef1 --- /dev/null +++ b/apps/sim/app/(landing)/blog/[slug]/loading.tsx @@ -0,0 +1,59 @@ +import { Skeleton } from '@/components/emcn' + +export default function BlogPostLoading() { + return ( +
+ {/* Header area */} +
+ {/* Back link */} +
+ +
+ {/* Image + title row */} +
+ {/* Image */} +
+ +
+ {/* Title + author */} +
+
+ + +
+
+
+ + +
+ +
+
+
+ {/* Divider */} + + {/* Date + description */} +
+ +
+ + +
+
+
+ {/* Article body */} +
+
+ + + + + + + + +
+
+
+ ) +} diff --git a/apps/sim/app/(landing)/blog/authors/[id]/loading.tsx b/apps/sim/app/(landing)/blog/authors/[id]/loading.tsx new file mode 100644 index 00000000000..113e93c8419 --- /dev/null +++ b/apps/sim/app/(landing)/blog/authors/[id]/loading.tsx @@ -0,0 +1,25 @@ +import { Skeleton } from '@/components/emcn' + +const SKELETON_POST_COUNT = 4 + +export default function AuthorLoading() { + return ( +
+
+ + +
+
+ {Array.from({ length: SKELETON_POST_COUNT }).map((_, i) => ( +
+ +
+ + +
+
+ ))} +
+
+ ) +} diff --git a/apps/sim/app/(landing)/blog/loading.tsx b/apps/sim/app/(landing)/blog/loading.tsx new file mode 100644 index 00000000000..5fabbd4e792 --- /dev/null +++ b/apps/sim/app/(landing)/blog/loading.tsx @@ -0,0 +1,29 @@ +import { Skeleton } from '@/components/emcn' + +const SKELETON_CARD_COUNT = 6 + +export default function BlogLoading() { + return ( +
+ + +
+ {Array.from({ length: SKELETON_CARD_COUNT }).map((_, i) => ( +
+ +
+ + + + +
+ + +
+
+
+ ))} +
+
+ ) +} diff --git a/apps/sim/app/(landing)/blog/tags/loading.tsx b/apps/sim/app/(landing)/blog/tags/loading.tsx new file mode 100644 index 00000000000..6c395b3add4 --- /dev/null +++ b/apps/sim/app/(landing)/blog/tags/loading.tsx @@ -0,0 +1,20 @@ +import { Skeleton } from '@/components/emcn' + +const SKELETON_TAG_COUNT = 12 + +export default function TagsLoading() { + return ( +
+ +
+ {Array.from({ length: SKELETON_TAG_COUNT }).map((_, i) => ( + + ))} +
+
+ ) +} diff --git a/apps/sim/app/(landing)/privacy/loading.tsx b/apps/sim/app/(landing)/privacy/loading.tsx new file mode 100644 index 00000000000..98727e7d450 --- /dev/null +++ b/apps/sim/app/(landing)/privacy/loading.tsx @@ -0,0 +1,59 @@ +import { Skeleton } from '@/components/emcn' + +export default function PrivacyLoading() { + return ( +
+
+ +
+ + +
+
+
+ +
+
+ + + + +
+
+ +
+ + + + +
+
+
+ + + +
+ + + + +
+
+
+ + + + + +
+
+ + + + +
+
+
+
+ ) +} diff --git a/apps/sim/app/(landing)/terms/loading.tsx b/apps/sim/app/(landing)/terms/loading.tsx new file mode 100644 index 00000000000..5c9d573cafb --- /dev/null +++ b/apps/sim/app/(landing)/terms/loading.tsx @@ -0,0 +1,52 @@ +import { Skeleton } from '@/components/emcn' + +export default function TermsLoading() { + return ( +
+
+ +
+ + +
+
+
+ +
+
+ + + + +
+
+ + + + + +
+
+ + + + +
+
+ + + + + +
+
+ + + + +
+
+
+
+ ) +} diff --git a/apps/sim/app/changelog/loading.tsx b/apps/sim/app/changelog/loading.tsx new file mode 100644 index 00000000000..e81c5c19e06 --- /dev/null +++ b/apps/sim/app/changelog/loading.tsx @@ -0,0 +1,38 @@ +import { Skeleton } from '@/components/emcn' + +export default function ChangelogLoading() { + return ( +
+
+
+
+ + + + +
+ + + +
+
+
+
+
+ {Array.from({ length: 4 }).map((_, i) => ( +
+ + +
+ + + +
+
+ ))} +
+
+
+
+ ) +} diff --git a/apps/sim/app/chat/[identifier]/loading.tsx b/apps/sim/app/chat/[identifier]/loading.tsx new file mode 100644 index 00000000000..39521ac8912 --- /dev/null +++ b/apps/sim/app/chat/[identifier]/loading.tsx @@ -0,0 +1,39 @@ +import { Skeleton } from '@/components/emcn' + +export default function ChatLoading() { + return ( +
+
+
+
+ + +
+ +
+
+
+
+
+
+ + +
+
+
+ + +
+ +
+
+
+
+
+
+ +
+
+
+ ) +} diff --git a/apps/sim/app/credential-account/[token]/loading.tsx b/apps/sim/app/credential-account/[token]/loading.tsx new file mode 100644 index 00000000000..aa97c96ae0d --- /dev/null +++ b/apps/sim/app/credential-account/[token]/loading.tsx @@ -0,0 +1,19 @@ +import { Skeleton } from '@/components/emcn' + +export default function CredentialAccountLoading() { + return ( +
+
+
+
+ + + + + +
+
+
+
+ ) +} diff --git a/apps/sim/app/form/[identifier]/loading.tsx b/apps/sim/app/form/[identifier]/loading.tsx new file mode 100644 index 00000000000..6c8fd36d0ee --- /dev/null +++ b/apps/sim/app/form/[identifier]/loading.tsx @@ -0,0 +1,29 @@ +import { Skeleton } from '@/components/emcn' + +export default function FormLoading() { + return ( +
+
+
+
+
+ + +
+
+
+ + +
+
+ + +
+ +
+
+
+
+
+ ) +} diff --git a/apps/sim/app/invite/[id]/loading.tsx b/apps/sim/app/invite/[id]/loading.tsx new file mode 100644 index 00000000000..cc73d0ec379 --- /dev/null +++ b/apps/sim/app/invite/[id]/loading.tsx @@ -0,0 +1,13 @@ +import { Skeleton } from '@/components/emcn' + +export default function InviteLoading() { + return ( +
+ + + + + +
+ ) +} diff --git a/apps/sim/app/resume/[workflowId]/[executionId]/loading.tsx b/apps/sim/app/resume/[workflowId]/[executionId]/loading.tsx new file mode 100644 index 00000000000..3c7197a7e96 --- /dev/null +++ b/apps/sim/app/resume/[workflowId]/[executionId]/loading.tsx @@ -0,0 +1,42 @@ +import { Skeleton } from '@/components/emcn' + +export default function ResumeLoading() { + return ( +
+
+
+ + +
+
+
+
+
+ + {Array.from({ length: 3 }).map((_, i) => ( + + ))} +
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+
+
+
+
+ ) +} diff --git a/apps/sim/app/templates/[id]/loading.tsx b/apps/sim/app/templates/[id]/loading.tsx new file mode 100644 index 00000000000..bb9f8c1f1e9 --- /dev/null +++ b/apps/sim/app/templates/[id]/loading.tsx @@ -0,0 +1,55 @@ +import { Skeleton } from '@/components/emcn' + +export default function TemplateDetailLoading() { + return ( +
+
+
+ +
+ + +
+
+
+
+
+ + + +
+ +
+ +
+ + +
+
+ +
+ + + + + +
+ + +
+ + + +
+ +
+ +
+ + +
+
+
+
+ ) +} diff --git a/apps/sim/app/templates/loading.tsx b/apps/sim/app/templates/loading.tsx new file mode 100644 index 00000000000..ae6b87ac503 --- /dev/null +++ b/apps/sim/app/templates/loading.tsx @@ -0,0 +1,36 @@ +import { Skeleton } from '@/components/emcn' + +const SKELETON_CARD_COUNT = 8 + +export default function TemplatesLoading() { + return ( +
+
+
+ +
+ + +
+
+
+
+ +
+ +
+
+ {Array.from({ length: SKELETON_CARD_COUNT }).map((_, i) => ( +
+ +
+ + +
+
+ ))} +
+
+
+ ) +} diff --git a/apps/sim/app/unsubscribe/loading.tsx b/apps/sim/app/unsubscribe/loading.tsx new file mode 100644 index 00000000000..39d410d4245 --- /dev/null +++ b/apps/sim/app/unsubscribe/loading.tsx @@ -0,0 +1,13 @@ +import { Skeleton } from '@/components/emcn' + +export default function UnsubscribeLoading() { + return ( +
+ + + + + +
+ ) +} diff --git a/apps/sim/app/workspace/[workspaceId]/files/[fileId]/view/loading.tsx b/apps/sim/app/workspace/[workspaceId]/files/[fileId]/view/loading.tsx new file mode 100644 index 00000000000..c64c3a39e27 --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/files/[fileId]/view/loading.tsx @@ -0,0 +1,9 @@ +import { Loader2 } from 'lucide-react' + +export default function FileViewLoading() { + return ( +
+ +
+ ) +} diff --git a/apps/sim/app/workspace/[workspaceId]/files/loading.tsx b/apps/sim/app/workspace/[workspaceId]/files/loading.tsx new file mode 100644 index 00000000000..806f4f73b30 --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/files/loading.tsx @@ -0,0 +1,62 @@ +import { Skeleton } from '@/components/emcn' + +const SKELETON_ROW_COUNT = 5 +const COLUMN_COUNT = 6 + +export default function FilesLoading() { + return ( +
+
+
+
+ + +
+
+ + +
+
+
+
+
+ + +
+
+
+ + + + + {Array.from({ length: COLUMN_COUNT }).map((_, i) => ( + + ))} + + + + {Array.from({ length: SKELETON_ROW_COUNT }).map((_, rowIndex) => ( + + + {Array.from({ length: COLUMN_COUNT }).map((_, colIndex) => ( + + ))} + + ))} + +
+ + + +
+ + + +
+
+
+ ) +} diff --git a/apps/sim/app/workspace/[workspaceId]/home/loading.tsx b/apps/sim/app/workspace/[workspaceId]/home/loading.tsx new file mode 100644 index 00000000000..98b656ef94e --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/home/loading.tsx @@ -0,0 +1,22 @@ +import { Skeleton } from '@/components/emcn' + +const SKELETON_LINE_COUNT = 4 + +export default function HomeLoading() { + return ( +
+
+
+ {Array.from({ length: SKELETON_LINE_COUNT }).map((_, i) => ( + + ))} +
+
+
+
+ +
+
+
+ ) +} diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/loading.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/loading.tsx new file mode 100644 index 00000000000..577be0ff2b0 --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/loading.tsx @@ -0,0 +1,67 @@ +import { Skeleton } from '@/components/emcn' + +const SKELETON_ROW_COUNT = 5 +const COLUMN_COUNT = 4 + +export default function DocumentLoading() { + return ( +
+
+
+
+ + + + + + +
+
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + + {Array.from({ length: COLUMN_COUNT }).map((_, i) => ( + + ))} + + + + {Array.from({ length: SKELETON_ROW_COUNT }).map((_, rowIndex) => ( + + + {Array.from({ length: COLUMN_COUNT }).map((_, colIndex) => ( + + ))} + + ))} + +
+ + + +
+ + + +
+
+
+ ) +} diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/loading.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/loading.tsx new file mode 100644 index 00000000000..ad27d19a9a7 --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/loading.tsx @@ -0,0 +1,69 @@ +import { Skeleton } from '@/components/emcn' + +const SKELETON_ROW_COUNT = 5 +const COLUMN_COUNT = 7 + +export default function KnowledgeBaseLoading() { + return ( +
+
+
+
+ + + + +
+
+ +
+
+
+
+
+
+ + +
+
+ + +
+
+
+
+ + + + + {Array.from({ length: COLUMN_COUNT }).map((_, i) => ( + + ))} + + + + {Array.from({ length: SKELETON_ROW_COUNT }).map((_, rowIndex) => ( + + + {Array.from({ length: COLUMN_COUNT }).map((_, colIndex) => ( + + ))} + + ))} + +
+ + + +
+ + + +
+
+
+ ) +} diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/loading.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/loading.tsx new file mode 100644 index 00000000000..acb223d33a7 --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/loading.tsx @@ -0,0 +1,63 @@ +import { Skeleton } from '@/components/emcn' + +const SKELETON_ROW_COUNT = 5 +const COLUMN_COUNT = 6 + +export default function KnowledgeLoading() { + return ( +
+
+
+
+ + +
+
+ +
+
+
+ +
+
+ + +
+
+ +
+ + + + + {Array.from({ length: COLUMN_COUNT }).map((_, i) => ( + + ))} + + + + {Array.from({ length: SKELETON_ROW_COUNT }).map((_, rowIndex) => ( + + + {Array.from({ length: COLUMN_COUNT }).map((_, colIndex) => ( + + ))} + + ))} + +
+ + + +
+ + + +
+
+
+ ) +} diff --git a/apps/sim/app/workspace/[workspaceId]/logs/loading.tsx b/apps/sim/app/workspace/[workspaceId]/logs/loading.tsx new file mode 100644 index 00000000000..6c20d8d3774 --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/logs/loading.tsx @@ -0,0 +1,71 @@ +import { Skeleton } from '@/components/emcn' + +const SKELETON_ROW_COUNT = 5 +const COLUMN_COUNT = 6 + +export default function LogsLoading() { + return ( +
+
+
+
+ + +
+
+ + + + + +
+
+
+
+
+
+ + +
+
+ + +
+
+
+
+ + + + + {Array.from({ length: COLUMN_COUNT }).map((_, i) => ( + + ))} + + + + {Array.from({ length: SKELETON_ROW_COUNT }).map((_, rowIndex) => ( + + + {Array.from({ length: COLUMN_COUNT }).map((_, colIndex) => ( + + ))} + + ))} + +
+ + + +
+ + + +
+
+
+ ) +} diff --git a/apps/sim/app/workspace/[workspaceId]/scheduled-tasks/loading.tsx b/apps/sim/app/workspace/[workspaceId]/scheduled-tasks/loading.tsx new file mode 100644 index 00000000000..4bdba810493 --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/scheduled-tasks/loading.tsx @@ -0,0 +1,63 @@ +import { Skeleton } from '@/components/emcn' + +const SKELETON_ROW_COUNT = 5 +const COLUMN_COUNT = 4 + +export default function ScheduledTasksLoading() { + return ( +
+
+
+
+ + +
+
+ +
+
+
+
+
+ + +
+
+
+ + + + + {Array.from({ length: COLUMN_COUNT }).map((_, i) => ( + + ))} + + + + {Array.from({ length: SKELETON_ROW_COUNT }).map((_, rowIndex) => ( + + + {Array.from({ length: COLUMN_COUNT }).map((_, colIndex) => ( + + ))} + + ))} + +
+ + + +
+ + + +
+
+
+ ) +} diff --git a/apps/sim/app/workspace/[workspaceId]/settings/[section]/loading.tsx b/apps/sim/app/workspace/[workspaceId]/settings/[section]/loading.tsx new file mode 100644 index 00000000000..1413bedfc79 --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/settings/[section]/loading.tsx @@ -0,0 +1,15 @@ +import { Skeleton } from '@/components/emcn' + +export default function SettingsLoading() { + return ( +
+ +
+ + + + +
+
+ ) +} diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/loading.tsx b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/loading.tsx new file mode 100644 index 00000000000..3eb4cd58d01 --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/loading.tsx @@ -0,0 +1,51 @@ +import { Skeleton } from '@/components/emcn' + +const SKELETON_ROW_COUNT = 8 +const COLUMN_COUNT = 5 + +export default function TableDetailLoading() { + return ( +
+
+
+
+ + + + +
+
+ +
+
+
+
+ + + + {Array.from({ length: COLUMN_COUNT }).map((_, i) => ( + + ))} + + + + {Array.from({ length: SKELETON_ROW_COUNT }).map((_, rowIndex) => ( + + {Array.from({ length: COLUMN_COUNT }).map((_, colIndex) => ( + + ))} + + ))} + +
+ +
+ +
+
+
+ ) +} diff --git a/apps/sim/app/workspace/[workspaceId]/tables/loading.tsx b/apps/sim/app/workspace/[workspaceId]/tables/loading.tsx new file mode 100644 index 00000000000..2ce948245ec --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/tables/loading.tsx @@ -0,0 +1,61 @@ +import { Skeleton } from '@/components/emcn' + +const SKELETON_ROW_COUNT = 5 +const COLUMN_COUNT = 6 + +export default function TablesLoading() { + return ( +
+
+
+
+ + +
+
+ +
+
+
+
+
+ + +
+
+
+ + + + + {Array.from({ length: COLUMN_COUNT }).map((_, i) => ( + + ))} + + + + {Array.from({ length: SKELETON_ROW_COUNT }).map((_, rowIndex) => ( + + + {Array.from({ length: COLUMN_COUNT }).map((_, colIndex) => ( + + ))} + + ))} + +
+ + + +
+ + + +
+
+
+ ) +} diff --git a/apps/sim/app/workspace/[workspaceId]/templates/[id]/loading.tsx b/apps/sim/app/workspace/[workspaceId]/templates/[id]/loading.tsx new file mode 100644 index 00000000000..f10ed17843c --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/templates/[id]/loading.tsx @@ -0,0 +1,47 @@ +import { Skeleton } from '@/components/emcn' + +export default function TemplateDetailLoading() { + return ( +
+
+
+
+ + + +
+
+ +
+ + +
+
+ +
+ + + + + +
+ + +
+ + + +
+ +
+ +
+ + +
+
+
+
+
+ ) +} diff --git a/apps/sim/app/workspace/[workspaceId]/templates/loading.tsx b/apps/sim/app/workspace/[workspaceId]/templates/loading.tsx new file mode 100644 index 00000000000..41ae5d297d8 --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/templates/loading.tsx @@ -0,0 +1,38 @@ +import { Skeleton } from '@/components/emcn' + +const SKELETON_CARD_COUNT = 8 + +export default function TemplatesLoading() { + return ( +
+
+
+
+ + +
+ + +
+ +
+ + +
+
+
+ {Array.from({ length: SKELETON_CARD_COUNT }).map((_, i) => ( +
+ +
+ + +
+
+ ))} +
+
+
+
+ ) +} diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/loading.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/loading.tsx new file mode 100644 index 00000000000..6a65da73c7e --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/loading.tsx @@ -0,0 +1,11 @@ +import { Loader2 } from 'lucide-react' + +export default function WorkflowLoading() { + return ( +
+
+ +
+
+ ) +} diff --git a/apps/sim/app/workspace/[workspaceId]/w/loading.tsx b/apps/sim/app/workspace/[workspaceId]/w/loading.tsx new file mode 100644 index 00000000000..9bb97126c6a --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/w/loading.tsx @@ -0,0 +1,11 @@ +import { Loader2 } from 'lucide-react' + +export default function WorkflowsLoading() { + return ( +
+
+ +
+
+ ) +} From e270756886beffb9b5fa4103de9926aa2720c9bf Mon Sep 17 00:00:00 2001 From: Vikhyath Mondreti Date: Fri, 20 Mar 2026 15:23:44 -0700 Subject: [PATCH 2/7] fix(kb): max depth exceeded chunks page error (#3695) --- apps/sim/hooks/kb/use-knowledge-base-tag-definitions.ts | 6 ++++-- apps/sim/hooks/kb/use-tag-definitions.ts | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/sim/hooks/kb/use-knowledge-base-tag-definitions.ts b/apps/sim/hooks/kb/use-knowledge-base-tag-definitions.ts index 1a90410bbb2..5ca10cbf7c5 100644 --- a/apps/sim/hooks/kb/use-knowledge-base-tag-definitions.ts +++ b/apps/sim/hooks/kb/use-knowledge-base-tag-definitions.ts @@ -1,6 +1,6 @@ 'use client' -import { useCallback } from 'react' +import { useCallback, useMemo } from 'react' import { useQueryClient } from '@tanstack/react-query' import type { AllTagSlot } from '@/lib/knowledge/constants' import { knowledgeKeys, useTagDefinitionsQuery } from '@/hooks/queries/kb/knowledge' @@ -29,8 +29,10 @@ export function useKnowledgeBaseTagDefinitions(knowledgeBaseId: string | null) { }) }, [queryClient, knowledgeBaseId]) + const tagDefinitions = useMemo(() => (query.data ?? []) as TagDefinition[], [query.data]) + return { - tagDefinitions: (query.data ?? []) as TagDefinition[], + tagDefinitions, isLoading: query.isLoading, error: query.error instanceof Error ? query.error.message : null, fetchTagDefinitions, diff --git a/apps/sim/hooks/kb/use-tag-definitions.ts b/apps/sim/hooks/kb/use-tag-definitions.ts index f328c5f57d6..19e6efee8ac 100644 --- a/apps/sim/hooks/kb/use-tag-definitions.ts +++ b/apps/sim/hooks/kb/use-tag-definitions.ts @@ -1,6 +1,6 @@ 'use client' -import { useCallback } from 'react' +import { useCallback, useMemo } from 'react' import { useQueryClient } from '@tanstack/react-query' import type { AllTagSlot } from '@/lib/knowledge/constants' import { @@ -40,7 +40,7 @@ export function useTagDefinitions( const { mutateAsync: saveTagDefinitionsMutation } = useSaveDocumentTagDefinitions() const { mutateAsync: deleteTagDefinitionsMutation } = useDeleteDocumentTagDefinitions() - const tagDefinitions = (query.data ?? []) as TagDefinition[] + const tagDefinitions = useMemo(() => (query.data ?? []) as TagDefinition[], [query.data]) const fetchTagDefinitions = useCallback(async () => { if (!knowledgeBaseId || !documentId) return From a64afac075967a02d626bd61cb7bb71db352adbb Mon Sep 17 00:00:00 2001 From: Waleed Date: Sat, 21 Mar 2026 09:36:43 -0700 Subject: [PATCH 3/7] feat(kb): harden sync engine and add connector audit logging (#3697) * feat(kb): harden sync engine and add connector audit logging - Fix stuck syncing status: added finally block in executeSync + stale lock recovery in cron scheduler (2hr TTL) - Fix token expiry mid-sync: refresh OAuth token between pagination pages and before deferred content hydration - GitHub deferred content loading: use Git blob SHA for change detection, only fetch content for new/changed docs - Add network error keywords to isRetryableError (fetch failed, econnreset, etc.) - Extract sanitizeStorageTitle helper to fix S3 key length limit issues - Add audit logging for connector CRUD, sync triggers, document exclude/restore, and resource restoration paths * lint * fix(tests): update audit mock and route tests for new audit actions * fix(kb): address PR review - finally block race, contentHash propagation, resourceName - Replace DB-read finally block with local syncExitedCleanly flag to avoid race condition - Propagate fullDoc.contentHash during deferred content hydration - Add resourceName to file restore audit record * fix(audit): include fileId in file restore audit description --- .../[connectorId]/documents/route.test.ts | 29 +++++- .../[connectorId]/documents/route.ts | 27 ++++++ .../connectors/[connectorId]/route.test.ts | 29 +++++- .../[id]/connectors/[connectorId]/route.ts | 32 ++++++- .../[connectorId]/sync/route.test.ts | 17 +++- .../connectors/[connectorId]/sync/route.ts | 15 +++ .../api/knowledge/[id]/connectors/route.ts | 15 +++ .../app/api/knowledge/[id]/restore/route.ts | 15 +++ .../api/knowledge/connectors/sync/route.ts | 28 ++++++ .../app/api/table/[tableId]/restore/route.ts | 14 +++ .../app/api/workflows/[id]/restore/route.ts | 14 +++ .../[id]/files/[fileId]/restore/route.ts | 14 +++ .../workspace/[workspaceId]/files/loading.tsx | 8 +- .../knowledge/[id]/[documentId]/loading.tsx | 8 +- .../[workspaceId]/knowledge/[id]/loading.tsx | 8 +- .../[workspaceId]/knowledge/loading.tsx | 8 +- .../workspace/[workspaceId]/logs/loading.tsx | 8 +- .../[workspaceId]/scheduled-tasks/loading.tsx | 8 +- .../tables/[tableId]/loading.tsx | 6 +- .../[workspaceId]/tables/loading.tsx | 8 +- apps/sim/connectors/github/github.ts | 76 +++------------ apps/sim/connectors/types.ts | 4 +- apps/sim/lib/audit/log.ts | 15 +++ .../lib/knowledge/connectors/sync-engine.ts | 92 ++++++++++++++++++- apps/sim/lib/knowledge/documents/service.ts | 1 - apps/sim/lib/knowledge/documents/utils.ts | 21 ++++- packages/testing/src/mocks/audit.mock.ts | 11 +++ 27 files changed, 417 insertions(+), 114 deletions(-) diff --git a/apps/sim/app/api/knowledge/[id]/connectors/[connectorId]/documents/route.test.ts b/apps/sim/app/api/knowledge/[id]/connectors/[connectorId]/documents/route.test.ts index 4c34f2e5ffa..132ddfb1ba8 100644 --- a/apps/sim/app/api/knowledge/[id]/connectors/[connectorId]/documents/route.test.ts +++ b/apps/sim/app/api/knowledge/[id]/connectors/[connectorId]/documents/route.test.ts @@ -53,6 +53,11 @@ vi.mock('@/lib/auth/hybrid', () => ({ vi.mock('@/lib/core/utils/request', () => ({ generateRequestId: vi.fn().mockReturnValue('test-req-id'), })) +vi.mock('@/lib/audit/log', () => ({ + recordAudit: vi.fn(), + AuditAction: {}, + AuditResourceType: {}, +})) import { GET, PATCH } from '@/app/api/knowledge/[id]/connectors/[connectorId]/documents/route' @@ -168,8 +173,16 @@ describe('Connector Documents API Route', () => { }) it('returns success for restore operation', async () => { - mockCheckSession.mockResolvedValue({ success: true, userId: 'user-1' }) - mockCheckWriteAccess.mockResolvedValue({ hasAccess: true }) + mockCheckSession.mockResolvedValue({ + success: true, + userId: 'user-1', + userName: 'Test', + userEmail: 'test@test.com', + }) + mockCheckWriteAccess.mockResolvedValue({ + hasAccess: true, + knowledgeBase: { workspaceId: 'ws-1', name: 'Test KB' }, + }) mockDbChain.limit.mockResolvedValueOnce([{ id: 'conn-456' }]) mockDbChain.returning.mockResolvedValueOnce([{ id: 'doc-1' }]) @@ -182,8 +195,16 @@ describe('Connector Documents API Route', () => { }) it('returns success for exclude operation', async () => { - mockCheckSession.mockResolvedValue({ success: true, userId: 'user-1' }) - mockCheckWriteAccess.mockResolvedValue({ hasAccess: true }) + mockCheckSession.mockResolvedValue({ + success: true, + userId: 'user-1', + userName: 'Test', + userEmail: 'test@test.com', + }) + mockCheckWriteAccess.mockResolvedValue({ + hasAccess: true, + knowledgeBase: { workspaceId: 'ws-1', name: 'Test KB' }, + }) mockDbChain.limit.mockResolvedValueOnce([{ id: 'conn-456' }]) mockDbChain.returning.mockResolvedValueOnce([{ id: 'doc-2' }, { id: 'doc-3' }]) diff --git a/apps/sim/app/api/knowledge/[id]/connectors/[connectorId]/documents/route.ts b/apps/sim/app/api/knowledge/[id]/connectors/[connectorId]/documents/route.ts index 0b5e64c528d..48e0d0deb2d 100644 --- a/apps/sim/app/api/knowledge/[id]/connectors/[connectorId]/documents/route.ts +++ b/apps/sim/app/api/knowledge/[id]/connectors/[connectorId]/documents/route.ts @@ -4,6 +4,7 @@ import { createLogger } from '@sim/logger' import { and, eq, inArray, isNull } from 'drizzle-orm' import { type NextRequest, NextResponse } from 'next/server' import { z } from 'zod' +import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { generateRequestId } from '@/lib/core/utils/request' import { checkKnowledgeBaseAccess, checkKnowledgeBaseWriteAccess } from '@/app/api/knowledge/utils' @@ -184,6 +185,19 @@ export async function PATCH(request: NextRequest, { params }: RouteParams) { logger.info(`[${requestId}] Restored ${updated.length} excluded documents`, { connectorId }) + recordAudit({ + workspaceId: writeCheck.knowledgeBase.workspaceId, + actorId: auth.userId, + actorName: auth.userName, + actorEmail: auth.userEmail, + action: AuditAction.CONNECTOR_DOCUMENT_RESTORED, + resourceType: AuditResourceType.CONNECTOR, + resourceId: connectorId, + description: `Restored ${updated.length} excluded document(s) for knowledge base "${writeCheck.knowledgeBase.name}"`, + metadata: { knowledgeBaseId, documentCount: updated.length }, + request, + }) + return NextResponse.json({ success: true, data: { restoredCount: updated.length, documentIds: updated.map((d) => d.id) }, @@ -206,6 +220,19 @@ export async function PATCH(request: NextRequest, { params }: RouteParams) { logger.info(`[${requestId}] Excluded ${updated.length} documents`, { connectorId }) + recordAudit({ + workspaceId: writeCheck.knowledgeBase.workspaceId, + actorId: auth.userId, + actorName: auth.userName, + actorEmail: auth.userEmail, + action: AuditAction.CONNECTOR_DOCUMENT_EXCLUDED, + resourceType: AuditResourceType.CONNECTOR, + resourceId: connectorId, + description: `Excluded ${updated.length} document(s) from knowledge base "${writeCheck.knowledgeBase.name}"`, + metadata: { knowledgeBaseId, documentCount: updated.length }, + request, + }) + return NextResponse.json({ success: true, data: { excludedCount: updated.length, documentIds: updated.map((d) => d.id) }, diff --git a/apps/sim/app/api/knowledge/[id]/connectors/[connectorId]/route.test.ts b/apps/sim/app/api/knowledge/[id]/connectors/[connectorId]/route.test.ts index c39c7866b69..dd2f4fb1984 100644 --- a/apps/sim/app/api/knowledge/[id]/connectors/[connectorId]/route.test.ts +++ b/apps/sim/app/api/knowledge/[id]/connectors/[connectorId]/route.test.ts @@ -75,6 +75,11 @@ vi.mock('@/lib/knowledge/tags/service', () => ({ vi.mock('@/lib/knowledge/documents/service', () => ({ deleteDocumentStorageFiles: vi.fn().mockResolvedValue(undefined), })) +vi.mock('@/lib/audit/log', () => ({ + recordAudit: vi.fn(), + AuditAction: {}, + AuditResourceType: {}, +})) import { DELETE, GET, PATCH } from '@/app/api/knowledge/[id]/connectors/[connectorId]/route' @@ -183,8 +188,16 @@ describe('Knowledge Connector By ID API Route', () => { }) it('returns 200 and updates status', async () => { - mockCheckSession.mockResolvedValue({ success: true, userId: 'user-1' }) - mockCheckWriteAccess.mockResolvedValue({ hasAccess: true }) + mockCheckSession.mockResolvedValue({ + success: true, + userId: 'user-1', + userName: 'Test', + userEmail: 'test@test.com', + }) + mockCheckWriteAccess.mockResolvedValue({ + hasAccess: true, + knowledgeBase: { workspaceId: 'ws-1', name: 'Test KB' }, + }) const updatedConnector = { id: 'conn-456', status: 'paused', syncIntervalMinutes: 120 } mockDbChain.limit.mockResolvedValueOnce([updatedConnector]) @@ -210,8 +223,16 @@ describe('Knowledge Connector By ID API Route', () => { }) it('returns 200 on successful hard-delete', async () => { - mockCheckSession.mockResolvedValue({ success: true, userId: 'user-1' }) - mockCheckWriteAccess.mockResolvedValue({ hasAccess: true }) + mockCheckSession.mockResolvedValue({ + success: true, + userId: 'user-1', + userName: 'Test', + userEmail: 'test@test.com', + }) + mockCheckWriteAccess.mockResolvedValue({ + hasAccess: true, + knowledgeBase: { workspaceId: 'ws-1', name: 'Test KB' }, + }) mockDbChain.where .mockReturnValueOnce(mockDbChain) .mockResolvedValueOnce([{ id: 'doc-1', fileUrl: '/api/uploads/test.txt' }]) diff --git a/apps/sim/app/api/knowledge/[id]/connectors/[connectorId]/route.ts b/apps/sim/app/api/knowledge/[id]/connectors/[connectorId]/route.ts index cfdca60afa0..0d8212c98fd 100644 --- a/apps/sim/app/api/knowledge/[id]/connectors/[connectorId]/route.ts +++ b/apps/sim/app/api/knowledge/[id]/connectors/[connectorId]/route.ts @@ -11,6 +11,7 @@ import { and, desc, eq, inArray, isNull, sql } from 'drizzle-orm' import { type NextRequest, NextResponse } from 'next/server' import { z } from 'zod' import { decryptApiKey } from '@/lib/api-key/crypto' +import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { generateRequestId } from '@/lib/core/utils/request' import { deleteDocumentStorageFiles } from '@/lib/knowledge/documents/service' @@ -233,6 +234,21 @@ export async function PATCH(request: NextRequest, { params }: RouteParams) { .limit(1) const { encryptedApiKey: __, ...updatedData } = updated[0] + + recordAudit({ + workspaceId: writeCheck.knowledgeBase.workspaceId, + actorId: auth.userId, + actorName: auth.userName, + actorEmail: auth.userEmail, + action: AuditAction.CONNECTOR_UPDATED, + resourceType: AuditResourceType.CONNECTOR, + resourceId: connectorId, + resourceName: updatedData.connectorType, + description: `Updated connector for knowledge base "${writeCheck.knowledgeBase.name}"`, + metadata: { knowledgeBaseId, updatedFields: Object.keys(parsed.data) }, + request, + }) + return NextResponse.json({ success: true, data: updatedData }) } catch (error) { logger.error(`[${requestId}] Error updating connector`, error) @@ -260,7 +276,7 @@ export async function DELETE(request: NextRequest, { params }: RouteParams) { } const existingConnector = await db - .select({ id: knowledgeConnector.id }) + .select({ id: knowledgeConnector.id, connectorType: knowledgeConnector.connectorType }) .from(knowledgeConnector) .where( and( @@ -323,6 +339,20 @@ export async function DELETE(request: NextRequest, { params }: RouteParams) { logger.info(`[${requestId}] Hard-deleted connector ${connectorId} and its documents`) + recordAudit({ + workspaceId: writeCheck.knowledgeBase.workspaceId, + actorId: auth.userId, + actorName: auth.userName, + actorEmail: auth.userEmail, + action: AuditAction.CONNECTOR_DELETED, + resourceType: AuditResourceType.CONNECTOR, + resourceId: connectorId, + resourceName: existingConnector[0].connectorType, + description: `Deleted connector from knowledge base "${writeCheck.knowledgeBase.name}"`, + metadata: { knowledgeBaseId, documentsDeleted: connectorDocuments.length }, + request, + }) + return NextResponse.json({ success: true }) } catch (error) { logger.error(`[${requestId}] Error deleting connector`, error) diff --git a/apps/sim/app/api/knowledge/[id]/connectors/[connectorId]/sync/route.test.ts b/apps/sim/app/api/knowledge/[id]/connectors/[connectorId]/sync/route.test.ts index 12a873a6f43..af517a61bb4 100644 --- a/apps/sim/app/api/knowledge/[id]/connectors/[connectorId]/sync/route.test.ts +++ b/apps/sim/app/api/knowledge/[id]/connectors/[connectorId]/sync/route.test.ts @@ -43,6 +43,11 @@ vi.mock('@/lib/core/utils/request', () => ({ vi.mock('@/lib/knowledge/connectors/sync-engine', () => ({ dispatchSync: mockDispatchSync, })) +vi.mock('@/lib/audit/log', () => ({ + recordAudit: vi.fn(), + AuditAction: {}, + AuditResourceType: {}, +})) import { POST } from '@/app/api/knowledge/[id]/connectors/[connectorId]/sync/route' @@ -92,8 +97,16 @@ describe('Connector Manual Sync API Route', () => { }) it('dispatches sync on valid request', async () => { - mockCheckSession.mockResolvedValue({ success: true, userId: 'user-1' }) - mockCheckWriteAccess.mockResolvedValue({ hasAccess: true }) + mockCheckSession.mockResolvedValue({ + success: true, + userId: 'user-1', + userName: 'Test', + userEmail: 'test@test.com', + }) + mockCheckWriteAccess.mockResolvedValue({ + hasAccess: true, + knowledgeBase: { workspaceId: 'ws-1', name: 'Test KB' }, + }) mockDbChain.limit.mockResolvedValueOnce([{ id: 'conn-456', status: 'active' }]) const req = createMockRequest('POST') diff --git a/apps/sim/app/api/knowledge/[id]/connectors/[connectorId]/sync/route.ts b/apps/sim/app/api/knowledge/[id]/connectors/[connectorId]/sync/route.ts index e6aae66eb27..4faa2013698 100644 --- a/apps/sim/app/api/knowledge/[id]/connectors/[connectorId]/sync/route.ts +++ b/apps/sim/app/api/knowledge/[id]/connectors/[connectorId]/sync/route.ts @@ -3,6 +3,7 @@ import { knowledgeConnector } from '@sim/db/schema' import { createLogger } from '@sim/logger' import { and, eq, isNull } from 'drizzle-orm' import { type NextRequest, NextResponse } from 'next/server' +import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { generateRequestId } from '@/lib/core/utils/request' import { dispatchSync } from '@/lib/knowledge/connectors/sync-engine' @@ -54,6 +55,20 @@ export async function POST(request: NextRequest, { params }: RouteParams) { logger.info(`[${requestId}] Manual sync triggered for connector ${connectorId}`) + recordAudit({ + workspaceId: writeCheck.knowledgeBase.workspaceId, + actorId: auth.userId, + actorName: auth.userName, + actorEmail: auth.userEmail, + action: AuditAction.CONNECTOR_SYNCED, + resourceType: AuditResourceType.CONNECTOR, + resourceId: connectorId, + resourceName: connectorRows[0].connectorType, + description: `Triggered manual sync for connector on knowledge base "${writeCheck.knowledgeBase.name}"`, + metadata: { knowledgeBaseId }, + request, + }) + dispatchSync(connectorId, { requestId }).catch((error) => { logger.error( `[${requestId}] Failed to dispatch manual sync for connector ${connectorId}`, diff --git a/apps/sim/app/api/knowledge/[id]/connectors/route.ts b/apps/sim/app/api/knowledge/[id]/connectors/route.ts index c28cea60e46..989d6056ba5 100644 --- a/apps/sim/app/api/knowledge/[id]/connectors/route.ts +++ b/apps/sim/app/api/knowledge/[id]/connectors/route.ts @@ -5,6 +5,7 @@ import { and, desc, eq, isNull, sql } from 'drizzle-orm' import { type NextRequest, NextResponse } from 'next/server' import { z } from 'zod' import { encryptApiKey } from '@/lib/api-key/crypto' +import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { generateRequestId } from '@/lib/core/utils/request' import { dispatchSync } from '@/lib/knowledge/connectors/sync-engine' @@ -226,6 +227,20 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{ logger.info(`[${requestId}] Created connector ${connectorId} for KB ${knowledgeBaseId}`) + recordAudit({ + workspaceId: writeCheck.knowledgeBase.workspaceId, + actorId: auth.userId, + actorName: auth.userName, + actorEmail: auth.userEmail, + action: AuditAction.CONNECTOR_CREATED, + resourceType: AuditResourceType.CONNECTOR, + resourceId: connectorId, + resourceName: connectorType, + description: `Created ${connectorType} connector for knowledge base "${writeCheck.knowledgeBase.name}"`, + metadata: { knowledgeBaseId, connectorType, syncIntervalMinutes }, + request, + }) + dispatchSync(connectorId, { requestId }).catch((error) => { logger.error( `[${requestId}] Failed to dispatch initial sync for connector ${connectorId}`, diff --git a/apps/sim/app/api/knowledge/[id]/restore/route.ts b/apps/sim/app/api/knowledge/[id]/restore/route.ts index d2021685320..c8f4844f14d 100644 --- a/apps/sim/app/api/knowledge/[id]/restore/route.ts +++ b/apps/sim/app/api/knowledge/[id]/restore/route.ts @@ -3,6 +3,7 @@ import { knowledgeBase } from '@sim/db/schema' import { createLogger } from '@sim/logger' import { eq } from 'drizzle-orm' import { type NextRequest, NextResponse } from 'next/server' +import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { generateRequestId } from '@/lib/core/utils/request' import { restoreKnowledgeBase } from '@/lib/knowledge/service' @@ -23,6 +24,7 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{ const [kb] = await db .select({ id: knowledgeBase.id, + name: knowledgeBase.name, workspaceId: knowledgeBase.workspaceId, userId: knowledgeBase.userId, }) @@ -47,6 +49,19 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{ logger.info(`[${requestId}] Restored knowledge base ${id}`) + recordAudit({ + workspaceId: kb.workspaceId, + actorId: auth.userId, + actorName: auth.userName, + actorEmail: auth.userEmail, + action: AuditAction.KNOWLEDGE_BASE_RESTORED, + resourceType: AuditResourceType.KNOWLEDGE_BASE, + resourceId: id, + resourceName: kb.name, + description: `Restored knowledge base "${kb.name}"`, + request, + }) + return NextResponse.json({ success: true }) } catch (error) { logger.error(`[${requestId}] Error restoring knowledge base ${id}`, error) diff --git a/apps/sim/app/api/knowledge/connectors/sync/route.ts b/apps/sim/app/api/knowledge/connectors/sync/route.ts index dfddc72e445..df356bc3222 100644 --- a/apps/sim/app/api/knowledge/connectors/sync/route.ts +++ b/apps/sim/app/api/knowledge/connectors/sync/route.ts @@ -27,6 +27,34 @@ export async function GET(request: NextRequest) { try { const now = new Date() + const STALE_SYNC_TTL_MS = 120 * 60 * 1000 + const staleCutoff = new Date(now.getTime() - STALE_SYNC_TTL_MS) + + const recoveredConnectors = await db + .update(knowledgeConnector) + .set({ + status: 'error', + lastSyncError: 'Sync timed out (stale lock recovered)', + nextSyncAt: new Date(now.getTime() + 10 * 60 * 1000), + updatedAt: now, + }) + .where( + and( + eq(knowledgeConnector.status, 'syncing'), + lte(knowledgeConnector.updatedAt, staleCutoff), + isNull(knowledgeConnector.archivedAt), + isNull(knowledgeConnector.deletedAt) + ) + ) + .returning({ id: knowledgeConnector.id }) + + if (recoveredConnectors.length > 0) { + logger.warn( + `[${requestId}] Recovered ${recoveredConnectors.length} stale syncing connectors`, + { ids: recoveredConnectors.map((c) => c.id) } + ) + } + const dueConnectors = await db .select({ id: knowledgeConnector.id, diff --git a/apps/sim/app/api/table/[tableId]/restore/route.ts b/apps/sim/app/api/table/[tableId]/restore/route.ts index 8622f849f1d..7ebff57dce5 100644 --- a/apps/sim/app/api/table/[tableId]/restore/route.ts +++ b/apps/sim/app/api/table/[tableId]/restore/route.ts @@ -1,5 +1,6 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' +import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { generateRequestId } from '@/lib/core/utils/request' import { getTableById, restoreTable } from '@/lib/table' @@ -34,6 +35,19 @@ export async function POST( logger.info(`[${requestId}] Restored table ${tableId}`) + recordAudit({ + workspaceId: table.workspaceId, + actorId: auth.userId, + actorName: auth.userName, + actorEmail: auth.userEmail, + action: AuditAction.TABLE_RESTORED, + resourceType: AuditResourceType.TABLE, + resourceId: tableId, + resourceName: table.name, + description: `Restored table "${table.name}"`, + request, + }) + return NextResponse.json({ success: true }) } catch (error) { logger.error(`[${requestId}] Error restoring table ${tableId}`, error) diff --git a/apps/sim/app/api/workflows/[id]/restore/route.ts b/apps/sim/app/api/workflows/[id]/restore/route.ts index 7e8a76e8a35..df9c0966de9 100644 --- a/apps/sim/app/api/workflows/[id]/restore/route.ts +++ b/apps/sim/app/api/workflows/[id]/restore/route.ts @@ -1,5 +1,6 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' +import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { generateRequestId } from '@/lib/core/utils/request' import { restoreWorkflow } from '@/lib/workflows/lifecycle' @@ -44,6 +45,19 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{ logger.info(`[${requestId}] Restored workflow ${workflowId}`) + recordAudit({ + workspaceId: workflowData.workspaceId, + actorId: auth.userId, + actorName: auth.userName, + actorEmail: auth.userEmail, + action: AuditAction.WORKFLOW_RESTORED, + resourceType: AuditResourceType.WORKFLOW, + resourceId: workflowId, + resourceName: workflowData.name, + description: `Restored workflow "${workflowData.name}"`, + request, + }) + return NextResponse.json({ success: true }) } catch (error) { logger.error(`[${requestId}] Error restoring workflow ${workflowId}`, error) diff --git a/apps/sim/app/api/workspaces/[id]/files/[fileId]/restore/route.ts b/apps/sim/app/api/workspaces/[id]/files/[fileId]/restore/route.ts index eae4bae4368..f4d7c8980e6 100644 --- a/apps/sim/app/api/workspaces/[id]/files/[fileId]/restore/route.ts +++ b/apps/sim/app/api/workspaces/[id]/files/[fileId]/restore/route.ts @@ -1,5 +1,6 @@ import { createLogger } from '@sim/logger' import { type NextRequest, NextResponse } from 'next/server' +import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log' import { getSession } from '@/lib/auth' import { generateRequestId } from '@/lib/core/utils/request' import { restoreWorkspaceFile } from '@/lib/uploads/contexts/workspace' @@ -29,6 +30,19 @@ export async function POST( logger.info(`[${requestId}] Restored workspace file ${fileId}`) + recordAudit({ + workspaceId, + actorId: session.user.id, + actorName: session.user.name, + actorEmail: session.user.email, + action: AuditAction.FILE_RESTORED, + resourceType: AuditResourceType.FILE, + resourceId: fileId, + resourceName: fileId, + description: `Restored workspace file ${fileId}`, + request, + }) + return NextResponse.json({ success: true }) } catch (error) { logger.error(`[${requestId}] Error restoring workspace file ${fileId}`, error) diff --git a/apps/sim/app/workspace/[workspaceId]/files/loading.tsx b/apps/sim/app/workspace/[workspaceId]/files/loading.tsx index 806f4f73b30..9f2250d79e2 100644 --- a/apps/sim/app/workspace/[workspaceId]/files/loading.tsx +++ b/apps/sim/app/workspace/[workspaceId]/files/loading.tsx @@ -6,7 +6,7 @@ const COLUMN_COUNT = 6 export default function FilesLoading() { return (
-
+
@@ -18,7 +18,7 @@ export default function FilesLoading() {
-
+
@@ -27,7 +27,7 @@ export default function FilesLoading() {
- + @@ -40,7 +40,7 @@ export default function FilesLoading() { {Array.from({ length: SKELETON_ROW_COUNT }).map((_, rowIndex) => ( - + diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/loading.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/loading.tsx index 577be0ff2b0..4b98c9a8543 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/loading.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/loading.tsx @@ -6,7 +6,7 @@ const COLUMN_COUNT = 4 export default function DocumentLoading() { return (
-
+
@@ -18,7 +18,7 @@ export default function DocumentLoading() {
-
+
@@ -32,7 +32,7 @@ export default function DocumentLoading() {
- + @@ -45,7 +45,7 @@ export default function DocumentLoading() { {Array.from({ length: SKELETON_ROW_COUNT }).map((_, rowIndex) => ( - + diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/loading.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/loading.tsx index ad27d19a9a7..b926f0d4f5c 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/loading.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/loading.tsx @@ -6,7 +6,7 @@ const COLUMN_COUNT = 7 export default function KnowledgeBaseLoading() { return (
-
+
@@ -19,7 +19,7 @@ export default function KnowledgeBaseLoading() {
-
+
@@ -34,7 +34,7 @@ export default function KnowledgeBaseLoading() {
- + @@ -47,7 +47,7 @@ export default function KnowledgeBaseLoading() { {Array.from({ length: SKELETON_ROW_COUNT }).map((_, rowIndex) => ( - + diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/loading.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/loading.tsx index acb223d33a7..9011fcccca6 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/loading.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/loading.tsx @@ -6,7 +6,7 @@ const COLUMN_COUNT = 6 export default function KnowledgeLoading() { return (
-
+
@@ -18,7 +18,7 @@ export default function KnowledgeLoading() {
-
+
@@ -28,7 +28,7 @@ export default function KnowledgeLoading() {
- + @@ -41,7 +41,7 @@ export default function KnowledgeLoading() { {Array.from({ length: SKELETON_ROW_COUNT }).map((_, rowIndex) => ( - + diff --git a/apps/sim/app/workspace/[workspaceId]/logs/loading.tsx b/apps/sim/app/workspace/[workspaceId]/logs/loading.tsx index 6c20d8d3774..d3565504d4c 100644 --- a/apps/sim/app/workspace/[workspaceId]/logs/loading.tsx +++ b/apps/sim/app/workspace/[workspaceId]/logs/loading.tsx @@ -6,7 +6,7 @@ const COLUMN_COUNT = 6 export default function LogsLoading() { return (
-
+
@@ -21,7 +21,7 @@ export default function LogsLoading() {
-
+
@@ -36,7 +36,7 @@ export default function LogsLoading() {
- + @@ -49,7 +49,7 @@ export default function LogsLoading() { {Array.from({ length: SKELETON_ROW_COUNT }).map((_, rowIndex) => ( - + diff --git a/apps/sim/app/workspace/[workspaceId]/scheduled-tasks/loading.tsx b/apps/sim/app/workspace/[workspaceId]/scheduled-tasks/loading.tsx index 4bdba810493..4330f14d360 100644 --- a/apps/sim/app/workspace/[workspaceId]/scheduled-tasks/loading.tsx +++ b/apps/sim/app/workspace/[workspaceId]/scheduled-tasks/loading.tsx @@ -6,7 +6,7 @@ const COLUMN_COUNT = 4 export default function ScheduledTasksLoading() { return (
-
+
@@ -17,7 +17,7 @@ export default function ScheduledTasksLoading() {
-
+
@@ -26,7 +26,7 @@ export default function ScheduledTasksLoading() {
- + @@ -39,7 +39,7 @@ export default function ScheduledTasksLoading() { {Array.from({ length: SKELETON_ROW_COUNT }).map((_, rowIndex) => ( - + diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/loading.tsx b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/loading.tsx index 3eb4cd58d01..02a5db5882c 100644 --- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/loading.tsx +++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/loading.tsx @@ -6,7 +6,7 @@ const COLUMN_COUNT = 5 export default function TableDetailLoading() { return (
-
+
@@ -22,7 +22,7 @@ export default function TableDetailLoading() {
- + {Array.from({ length: COLUMN_COUNT }).map((_, i) => ( {Array.from({ length: SKELETON_ROW_COUNT }).map((_, rowIndex) => ( - + {Array.from({ length: COLUMN_COUNT }).map((_, colIndex) => (
@@ -32,7 +32,7 @@ export default function TableDetailLoading() {
-
+
@@ -17,7 +17,7 @@ export default function TablesLoading() {
-
+
@@ -26,7 +26,7 @@ export default function TablesLoading() {
- + @@ -39,7 +39,7 @@ export default function TablesLoading() { {Array.from({ length: SKELETON_ROW_COUNT }).map((_, rowIndex) => ( - + diff --git a/apps/sim/connectors/github/github.ts b/apps/sim/connectors/github/github.ts index 065f6e08355..2ff2276eaff 100644 --- a/apps/sim/connectors/github/github.ts +++ b/apps/sim/connectors/github/github.ts @@ -2,12 +2,13 @@ import { createLogger } from '@sim/logger' import { GithubIcon } from '@/components/icons' import { fetchWithRetry, VALIDATE_RETRY_OPTIONS } from '@/lib/knowledge/documents/utils' import type { ConnectorConfig, ExternalDocument, ExternalDocumentList } from '@/connectors/types' -import { computeContentHash, parseTagDate } from '@/connectors/utils' +import { parseTagDate } from '@/connectors/utils' const logger = createLogger('GitHubConnector') const GITHUB_API_URL = 'https://api.github.com' const BATCH_SIZE = 30 +const GIT_SHA_PREFIX = 'git-sha:' /** * Parses the repository string into owner and repo. @@ -89,58 +90,25 @@ async function fetchTree( } /** - * Fetches file content via the Blobs API and decodes base64. + * Creates a lightweight stub ExternalDocument from a tree item. + * Uses the Git blob SHA as contentHash for change detection, avoiding + * the need to fetch blob content for every file during listing. + * Content is deferred and only fetched for new/changed documents. */ -async function fetchBlobContent( - accessToken: string, - owner: string, - repo: string, - sha: string -): Promise { - const url = `${GITHUB_API_URL}/repos/${owner}/${repo}/git/blobs/${sha}` - - const response = await fetchWithRetry(url, { - method: 'GET', - headers: { - Accept: 'application/vnd.github+json', - Authorization: `Bearer ${accessToken}`, - 'X-GitHub-Api-Version': '2022-11-28', - }, - }) - - if (!response.ok) { - throw new Error(`Failed to fetch blob ${sha}: ${response.status}`) - } - - const data = await response.json() - - if (data.encoding === 'base64') { - return Buffer.from(data.content, 'base64').toString('utf-8') - } - - return data.content || '' -} - -/** - * Converts a tree item to an ExternalDocument by fetching its content. - */ -async function treeItemToDocument( - accessToken: string, +function treeItemToStub( owner: string, repo: string, branch: string, item: TreeItem -): Promise { - const content = await fetchBlobContent(accessToken, owner, repo, item.sha) - const contentHash = await computeContentHash(content) - +): ExternalDocument { return { externalId: item.path, title: item.path.split('/').pop() || item.path, - content, + content: '', + contentDeferred: true, mimeType: 'text/plain', sourceUrl: `https://github.com/${owner}/${repo}/blob/${encodeURIComponent(branch)}/${item.path.split('/').map(encodeURIComponent).join('/')}`, - contentHash, + contentHash: `${GIT_SHA_PREFIX}${item.sha}`, metadata: { path: item.path, sha: item.sha, @@ -245,24 +213,7 @@ export const githubConnector: ConnectorConfig = { batchSize: batch.length, }) - const BLOB_CONCURRENCY = 5 - const documents: ExternalDocument[] = [] - for (let i = 0; i < batch.length; i += BLOB_CONCURRENCY) { - const chunk = batch.slice(i, i + BLOB_CONCURRENCY) - const results = await Promise.all( - chunk.map(async (item) => { - try { - return await treeItemToDocument(accessToken, owner, repo, branch, item) - } catch (error) { - logger.warn(`Failed to fetch content for ${item.path}`, { - error: error instanceof Error ? error.message : String(error), - }) - return null - } - }) - ) - documents.push(...(results.filter(Boolean) as ExternalDocument[])) - } + const documents = batch.map((item) => treeItemToStub(owner, repo, branch, item)) const nextOffset = offset + BATCH_SIZE const hasMore = nextOffset < capped.length @@ -308,7 +259,6 @@ export const githubConnector: ConnectorConfig = { data.encoding === 'base64' ? Buffer.from(data.content as string, 'base64').toString('utf-8') : (data.content as string) || '' - const contentHash = await computeContentHash(content) return { externalId, @@ -316,7 +266,7 @@ export const githubConnector: ConnectorConfig = { content, mimeType: 'text/plain', sourceUrl: `https://github.com/${owner}/${repo}/blob/${encodeURIComponent(branch)}/${path.split('/').map(encodeURIComponent).join('/')}`, - contentHash, + contentHash: `${GIT_SHA_PREFIX}${data.sha as string}`, metadata: { path, sha: data.sha as string, diff --git a/apps/sim/connectors/types.ts b/apps/sim/connectors/types.ts index 79c19b8355a..18244990224 100644 --- a/apps/sim/connectors/types.ts +++ b/apps/sim/connectors/types.ts @@ -24,8 +24,10 @@ export interface ExternalDocument { mimeType: string /** Link back to the original document */ sourceUrl?: string - /** SHA-256 of content for change detection */ + /** Hash of content for change detection (format varies by connector) */ contentHash: string + /** When true, content is empty and will be fetched via getDocument for new/changed docs only */ + contentDeferred?: boolean /** Additional source-specific metadata */ metadata?: Record } diff --git a/apps/sim/lib/audit/log.ts b/apps/sim/lib/audit/log.ts index c3871e10893..6a45f49664f 100644 --- a/apps/sim/lib/audit/log.ts +++ b/apps/sim/lib/audit/log.ts @@ -40,6 +40,10 @@ export const AuditAction = { CREDENTIAL_SET_INVITATION_RESENT: 'credential_set_invitation.resent', CREDENTIAL_SET_INVITATION_REVOKED: 'credential_set_invitation.revoked', + // Connector Documents + CONNECTOR_DOCUMENT_RESTORED: 'connector_document.restored', + CONNECTOR_DOCUMENT_EXCLUDED: 'connector_document.excluded', + // Documents DOCUMENT_UPLOADED: 'document.uploaded', DOCUMENT_UPDATED: 'document.updated', @@ -52,6 +56,7 @@ export const AuditAction = { FILE_UPLOADED: 'file.uploaded', FILE_UPDATED: 'file.updated', FILE_DELETED: 'file.deleted', + FILE_RESTORED: 'file.restored', // Folders FOLDER_CREATED: 'folder.created', @@ -67,10 +72,17 @@ export const AuditAction = { INVITATION_ACCEPTED: 'invitation.accepted', INVITATION_REVOKED: 'invitation.revoked', + // Knowledge Base Connectors + CONNECTOR_CREATED: 'connector.created', + CONNECTOR_UPDATED: 'connector.updated', + CONNECTOR_DELETED: 'connector.deleted', + CONNECTOR_SYNCED: 'connector.synced', + // Knowledge Bases KNOWLEDGE_BASE_CREATED: 'knowledge_base.created', KNOWLEDGE_BASE_UPDATED: 'knowledge_base.updated', KNOWLEDGE_BASE_DELETED: 'knowledge_base.deleted', + KNOWLEDGE_BASE_RESTORED: 'knowledge_base.restored', // MCP Servers MCP_SERVER_ADDED: 'mcp_server.added', @@ -119,6 +131,7 @@ export const AuditAction = { TABLE_CREATED: 'table.created', TABLE_UPDATED: 'table.updated', TABLE_DELETED: 'table.deleted', + TABLE_RESTORED: 'table.restored', // Templates TEMPLATE_CREATED: 'template.created', @@ -132,6 +145,7 @@ export const AuditAction = { // Workflows WORKFLOW_CREATED: 'workflow.created', WORKFLOW_DELETED: 'workflow.deleted', + WORKFLOW_RESTORED: 'workflow.restored', WORKFLOW_DEPLOYED: 'workflow.deployed', WORKFLOW_UNDEPLOYED: 'workflow.undeployed', WORKFLOW_DUPLICATED: 'workflow.duplicated', @@ -157,6 +171,7 @@ export const AuditResourceType = { BILLING: 'billing', BYOK_KEY: 'byok_key', CHAT: 'chat', + CONNECTOR: 'connector', CREDENTIAL_SET: 'credential_set', DOCUMENT: 'document', ENVIRONMENT: 'environment', diff --git a/apps/sim/lib/knowledge/connectors/sync-engine.ts b/apps/sim/lib/knowledge/connectors/sync-engine.ts index 3ec619e723a..a07005a95d9 100644 --- a/apps/sim/lib/knowledge/connectors/sync-engine.ts +++ b/apps/sim/lib/knowledge/connectors/sync-engine.ts @@ -38,6 +38,12 @@ class ConnectorDeletedException extends Error { const SYNC_BATCH_SIZE = 5 const MAX_PAGES = 500 +const MAX_SAFE_TITLE_LENGTH = 200 + +/** Sanitizes a document title for use in S3 storage keys. */ +function sanitizeStorageTitle(title: string): string { + return title.replace(/[^a-zA-Z0-9.-]/g, '_').slice(0, MAX_SAFE_TITLE_LENGTH) +} type KnowledgeBaseLockingTx = Pick type DocOp = @@ -241,7 +247,7 @@ export async function executeSync( const userId = kbRows[0].userId const sourceConfig = connector.sourceConfig as Record - const accessToken = await resolveAccessToken(connector, connectorConfig, userId) + let accessToken = await resolveAccessToken(connector, connectorConfig, userId) if (!accessToken) { throw new Error('Failed to obtain access token') @@ -273,6 +279,8 @@ export async function executeSync( startedAt: new Date(), }) + let syncExitedCleanly = false + try { const externalDocs: ExternalDocument[] = [] let cursor: string | undefined @@ -289,6 +297,11 @@ export async function executeSync( isIncremental && connector.lastSyncAt ? new Date(connector.lastSyncAt) : undefined for (let pageNum = 0; hasMore && pageNum < MAX_PAGES; pageNum++) { + if (pageNum > 0 && connectorConfig.auth.mode === 'oauth') { + const refreshed = await resolveAccessToken(connector, connectorConfig, userId) + if (refreshed) accessToken = refreshed + } + const page = await connectorConfig.listDocuments( accessToken, sourceConfig, @@ -390,7 +403,7 @@ export async function executeSync( continue } - if (!extDoc.content.trim()) { + if (!extDoc.content.trim() && !extDoc.contentDeferred) { logger.info(`Skipping empty document: ${extDoc.title}`, { externalId: extDoc.externalId, }) @@ -416,7 +429,54 @@ export async function executeSync( throw new Error(`Knowledge base ${connector.knowledgeBaseId} was deleted during sync`) } - const batch = pendingOps.slice(i, i + SYNC_BATCH_SIZE) + const rawBatch = pendingOps.slice(i, i + SYNC_BATCH_SIZE) + + const deferredOps = rawBatch.filter((op) => op.extDoc.contentDeferred) + const readyOps = rawBatch.filter((op) => !op.extDoc.contentDeferred) + + if (deferredOps.length > 0) { + if (connectorConfig.auth.mode === 'oauth') { + const refreshed = await resolveAccessToken(connector, connectorConfig, userId) + if (refreshed) accessToken = refreshed + } + + const hydrated = await Promise.allSettled( + deferredOps.map(async (op) => { + const fullDoc = await connectorConfig.getDocument( + accessToken!, + sourceConfig, + op.extDoc.externalId, + syncContext + ) + if (!fullDoc?.content.trim()) return null + return { + ...op, + extDoc: { + ...op.extDoc, + content: fullDoc.content, + contentHash: fullDoc.contentHash ?? op.extDoc.contentHash, + contentDeferred: false, + }, + } + }) + ) + + for (const outcome of hydrated) { + if (outcome.status === 'fulfilled' && outcome.value) { + readyOps.push(outcome.value) + } else if (outcome.status === 'rejected') { + result.docsFailed++ + logger.error('Failed to hydrate deferred document', { + connectorId, + error: + outcome.reason instanceof Error ? outcome.reason.message : String(outcome.reason), + }) + } + } + } + + const batch = readyOps + const settled = await Promise.allSettled( batch.map((op) => { if (op.type === 'add') { @@ -540,6 +600,7 @@ export async function executeSync( ) logger.info('Sync completed', { connectorId, ...result }) + syncExitedCleanly = true return result } catch (error) { if (error instanceof ConnectorDeletedException) { @@ -571,6 +632,7 @@ export async function executeSync( } result.error = 'Connector deleted during sync' + syncExitedCleanly = true return result } @@ -610,7 +672,27 @@ export async function executeSync( } result.error = errorMessage + syncExitedCleanly = true return result + } finally { + if (!syncExitedCleanly) { + try { + await db + .update(knowledgeConnector) + .set({ + status: 'error', + lastSyncError: 'Sync terminated unexpectedly', + updatedAt: new Date(), + }) + .where(eq(knowledgeConnector.id, connectorId)) + logger.warn('Reset stale syncing status in finally block', { connectorId }) + } catch (finallyError) { + logger.warn('Failed to reset syncing status in finally block', { + connectorId, + error: finallyError instanceof Error ? finallyError.message : String(finallyError), + }) + } + } } } @@ -630,7 +712,7 @@ async function addDocument( } const documentId = crypto.randomUUID() const contentBuffer = Buffer.from(extDoc.content, 'utf-8') - const safeTitle = extDoc.title.replace(/[^a-zA-Z0-9.-]/g, '_') + const safeTitle = sanitizeStorageTitle(extDoc.title) const customKey = `kb/${Date.now()}-${documentId}-${safeTitle}.txt` const fileInfo = await StorageService.uploadFile({ @@ -729,7 +811,7 @@ async function updateDocument( const oldFileUrl = existingRows[0]?.fileUrl const contentBuffer = Buffer.from(extDoc.content, 'utf-8') - const safeTitle = extDoc.title.replace(/[^a-zA-Z0-9.-]/g, '_') + const safeTitle = sanitizeStorageTitle(extDoc.title) const customKey = `kb/${Date.now()}-${existingDocId}-${safeTitle}.txt` const fileInfo = await StorageService.uploadFile({ diff --git a/apps/sim/lib/knowledge/documents/service.ts b/apps/sim/lib/knowledge/documents/service.ts index 2d607c41da5..4d1b1dc71e3 100644 --- a/apps/sim/lib/knowledge/documents/service.ts +++ b/apps/sim/lib/knowledge/documents/service.ts @@ -47,7 +47,6 @@ const logger = createLogger('DocumentService') const TIMEOUTS = { OVERALL_PROCESSING: (env.KB_CONFIG_MAX_DURATION || 600) * 1000, // Default 10 minutes for KB document processing - EMBEDDINGS_API: (env.KB_CONFIG_MAX_TIMEOUT || 10000) * 18, } as const // Configuration for handling large documents diff --git a/apps/sim/lib/knowledge/documents/utils.ts b/apps/sim/lib/knowledge/documents/utils.ts index a7eaaf29331..95708063f82 100644 --- a/apps/sim/lib/knowledge/documents/utils.ts +++ b/apps/sim/lib/knowledge/documents/utils.ts @@ -52,8 +52,25 @@ export function isRetryableError(error: unknown): boolean { return true } - // Check for rate limiting in error messages + // Check for network-level errors (DNS, connection, timeout) const errorMessage = error instanceof Error ? error.message : String(error) + const lowerMessage = errorMessage.toLowerCase() + + const networkKeywords = [ + 'fetch failed', + 'econnreset', + 'econnrefused', + 'etimedout', + 'enetunreach', + 'socket hang up', + 'network error', + ] + + if (networkKeywords.some((keyword) => lowerMessage.includes(keyword))) { + return true + } + + // Check for rate limiting in error messages const rateLimitKeywords = [ 'rate limit', 'rate_limit', @@ -65,7 +82,7 @@ export function isRetryableError(error: unknown): boolean { 'service unavailable', ] - return rateLimitKeywords.some((keyword) => errorMessage.toLowerCase().includes(keyword)) + return rateLimitKeywords.some((keyword) => lowerMessage.includes(keyword)) } /** diff --git a/packages/testing/src/mocks/audit.mock.ts b/packages/testing/src/mocks/audit.mock.ts index b077122c8ea..69b76442895 100644 --- a/packages/testing/src/mocks/audit.mock.ts +++ b/packages/testing/src/mocks/audit.mock.ts @@ -32,6 +32,8 @@ export const auditMock = { CREDENTIAL_SET_INVITATION_ACCEPTED: 'credential_set_invitation.accepted', CREDENTIAL_SET_INVITATION_RESENT: 'credential_set_invitation.resent', CREDENTIAL_SET_INVITATION_REVOKED: 'credential_set_invitation.revoked', + CONNECTOR_DOCUMENT_RESTORED: 'connector_document.restored', + CONNECTOR_DOCUMENT_EXCLUDED: 'connector_document.excluded', DOCUMENT_UPLOADED: 'document.uploaded', DOCUMENT_UPDATED: 'document.updated', DOCUMENT_DELETED: 'document.deleted', @@ -39,6 +41,7 @@ export const auditMock = { FILE_UPLOADED: 'file.uploaded', FILE_UPDATED: 'file.updated', FILE_DELETED: 'file.deleted', + FILE_RESTORED: 'file.restored', FOLDER_CREATED: 'folder.created', FOLDER_DELETED: 'folder.deleted', FOLDER_DUPLICATED: 'folder.duplicated', @@ -47,9 +50,14 @@ export const auditMock = { FORM_DELETED: 'form.deleted', INVITATION_ACCEPTED: 'invitation.accepted', INVITATION_REVOKED: 'invitation.revoked', + CONNECTOR_CREATED: 'connector.created', + CONNECTOR_UPDATED: 'connector.updated', + CONNECTOR_DELETED: 'connector.deleted', + CONNECTOR_SYNCED: 'connector.synced', KNOWLEDGE_BASE_CREATED: 'knowledge_base.created', KNOWLEDGE_BASE_UPDATED: 'knowledge_base.updated', KNOWLEDGE_BASE_DELETED: 'knowledge_base.deleted', + KNOWLEDGE_BASE_RESTORED: 'knowledge_base.restored', MCP_SERVER_ADDED: 'mcp_server.added', MCP_SERVER_UPDATED: 'mcp_server.updated', MCP_SERVER_REMOVED: 'mcp_server.removed', @@ -80,6 +88,7 @@ export const auditMock = { TABLE_CREATED: 'table.created', TABLE_UPDATED: 'table.updated', TABLE_DELETED: 'table.deleted', + TABLE_RESTORED: 'table.restored', TEMPLATE_CREATED: 'template.created', TEMPLATE_UPDATED: 'template.updated', TEMPLATE_DELETED: 'template.deleted', @@ -87,6 +96,7 @@ export const auditMock = { WEBHOOK_DELETED: 'webhook.deleted', WORKFLOW_CREATED: 'workflow.created', WORKFLOW_DELETED: 'workflow.deleted', + WORKFLOW_RESTORED: 'workflow.restored', WORKFLOW_DEPLOYED: 'workflow.deployed', WORKFLOW_UNDEPLOYED: 'workflow.undeployed', WORKFLOW_DUPLICATED: 'workflow.duplicated', @@ -104,6 +114,7 @@ export const auditMock = { BILLING: 'billing', BYOK_KEY: 'byok_key', CHAT: 'chat', + CONNECTOR: 'connector', CREDENTIAL_SET: 'credential_set', DOCUMENT: 'document', ENVIRONMENT: 'environment', From cb3cc378b8cd0a157a0aa43873ad3e627e441f8d Mon Sep 17 00:00:00 2001 From: Waleed Date: Sat, 21 Mar 2026 10:21:13 -0700 Subject: [PATCH 4/7] fix(canvas): correct z-index layering for selected blocks and connected edges (#3698) * fix(canvas): correct z-index layering for selected blocks and connected edges * fix(canvas): derive subflow edge z-index from connected node z-index * fix(canvas): fix nodesForRender early-return guard for regular blocks * lint * fix(canvas): ensure elevated edges and last-interacted nodes sit above siblings at same base z-index --- .../[workspaceId]/w/[workflowId]/workflow.tsx | 64 +++++++++++++++++-- 1 file changed, 59 insertions(+), 5 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx index 59e56a16b6c..374340af825 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx @@ -201,8 +201,6 @@ const edgeTypes: EdgeTypes = { const defaultEdgeOptions = { type: 'custom' } const reactFlowStyles = [ - '[&_.react-flow__edges]:!z-0', - '[&_.react-flow__node]:z-[21]', '[&_.react-flow__handle]:!z-[30]', '[&_.react-flow__edge-labels]:!z-[1001]', '[&_.react-flow__pane]:select-none', @@ -2478,6 +2476,7 @@ const WorkflowContent = React.memo( // Local state for nodes - allows smooth drag without store updates on every frame const [displayNodes, setDisplayNodes] = useState([]) + const [lastInteractedNodeId, setLastInteractedNodeId] = useState(null) const selectedNodeIds = useMemo( () => displayNodes.filter((node) => node.selected).map((node) => node.id), @@ -2489,6 +2488,14 @@ const WorkflowContent = React.memo( syncPanelWithSelection(selectedNodeIds) }, [selectedNodeIdsKey]) + // Keep the most recently selected block on top even after deselection, so a + // dragged block doesn't suddenly drop behind other overlapping blocks. + useEffect(() => { + if (selectedNodeIds.length > 0) { + setLastInteractedNodeId(selectedNodeIds[selectedNodeIds.length - 1]) + } + }, [selectedNodeIdsKey]) + useEffect(() => { // Check for pending selection (from paste/duplicate), otherwise preserve existing selection if (pendingSelection && pendingSelection.length > 0) { @@ -3723,18 +3730,58 @@ const WorkflowContent = React.memo( [removeEdge, edges, blocks, addNotification, activeWorkflowId] ) + // Elevate nodes using React Flow's native zIndex so selected/recent blocks + // always sit above edges and other blocks. + // + // Z-index layers (regular blocks): + // 21 — default + // 22 — last interacted (dragged/selected, now deselected) so it stays on + // top of siblings until another block is touched + // 31 — currently selected (above connected edges at z-22 and handles at z-30) + // + // Subflow container nodes are skipped — they use depth-based zIndex for + // correct parent/child layering and must not be bumped. + // Child blocks inside containers already carry zIndex 1000 and are bumped by + // +10 when selected so they stay above their sibling child blocks. + const nodesForRender = useMemo(() => { + return displayNodes.map((node) => { + if (node.type === 'subflowNode') return node + const base = node.zIndex ?? 21 + const target = node.selected + ? base + 10 + : node.id === lastInteractedNodeId + ? Math.max(base + 1, 22) + : base + if (target === (node.zIndex ?? 21)) return node + return { ...node, zIndex: target } + }) + }, [displayNodes, lastInteractedNodeId]) + /** Transforms edges to include selection state and delete handlers. Memoized to prevent re-renders. */ const edgesWithSelection = useMemo(() => { const nodeMap = new Map(displayNodes.map((n) => [n.id, n])) + const elevatedNodeIdSet = new Set( + lastInteractedNodeId ? [...selectedNodeIds, lastInteractedNodeId] : selectedNodeIds + ) return edgesForDisplay.map((edge) => { const sourceNode = nodeMap.get(edge.source) const targetNode = nodeMap.get(edge.target) const parentLoopId = sourceNode?.parentId || targetNode?.parentId const edgeContextId = `${edge.id}${parentLoopId ? `-${parentLoopId}` : ''}` + const connectedToElevated = + elevatedNodeIdSet.has(edge.source) || elevatedNodeIdSet.has(edge.target) + // Derive elevated z-index from connected nodes so edges inside subflows + // (child nodes at z-1000) stay above their sibling child blocks. + const elevatedZIndex = Math.max( + 22, + (sourceNode?.zIndex ?? 21) + 1, + (targetNode?.zIndex ?? 21) + 1 + ) return { ...edge, + zIndex: connectedToElevated ? elevatedZIndex : 0, data: { ...edge.data, isSelected: selectedEdges.has(edgeContextId), @@ -3745,7 +3792,14 @@ const WorkflowContent = React.memo( }, } }) - }, [edgesForDisplay, displayNodes, selectedEdges, handleEdgeDelete]) + }, [ + edgesForDisplay, + displayNodes, + selectedNodeIds, + selectedEdges, + handleEdgeDelete, + lastInteractedNodeId, + ]) /** Handles Delete/Backspace to remove selected edges or blocks. */ useEffect(() => { @@ -3885,7 +3939,7 @@ const WorkflowContent = React.memo( {showTrainingModal && } Date: Sat, 21 Mar 2026 11:05:17 -0700 Subject: [PATCH 5/7] chore(trust): replace Delve trust center with Vanta (#3701) * chore(trust): replace Delve trust center with Vanta * lint --- .../app/(home)/components/enterprise/enterprise.tsx | 2 +- .../footer/components/compliance-badges.tsx | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/sim/app/(home)/components/enterprise/enterprise.tsx b/apps/sim/app/(home)/components/enterprise/enterprise.tsx index 63f37fad989..c6b8e9916c2 100644 --- a/apps/sim/app/(home)/components/enterprise/enterprise.tsx +++ b/apps/sim/app/(home)/components/enterprise/enterprise.tsx @@ -460,7 +460,7 @@ function TrustStrip() {
{/* SOC 2 + HIPAA combined */} {/* SOC2 badge */} - + {/* HIPAA badge */} - +
From 4a34ac3015bb9f36b4aa3ebabab6498e06d60e6a Mon Sep 17 00:00:00 2001 From: Waleed Date: Sat, 21 Mar 2026 11:23:45 -0700 Subject: [PATCH 6/7] feat(auth): add Turnstile captcha + harmony disposable email blocking (#3699) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(turnstile): conditionally added CF turnstile to signup * feat(auth): add execute-on-submit Turnstile, conditional harmony, and feature flag - Switch Turnstile to execution: 'execute' mode so challenge runs on form submit (fresh token every time, no expiry issues) - Make emailHarmony conditional via SIGNUP_EMAIL_VALIDATION_ENABLED feature flag so self-hosted users can opt out - Add isSignupEmailValidationEnabled to feature-flags.ts following existing pattern - Add better-auth-harmony to Next.js transpilePackages (required for validator.js ESM compatibility) Co-Authored-By: Claude Sonnet 4.6 * refactor(validation): remove dead validateEmail and checkMXRecord Server-side disposable email blocking is now handled by better-auth-harmony. The async validateEmail (with MX check) had no remaining callers. Only quickValidateEmail remains for client-side form feedback. Co-Authored-By: Claude Sonnet 4.6 * fix(auth): add 15s timeout to Turnstile captcha promise Prevents form from hanging indefinitely if Turnstile never fires onSuccess/onError (e.g. script fails to load, network drop). Co-Authored-By: Claude Sonnet 4.6 * chore(helm): add Turnstile and harmony env vars to values.yaml Adds TURNSTILE_SECRET_KEY, NEXT_PUBLIC_TURNSTILE_SITE_KEY, and SIGNUP_EMAIL_VALIDATION_ENABLED to the helm chart so self-hosted deployments can configure captcha and disposable email blocking. Co-Authored-By: Claude Sonnet 4.6 * fix(auth): reject captcha promise on token expiry onExpire now rejects the pending promise so the form doesn't hang if the Turnstile token expires mid-challenge. Co-Authored-By: Claude Sonnet 4.6 * refactor(login): replace useEffect keydown listener with form onSubmit The forgot-password modal used a global window keydown listener in a useEffect to handle Enter key — a "you might not need an effect" anti-pattern with a stale closure risk. Replaced with a native
wrapper which handles Enter natively, eliminating the useEffect, the global listener, and the stale closure. Co-Authored-By: Claude Sonnet 4.6 * fix(auth): clear dangling timeout after captcha promise settles Use .finally(() => clearTimeout(timeoutId)) to clean up the 15s timeout timer when the captcha resolves before the deadline. Co-Authored-By: Claude Sonnet 4.6 * refactor(auth): use getResponsePromise() for Turnstile token retrieval Replace the manual Promise + refs + timeout pattern with the documented getResponsePromise(timeout) API from @marsidev/react-turnstile. This eliminates captchaToken state, captchaResolveRef, captchaRejectRef, and all callback wiring on the Turnstile component. Co-Authored-By: Claude Sonnet 4.6 * fix(auth): show captcha errors as form-level message, not password error Captcha failures were misleadingly displayed under the password field. Added a dedicated formError state that renders above the submit button, making it clear the issue is with verification, not the password. Co-Authored-By: Claude Sonnet 4.6 --------- Co-authored-by: Claude Sonnet 4.6 --- apps/sim/app/(auth)/login/login-form.tsx | 127 +- apps/sim/app/(auth)/signup/signup-form.tsx | 40 +- apps/sim/lib/auth/auth.ts | 38 +- apps/sim/lib/core/config/env.ts | 4 + apps/sim/lib/core/config/feature-flags.ts | 5 + .../lib/messaging/email/validation.test.ts | 443 +- apps/sim/lib/messaging/email/validation.ts | 240 +- apps/sim/next.config.ts | 1 + apps/sim/package.json | 3 +- bun.lock | 15 +- helm/sim/values.yaml | 5 + .../migrations/0178_clumsy_living_mummy.sql | 2 + .../db/migrations/meta/0178_snapshot.json | 13577 ++++++++++++++++ packages/db/migrations/meta/_journal.json | 7 + packages/db/schema.ts | 1 + 15 files changed, 13879 insertions(+), 629 deletions(-) create mode 100644 packages/db/migrations/0178_clumsy_living_mummy.sql create mode 100644 packages/db/migrations/meta/0178_snapshot.json diff --git a/apps/sim/app/(auth)/login/login-form.tsx b/apps/sim/app/(auth)/login/login-form.tsx index 9dd5cc78dbc..66e8fd261f1 100644 --- a/apps/sim/app/(auth)/login/login-form.tsx +++ b/apps/sim/app/(auth)/login/login-form.tsx @@ -1,6 +1,7 @@ 'use client' -import { useEffect, useRef, useState } from 'react' +import { useMemo, useRef, useState } from 'react' +import { Turnstile, type TurnstileInstance } from '@marsidev/react-turnstile' import { createLogger } from '@sim/logger' import { Eye, EyeOff } from 'lucide-react' import Link from 'next/link' @@ -86,6 +87,9 @@ export default function LoginPage({ const [password, setPassword] = useState('') const [passwordErrors, setPasswordErrors] = useState([]) const [showValidationError, setShowValidationError] = useState(false) + const [formError, setFormError] = useState(null) + const turnstileRef = useRef(null) + const turnstileSiteKey = useMemo(() => getEnv('NEXT_PUBLIC_TURNSTILE_SITE_KEY'), []) const buttonClass = useBrandedButtonClass() const callbackUrlParam = searchParams?.get('callbackUrl') @@ -115,19 +119,6 @@ export default function LoginPage({ : null ) - useEffect(() => { - const handleKeyDown = (event: KeyboardEvent) => { - if (event.key === 'Enter' && forgotPasswordOpen) { - handleForgotPassword() - } - } - - window.addEventListener('keydown', handleKeyDown) - return () => { - window.removeEventListener('keydown', handleKeyDown) - } - }, [forgotPasswordEmail, forgotPasswordOpen]) - const handleEmailChange = (e: React.ChangeEvent) => { const newEmail = e.target.value setEmail(newEmail) @@ -178,6 +169,21 @@ export default function LoginPage({ const safeCallbackUrl = callbackUrl let errorHandled = false + // Execute Turnstile challenge on submit and get a fresh token + let token: string | undefined + if (turnstileSiteKey && turnstileRef.current) { + try { + turnstileRef.current.reset() + turnstileRef.current.execute() + token = await turnstileRef.current.getResponsePromise(15_000) + } catch { + setFormError('Captcha verification failed. Please try again.') + setIsLoading(false) + return + } + } + + setFormError(null) const result = await client.signIn.email( { email, @@ -185,6 +191,11 @@ export default function LoginPage({ callbackURL: safeCallbackUrl, }, { + fetchOptions: { + headers: { + ...(token ? { 'x-captcha-response': token } : {}), + }, + }, onError: (ctx) => { logger.error('Login error:', ctx.error) @@ -460,6 +471,20 @@ export default function LoginPage({ + {turnstileSiteKey && ( + + )} + + {formError && ( +
+

{formError}

+
+ )} + Reset Password - - Enter your email address and we'll send you a link to reset your password if your - account exists. - -
-
- - setForgotPasswordEmail(e.target.value)} - placeholder='Enter your email' - required - type='email' - className={cn( - resetStatus.type === 'error' && 'border-red-500 focus:border-red-500' + { + e.preventDefault() + handleForgotPassword() + }} + > + + Enter your email address and we'll send you a link to reset your password if your + account exists. + +
+
+ + setForgotPasswordEmail(e.target.value)} + placeholder='Enter your email' + required + type='email' + className={cn( + resetStatus.type === 'error' && 'border-red-500 focus:border-red-500' + )} + /> + {resetStatus.type === 'error' && ( +
+

{resetStatus.message}

+
)} - /> - {resetStatus.type === 'error' && ( -
+
+ {resetStatus.type === 'success' && ( +

{resetStatus.message}

)} + + Send Reset Link +
- {resetStatus.type === 'success' && ( -
-

{resetStatus.message}

-
- )} - - Send Reset Link - -
+ diff --git a/apps/sim/app/(auth)/signup/signup-form.tsx b/apps/sim/app/(auth)/signup/signup-form.tsx index 0a8138053a1..b5d59f73b98 100644 --- a/apps/sim/app/(auth)/signup/signup-form.tsx +++ b/apps/sim/app/(auth)/signup/signup-form.tsx @@ -1,6 +1,7 @@ 'use client' -import { Suspense, useMemo, useState } from 'react' +import { Suspense, useMemo, useRef, useState } from 'react' +import { Turnstile, type TurnstileInstance } from '@marsidev/react-turnstile' import { createLogger } from '@sim/logger' import { Eye, EyeOff } from 'lucide-react' import Link from 'next/link' @@ -90,6 +91,9 @@ function SignupFormContent({ const [emailError, setEmailError] = useState('') const [emailErrors, setEmailErrors] = useState([]) const [showEmailValidationError, setShowEmailValidationError] = useState(false) + const [formError, setFormError] = useState(null) + const turnstileRef = useRef(null) + const turnstileSiteKey = useMemo(() => getEnv('NEXT_PUBLIC_TURNSTILE_SITE_KEY'), []) const buttonClass = useBrandedButtonClass() const redirectUrl = useMemo( @@ -245,6 +249,21 @@ function SignupFormContent({ const sanitizedName = trimmedName + // Execute Turnstile challenge on submit and get a fresh token + let token: string | undefined + if (turnstileSiteKey && turnstileRef.current) { + try { + turnstileRef.current.reset() + turnstileRef.current.execute() + token = await turnstileRef.current.getResponsePromise(15_000) + } catch { + setFormError('Captcha verification failed. Please try again.') + setIsLoading(false) + return + } + } + + setFormError(null) const response = await client.signUp.email( { email: emailValue, @@ -252,6 +271,11 @@ function SignupFormContent({ name: sanitizedName, }, { + fetchOptions: { + headers: { + ...(token ? { 'x-captcha-response': token } : {}), + }, + }, onError: (ctx) => { logger.error('Signup error:', ctx.error) const errorMessage: string[] = ['Failed to create account'] @@ -453,6 +477,20 @@ function SignupFormContent({
+ {turnstileSiteKey && ( + + )} + + {formError && ( +
+

{formError}

+
+ )} + loggerMock) - -const { mockResolveMx } = vi.hoisted(() => ({ - mockResolveMx: vi.fn( - ( - _domain: string, - callback: (err: Error | null, addresses: { exchange: string; priority: number }[]) => void - ) => { - callback(null, [{ exchange: 'mail.example.com', priority: 10 }]) - } - ), -})) - -vi.mock('dns', () => ({ - resolveMx: mockResolveMx, -})) - -describe('Email Validation', () => { - beforeEach(() => { - mockResolveMx.mockImplementation( - ( - _domain: string, - callback: (err: Error | null, addresses: { exchange: string; priority: number }[]) => void - ) => { - callback(null, [{ exchange: 'mail.example.com', priority: 10 }]) - } - ) +import { describe, expect, it } from 'vitest' +import { quickValidateEmail } from '@/lib/messaging/email/validation' + +describe('quickValidateEmail', () => { + it.concurrent('should validate a correct email', () => { + const result = quickValidateEmail('user@example.com') + expect(result.isValid).toBe(true) + expect(result.checks.syntax).toBe(true) + expect(result.checks.disposable).toBe(true) + expect(result.checks.mxRecord).toBe(true) + expect(result.confidence).toBe('medium') }) - describe('validateEmail', () => { - it.concurrent('should validate a correct email', async () => { - const result = await validateEmail('user@example.com') - expect(result.isValid).toBe(true) - expect(result.checks.syntax).toBe(true) - expect(result.checks.disposable).toBe(true) - }) - - it.concurrent('should reject invalid syntax', async () => { - const result = await validateEmail('invalid-email') - expect(result.isValid).toBe(false) - expect(result.reason).toBe('Invalid email format') - expect(result.checks.syntax).toBe(false) - }) + it.concurrent('should reject invalid syntax', () => { + const result = quickValidateEmail('invalid-email') + expect(result.isValid).toBe(false) + expect(result.reason).toBe('Invalid email format') + }) - it.concurrent('should reject disposable email addresses', async () => { - const result = await validateEmail('test@10minutemail.com') + it.concurrent('should reject disposable email addresses', () => { + const disposableDomains = [ + 'mailinator.com', + 'yopmail.com', + 'guerrillamail.com', + 'temp-mail.org', + 'throwaway.email', + 'getnada.com', + 'sharklasers.com', + 'spam4.me', + 'sharebot.net', + 'oakon.com', + 'catchmail.io', + 'salt.email', + 'mail.gw', + 'tempmail.org', + ] + + for (const domain of disposableDomains) { + const result = quickValidateEmail(`test@${domain}`) expect(result.isValid).toBe(false) expect(result.reason).toBe('Disposable email addresses are not allowed') expect(result.checks.disposable).toBe(false) - }) - - it.concurrent('should reject consecutive dots (RFC violation)', async () => { - const result = await validateEmail('user..name@example.com') - expect(result.isValid).toBe(false) - expect(result.reason).toBe('Email contains suspicious patterns') - }) - - it.concurrent('should reject very long local parts (RFC violation)', async () => { - const longLocalPart = 'a'.repeat(65) - const result = await validateEmail(`${longLocalPart}@example.com`) - expect(result.isValid).toBe(false) - expect(result.reason).toBe('Email contains suspicious patterns') - }) - - it.concurrent('should reject email with missing domain', async () => { - const result = await validateEmail('user@') - expect(result.isValid).toBe(false) - expect(result.reason).toBe('Invalid email format') - }) - - it.concurrent('should reject email with domain starting with dot', async () => { - const result = await validateEmail('user@.example.com') - expect(result.isValid).toBe(false) - // The regex catches this as a syntax error before domain validation - expect(result.reason).toBe('Invalid email format') - }) - - it.concurrent('should reject email with domain ending with dot', async () => { - const result = await validateEmail('user@example.') - expect(result.isValid).toBe(false) - // The regex catches this as a syntax error before domain validation - expect(result.reason).toBe('Invalid email format') - }) - - it.concurrent('should reject email with domain missing TLD', async () => { - const result = await validateEmail('user@localhost') - expect(result.isValid).toBe(false) - expect(result.reason).toBe('Invalid domain format') - }) - - it.concurrent('should reject email longer than 254 characters', async () => { - const longLocal = 'a'.repeat(64) - const longDomain = `${'b'.repeat(180)}.com` - const result = await validateEmail(`${longLocal}@${longDomain}`) - expect(result.isValid).toBe(false) - }) - - it.concurrent('should validate various known disposable email domains', async () => { - const disposableDomains = [ - 'mailinator.com', - 'yopmail.com', - 'guerrillamail.com', - 'temp-mail.org', - 'throwaway.email', - 'getnada.com', - 'sharklasers.com', - 'spam4.me', - ] - - for (const domain of disposableDomains) { - const result = await validateEmail(`test@${domain}`) - expect(result.isValid).toBe(false) - expect(result.reason).toBe('Disposable email addresses are not allowed') - expect(result.checks.disposable).toBe(false) - } - }) - - it.concurrent('should accept valid email formats', async () => { - const validEmails = [ - 'simple@example.com', - 'very.common@example.com', - 'disposable.style.email.with+symbol@example.com', - 'other.email-with-hyphen@example.com', - 'fully-qualified-domain@example.com', - 'user.name+tag+sorting@example.com', - 'x@example.com', - 'example-indeed@strange-example.com', - 'example@s.example', - ] - - for (const email of validEmails) { - const result = await validateEmail(email) - // We check syntax passes; MX might fail for fake domains - expect(result.checks.syntax).toBe(true) - expect(result.checks.disposable).toBe(true) - } - }) - - it.concurrent('should return high confidence for syntax failures', async () => { - const result = await validateEmail('not-an-email') - expect(result.confidence).toBe('high') - }) - - it.concurrent('should handle email with special characters in local part', async () => { - const result = await validateEmail("user!#$%&'*+/=?^_`{|}~@example.com") - expect(result.checks.syntax).toBe(true) - }) + } }) - describe('quickValidateEmail', () => { - it.concurrent('should validate quickly without MX check', () => { - const result = quickValidateEmail('user@example.com') - expect(result.isValid).toBe(true) - expect(result.checks.mxRecord).toBe(true) // Skipped, so assumed true - expect(result.confidence).toBe('medium') - }) - - it.concurrent('should reject invalid emails quickly', () => { - const result = quickValidateEmail('invalid-email') - expect(result.isValid).toBe(false) - expect(result.reason).toBe('Invalid email format') - }) - - it.concurrent('should reject disposable emails quickly', () => { - const result = quickValidateEmail('test@tempmail.org') - expect(result.isValid).toBe(false) - expect(result.reason).toBe('Disposable email addresses are not allowed') - }) - - it.concurrent('should reject email with missing domain', () => { - const result = quickValidateEmail('user@') - expect(result.isValid).toBe(false) - expect(result.reason).toBe('Invalid email format') - }) - - it.concurrent('should reject email with invalid domain format', () => { - const result = quickValidateEmail('user@.invalid') - expect(result.isValid).toBe(false) - // The regex catches this as a syntax error before domain validation - expect(result.reason).toBe('Invalid email format') - }) + it.concurrent('should reject consecutive dots (RFC violation)', () => { + const result = quickValidateEmail('user..name@example.com') + expect(result.isValid).toBe(false) + expect(result.reason).toBe('Email contains suspicious patterns') + expect(result.confidence).toBe('medium') + }) - it.concurrent('should return medium confidence for suspicious patterns', () => { - const result = quickValidateEmail('user..double@example.com') - expect(result.isValid).toBe(false) - expect(result.reason).toBe('Email contains suspicious patterns') - expect(result.confidence).toBe('medium') - }) + it.concurrent('should reject very long local parts (RFC violation)', () => { + const longLocalPart = 'a'.repeat(65) + const result = quickValidateEmail(`${longLocalPart}@example.com`) + expect(result.isValid).toBe(false) + expect(result.reason).toBe('Email contains suspicious patterns') + }) - it.concurrent('should return high confidence for syntax errors', () => { - const result = quickValidateEmail('not-valid-email') - expect(result.confidence).toBe('high') - }) + it.concurrent('should reject email with missing domain', () => { + const result = quickValidateEmail('user@') + expect(result.isValid).toBe(false) + expect(result.reason).toBe('Invalid email format') + }) - it.concurrent('should handle empty string', () => { - const result = quickValidateEmail('') - expect(result.isValid).toBe(false) - expect(result.reason).toBe('Invalid email format') - }) + it.concurrent('should reject email with domain starting with dot', () => { + const result = quickValidateEmail('user@.example.com') + expect(result.isValid).toBe(false) + expect(result.reason).toBe('Invalid email format') + }) - it.concurrent('should handle email with only @ symbol', () => { - const result = quickValidateEmail('@') - expect(result.isValid).toBe(false) - expect(result.reason).toBe('Invalid email format') - }) + it.concurrent('should reject email with domain ending with dot', () => { + const result = quickValidateEmail('user@example.') + expect(result.isValid).toBe(false) + expect(result.reason).toBe('Invalid email format') + }) - it.concurrent('should handle email with spaces', () => { - const result = quickValidateEmail('user name@example.com') - expect(result.isValid).toBe(false) - expect(result.reason).toBe('Invalid email format') - }) + it.concurrent('should reject email with domain missing TLD', () => { + const result = quickValidateEmail('user@localhost') + expect(result.isValid).toBe(false) + expect(result.reason).toBe('Invalid domain format') + }) - it.concurrent('should handle email with multiple @ symbols', () => { - const result = quickValidateEmail('user@domain@example.com') - expect(result.isValid).toBe(false) - expect(result.reason).toBe('Invalid email format') - }) + it.concurrent('should reject email longer than 254 characters', () => { + const longLocal = 'a'.repeat(64) + const longDomain = `${'b'.repeat(180)}.com` + const result = quickValidateEmail(`${longLocal}@${longDomain}`) + expect(result.isValid).toBe(false) + }) - it.concurrent('should validate complex but valid local parts', () => { - const result = quickValidateEmail('user+tag@example.com') + it.concurrent('should accept valid email formats', () => { + const validEmails = [ + 'simple@example.com', + 'very.common@example.com', + 'disposable.style.email.with+symbol@example.com', + 'other.email-with-hyphen@example.com', + 'user.name+tag+sorting@example.com', + 'x@example.com', + 'example-indeed@strange-example.com', + 'example@s.example', + ] + + for (const email of validEmails) { + const result = quickValidateEmail(email) expect(result.isValid).toBe(true) expect(result.checks.syntax).toBe(true) - }) - - it.concurrent('should validate subdomains', () => { - const result = quickValidateEmail('user@mail.subdomain.example.com') - expect(result.isValid).toBe(true) - expect(result.checks.domain).toBe(true) - }) + expect(result.checks.disposable).toBe(true) + } }) - describe('isDisposableEmailFull', () => { - it('should reject domains from the inline blocklist', () => { - expect(isDisposableEmailFull('user@sharebot.net')).toBe(true) - expect(isDisposableEmailFull('user@oakon.com')).toBe(true) - expect(isDisposableEmailFull('user@catchmail.io')).toBe(true) - expect(isDisposableEmailFull('user@salt.email')).toBe(true) - expect(isDisposableEmailFull('user@mail.gw')).toBe(true) - expect(isDisposableEmailFull('user@mailinator.com')).toBe(true) - }) - - it('should reject domains from the npm package list that are not in the inline list', () => { - expect(isDisposableEmailFull('user@0-mail.com')).toBe(true) - expect(isDisposableEmailFull('user@0-180.com')).toBe(true) - }) - - it('should allow legitimate email domains', () => { - expect(isDisposableEmailFull('user@gmail.com')).toBe(false) - expect(isDisposableEmailFull('user@company.com')).toBe(false) - expect(isDisposableEmailFull('user@outlook.com')).toBe(false) - }) - - it('should handle invalid input', () => { - expect(isDisposableEmailFull('')).toBe(false) - expect(isDisposableEmailFull('nodomain')).toBe(false) - expect(isDisposableEmailFull('user@')).toBe(false) - }) - - it('should be case-insensitive', () => { - expect(isDisposableEmailFull('user@MAILINATOR.COM')).toBe(true) - expect(isDisposableEmailFull('user@ShareBot.Net')).toBe(true) - }) + it.concurrent('should return high confidence for syntax errors', () => { + const result = quickValidateEmail('not-valid-email') + expect(result.confidence).toBe('high') }) - describe('isDisposableMxBackend', () => { - it('should detect mail.gw MX backend', async () => { - mockResolveMx.mockImplementation( - ( - _domain: string, - callback: (err: Error | null, addresses: { exchange: string; priority: number }[]) => void - ) => { - callback(null, [{ exchange: 'in.mail.gw', priority: 10 }]) - } - ) - expect(await isDisposableMxBackend('user@some-random-domain.xyz')).toBe(true) - }) - - it('should detect catchmail.io MX backend', async () => { - mockResolveMx.mockImplementation( - ( - _domain: string, - callback: (err: Error | null, addresses: { exchange: string; priority: number }[]) => void - ) => { - callback(null, [{ exchange: 'smtp.catchmail.io', priority: 10 }]) - } - ) - expect(await isDisposableMxBackend('user@custom-domain.com')).toBe(true) - }) + it.concurrent('should handle special characters in local part', () => { + const result = quickValidateEmail("user!#$%&'*+/=?^_`{|}~@example.com") + expect(result.checks.syntax).toBe(true) + }) - it('should handle trailing dot in MX exchange', async () => { - mockResolveMx.mockImplementation( - ( - _domain: string, - callback: (err: Error | null, addresses: { exchange: string; priority: number }[]) => void - ) => { - callback(null, [{ exchange: 'in.mail.gw.', priority: 10 }]) - } - ) - expect(await isDisposableMxBackend('user@trailing-dot.com')).toBe(true) - }) + it.concurrent('should handle empty string', () => { + const result = quickValidateEmail('') + expect(result.isValid).toBe(false) + expect(result.reason).toBe('Invalid email format') + }) - it('should allow legitimate MX backends', async () => { - mockResolveMx.mockImplementation( - ( - _domain: string, - callback: (err: Error | null, addresses: { exchange: string; priority: number }[]) => void - ) => { - callback(null, [{ exchange: 'aspmx.l.google.com', priority: 10 }]) - } - ) - expect(await isDisposableMxBackend('user@legitimate.com')).toBe(false) - }) + it.concurrent('should handle email with only @ symbol', () => { + const result = quickValidateEmail('@') + expect(result.isValid).toBe(false) + }) - it('should return false on DNS errors', async () => { - mockResolveMx.mockImplementation( - (_domain: string, callback: (err: Error | null, addresses: null) => void) => { - callback(new Error('ENOTFOUND'), null) - } - ) - expect(await isDisposableMxBackend('user@nonexistent.invalid')).toBe(false) - }) + it.concurrent('should handle email with spaces', () => { + const result = quickValidateEmail('user name@example.com') + expect(result.isValid).toBe(false) + }) - it('should return false for invalid input', async () => { - expect(await isDisposableMxBackend('')).toBe(false) - expect(await isDisposableMxBackend('nodomain')).toBe(false) - }) + it.concurrent('should handle email with multiple @ symbols', () => { + const result = quickValidateEmail('user@domain@example.com') + expect(result.isValid).toBe(false) }) - describe('validateEmail with disposable MX backend', () => { - it('should reject emails with disposable MX backend even if domain is not in blocklist', async () => { - mockResolveMx.mockImplementation( - ( - _domain: string, - callback: (err: Error | null, addresses: { exchange: string; priority: number }[]) => void - ) => { - callback(null, [{ exchange: 'in.mail.gw', priority: 10 }]) - } - ) - const result = await validateEmail('user@unknown-disposable.xyz') - expect(result.isValid).toBe(false) - expect(result.reason).toBe('Disposable email addresses are not allowed') - expect(result.checks.disposable).toBe(false) - }) + it.concurrent('should validate subdomains', () => { + const result = quickValidateEmail('user@mail.subdomain.example.com') + expect(result.isValid).toBe(true) + expect(result.checks.domain).toBe(true) }) }) diff --git a/apps/sim/lib/messaging/email/validation.ts b/apps/sim/lib/messaging/email/validation.ts index 4e076a30e19..8731f5f7449 100644 --- a/apps/sim/lib/messaging/email/validation.ts +++ b/apps/sim/lib/messaging/email/validation.ts @@ -1,7 +1,3 @@ -import { createLogger } from '@sim/logger' - -const logger = createLogger('EmailValidation') - export interface EmailValidationResult { isValid: boolean reason?: string @@ -14,8 +10,8 @@ export interface EmailValidationResult { } } -/** Common disposable domains for fast client-side checks (no heavy import needed) */ -const DISPOSABLE_DOMAINS_INLINE = new Set([ +/** Common disposable domains for fast client-side feedback */ +const DISPOSABLE_DOMAINS = new Set([ '10minutemail.com', '10minutemail.net', 'catchmail.io', @@ -42,37 +38,6 @@ const DISPOSABLE_DOMAINS_INLINE = new Set([ 'yopmail.com', ]) -/** Full disposable domain list from npm package (~5.3K domains), lazy-loaded server-side only */ -let disposableDomainsFull: Set | null = null - -function getDisposableDomainsFull(): Set { - if (!disposableDomainsFull) { - try { - // eslint-disable-next-line @typescript-eslint/no-require-imports - const domains = require('disposable-email-domains') as string[] - disposableDomainsFull = new Set(domains) - } catch { - logger.warn('Failed to load disposable-email-domains package') - disposableDomainsFull = new Set() - } - } - return disposableDomainsFull -} - -/** MX hostnames used by known disposable email backends */ -const DISPOSABLE_MX_BACKENDS = new Set(['in.mail.gw', 'smtp.catchmail.io', 'mx.yopmail.com']) - -/** Per-domain MX result cache — avoids redundant DNS queries for concurrent or repeated sign-ups */ -const mxCache = new Map() -const MX_CACHE_MAX = 1_000 - -function setMxCache(domain: string, entry: { result: boolean; expires: number }) { - if (mxCache.size >= MX_CACHE_MAX && !mxCache.has(domain)) { - mxCache.delete(mxCache.keys().next().value!) - } - mxCache.set(domain, entry) -} - /** * Validates email syntax using RFC 5322 compliant regex */ @@ -83,87 +48,19 @@ function validateEmailSyntax(email: string): boolean { } /** - * Checks if domain has valid MX records and is not backed by a disposable email service (server-side only) - */ -async function checkMXRecord( - domain: string -): Promise<{ exists: boolean; isDisposableBackend: boolean }> { - // Skip MX check on client-side (browser) - if (typeof window !== 'undefined') { - return { exists: true, isDisposableBackend: false } - } - - try { - const { promisify } = await import('util') - const dns = await import('dns') - const resolveMx = promisify(dns.resolveMx) - - const mxRecords = await resolveMx(domain) - if (!mxRecords || mxRecords.length === 0) { - return { exists: false, isDisposableBackend: false } - } - - const isDisposableBackend = mxRecords.some((record: { exchange: string }) => - DISPOSABLE_MX_BACKENDS.has(record.exchange.toLowerCase().replace(/\.$/, '')) - ) - - return { exists: true, isDisposableBackend } - } catch (error) { - logger.debug('MX record check failed', { domain, error }) - return { exists: false, isDisposableBackend: false } - } -} - -/** - * Checks against the full disposable email domain list (~5.3K domains server-side, inline list client-side) + * Checks if email is from a known disposable email provider */ -export function isDisposableEmailFull(email: string): boolean { +function isDisposableEmail(email: string): boolean { const domain = email.split('@')[1]?.toLowerCase() - if (!domain) return false - return DISPOSABLE_DOMAINS_INLINE.has(domain) || getDisposableDomainsFull().has(domain) -} - -/** - * Checks if an email's MX records point to a known disposable email backend (server-side only) - */ -export async function isDisposableMxBackend(email: string): Promise { - const domain = email.split('@')[1]?.toLowerCase() - if (!domain) return false - - const now = Date.now() - const cached = mxCache.get(domain) - if (cached) { - if (cached.expires > now) return cached.result - mxCache.delete(domain) - } - - let timeoutId: ReturnType | undefined - try { - const mxCheckPromise = checkMXRecord(domain) - const timeoutPromise = new Promise<{ exists: boolean; isDisposableBackend: boolean }>( - (_, reject) => { - timeoutId = setTimeout(() => reject(new Error('MX check timeout')), 5000) - } - ) - const result = await Promise.race([mxCheckPromise, timeoutPromise]) - setMxCache(domain, { result: result.isDisposableBackend, expires: now + 5 * 60 * 1000 }) - return result.isDisposableBackend - } catch { - setMxCache(domain, { result: false, expires: now + 60 * 1000 }) - return false - } finally { - clearTimeout(timeoutId) - } + return domain ? DISPOSABLE_DOMAINS.has(domain) : false } /** * Checks for obvious patterns that indicate invalid emails */ function hasInvalidPatterns(email: string): boolean { - // Check for consecutive dots (RFC violation) if (email.includes('..')) return true - // Check for local part length (RFC limit is 64 characters) const localPart = email.split('@')[0] if (localPart && localPart.length > 64) return true @@ -171,133 +68,14 @@ function hasInvalidPatterns(email: string): boolean { } /** - * Validates an email address comprehensively - */ -export async function validateEmail(email: string): Promise { - const checks = { - syntax: false, - domain: false, - mxRecord: false, - disposable: false, - } - - try { - // 1. Basic syntax validation - checks.syntax = validateEmailSyntax(email) - if (!checks.syntax) { - return { - isValid: false, - reason: 'Invalid email format', - confidence: 'high', - checks, - } - } - - const domain = email.split('@')[1]?.toLowerCase() - if (!domain) { - return { - isValid: false, - reason: 'Missing domain', - confidence: 'high', - checks, - } - } - - // 2. Check for disposable email against full list (server-side) - checks.disposable = !isDisposableEmailFull(email) - if (!checks.disposable) { - return { - isValid: false, - reason: 'Disposable email addresses are not allowed', - confidence: 'high', - checks, - } - } - - // 3. Check for invalid patterns - if (hasInvalidPatterns(email)) { - return { - isValid: false, - reason: 'Email contains suspicious patterns', - confidence: 'high', - checks, - } - } - - // 4. Domain validation - check for obvious invalid domains - checks.domain = domain.includes('.') && !domain.startsWith('.') && !domain.endsWith('.') - if (!checks.domain) { - return { - isValid: false, - reason: 'Invalid domain format', - confidence: 'high', - checks, - } - } - - // 5. MX record check (with timeout) — also detects disposable email backends - let mxTimeoutId: ReturnType | undefined - try { - const mxCheckPromise = checkMXRecord(domain) - const timeoutPromise = new Promise<{ exists: boolean; isDisposableBackend: boolean }>( - (_, reject) => { - mxTimeoutId = setTimeout(() => reject(new Error('MX check timeout')), 5000) - } - ) - - const mxResult = await Promise.race([mxCheckPromise, timeoutPromise]) - checks.mxRecord = mxResult.exists - - if (mxResult.isDisposableBackend) { - checks.disposable = false - return { - isValid: false, - reason: 'Disposable email addresses are not allowed', - confidence: 'high', - checks, - } - } - } catch (error) { - logger.debug('MX record check failed or timed out', { domain, error }) - checks.mxRecord = false - } finally { - clearTimeout(mxTimeoutId) - } - - // Determine overall validity and confidence - if (!checks.mxRecord) { - return { - isValid: false, - reason: 'Domain does not accept emails (no MX records)', - confidence: 'high', - checks, - } - } - - return { - isValid: true, - confidence: 'high', - checks, - } - } catch (error) { - logger.error('Email validation error', { email, error }) - return { - isValid: false, - reason: 'Validation service temporarily unavailable', - confidence: 'low', - checks, - } - } -} - -/** - * Quick validation for high-volume scenarios (skips MX check) + * Quick email validation for client-side form feedback. + * Server-side disposable blocking is handled by better-auth-harmony (55K+ domains). */ export function quickValidateEmail(email: string): EmailValidationResult { const checks = { syntax: false, domain: false, - mxRecord: true, // Skip MX check for performance + mxRecord: true, disposable: false, } @@ -321,7 +99,7 @@ export function quickValidateEmail(email: string): EmailValidationResult { } } - checks.disposable = !isDisposableEmailFull(email) + checks.disposable = !isDisposableEmail(email) if (!checks.disposable) { return { isValid: false, diff --git a/apps/sim/next.config.ts b/apps/sim/next.config.ts index 1b23b9ec93d..48cefec6661 100644 --- a/apps/sim/next.config.ts +++ b/apps/sim/next.config.ts @@ -120,6 +120,7 @@ const nextConfig: NextConfig = { '@t3-oss/env-nextjs', '@t3-oss/env-core', '@sim/db', + 'better-auth-harmony', ], async headers() { return [ diff --git a/apps/sim/package.json b/apps/sim/package.json index 8e958df57ad..5c3fb544b95 100644 --- a/apps/sim/package.json +++ b/apps/sim/package.json @@ -41,6 +41,7 @@ "@azure/storage-blob": "12.27.0", "@better-auth/sso": "1.3.12", "@better-auth/stripe": "1.3.12", + "@marsidev/react-turnstile": "1.4.2", "@browserbasehq/stagehand": "^3.0.5", "@cerebras/cerebras_cloud_sdk": "^1.23.0", "@e2b/code-interpreter": "^2.0.0", @@ -87,6 +88,7 @@ "@types/react-window": "2.0.0", "@types/three": "0.177.0", "better-auth": "1.3.12", + "better-auth-harmony": "1.3.1", "binary-extensions": "^2.0.0", "browser-image-compression": "^2.0.2", "chalk": "5.6.2", @@ -99,7 +101,6 @@ "csv-parse": "6.1.0", "date-fns": "4.1.0", "decimal.js": "10.6.0", - "disposable-email-domains": "1.0.62", "drizzle-orm": "^0.44.5", "encoding": "0.1.13", "entities": "6.0.1", diff --git a/bun.lock b/bun.lock index 1978ecadb87..cd5dc2f1e00 100644 --- a/bun.lock +++ b/bun.lock @@ -73,6 +73,7 @@ "@google/genai": "1.34.0", "@hookform/resolvers": "^4.1.3", "@linear/sdk": "40.0.0", + "@marsidev/react-turnstile": "1.4.2", "@modelcontextprotocol/sdk": "1.20.2", "@opentelemetry/api": "^1.9.0", "@opentelemetry/exporter-jaeger": "2.1.0", @@ -113,6 +114,7 @@ "@types/react-window": "2.0.0", "@types/three": "0.177.0", "better-auth": "1.3.12", + "better-auth-harmony": "1.3.1", "binary-extensions": "^2.0.0", "browser-image-compression": "^2.0.2", "chalk": "5.6.2", @@ -125,7 +127,6 @@ "csv-parse": "6.1.0", "date-fns": "4.1.0", "decimal.js": "10.6.0", - "disposable-email-domains": "1.0.62", "drizzle-orm": "^0.44.5", "encoding": "0.1.13", "entities": "6.0.1", @@ -810,6 +811,8 @@ "@linear/sdk": ["@linear/sdk@40.0.0", "", { "dependencies": { "@graphql-typed-document-node/core": "^3.1.0", "graphql": "^15.4.0", "isomorphic-unfetch": "^3.1.0" } }, "sha512-R4lyDIivdi00fO+DYPs7gWNX221dkPJhgDowFrsfos/rNG6o5HixsCPgwXWtKN0GA0nlqLvFTmzvzLXpud1xKw=="], + "@marsidev/react-turnstile": ["@marsidev/react-turnstile@1.4.2", "", { "peerDependencies": { "react": "^17.0.2 || ^18.0.0 || ^19.0", "react-dom": "^17.0.2 || ^18.0.0 || ^19.0" } }, "sha512-xs1qOuyeMOz6t9BXXCXWiukC0/0+48vR08B7uwNdG05wCMnbcNgxiFmdFKDOFbM76qFYFRYlGeRfhfq1U/iZmA=="], + "@mdx-js/mdx": ["@mdx-js/mdx@3.1.1", "", { "dependencies": { "@types/estree": "^1.0.0", "@types/estree-jsx": "^1.0.0", "@types/hast": "^3.0.0", "@types/mdx": "^2.0.0", "acorn": "^8.0.0", "collapse-white-space": "^2.0.0", "devlop": "^1.0.0", "estree-util-is-identifier-name": "^3.0.0", "estree-util-scope": "^1.0.0", "estree-walker": "^3.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "markdown-extensions": "^2.0.0", "recma-build-jsx": "^1.0.0", "recma-jsx": "^1.0.0", "recma-stringify": "^1.0.0", "rehype-recma": "^1.0.0", "remark-mdx": "^3.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "source-map": "^0.7.0", "unified": "^11.0.0", "unist-util-position-from-estree": "^2.0.0", "unist-util-stringify-position": "^4.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ=="], "@mdx-js/react": ["@mdx-js/react@3.1.1", "", { "dependencies": { "@types/mdx": "^2.0.0" }, "peerDependencies": { "@types/react": ">=16", "react": ">=16" } }, "sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw=="], @@ -1762,6 +1765,8 @@ "better-auth": ["better-auth@1.3.12", "", { "dependencies": { "@better-auth/utils": "0.3.0", "@better-fetch/fetch": "^1.1.18", "@noble/ciphers": "^2.0.0", "@noble/hashes": "^2.0.0", "@simplewebauthn/browser": "^13.1.2", "@simplewebauthn/server": "^13.1.2", "better-call": "1.0.19", "defu": "^6.1.4", "jose": "^6.1.0", "kysely": "^0.28.5", "nanostores": "^1.0.1", "zod": "^4.1.5" }, "peerDependencies": { "@lynx-js/react": "*", "@sveltejs/kit": "^2.0.0", "next": "^14.0.0 || ^15.0.0", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0", "solid-js": "^1.0.0", "svelte": "^4.0.0 || ^5.0.0", "vue": "^3.0.0" }, "optionalPeers": ["@lynx-js/react", "@sveltejs/kit", "next", "react", "react-dom", "solid-js", "svelte", "vue"] }, "sha512-FckxiAexCkkk2F0EOPmhXjWhYYE8eYg2x68lOIirSgyQ0TWc4JDvA5y8Vax5Jc7iyXk5MjJBY3DfwTPDZ87Lbg=="], + "better-auth-harmony": ["better-auth-harmony@1.3.1", "", { "dependencies": { "libphonenumber-js": "^1.12.37", "mailchecker": "^6.0.19", "validator": "^13.15.26" }, "peerDependencies": { "better-auth": "^1.0.3" } }, "sha512-CiChZMBxuq35YqwyA2pcuL7KfAdrxa+VGLShL+yortprC5E04kttV0XsdsaTIej+d0MxFKIcq7PPaInaEyV3DQ=="], + "better-call": ["better-call@1.0.19", "", { "dependencies": { "@better-auth/utils": "^0.3.0", "@better-fetch/fetch": "^1.1.4", "rou3": "^0.5.1", "set-cookie-parser": "^2.7.1", "uncrypto": "^0.1.3" } }, "sha512-sI3GcA1SCVa3H+CDHl8W8qzhlrckwXOTKhqq3OOPXjgn5aTOMIqGY34zLY/pHA6tRRMjTUC3lz5Mi7EbDA24Kw=="], "bignumber.js": ["bignumber.js@9.3.1", "", {}, "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ=="], @@ -2056,8 +2061,6 @@ "dingbat-to-unicode": ["dingbat-to-unicode@1.0.1", "", {}, "sha512-98l0sW87ZT58pU4i61wa2OHwxbiYSbuxsCBozaVnYX2iCnr3bLM3fIes1/ej7h1YdOKuKt/MLs706TVnALA65w=="], - "disposable-email-domains": ["disposable-email-domains@1.0.62", "", {}, "sha512-LBQvhRw7mznQTPoyZbsmYeNOZt1pN5aCsx4BAU/3siVFuiM9f2oyKzUaB8v1jbxFjE3aYqYiMo63kAL4pHgfWQ=="], - "dlv": ["dlv@1.1.3", "", {}, "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="], "dockerfile-ast": ["dockerfile-ast@0.7.1", "", { "dependencies": { "vscode-languageserver-textdocument": "^1.0.8", "vscode-languageserver-types": "^3.17.3" } }, "sha512-oX/A4I0EhSkGqrFv0YuvPkBUSYp1XiY8O8zAKc8Djglx8ocz+JfOr8gP0ryRMC2myqvDLagmnZaU9ot1vG2ijw=="], @@ -2576,6 +2579,8 @@ "libmime": ["libmime@5.3.7", "", { "dependencies": { "encoding-japanese": "2.2.0", "iconv-lite": "0.6.3", "libbase64": "1.3.0", "libqp": "2.1.1" } }, "sha512-FlDb3Wtha8P01kTL3P9M+ZDNDWPKPmKHWaU/cG/lg5pfuAwdflVpZE+wm9m7pKmC5ww6s+zTxBKS1p6yl3KpSw=="], + "libphonenumber-js": ["libphonenumber-js@1.12.40", "", {}, "sha512-HKGs7GowShNls3Zh+7DTr6wYpPk5jC78l508yQQY3e8ZgJChM3A9JZghmMJZuK+5bogSfuTafpjksGSR3aMIEg=="], + "libqp": ["libqp@2.1.1", "", {}, "sha512-0Wd+GPz1O134cP62YU2GTOPNA7Qgl09XwCqM5zpBv87ERCXdfDtyKXvV7c9U22yWJh44QZqBocFnXN11K96qow=="], "lie": ["lie@3.3.0", "", { "dependencies": { "immediate": "~3.0.5" } }, "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ=="], @@ -2660,6 +2665,8 @@ "magicast": ["magicast@0.3.5", "", { "dependencies": { "@babel/parser": "^7.25.4", "@babel/types": "^7.25.4", "source-map-js": "^1.2.0" } }, "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ=="], + "mailchecker": ["mailchecker@6.0.20", "", {}, "sha512-mZ3kmtfXzGj06prtNm6d8an7D++Kf1G4jEkPZ1QQyhknYNLkmGoMtfaNPNHJU6E8J+Bm3AcZlIIfq5D6L4MS2g=="], + "make-dir": ["make-dir@4.0.0", "", { "dependencies": { "semver": "^7.5.3" } }, "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw=="], "mammoth": ["mammoth@1.11.0", "", { "dependencies": { "@xmldom/xmldom": "^0.8.6", "argparse": "~1.0.3", "base64-js": "^1.5.1", "bluebird": "~3.4.0", "dingbat-to-unicode": "^1.0.1", "jszip": "^3.7.1", "lop": "^0.4.2", "path-is-absolute": "^1.0.0", "underscore": "^1.13.1", "xmlbuilder": "^10.0.0" }, "bin": { "mammoth": "bin/mammoth" } }, "sha512-BcEqqY/BOwIcI1iR5tqyVlqc3KIaMRa4egSoK83YAVrBf6+yqdAAbtUcFDCWX8Zef8/fgNZ6rl4VUv+vVX8ddQ=="], @@ -3622,6 +3629,8 @@ "uzip": ["uzip@0.20201231.0", "", {}, "sha512-OZeJfZP+R0z9D6TmBgLq2LHzSSptGMGDGigGiEe0pr8UBe/7fdflgHlHBNDASTXB5jnFuxHpNaJywSg8YFeGng=="], + "validator": ["validator@13.15.26", "", {}, "sha512-spH26xU080ydGggxRyR1Yhcbgx+j3y5jbNXk/8L+iRvdIEQ4uTRH2Sgf2dokud6Q4oAtsbNvJ1Ft+9xmm6IZcA=="], + "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], "vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="], diff --git a/helm/sim/values.yaml b/helm/sim/values.yaml index af6bbc10c3b..9b59e1b7582 100644 --- a/helm/sim/values.yaml +++ b/helm/sim/values.yaml @@ -176,6 +176,11 @@ app: DISABLE_REGISTRATION: "" # Set to "true" to disable new user signups EMAIL_PASSWORD_SIGNUP_ENABLED: "" # Set to "false" to disable email/password login (SSO-only mode, server-side enforcement) NEXT_PUBLIC_EMAIL_PASSWORD_SIGNUP_ENABLED: "" # Set to "false" to hide email/password login form (UI-side) + SIGNUP_EMAIL_VALIDATION_ENABLED: "" # Set to "true" to block 55K+ disposable email domains (requires normalized_email migration) + + # Bot Protection (Cloudflare Turnstile) + TURNSTILE_SECRET_KEY: "" # Cloudflare Turnstile secret key (leave empty to disable captcha) + NEXT_PUBLIC_TURNSTILE_SITE_KEY: "" # Cloudflare Turnstile site key (leave empty to disable captcha) # Access Control (leave empty if not restricting login) ALLOWED_LOGIN_EMAILS: "" # Comma-separated list of allowed email addresses for login diff --git a/packages/db/migrations/0178_clumsy_living_mummy.sql b/packages/db/migrations/0178_clumsy_living_mummy.sql new file mode 100644 index 00000000000..81df303f22b --- /dev/null +++ b/packages/db/migrations/0178_clumsy_living_mummy.sql @@ -0,0 +1,2 @@ +ALTER TABLE "user" ADD COLUMN "normalized_email" text;--> statement-breakpoint +ALTER TABLE "user" ADD CONSTRAINT "user_normalized_email_unique" UNIQUE("normalized_email"); \ No newline at end of file diff --git a/packages/db/migrations/meta/0178_snapshot.json b/packages/db/migrations/meta/0178_snapshot.json new file mode 100644 index 00000000000..d68aa20ce96 --- /dev/null +++ b/packages/db/migrations/meta/0178_snapshot.json @@ -0,0 +1,13577 @@ +{ + "id": "4ca60b0b-40a0-4bc4-90bc-2b11647361ee", + "prevId": "b8080b7c-bf0f-46eb-b689-f5019c66771f", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.a2a_agent": { + "name": "a2a_agent", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "version": { + "name": "version", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'1.0.0'" + }, + "capabilities": { + "name": "capabilities", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "skills": { + "name": "skills", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'" + }, + "authentication": { + "name": "authentication", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "signatures": { + "name": "signatures", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'" + }, + "is_published": { + "name": "is_published", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "published_at": { + "name": "published_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "a2a_agent_workflow_id_idx": { + "name": "a2a_agent_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "a2a_agent_created_by_idx": { + "name": "a2a_agent_created_by_idx", + "columns": [ + { + "expression": "created_by", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "a2a_agent_workspace_workflow_unique": { + "name": "a2a_agent_workspace_workflow_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"a2a_agent\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "a2a_agent_archived_at_idx": { + "name": "a2a_agent_archived_at_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "a2a_agent_workspace_id_workspace_id_fk": { + "name": "a2a_agent_workspace_id_workspace_id_fk", + "tableFrom": "a2a_agent", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "a2a_agent_workflow_id_workflow_id_fk": { + "name": "a2a_agent_workflow_id_workflow_id_fk", + "tableFrom": "a2a_agent", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "a2a_agent_created_by_user_id_fk": { + "name": "a2a_agent_created_by_user_id_fk", + "tableFrom": "a2a_agent", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.a2a_push_notification_config": { + "name": "a2a_push_notification_config", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "task_id": { + "name": "task_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "auth_schemes": { + "name": "auth_schemes", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'" + }, + "auth_credentials": { + "name": "auth_credentials", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "a2a_push_notification_config_task_unique": { + "name": "a2a_push_notification_config_task_unique", + "columns": [ + { + "expression": "task_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "a2a_push_notification_config_task_id_a2a_task_id_fk": { + "name": "a2a_push_notification_config_task_id_a2a_task_id_fk", + "tableFrom": "a2a_push_notification_config", + "tableTo": "a2a_task", + "columnsFrom": ["task_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.a2a_task": { + "name": "a2a_task", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "agent_id": { + "name": "agent_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "a2a_task_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'submitted'" + }, + "messages": { + "name": "messages", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'" + }, + "artifacts": { + "name": "artifacts", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'" + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "a2a_task_agent_id_idx": { + "name": "a2a_task_agent_id_idx", + "columns": [ + { + "expression": "agent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "a2a_task_session_id_idx": { + "name": "a2a_task_session_id_idx", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "a2a_task_status_idx": { + "name": "a2a_task_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "a2a_task_execution_id_idx": { + "name": "a2a_task_execution_id_idx", + "columns": [ + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "a2a_task_created_at_idx": { + "name": "a2a_task_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "a2a_task_agent_id_a2a_agent_id_fk": { + "name": "a2a_task_agent_id_a2a_agent_id_fk", + "tableFrom": "a2a_task", + "tableTo": "a2a_agent", + "columnsFrom": ["agent_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.account": { + "name": "account", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "account_user_id_idx": { + "name": "account_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_account_on_account_id_provider_id": { + "name": "idx_account_on_account_id_provider_id", + "columns": [ + { + "expression": "account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.api_key": { + "name": "api_key", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'personal'" + }, + "last_used": { + "name": "last_used", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "api_key_workspace_type_idx": { + "name": "api_key_workspace_type_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "api_key_user_type_idx": { + "name": "api_key_user_type_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "api_key_user_id_user_id_fk": { + "name": "api_key_user_id_user_id_fk", + "tableFrom": "api_key", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "api_key_workspace_id_workspace_id_fk": { + "name": "api_key_workspace_id_workspace_id_fk", + "tableFrom": "api_key", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "api_key_created_by_user_id_fk": { + "name": "api_key_created_by_user_id_fk", + "tableFrom": "api_key", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "api_key_key_unique": { + "name": "api_key_key_unique", + "nullsNotDistinct": false, + "columns": ["key"] + } + }, + "policies": {}, + "checkConstraints": { + "workspace_type_check": { + "name": "workspace_type_check", + "value": "(type = 'workspace' AND workspace_id IS NOT NULL) OR (type = 'personal' AND workspace_id IS NULL)" + } + }, + "isRLSEnabled": false + }, + "public.async_jobs": { + "name": "async_jobs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "run_at": { + "name": "run_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "max_attempts": { + "name": "max_attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 3 + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "output": { + "name": "output", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "async_jobs_status_started_at_idx": { + "name": "async_jobs_status_started_at_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "async_jobs_status_completed_at_idx": { + "name": "async_jobs_status_completed_at_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "completed_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.audit_log": { + "name": "audit_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "actor_id": { + "name": "actor_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_type": { + "name": "resource_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "actor_name": { + "name": "actor_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "actor_email": { + "name": "actor_email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "resource_name": { + "name": "resource_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "audit_log_workspace_created_idx": { + "name": "audit_log_workspace_created_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "audit_log_actor_created_idx": { + "name": "audit_log_actor_created_idx", + "columns": [ + { + "expression": "actor_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "audit_log_resource_idx": { + "name": "audit_log_resource_idx", + "columns": [ + { + "expression": "resource_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "audit_log_action_idx": { + "name": "audit_log_action_idx", + "columns": [ + { + "expression": "action", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "audit_log_workspace_id_workspace_id_fk": { + "name": "audit_log_workspace_id_workspace_id_fk", + "tableFrom": "audit_log", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "audit_log_actor_id_user_id_fk": { + "name": "audit_log_actor_id_user_id_fk", + "tableFrom": "audit_log", + "tableTo": "user", + "columnsFrom": ["actor_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.chat": { + "name": "chat", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "customizations": { + "name": "customizations", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "auth_type": { + "name": "auth_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'public'" + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "allowed_emails": { + "name": "allowed_emails", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'[]'" + }, + "output_configs": { + "name": "output_configs", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'[]'" + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "identifier_idx": { + "name": "identifier_idx", + "columns": [ + { + "expression": "identifier", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"chat\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "chat_archived_at_idx": { + "name": "chat_archived_at_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "chat_workflow_id_workflow_id_fk": { + "name": "chat_workflow_id_workflow_id_fk", + "tableFrom": "chat", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "chat_user_id_user_id_fk": { + "name": "chat_user_id_user_id_fk", + "tableFrom": "chat", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.copilot_chats": { + "name": "copilot_chats", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "chat_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'copilot'" + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "messages": { + "name": "messages", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'" + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'claude-3-7-sonnet-latest'" + }, + "conversation_id": { + "name": "conversation_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "preview_yaml": { + "name": "preview_yaml", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "plan_artifact": { + "name": "plan_artifact", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "config": { + "name": "config", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "resources": { + "name": "resources", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'" + }, + "last_seen_at": { + "name": "last_seen_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "copilot_chats_user_id_idx": { + "name": "copilot_chats_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_workflow_id_idx": { + "name": "copilot_chats_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_user_workflow_idx": { + "name": "copilot_chats_user_workflow_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_user_workspace_idx": { + "name": "copilot_chats_user_workspace_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_created_at_idx": { + "name": "copilot_chats_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_updated_at_idx": { + "name": "copilot_chats_updated_at_idx", + "columns": [ + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "copilot_chats_user_id_user_id_fk": { + "name": "copilot_chats_user_id_user_id_fk", + "tableFrom": "copilot_chats", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_chats_workflow_id_workflow_id_fk": { + "name": "copilot_chats_workflow_id_workflow_id_fk", + "tableFrom": "copilot_chats", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_chats_workspace_id_workspace_id_fk": { + "name": "copilot_chats_workspace_id_workspace_id_fk", + "tableFrom": "copilot_chats", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.copilot_feedback": { + "name": "copilot_feedback", + "schema": "", + "columns": { + "feedback_id": { + "name": "feedback_id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chat_id": { + "name": "chat_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_query": { + "name": "user_query", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "agent_response": { + "name": "agent_response", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "is_positive": { + "name": "is_positive", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "feedback": { + "name": "feedback", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workflow_yaml": { + "name": "workflow_yaml", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "copilot_feedback_user_id_idx": { + "name": "copilot_feedback_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_feedback_chat_id_idx": { + "name": "copilot_feedback_chat_id_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_feedback_user_chat_idx": { + "name": "copilot_feedback_user_chat_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_feedback_is_positive_idx": { + "name": "copilot_feedback_is_positive_idx", + "columns": [ + { + "expression": "is_positive", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_feedback_created_at_idx": { + "name": "copilot_feedback_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "copilot_feedback_user_id_user_id_fk": { + "name": "copilot_feedback_user_id_user_id_fk", + "tableFrom": "copilot_feedback", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_feedback_chat_id_copilot_chats_id_fk": { + "name": "copilot_feedback_chat_id_copilot_chats_id_fk", + "tableFrom": "copilot_feedback", + "tableTo": "copilot_chats", + "columnsFrom": ["chat_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.credential": { + "name": "credential", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "credential_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env_key": { + "name": "env_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env_owner_user_id": { + "name": "env_owner_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "credential_workspace_id_idx": { + "name": "credential_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_type_idx": { + "name": "credential_type_idx", + "columns": [ + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_provider_id_idx": { + "name": "credential_provider_id_idx", + "columns": [ + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_account_id_idx": { + "name": "credential_account_id_idx", + "columns": [ + { + "expression": "account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_env_owner_user_id_idx": { + "name": "credential_env_owner_user_id_idx", + "columns": [ + { + "expression": "env_owner_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_workspace_account_unique": { + "name": "credential_workspace_account_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "account_id IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_workspace_env_unique": { + "name": "credential_workspace_env_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "env_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "type = 'env_workspace'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_workspace_personal_env_unique": { + "name": "credential_workspace_personal_env_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "env_key", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "env_owner_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "type = 'env_personal'", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "credential_workspace_id_workspace_id_fk": { + "name": "credential_workspace_id_workspace_id_fk", + "tableFrom": "credential", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_account_id_account_id_fk": { + "name": "credential_account_id_account_id_fk", + "tableFrom": "credential", + "tableTo": "account", + "columnsFrom": ["account_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_env_owner_user_id_user_id_fk": { + "name": "credential_env_owner_user_id_user_id_fk", + "tableFrom": "credential", + "tableTo": "user", + "columnsFrom": ["env_owner_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_created_by_user_id_fk": { + "name": "credential_created_by_user_id_fk", + "tableFrom": "credential", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "credential_oauth_source_check": { + "name": "credential_oauth_source_check", + "value": "(type <> 'oauth') OR (account_id IS NOT NULL AND provider_id IS NOT NULL)" + }, + "credential_workspace_env_source_check": { + "name": "credential_workspace_env_source_check", + "value": "(type <> 'env_workspace') OR (env_key IS NOT NULL AND env_owner_user_id IS NULL)" + }, + "credential_personal_env_source_check": { + "name": "credential_personal_env_source_check", + "value": "(type <> 'env_personal') OR (env_key IS NOT NULL AND env_owner_user_id IS NOT NULL)" + } + }, + "isRLSEnabled": false + }, + "public.credential_member": { + "name": "credential_member", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "credential_id": { + "name": "credential_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "credential_member_role", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'member'" + }, + "status": { + "name": "status", + "type": "credential_member_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "joined_at": { + "name": "joined_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "invited_by": { + "name": "invited_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "credential_member_user_id_idx": { + "name": "credential_member_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_member_role_idx": { + "name": "credential_member_role_idx", + "columns": [ + { + "expression": "role", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_member_status_idx": { + "name": "credential_member_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_member_unique": { + "name": "credential_member_unique", + "columns": [ + { + "expression": "credential_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "credential_member_credential_id_credential_id_fk": { + "name": "credential_member_credential_id_credential_id_fk", + "tableFrom": "credential_member", + "tableTo": "credential", + "columnsFrom": ["credential_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_member_user_id_user_id_fk": { + "name": "credential_member_user_id_user_id_fk", + "tableFrom": "credential_member", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_member_invited_by_user_id_fk": { + "name": "credential_member_invited_by_user_id_fk", + "tableFrom": "credential_member", + "tableTo": "user", + "columnsFrom": ["invited_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.credential_set": { + "name": "credential_set", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "credential_set_created_by_idx": { + "name": "credential_set_created_by_idx", + "columns": [ + { + "expression": "created_by", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_set_org_name_unique": { + "name": "credential_set_org_name_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_set_provider_id_idx": { + "name": "credential_set_provider_id_idx", + "columns": [ + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "credential_set_organization_id_organization_id_fk": { + "name": "credential_set_organization_id_organization_id_fk", + "tableFrom": "credential_set", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_set_created_by_user_id_fk": { + "name": "credential_set_created_by_user_id_fk", + "tableFrom": "credential_set", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.credential_set_invitation": { + "name": "credential_set_invitation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "credential_set_id": { + "name": "credential_set_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "invited_by": { + "name": "invited_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "credential_set_invitation_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "accepted_at": { + "name": "accepted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "accepted_by_user_id": { + "name": "accepted_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "credential_set_invitation_set_id_idx": { + "name": "credential_set_invitation_set_id_idx", + "columns": [ + { + "expression": "credential_set_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_set_invitation_token_idx": { + "name": "credential_set_invitation_token_idx", + "columns": [ + { + "expression": "token", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_set_invitation_status_idx": { + "name": "credential_set_invitation_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_set_invitation_expires_at_idx": { + "name": "credential_set_invitation_expires_at_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "credential_set_invitation_credential_set_id_credential_set_id_fk": { + "name": "credential_set_invitation_credential_set_id_credential_set_id_fk", + "tableFrom": "credential_set_invitation", + "tableTo": "credential_set", + "columnsFrom": ["credential_set_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_set_invitation_invited_by_user_id_fk": { + "name": "credential_set_invitation_invited_by_user_id_fk", + "tableFrom": "credential_set_invitation", + "tableTo": "user", + "columnsFrom": ["invited_by"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_set_invitation_accepted_by_user_id_user_id_fk": { + "name": "credential_set_invitation_accepted_by_user_id_user_id_fk", + "tableFrom": "credential_set_invitation", + "tableTo": "user", + "columnsFrom": ["accepted_by_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "credential_set_invitation_token_unique": { + "name": "credential_set_invitation_token_unique", + "nullsNotDistinct": false, + "columns": ["token"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.credential_set_member": { + "name": "credential_set_member", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "credential_set_id": { + "name": "credential_set_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "credential_set_member_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "joined_at": { + "name": "joined_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "invited_by": { + "name": "invited_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "credential_set_member_user_id_idx": { + "name": "credential_set_member_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_set_member_unique": { + "name": "credential_set_member_unique", + "columns": [ + { + "expression": "credential_set_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_set_member_status_idx": { + "name": "credential_set_member_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "credential_set_member_credential_set_id_credential_set_id_fk": { + "name": "credential_set_member_credential_set_id_credential_set_id_fk", + "tableFrom": "credential_set_member", + "tableTo": "credential_set", + "columnsFrom": ["credential_set_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_set_member_user_id_user_id_fk": { + "name": "credential_set_member_user_id_user_id_fk", + "tableFrom": "credential_set_member", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_set_member_invited_by_user_id_fk": { + "name": "credential_set_member_invited_by_user_id_fk", + "tableFrom": "credential_set_member", + "tableTo": "user", + "columnsFrom": ["invited_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.custom_tools": { + "name": "custom_tools", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "schema": { + "name": "schema", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "code": { + "name": "code", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "custom_tools_workspace_id_idx": { + "name": "custom_tools_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "custom_tools_workspace_title_unique": { + "name": "custom_tools_workspace_title_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "title", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "custom_tools_workspace_id_workspace_id_fk": { + "name": "custom_tools_workspace_id_workspace_id_fk", + "tableFrom": "custom_tools", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "custom_tools_user_id_user_id_fk": { + "name": "custom_tools_user_id_user_id_fk", + "tableFrom": "custom_tools", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.docs_embeddings": { + "name": "docs_embeddings", + "schema": "", + "columns": { + "chunk_id": { + "name": "chunk_id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "chunk_text": { + "name": "chunk_text", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_document": { + "name": "source_document", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_link": { + "name": "source_link", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "header_text": { + "name": "header_text", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "header_level": { + "name": "header_level", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "token_count": { + "name": "token_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "embedding": { + "name": "embedding", + "type": "vector(1536)", + "primaryKey": false, + "notNull": true + }, + "embedding_model": { + "name": "embedding_model", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'text-embedding-3-small'" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "chunk_text_tsv": { + "name": "chunk_text_tsv", + "type": "tsvector", + "primaryKey": false, + "notNull": false, + "generated": { + "as": "to_tsvector('english', \"docs_embeddings\".\"chunk_text\")", + "type": "stored" + } + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "docs_emb_source_document_idx": { + "name": "docs_emb_source_document_idx", + "columns": [ + { + "expression": "source_document", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "docs_emb_header_level_idx": { + "name": "docs_emb_header_level_idx", + "columns": [ + { + "expression": "header_level", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "docs_emb_source_header_idx": { + "name": "docs_emb_source_header_idx", + "columns": [ + { + "expression": "source_document", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "header_level", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "docs_emb_model_idx": { + "name": "docs_emb_model_idx", + "columns": [ + { + "expression": "embedding_model", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "docs_emb_created_at_idx": { + "name": "docs_emb_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "docs_embedding_vector_hnsw_idx": { + "name": "docs_embedding_vector_hnsw_idx", + "columns": [ + { + "expression": "embedding", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "vector_cosine_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "hnsw", + "with": { + "m": 16, + "ef_construction": 64 + } + }, + "docs_emb_metadata_gin_idx": { + "name": "docs_emb_metadata_gin_idx", + "columns": [ + { + "expression": "metadata", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + }, + "docs_emb_chunk_text_fts_idx": { + "name": "docs_emb_chunk_text_fts_idx", + "columns": [ + { + "expression": "chunk_text_tsv", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "docs_embedding_not_null_check": { + "name": "docs_embedding_not_null_check", + "value": "\"embedding\" IS NOT NULL" + }, + "docs_header_level_check": { + "name": "docs_header_level_check", + "value": "\"header_level\" >= 1 AND \"header_level\" <= 6" + } + }, + "isRLSEnabled": false + }, + "public.document": { + "name": "document", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "knowledge_base_id": { + "name": "knowledge_base_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "filename": { + "name": "filename", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "file_url": { + "name": "file_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "file_size": { + "name": "file_size", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "mime_type": { + "name": "mime_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chunk_count": { + "name": "chunk_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "token_count": { + "name": "token_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "character_count": { + "name": "character_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "processing_status": { + "name": "processing_status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "processing_started_at": { + "name": "processing_started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "processing_completed_at": { + "name": "processing_completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "processing_error": { + "name": "processing_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "user_excluded": { + "name": "user_excluded", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "tag1": { + "name": "tag1", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag2": { + "name": "tag2", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag3": { + "name": "tag3", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag4": { + "name": "tag4", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag5": { + "name": "tag5", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag6": { + "name": "tag6", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag7": { + "name": "tag7", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "number1": { + "name": "number1", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number2": { + "name": "number2", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number3": { + "name": "number3", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number4": { + "name": "number4", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number5": { + "name": "number5", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "date1": { + "name": "date1", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "date2": { + "name": "date2", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "boolean1": { + "name": "boolean1", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "boolean2": { + "name": "boolean2", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "boolean3": { + "name": "boolean3", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "connector_id": { + "name": "connector_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "external_id": { + "name": "external_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content_hash": { + "name": "content_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_url": { + "name": "source_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uploaded_at": { + "name": "uploaded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "doc_kb_id_idx": { + "name": "doc_kb_id_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_filename_idx": { + "name": "doc_filename_idx", + "columns": [ + { + "expression": "filename", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_processing_status_idx": { + "name": "doc_processing_status_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "processing_status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_connector_external_id_idx": { + "name": "doc_connector_external_id_idx", + "columns": [ + { + "expression": "connector_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "external_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"document\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_connector_id_idx": { + "name": "doc_connector_id_idx", + "columns": [ + { + "expression": "connector_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_archived_at_idx": { + "name": "doc_archived_at_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_deleted_at_idx": { + "name": "doc_deleted_at_idx", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_tag1_idx": { + "name": "doc_tag1_idx", + "columns": [ + { + "expression": "tag1", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_tag2_idx": { + "name": "doc_tag2_idx", + "columns": [ + { + "expression": "tag2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_tag3_idx": { + "name": "doc_tag3_idx", + "columns": [ + { + "expression": "tag3", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_tag4_idx": { + "name": "doc_tag4_idx", + "columns": [ + { + "expression": "tag4", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_tag5_idx": { + "name": "doc_tag5_idx", + "columns": [ + { + "expression": "tag5", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_tag6_idx": { + "name": "doc_tag6_idx", + "columns": [ + { + "expression": "tag6", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_tag7_idx": { + "name": "doc_tag7_idx", + "columns": [ + { + "expression": "tag7", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_number1_idx": { + "name": "doc_number1_idx", + "columns": [ + { + "expression": "number1", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_number2_idx": { + "name": "doc_number2_idx", + "columns": [ + { + "expression": "number2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_number3_idx": { + "name": "doc_number3_idx", + "columns": [ + { + "expression": "number3", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_number4_idx": { + "name": "doc_number4_idx", + "columns": [ + { + "expression": "number4", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_number5_idx": { + "name": "doc_number5_idx", + "columns": [ + { + "expression": "number5", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_date1_idx": { + "name": "doc_date1_idx", + "columns": [ + { + "expression": "date1", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_date2_idx": { + "name": "doc_date2_idx", + "columns": [ + { + "expression": "date2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_boolean1_idx": { + "name": "doc_boolean1_idx", + "columns": [ + { + "expression": "boolean1", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_boolean2_idx": { + "name": "doc_boolean2_idx", + "columns": [ + { + "expression": "boolean2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_boolean3_idx": { + "name": "doc_boolean3_idx", + "columns": [ + { + "expression": "boolean3", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "document_knowledge_base_id_knowledge_base_id_fk": { + "name": "document_knowledge_base_id_knowledge_base_id_fk", + "tableFrom": "document", + "tableTo": "knowledge_base", + "columnsFrom": ["knowledge_base_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "document_connector_id_knowledge_connector_id_fk": { + "name": "document_connector_id_knowledge_connector_id_fk", + "tableFrom": "document", + "tableTo": "knowledge_connector", + "columnsFrom": ["connector_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.embedding": { + "name": "embedding", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "knowledge_base_id": { + "name": "knowledge_base_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "document_id": { + "name": "document_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chunk_index": { + "name": "chunk_index", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "chunk_hash": { + "name": "chunk_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content_length": { + "name": "content_length", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "token_count": { + "name": "token_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "embedding": { + "name": "embedding", + "type": "vector(1536)", + "primaryKey": false, + "notNull": false + }, + "embedding_model": { + "name": "embedding_model", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'text-embedding-3-small'" + }, + "start_offset": { + "name": "start_offset", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "end_offset": { + "name": "end_offset", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "tag1": { + "name": "tag1", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag2": { + "name": "tag2", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag3": { + "name": "tag3", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag4": { + "name": "tag4", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag5": { + "name": "tag5", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag6": { + "name": "tag6", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag7": { + "name": "tag7", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "number1": { + "name": "number1", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number2": { + "name": "number2", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number3": { + "name": "number3", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number4": { + "name": "number4", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number5": { + "name": "number5", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "date1": { + "name": "date1", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "date2": { + "name": "date2", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "boolean1": { + "name": "boolean1", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "boolean2": { + "name": "boolean2", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "boolean3": { + "name": "boolean3", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "content_tsv": { + "name": "content_tsv", + "type": "tsvector", + "primaryKey": false, + "notNull": false, + "generated": { + "as": "to_tsvector('english', \"embedding\".\"content\")", + "type": "stored" + } + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "emb_kb_id_idx": { + "name": "emb_kb_id_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_doc_id_idx": { + "name": "emb_doc_id_idx", + "columns": [ + { + "expression": "document_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_doc_chunk_idx": { + "name": "emb_doc_chunk_idx", + "columns": [ + { + "expression": "document_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "chunk_index", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_kb_model_idx": { + "name": "emb_kb_model_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "embedding_model", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_kb_enabled_idx": { + "name": "emb_kb_enabled_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "enabled", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_doc_enabled_idx": { + "name": "emb_doc_enabled_idx", + "columns": [ + { + "expression": "document_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "enabled", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "embedding_vector_hnsw_idx": { + "name": "embedding_vector_hnsw_idx", + "columns": [ + { + "expression": "embedding", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "vector_cosine_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "hnsw", + "with": { + "m": 16, + "ef_construction": 64 + } + }, + "emb_tag1_idx": { + "name": "emb_tag1_idx", + "columns": [ + { + "expression": "tag1", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_tag2_idx": { + "name": "emb_tag2_idx", + "columns": [ + { + "expression": "tag2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_tag3_idx": { + "name": "emb_tag3_idx", + "columns": [ + { + "expression": "tag3", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_tag4_idx": { + "name": "emb_tag4_idx", + "columns": [ + { + "expression": "tag4", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_tag5_idx": { + "name": "emb_tag5_idx", + "columns": [ + { + "expression": "tag5", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_tag6_idx": { + "name": "emb_tag6_idx", + "columns": [ + { + "expression": "tag6", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_tag7_idx": { + "name": "emb_tag7_idx", + "columns": [ + { + "expression": "tag7", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_number1_idx": { + "name": "emb_number1_idx", + "columns": [ + { + "expression": "number1", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_number2_idx": { + "name": "emb_number2_idx", + "columns": [ + { + "expression": "number2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_number3_idx": { + "name": "emb_number3_idx", + "columns": [ + { + "expression": "number3", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_number4_idx": { + "name": "emb_number4_idx", + "columns": [ + { + "expression": "number4", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_number5_idx": { + "name": "emb_number5_idx", + "columns": [ + { + "expression": "number5", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_date1_idx": { + "name": "emb_date1_idx", + "columns": [ + { + "expression": "date1", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_date2_idx": { + "name": "emb_date2_idx", + "columns": [ + { + "expression": "date2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_boolean1_idx": { + "name": "emb_boolean1_idx", + "columns": [ + { + "expression": "boolean1", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_boolean2_idx": { + "name": "emb_boolean2_idx", + "columns": [ + { + "expression": "boolean2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_boolean3_idx": { + "name": "emb_boolean3_idx", + "columns": [ + { + "expression": "boolean3", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_content_fts_idx": { + "name": "emb_content_fts_idx", + "columns": [ + { + "expression": "content_tsv", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + } + }, + "foreignKeys": { + "embedding_knowledge_base_id_knowledge_base_id_fk": { + "name": "embedding_knowledge_base_id_knowledge_base_id_fk", + "tableFrom": "embedding", + "tableTo": "knowledge_base", + "columnsFrom": ["knowledge_base_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "embedding_document_id_document_id_fk": { + "name": "embedding_document_id_document_id_fk", + "tableFrom": "embedding", + "tableTo": "document", + "columnsFrom": ["document_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "embedding_not_null_check": { + "name": "embedding_not_null_check", + "value": "\"embedding\" IS NOT NULL" + } + }, + "isRLSEnabled": false + }, + "public.environment": { + "name": "environment", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "variables": { + "name": "variables", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "environment_user_id_user_id_fk": { + "name": "environment_user_id_user_id_fk", + "tableFrom": "environment", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "environment_user_id_unique": { + "name": "environment_user_id_unique", + "nullsNotDistinct": false, + "columns": ["user_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.form": { + "name": "form", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "customizations": { + "name": "customizations", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "auth_type": { + "name": "auth_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'public'" + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "allowed_emails": { + "name": "allowed_emails", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'[]'" + }, + "show_branding": { + "name": "show_branding", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "form_identifier_idx": { + "name": "form_identifier_idx", + "columns": [ + { + "expression": "identifier", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"form\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "form_workflow_id_idx": { + "name": "form_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "form_user_id_idx": { + "name": "form_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "form_archived_at_idx": { + "name": "form_archived_at_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "form_workflow_id_workflow_id_fk": { + "name": "form_workflow_id_workflow_id_fk", + "tableFrom": "form", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "form_user_id_user_id_fk": { + "name": "form_user_id_user_id_fk", + "tableFrom": "form", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.idempotency_key": { + "name": "idempotency_key", + "schema": "", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "result": { + "name": "result", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idempotency_key_created_at_idx": { + "name": "idempotency_key_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.invitation": { + "name": "invitation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "inviter_id": { + "name": "inviter_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "invitation_email_idx": { + "name": "invitation_email_idx", + "columns": [ + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "invitation_organization_id_idx": { + "name": "invitation_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "invitation_inviter_id_user_id_fk": { + "name": "invitation_inviter_id_user_id_fk", + "tableFrom": "invitation", + "tableTo": "user", + "columnsFrom": ["inviter_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "invitation_organization_id_organization_id_fk": { + "name": "invitation_organization_id_organization_id_fk", + "tableFrom": "invitation", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.job_execution_logs": { + "name": "job_execution_logs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "schedule_id": { + "name": "schedule_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "level": { + "name": "level", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'running'" + }, + "trigger": { + "name": "trigger", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "total_duration_ms": { + "name": "total_duration_ms", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "execution_data": { + "name": "execution_data", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "cost": { + "name": "cost", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "job_execution_logs_schedule_id_idx": { + "name": "job_execution_logs_schedule_id_idx", + "columns": [ + { + "expression": "schedule_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "job_execution_logs_workspace_started_at_idx": { + "name": "job_execution_logs_workspace_started_at_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "job_execution_logs_execution_id_unique": { + "name": "job_execution_logs_execution_id_unique", + "columns": [ + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "job_execution_logs_trigger_idx": { + "name": "job_execution_logs_trigger_idx", + "columns": [ + { + "expression": "trigger", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "job_execution_logs_schedule_id_workflow_schedule_id_fk": { + "name": "job_execution_logs_schedule_id_workflow_schedule_id_fk", + "tableFrom": "job_execution_logs", + "tableTo": "workflow_schedule", + "columnsFrom": ["schedule_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "job_execution_logs_workspace_id_workspace_id_fk": { + "name": "job_execution_logs_workspace_id_workspace_id_fk", + "tableFrom": "job_execution_logs", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.jwks": { + "name": "jwks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "public_key": { + "name": "public_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "private_key": { + "name": "private_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.knowledge_base": { + "name": "knowledge_base", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token_count": { + "name": "token_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "embedding_model": { + "name": "embedding_model", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'text-embedding-3-small'" + }, + "embedding_dimension": { + "name": "embedding_dimension", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1536 + }, + "chunking_config": { + "name": "chunking_config", + "type": "json", + "primaryKey": false, + "notNull": true, + "default": "'{\"maxSize\": 1024, \"minSize\": 1, \"overlap\": 200}'" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "kb_user_id_idx": { + "name": "kb_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_workspace_id_idx": { + "name": "kb_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_user_workspace_idx": { + "name": "kb_user_workspace_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_deleted_at_idx": { + "name": "kb_deleted_at_idx", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "knowledge_base_user_id_user_id_fk": { + "name": "knowledge_base_user_id_user_id_fk", + "tableFrom": "knowledge_base", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "knowledge_base_workspace_id_workspace_id_fk": { + "name": "knowledge_base_workspace_id_workspace_id_fk", + "tableFrom": "knowledge_base", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.knowledge_base_tag_definitions": { + "name": "knowledge_base_tag_definitions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "knowledge_base_id": { + "name": "knowledge_base_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tag_slot": { + "name": "tag_slot", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "field_type": { + "name": "field_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'text'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "kb_tag_definitions_kb_slot_idx": { + "name": "kb_tag_definitions_kb_slot_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "tag_slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_tag_definitions_kb_display_name_idx": { + "name": "kb_tag_definitions_kb_display_name_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "display_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_tag_definitions_kb_id_idx": { + "name": "kb_tag_definitions_kb_id_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "knowledge_base_tag_definitions_knowledge_base_id_knowledge_base_id_fk": { + "name": "knowledge_base_tag_definitions_knowledge_base_id_knowledge_base_id_fk", + "tableFrom": "knowledge_base_tag_definitions", + "tableTo": "knowledge_base", + "columnsFrom": ["knowledge_base_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.knowledge_connector": { + "name": "knowledge_connector", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "knowledge_base_id": { + "name": "knowledge_base_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "connector_type": { + "name": "connector_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "credential_id": { + "name": "credential_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "encrypted_api_key": { + "name": "encrypted_api_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_config": { + "name": "source_config", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "sync_mode": { + "name": "sync_mode", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'full'" + }, + "sync_interval_minutes": { + "name": "sync_interval_minutes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1440 + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "last_sync_at": { + "name": "last_sync_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_sync_error": { + "name": "last_sync_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_sync_doc_count": { + "name": "last_sync_doc_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "next_sync_at": { + "name": "next_sync_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "consecutive_failures": { + "name": "consecutive_failures", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "kc_knowledge_base_id_idx": { + "name": "kc_knowledge_base_id_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kc_status_next_sync_idx": { + "name": "kc_status_next_sync_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "next_sync_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kc_archived_at_idx": { + "name": "kc_archived_at_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kc_deleted_at_idx": { + "name": "kc_deleted_at_idx", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "knowledge_connector_knowledge_base_id_knowledge_base_id_fk": { + "name": "knowledge_connector_knowledge_base_id_knowledge_base_id_fk", + "tableFrom": "knowledge_connector", + "tableTo": "knowledge_base", + "columnsFrom": ["knowledge_base_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.knowledge_connector_sync_log": { + "name": "knowledge_connector_sync_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "connector_id": { + "name": "connector_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "docs_added": { + "name": "docs_added", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_updated": { + "name": "docs_updated", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_deleted": { + "name": "docs_deleted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_unchanged": { + "name": "docs_unchanged", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_failed": { + "name": "docs_failed", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "kcsl_connector_id_idx": { + "name": "kcsl_connector_id_idx", + "columns": [ + { + "expression": "connector_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "knowledge_connector_sync_log_connector_id_knowledge_connector_id_fk": { + "name": "knowledge_connector_sync_log_connector_id_knowledge_connector_id_fk", + "tableFrom": "knowledge_connector_sync_log", + "tableTo": "knowledge_connector", + "columnsFrom": ["connector_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mcp_servers": { + "name": "mcp_servers", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "transport": { + "name": "transport", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "headers": { + "name": "headers", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "timeout": { + "name": "timeout", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 30000 + }, + "retries": { + "name": "retries", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3 + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "last_connected": { + "name": "last_connected", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "connection_status": { + "name": "connection_status", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'disconnected'" + }, + "last_error": { + "name": "last_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status_config": { + "name": "status_config", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "tool_count": { + "name": "tool_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "last_tools_refresh": { + "name": "last_tools_refresh", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "total_requests": { + "name": "total_requests", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "last_used": { + "name": "last_used", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "mcp_servers_workspace_enabled_idx": { + "name": "mcp_servers_workspace_enabled_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "enabled", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "mcp_servers_workspace_deleted_idx": { + "name": "mcp_servers_workspace_deleted_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "mcp_servers_workspace_id_workspace_id_fk": { + "name": "mcp_servers_workspace_id_workspace_id_fk", + "tableFrom": "mcp_servers", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mcp_servers_created_by_user_id_fk": { + "name": "mcp_servers_created_by_user_id_fk", + "tableFrom": "mcp_servers", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.member": { + "name": "member", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "member_user_id_unique": { + "name": "member_user_id_unique", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "member_organization_id_idx": { + "name": "member_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "member_user_id_user_id_fk": { + "name": "member_user_id_user_id_fk", + "tableFrom": "member", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "member_organization_id_organization_id_fk": { + "name": "member_organization_id_organization_id_fk", + "tableFrom": "member", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.memory": { + "name": "memory", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "memory_key_idx": { + "name": "memory_key_idx", + "columns": [ + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "memory_workspace_idx": { + "name": "memory_workspace_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "memory_workspace_key_idx": { + "name": "memory_workspace_key_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "memory_workspace_id_workspace_id_fk": { + "name": "memory_workspace_id_workspace_id_fk", + "tableFrom": "memory", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mothership_inbox_allowed_sender": { + "name": "mothership_inbox_allowed_sender", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "label": { + "name": "label", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "added_by": { + "name": "added_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "inbox_sender_ws_email_idx": { + "name": "inbox_sender_ws_email_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "mothership_inbox_allowed_sender_workspace_id_workspace_id_fk": { + "name": "mothership_inbox_allowed_sender_workspace_id_workspace_id_fk", + "tableFrom": "mothership_inbox_allowed_sender", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mothership_inbox_allowed_sender_added_by_user_id_fk": { + "name": "mothership_inbox_allowed_sender_added_by_user_id_fk", + "tableFrom": "mothership_inbox_allowed_sender", + "tableTo": "user", + "columnsFrom": ["added_by"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mothership_inbox_task": { + "name": "mothership_inbox_task", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "from_email": { + "name": "from_email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "from_name": { + "name": "from_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "subject": { + "name": "subject", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "body_preview": { + "name": "body_preview", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "body_text": { + "name": "body_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "body_html": { + "name": "body_html", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email_message_id": { + "name": "email_message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "in_reply_to": { + "name": "in_reply_to", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "response_message_id": { + "name": "response_message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "agentmail_message_id": { + "name": "agentmail_message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'received'" + }, + "chat_id": { + "name": "chat_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "trigger_job_id": { + "name": "trigger_job_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "result_summary": { + "name": "result_summary", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "rejection_reason": { + "name": "rejection_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "has_attachments": { + "name": "has_attachments", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cc_recipients": { + "name": "cc_recipients", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "processing_started_at": { + "name": "processing_started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "inbox_task_ws_created_at_idx": { + "name": "inbox_task_ws_created_at_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "inbox_task_ws_status_idx": { + "name": "inbox_task_ws_status_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "inbox_task_response_msg_id_idx": { + "name": "inbox_task_response_msg_id_idx", + "columns": [ + { + "expression": "response_message_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "inbox_task_email_msg_id_idx": { + "name": "inbox_task_email_msg_id_idx", + "columns": [ + { + "expression": "email_message_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "mothership_inbox_task_workspace_id_workspace_id_fk": { + "name": "mothership_inbox_task_workspace_id_workspace_id_fk", + "tableFrom": "mothership_inbox_task", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mothership_inbox_task_chat_id_copilot_chats_id_fk": { + "name": "mothership_inbox_task_chat_id_copilot_chats_id_fk", + "tableFrom": "mothership_inbox_task", + "tableTo": "copilot_chats", + "columnsFrom": ["chat_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mothership_inbox_webhook": { + "name": "mothership_inbox_webhook", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "webhook_id": { + "name": "webhook_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "mothership_inbox_webhook_workspace_id_workspace_id_fk": { + "name": "mothership_inbox_webhook_workspace_id_workspace_id_fk", + "tableFrom": "mothership_inbox_webhook", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mothership_inbox_webhook_workspace_id_unique": { + "name": "mothership_inbox_webhook_workspace_id_unique", + "nullsNotDistinct": false, + "columns": ["workspace_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.oauth_access_token": { + "name": "oauth_access_token", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scopes": { + "name": "scopes", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "oauth_access_token_access_token_idx": { + "name": "oauth_access_token_access_token_idx", + "columns": [ + { + "expression": "access_token", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "oauth_access_token_refresh_token_idx": { + "name": "oauth_access_token_refresh_token_idx", + "columns": [ + { + "expression": "refresh_token", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "oauth_access_token_client_id_oauth_application_client_id_fk": { + "name": "oauth_access_token_client_id_oauth_application_client_id_fk", + "tableFrom": "oauth_access_token", + "tableTo": "oauth_application", + "columnsFrom": ["client_id"], + "columnsTo": ["client_id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "oauth_access_token_user_id_user_id_fk": { + "name": "oauth_access_token_user_id_user_id_fk", + "tableFrom": "oauth_access_token", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "oauth_access_token_access_token_unique": { + "name": "oauth_access_token_access_token_unique", + "nullsNotDistinct": false, + "columns": ["access_token"] + }, + "oauth_access_token_refresh_token_unique": { + "name": "oauth_access_token_refresh_token_unique", + "nullsNotDistinct": false, + "columns": ["refresh_token"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.oauth_application": { + "name": "oauth_application", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "client_secret": { + "name": "client_secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "redirect_urls": { + "name": "redirect_urls", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "disabled": { + "name": "disabled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "oauth_application_client_id_idx": { + "name": "oauth_application_client_id_idx", + "columns": [ + { + "expression": "client_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "oauth_application_user_id_user_id_fk": { + "name": "oauth_application_user_id_user_id_fk", + "tableFrom": "oauth_application", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "oauth_application_client_id_unique": { + "name": "oauth_application_client_id_unique", + "nullsNotDistinct": false, + "columns": ["client_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.oauth_consent": { + "name": "oauth_consent", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "scopes": { + "name": "scopes", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "consent_given": { + "name": "consent_given", + "type": "boolean", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "oauth_consent_user_client_idx": { + "name": "oauth_consent_user_client_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "client_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "oauth_consent_client_id_oauth_application_client_id_fk": { + "name": "oauth_consent_client_id_oauth_application_client_id_fk", + "tableFrom": "oauth_consent", + "tableTo": "oauth_application", + "columnsFrom": ["client_id"], + "columnsTo": ["client_id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "oauth_consent_user_id_user_id_fk": { + "name": "oauth_consent_user_id_user_id_fk", + "tableFrom": "oauth_consent", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organization": { + "name": "organization", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "logo": { + "name": "logo", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "org_usage_limit": { + "name": "org_usage_limit", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "storage_used_bytes": { + "name": "storage_used_bytes", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "departed_member_usage": { + "name": "departed_member_usage", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "credit_balance": { + "name": "credit_balance", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.paused_executions": { + "name": "paused_executions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "execution_snapshot": { + "name": "execution_snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "pause_points": { + "name": "pause_points", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "total_pause_count": { + "name": "total_pause_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "resumed_count": { + "name": "resumed_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'paused'" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "paused_at": { + "name": "paused_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "paused_executions_workflow_id_idx": { + "name": "paused_executions_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "paused_executions_status_idx": { + "name": "paused_executions_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "paused_executions_execution_id_unique": { + "name": "paused_executions_execution_id_unique", + "columns": [ + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "paused_executions_workflow_id_workflow_id_fk": { + "name": "paused_executions_workflow_id_workflow_id_fk", + "tableFrom": "paused_executions", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.pending_credential_draft": { + "name": "pending_credential_draft", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "credential_id": { + "name": "credential_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "pending_draft_user_provider_ws": { + "name": "pending_draft_user_provider_ws", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "pending_credential_draft_user_id_user_id_fk": { + "name": "pending_credential_draft_user_id_user_id_fk", + "tableFrom": "pending_credential_draft", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "pending_credential_draft_workspace_id_workspace_id_fk": { + "name": "pending_credential_draft_workspace_id_workspace_id_fk", + "tableFrom": "pending_credential_draft", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "pending_credential_draft_credential_id_credential_id_fk": { + "name": "pending_credential_draft_credential_id_credential_id_fk", + "tableFrom": "pending_credential_draft", + "tableTo": "credential", + "columnsFrom": ["credential_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.permission_group": { + "name": "permission_group", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "config": { + "name": "config", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "auto_add_new_members": { + "name": "auto_add_new_members", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "permission_group_created_by_idx": { + "name": "permission_group_created_by_idx", + "columns": [ + { + "expression": "created_by", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permission_group_org_name_unique": { + "name": "permission_group_org_name_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permission_group_org_auto_add_unique": { + "name": "permission_group_org_auto_add_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "auto_add_new_members = true", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "permission_group_organization_id_organization_id_fk": { + "name": "permission_group_organization_id_organization_id_fk", + "tableFrom": "permission_group", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "permission_group_created_by_user_id_fk": { + "name": "permission_group_created_by_user_id_fk", + "tableFrom": "permission_group", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.permission_group_member": { + "name": "permission_group_member", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "permission_group_id": { + "name": "permission_group_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "assigned_by": { + "name": "assigned_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "assigned_at": { + "name": "assigned_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "permission_group_member_group_id_idx": { + "name": "permission_group_member_group_id_idx", + "columns": [ + { + "expression": "permission_group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permission_group_member_user_id_unique": { + "name": "permission_group_member_user_id_unique", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "permission_group_member_permission_group_id_permission_group_id_fk": { + "name": "permission_group_member_permission_group_id_permission_group_id_fk", + "tableFrom": "permission_group_member", + "tableTo": "permission_group", + "columnsFrom": ["permission_group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "permission_group_member_user_id_user_id_fk": { + "name": "permission_group_member_user_id_user_id_fk", + "tableFrom": "permission_group_member", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "permission_group_member_assigned_by_user_id_fk": { + "name": "permission_group_member_assigned_by_user_id_fk", + "tableFrom": "permission_group_member", + "tableTo": "user", + "columnsFrom": ["assigned_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.permissions": { + "name": "permissions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entity_type": { + "name": "entity_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entity_id": { + "name": "entity_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permission_type": { + "name": "permission_type", + "type": "permission_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "permissions_user_id_idx": { + "name": "permissions_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permissions_entity_idx": { + "name": "permissions_entity_idx", + "columns": [ + { + "expression": "entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permissions_user_entity_type_idx": { + "name": "permissions_user_entity_type_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permissions_user_entity_permission_idx": { + "name": "permissions_user_entity_permission_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "permission_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permissions_user_entity_idx": { + "name": "permissions_user_entity_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permissions_unique_constraint": { + "name": "permissions_unique_constraint", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "permissions_user_id_user_id_fk": { + "name": "permissions_user_id_user_id_fk", + "tableFrom": "permissions", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.rate_limit_bucket": { + "name": "rate_limit_bucket", + "schema": "", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "tokens": { + "name": "tokens", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "last_refill_at": { + "name": "last_refill_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.resume_queue": { + "name": "resume_queue", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "paused_execution_id": { + "name": "paused_execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent_execution_id": { + "name": "parent_execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "new_execution_id": { + "name": "new_execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "context_id": { + "name": "context_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resume_input": { + "name": "resume_input", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "queued_at": { + "name": "queued_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "claimed_at": { + "name": "claimed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "failure_reason": { + "name": "failure_reason", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "resume_queue_parent_status_idx": { + "name": "resume_queue_parent_status_idx", + "columns": [ + { + "expression": "parent_execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "queued_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "resume_queue_new_execution_idx": { + "name": "resume_queue_new_execution_idx", + "columns": [ + { + "expression": "new_execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "resume_queue_paused_execution_id_paused_executions_id_fk": { + "name": "resume_queue_paused_execution_id_paused_executions_id_fk", + "tableFrom": "resume_queue", + "tableTo": "paused_executions", + "columnsFrom": ["paused_execution_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "active_organization_id": { + "name": "active_organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "impersonated_by": { + "name": "impersonated_by", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "session_user_id_idx": { + "name": "session_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "session_token_idx": { + "name": "session_token_idx", + "columns": [ + { + "expression": "token", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "session_active_organization_id_organization_id_fk": { + "name": "session_active_organization_id_organization_id_fk", + "tableFrom": "session", + "tableTo": "organization", + "columnsFrom": ["active_organization_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_token_unique": { + "name": "session_token_unique", + "nullsNotDistinct": false, + "columns": ["token"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.settings": { + "name": "settings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "theme": { + "name": "theme", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'system'" + }, + "auto_connect": { + "name": "auto_connect", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "telemetry_enabled": { + "name": "telemetry_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "email_preferences": { + "name": "email_preferences", + "type": "json", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "billing_usage_notifications_enabled": { + "name": "billing_usage_notifications_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "show_training_controls": { + "name": "show_training_controls", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "super_user_mode_enabled": { + "name": "super_user_mode_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "error_notifications_enabled": { + "name": "error_notifications_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "snap_to_grid_size": { + "name": "snap_to_grid_size", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "show_action_bar": { + "name": "show_action_bar", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "copilot_enabled_models": { + "name": "copilot_enabled_models", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "copilot_auto_allowed_tools": { + "name": "copilot_auto_allowed_tools", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "settings_user_id_user_id_fk": { + "name": "settings_user_id_user_id_fk", + "tableFrom": "settings", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "settings_user_id_unique": { + "name": "settings_user_id_unique", + "nullsNotDistinct": false, + "columns": ["user_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.skill": { + "name": "skill", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "skill_workspace_name_unique": { + "name": "skill_workspace_name_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "skill_workspace_id_workspace_id_fk": { + "name": "skill_workspace_id_workspace_id_fk", + "tableFrom": "skill", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "skill_user_id_user_id_fk": { + "name": "skill_user_id_user_id_fk", + "tableFrom": "skill", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sso_provider": { + "name": "sso_provider", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "issuer": { + "name": "issuer", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "domain": { + "name": "domain", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "oidc_config": { + "name": "oidc_config", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "saml_config": { + "name": "saml_config", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "sso_provider_provider_id_idx": { + "name": "sso_provider_provider_id_idx", + "columns": [ + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sso_provider_domain_idx": { + "name": "sso_provider_domain_idx", + "columns": [ + { + "expression": "domain", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sso_provider_user_id_idx": { + "name": "sso_provider_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sso_provider_organization_id_idx": { + "name": "sso_provider_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "sso_provider_user_id_user_id_fk": { + "name": "sso_provider_user_id_user_id_fk", + "tableFrom": "sso_provider", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "sso_provider_organization_id_organization_id_fk": { + "name": "sso_provider_organization_id_organization_id_fk", + "tableFrom": "sso_provider", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.subscription": { + "name": "subscription", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "plan": { + "name": "plan", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "stripe_customer_id": { + "name": "stripe_customer_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "stripe_subscription_id": { + "name": "stripe_subscription_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "period_start": { + "name": "period_start", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "period_end": { + "name": "period_end", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "cancel_at_period_end": { + "name": "cancel_at_period_end", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "seats": { + "name": "seats", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "trial_start": { + "name": "trial_start", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "trial_end": { + "name": "trial_end", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "json", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "subscription_reference_status_idx": { + "name": "subscription_reference_status_idx", + "columns": [ + { + "expression": "reference_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "check_enterprise_metadata": { + "name": "check_enterprise_metadata", + "value": "plan != 'enterprise' OR metadata IS NOT NULL" + } + }, + "isRLSEnabled": false + }, + "public.template_creators": { + "name": "template_creators", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "reference_type": { + "name": "reference_type", + "type": "template_creator_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "profile_image_url": { + "name": "profile_image_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "details": { + "name": "details", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "verified": { + "name": "verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "template_creators_reference_idx": { + "name": "template_creators_reference_idx", + "columns": [ + { + "expression": "reference_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "reference_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "template_creators_reference_id_idx": { + "name": "template_creators_reference_id_idx", + "columns": [ + { + "expression": "reference_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "template_creators_created_by_idx": { + "name": "template_creators_created_by_idx", + "columns": [ + { + "expression": "created_by", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "template_creators_created_by_user_id_fk": { + "name": "template_creators_created_by_user_id_fk", + "tableFrom": "template_creators", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.template_stars": { + "name": "template_stars", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "template_id": { + "name": "template_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "starred_at": { + "name": "starred_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "template_stars_user_id_idx": { + "name": "template_stars_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "template_stars_template_id_idx": { + "name": "template_stars_template_id_idx", + "columns": [ + { + "expression": "template_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "template_stars_user_template_idx": { + "name": "template_stars_user_template_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "template_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "template_stars_template_user_idx": { + "name": "template_stars_template_user_idx", + "columns": [ + { + "expression": "template_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "template_stars_starred_at_idx": { + "name": "template_stars_starred_at_idx", + "columns": [ + { + "expression": "starred_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "template_stars_template_starred_at_idx": { + "name": "template_stars_template_starred_at_idx", + "columns": [ + { + "expression": "template_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "starred_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "template_stars_user_template_unique": { + "name": "template_stars_user_template_unique", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "template_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "template_stars_user_id_user_id_fk": { + "name": "template_stars_user_id_user_id_fk", + "tableFrom": "template_stars", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "template_stars_template_id_templates_id_fk": { + "name": "template_stars_template_id_templates_id_fk", + "tableFrom": "template_stars", + "tableTo": "templates", + "columnsFrom": ["template_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.templates": { + "name": "templates", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "details": { + "name": "details", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "creator_id": { + "name": "creator_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "views": { + "name": "views", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "stars": { + "name": "stars", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "status": { + "name": "status", + "type": "template_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "tags": { + "name": "tags", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "'{}'::text[]" + }, + "required_credentials": { + "name": "required_credentials", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'" + }, + "state": { + "name": "state", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "og_image_url": { + "name": "og_image_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "templates_status_idx": { + "name": "templates_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "templates_creator_id_idx": { + "name": "templates_creator_id_idx", + "columns": [ + { + "expression": "creator_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "templates_views_idx": { + "name": "templates_views_idx", + "columns": [ + { + "expression": "views", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "templates_stars_idx": { + "name": "templates_stars_idx", + "columns": [ + { + "expression": "stars", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "templates_status_views_idx": { + "name": "templates_status_views_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "views", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "templates_status_stars_idx": { + "name": "templates_status_stars_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "stars", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "templates_created_at_idx": { + "name": "templates_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "templates_updated_at_idx": { + "name": "templates_updated_at_idx", + "columns": [ + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "templates_workflow_id_workflow_id_fk": { + "name": "templates_workflow_id_workflow_id_fk", + "tableFrom": "templates", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "templates_creator_id_template_creators_id_fk": { + "name": "templates_creator_id_template_creators_id_fk", + "tableFrom": "templates", + "tableTo": "template_creators", + "columnsFrom": ["creator_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.usage_log": { + "name": "usage_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "usage_log_category", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "usage_log_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "cost": { + "name": "cost", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "usage_log_user_created_at_idx": { + "name": "usage_log_user_created_at_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "usage_log_source_idx": { + "name": "usage_log_source_idx", + "columns": [ + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "usage_log_workspace_id_idx": { + "name": "usage_log_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "usage_log_workflow_id_idx": { + "name": "usage_log_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "usage_log_user_id_user_id_fk": { + "name": "usage_log_user_id_user_id_fk", + "tableFrom": "usage_log", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "usage_log_workspace_id_workspace_id_fk": { + "name": "usage_log_workspace_id_workspace_id_fk", + "tableFrom": "usage_log", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "usage_log_workflow_id_workflow_id_fk": { + "name": "usage_log_workflow_id_workflow_id_fk", + "tableFrom": "usage_log", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "normalized_email": { + "name": "normalized_email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email_verified": { + "name": "email_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "stripe_customer_id": { + "name": "stripe_customer_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'user'" + }, + "banned": { + "name": "banned", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "ban_reason": { + "name": "ban_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ban_expires": { + "name": "ban_expires", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": ["email"] + }, + "user_normalized_email_unique": { + "name": "user_normalized_email_unique", + "nullsNotDistinct": false, + "columns": ["normalized_email"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_stats": { + "name": "user_stats", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "total_manual_executions": { + "name": "total_manual_executions", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_api_calls": { + "name": "total_api_calls", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_webhook_triggers": { + "name": "total_webhook_triggers", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_scheduled_executions": { + "name": "total_scheduled_executions", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_chat_executions": { + "name": "total_chat_executions", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_mcp_executions": { + "name": "total_mcp_executions", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_a2a_executions": { + "name": "total_a2a_executions", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_tokens_used": { + "name": "total_tokens_used", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_cost": { + "name": "total_cost", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "current_usage_limit": { + "name": "current_usage_limit", + "type": "numeric", + "primaryKey": false, + "notNull": false, + "default": "'5'" + }, + "usage_limit_updated_at": { + "name": "usage_limit_updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "current_period_cost": { + "name": "current_period_cost", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "last_period_cost": { + "name": "last_period_cost", + "type": "numeric", + "primaryKey": false, + "notNull": false, + "default": "'0'" + }, + "billed_overage_this_period": { + "name": "billed_overage_this_period", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "pro_period_cost_snapshot": { + "name": "pro_period_cost_snapshot", + "type": "numeric", + "primaryKey": false, + "notNull": false, + "default": "'0'" + }, + "credit_balance": { + "name": "credit_balance", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "total_copilot_cost": { + "name": "total_copilot_cost", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "current_period_copilot_cost": { + "name": "current_period_copilot_cost", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "last_period_copilot_cost": { + "name": "last_period_copilot_cost", + "type": "numeric", + "primaryKey": false, + "notNull": false, + "default": "'0'" + }, + "total_copilot_tokens": { + "name": "total_copilot_tokens", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_copilot_calls": { + "name": "total_copilot_calls", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_mcp_copilot_calls": { + "name": "total_mcp_copilot_calls", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_mcp_copilot_cost": { + "name": "total_mcp_copilot_cost", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "current_period_mcp_copilot_cost": { + "name": "current_period_mcp_copilot_cost", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "storage_used_bytes": { + "name": "storage_used_bytes", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "last_active": { + "name": "last_active", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "billing_blocked": { + "name": "billing_blocked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "billing_blocked_reason": { + "name": "billing_blocked_reason", + "type": "billing_blocked_reason", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_stats_user_id_user_id_fk": { + "name": "user_stats_user_id_user_id_fk", + "tableFrom": "user_stats", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_stats_user_id_unique": { + "name": "user_stats_user_id_unique", + "nullsNotDistinct": false, + "columns": ["user_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_table_definitions": { + "name": "user_table_definitions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "schema": { + "name": "schema", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "max_rows": { + "name": "max_rows", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 10000 + }, + "row_count": { + "name": "row_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "user_table_def_workspace_id_idx": { + "name": "user_table_def_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_table_def_workspace_name_unique": { + "name": "user_table_def_workspace_name_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"user_table_definitions\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_table_def_archived_at_idx": { + "name": "user_table_def_archived_at_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_table_definitions_workspace_id_workspace_id_fk": { + "name": "user_table_definitions_workspace_id_workspace_id_fk", + "tableFrom": "user_table_definitions", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_table_definitions_created_by_user_id_fk": { + "name": "user_table_definitions_created_by_user_id_fk", + "tableFrom": "user_table_definitions", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_table_rows": { + "name": "user_table_rows", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "table_id": { + "name": "table_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "position": { + "name": "position", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "user_table_rows_table_id_idx": { + "name": "user_table_rows_table_id_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_table_rows_data_gin_idx": { + "name": "user_table_rows_data_gin_idx", + "columns": [ + { + "expression": "data", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + }, + "user_table_rows_workspace_table_idx": { + "name": "user_table_rows_workspace_table_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_table_rows_table_position_idx": { + "name": "user_table_rows_table_position_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "position", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_table_rows_table_id_user_table_definitions_id_fk": { + "name": "user_table_rows_table_id_user_table_definitions_id_fk", + "tableFrom": "user_table_rows", + "tableTo": "user_table_definitions", + "columnsFrom": ["table_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_table_rows_workspace_id_workspace_id_fk": { + "name": "user_table_rows_workspace_id_workspace_id_fk", + "tableFrom": "user_table_rows", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_table_rows_created_by_user_id_fk": { + "name": "user_table_rows_created_by_user_id_fk", + "tableFrom": "user_table_rows", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.verification": { + "name": "verification", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "verification_identifier_idx": { + "name": "verification_identifier_idx", + "columns": [ + { + "expression": "identifier", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "verification_expires_at_idx": { + "name": "verification_expires_at_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.waitlist": { + "name": "waitlist", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "waitlist_email_unique": { + "name": "waitlist_email_unique", + "nullsNotDistinct": false, + "columns": ["email"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.webhook": { + "name": "webhook", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "deployment_version_id": { + "name": "deployment_version_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "block_id": { + "name": "block_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_config": { + "name": "provider_config", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "failed_count": { + "name": "failed_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "last_failed_at": { + "name": "last_failed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "credential_set_id": { + "name": "credential_set_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "path_deployment_unique": { + "name": "path_deployment_unique", + "columns": [ + { + "expression": "path", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"webhook\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_webhook_on_workflow_id_block_id": { + "name": "idx_webhook_on_workflow_id_block_id", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "webhook_workflow_deployment_idx": { + "name": "webhook_workflow_deployment_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "webhook_credential_set_id_idx": { + "name": "webhook_credential_set_id_idx", + "columns": [ + { + "expression": "credential_set_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "webhook_archived_at_idx": { + "name": "webhook_archived_at_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "webhook_workflow_id_workflow_id_fk": { + "name": "webhook_workflow_id_workflow_id_fk", + "tableFrom": "webhook", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "webhook_deployment_version_id_workflow_deployment_version_id_fk": { + "name": "webhook_deployment_version_id_workflow_deployment_version_id_fk", + "tableFrom": "webhook", + "tableTo": "workflow_deployment_version", + "columnsFrom": ["deployment_version_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "webhook_credential_set_id_credential_set_id_fk": { + "name": "webhook_credential_set_id_credential_set_id_fk", + "tableFrom": "webhook", + "tableTo": "credential_set", + "columnsFrom": ["credential_set_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow": { + "name": "workflow", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "folder_id": { + "name": "folder_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'#3972F6'" + }, + "last_synced": { + "name": "last_synced", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "is_deployed": { + "name": "is_deployed", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "deployed_at": { + "name": "deployed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "is_public_api": { + "name": "is_public_api", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "run_count": { + "name": "run_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "last_run_at": { + "name": "last_run_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "variables": { + "name": "variables", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "workflow_user_id_idx": { + "name": "workflow_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_workspace_id_idx": { + "name": "workflow_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_user_workspace_idx": { + "name": "workflow_user_workspace_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_workspace_folder_name_active_unique": { + "name": "workflow_workspace_folder_name_active_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "coalesce(\"folder_id\", '')", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workflow\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_folder_sort_idx": { + "name": "workflow_folder_sort_idx", + "columns": [ + { + "expression": "folder_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sort_order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_archived_at_idx": { + "name": "workflow_archived_at_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_user_id_user_id_fk": { + "name": "workflow_user_id_user_id_fk", + "tableFrom": "workflow", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_workspace_id_workspace_id_fk": { + "name": "workflow_workspace_id_workspace_id_fk", + "tableFrom": "workflow", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_folder_id_workflow_folder_id_fk": { + "name": "workflow_folder_id_workflow_folder_id_fk", + "tableFrom": "workflow", + "tableTo": "workflow_folder", + "columnsFrom": ["folder_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_blocks": { + "name": "workflow_blocks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "position_x": { + "name": "position_x", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "position_y": { + "name": "position_y", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "horizontal_handles": { + "name": "horizontal_handles", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "is_wide": { + "name": "is_wide", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "advanced_mode": { + "name": "advanced_mode", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "trigger_mode": { + "name": "trigger_mode", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "locked": { + "name": "locked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "height": { + "name": "height", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "sub_blocks": { + "name": "sub_blocks", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "outputs": { + "name": "outputs", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_blocks_workflow_id_idx": { + "name": "workflow_blocks_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_blocks_type_idx": { + "name": "workflow_blocks_type_idx", + "columns": [ + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_blocks_workflow_id_workflow_id_fk": { + "name": "workflow_blocks_workflow_id_workflow_id_fk", + "tableFrom": "workflow_blocks", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_checkpoints": { + "name": "workflow_checkpoints", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chat_id": { + "name": "chat_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "message_id": { + "name": "message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workflow_state": { + "name": "workflow_state", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_checkpoints_user_id_idx": { + "name": "workflow_checkpoints_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_checkpoints_workflow_id_idx": { + "name": "workflow_checkpoints_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_checkpoints_chat_id_idx": { + "name": "workflow_checkpoints_chat_id_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_checkpoints_message_id_idx": { + "name": "workflow_checkpoints_message_id_idx", + "columns": [ + { + "expression": "message_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_checkpoints_user_workflow_idx": { + "name": "workflow_checkpoints_user_workflow_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_checkpoints_workflow_chat_idx": { + "name": "workflow_checkpoints_workflow_chat_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_checkpoints_created_at_idx": { + "name": "workflow_checkpoints_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_checkpoints_chat_created_at_idx": { + "name": "workflow_checkpoints_chat_created_at_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_checkpoints_user_id_user_id_fk": { + "name": "workflow_checkpoints_user_id_user_id_fk", + "tableFrom": "workflow_checkpoints", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_checkpoints_workflow_id_workflow_id_fk": { + "name": "workflow_checkpoints_workflow_id_workflow_id_fk", + "tableFrom": "workflow_checkpoints", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_checkpoints_chat_id_copilot_chats_id_fk": { + "name": "workflow_checkpoints_chat_id_copilot_chats_id_fk", + "tableFrom": "workflow_checkpoints", + "tableTo": "copilot_chats", + "columnsFrom": ["chat_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_deployment_version": { + "name": "workflow_deployment_version", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "state": { + "name": "state", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "workflow_deployment_version_workflow_version_unique": { + "name": "workflow_deployment_version_workflow_version_unique", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "version", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_deployment_version_workflow_active_idx": { + "name": "workflow_deployment_version_workflow_active_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "is_active", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_deployment_version_created_at_idx": { + "name": "workflow_deployment_version_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_deployment_version_workflow_id_workflow_id_fk": { + "name": "workflow_deployment_version_workflow_id_workflow_id_fk", + "tableFrom": "workflow_deployment_version", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_edges": { + "name": "workflow_edges", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_block_id": { + "name": "source_block_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "target_block_id": { + "name": "target_block_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_handle": { + "name": "source_handle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "target_handle": { + "name": "target_handle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_edges_workflow_id_idx": { + "name": "workflow_edges_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_edges_workflow_source_idx": { + "name": "workflow_edges_workflow_source_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source_block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_edges_workflow_target_idx": { + "name": "workflow_edges_workflow_target_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "target_block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_edges_workflow_id_workflow_id_fk": { + "name": "workflow_edges_workflow_id_workflow_id_fk", + "tableFrom": "workflow_edges", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_edges_source_block_id_workflow_blocks_id_fk": { + "name": "workflow_edges_source_block_id_workflow_blocks_id_fk", + "tableFrom": "workflow_edges", + "tableTo": "workflow_blocks", + "columnsFrom": ["source_block_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_edges_target_block_id_workflow_blocks_id_fk": { + "name": "workflow_edges_target_block_id_workflow_blocks_id_fk", + "tableFrom": "workflow_edges", + "tableTo": "workflow_blocks", + "columnsFrom": ["target_block_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_execution_logs": { + "name": "workflow_execution_logs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "state_snapshot_id": { + "name": "state_snapshot_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "deployment_version_id": { + "name": "deployment_version_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "level": { + "name": "level", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'running'" + }, + "trigger": { + "name": "trigger", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "total_duration_ms": { + "name": "total_duration_ms", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "execution_data": { + "name": "execution_data", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "cost": { + "name": "cost", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "files": { + "name": "files", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_execution_logs_workflow_id_idx": { + "name": "workflow_execution_logs_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_state_snapshot_id_idx": { + "name": "workflow_execution_logs_state_snapshot_id_idx", + "columns": [ + { + "expression": "state_snapshot_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_deployment_version_id_idx": { + "name": "workflow_execution_logs_deployment_version_id_idx", + "columns": [ + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_trigger_idx": { + "name": "workflow_execution_logs_trigger_idx", + "columns": [ + { + "expression": "trigger", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_level_idx": { + "name": "workflow_execution_logs_level_idx", + "columns": [ + { + "expression": "level", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_started_at_idx": { + "name": "workflow_execution_logs_started_at_idx", + "columns": [ + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_execution_id_unique": { + "name": "workflow_execution_logs_execution_id_unique", + "columns": [ + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_workflow_started_at_idx": { + "name": "workflow_execution_logs_workflow_started_at_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_workspace_started_at_idx": { + "name": "workflow_execution_logs_workspace_started_at_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_running_started_at_idx": { + "name": "workflow_execution_logs_running_started_at_idx", + "columns": [ + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "status = 'running'", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_execution_logs_workflow_id_workflow_id_fk": { + "name": "workflow_execution_logs_workflow_id_workflow_id_fk", + "tableFrom": "workflow_execution_logs", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "workflow_execution_logs_workspace_id_workspace_id_fk": { + "name": "workflow_execution_logs_workspace_id_workspace_id_fk", + "tableFrom": "workflow_execution_logs", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_execution_logs_state_snapshot_id_workflow_execution_snapshots_id_fk": { + "name": "workflow_execution_logs_state_snapshot_id_workflow_execution_snapshots_id_fk", + "tableFrom": "workflow_execution_logs", + "tableTo": "workflow_execution_snapshots", + "columnsFrom": ["state_snapshot_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "workflow_execution_logs_deployment_version_id_workflow_deployment_version_id_fk": { + "name": "workflow_execution_logs_deployment_version_id_workflow_deployment_version_id_fk", + "tableFrom": "workflow_execution_logs", + "tableTo": "workflow_deployment_version", + "columnsFrom": ["deployment_version_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_execution_snapshots": { + "name": "workflow_execution_snapshots", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "state_hash": { + "name": "state_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "state_data": { + "name": "state_data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_snapshots_workflow_id_idx": { + "name": "workflow_snapshots_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_snapshots_hash_idx": { + "name": "workflow_snapshots_hash_idx", + "columns": [ + { + "expression": "state_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_snapshots_workflow_hash_idx": { + "name": "workflow_snapshots_workflow_hash_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "state_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_snapshots_created_at_idx": { + "name": "workflow_snapshots_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_execution_snapshots_workflow_id_workflow_id_fk": { + "name": "workflow_execution_snapshots_workflow_id_workflow_id_fk", + "tableFrom": "workflow_execution_snapshots", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_folder": { + "name": "workflow_folder", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent_id": { + "name": "parent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'#6B7280'" + }, + "is_expanded": { + "name": "is_expanded", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_folder_user_idx": { + "name": "workflow_folder_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_folder_workspace_parent_idx": { + "name": "workflow_folder_workspace_parent_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "parent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_folder_parent_sort_idx": { + "name": "workflow_folder_parent_sort_idx", + "columns": [ + { + "expression": "parent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sort_order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_folder_user_id_user_id_fk": { + "name": "workflow_folder_user_id_user_id_fk", + "tableFrom": "workflow_folder", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_folder_workspace_id_workspace_id_fk": { + "name": "workflow_folder_workspace_id_workspace_id_fk", + "tableFrom": "workflow_folder", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_mcp_server": { + "name": "workflow_mcp_server", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_public": { + "name": "is_public", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_mcp_server_workspace_id_idx": { + "name": "workflow_mcp_server_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_mcp_server_created_by_idx": { + "name": "workflow_mcp_server_created_by_idx", + "columns": [ + { + "expression": "created_by", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_mcp_server_deleted_at_idx": { + "name": "workflow_mcp_server_deleted_at_idx", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_mcp_server_workspace_id_workspace_id_fk": { + "name": "workflow_mcp_server_workspace_id_workspace_id_fk", + "tableFrom": "workflow_mcp_server", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_mcp_server_created_by_user_id_fk": { + "name": "workflow_mcp_server_created_by_user_id_fk", + "tableFrom": "workflow_mcp_server", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_mcp_tool": { + "name": "workflow_mcp_tool", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "server_id": { + "name": "server_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tool_name": { + "name": "tool_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tool_description": { + "name": "tool_description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "parameter_schema": { + "name": "parameter_schema", + "type": "json", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_mcp_tool_server_id_idx": { + "name": "workflow_mcp_tool_server_id_idx", + "columns": [ + { + "expression": "server_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_mcp_tool_workflow_id_idx": { + "name": "workflow_mcp_tool_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_mcp_tool_server_workflow_unique": { + "name": "workflow_mcp_tool_server_workflow_unique", + "columns": [ + { + "expression": "server_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workflow_mcp_tool\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_mcp_tool_archived_at_idx": { + "name": "workflow_mcp_tool_archived_at_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_mcp_tool_server_id_workflow_mcp_server_id_fk": { + "name": "workflow_mcp_tool_server_id_workflow_mcp_server_id_fk", + "tableFrom": "workflow_mcp_tool", + "tableTo": "workflow_mcp_server", + "columnsFrom": ["server_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_mcp_tool_workflow_id_workflow_id_fk": { + "name": "workflow_mcp_tool_workflow_id_workflow_id_fk", + "tableFrom": "workflow_mcp_tool", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_schedule": { + "name": "workflow_schedule", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "deployment_version_id": { + "name": "deployment_version_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "block_id": { + "name": "block_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cron_expression": { + "name": "cron_expression", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "next_run_at": { + "name": "next_run_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_ran_at": { + "name": "last_ran_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_queued_at": { + "name": "last_queued_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "trigger_type": { + "name": "trigger_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "timezone": { + "name": "timezone", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'UTC'" + }, + "failed_count": { + "name": "failed_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "last_failed_at": { + "name": "last_failed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "source_type": { + "name": "source_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'workflow'" + }, + "job_title": { + "name": "job_title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "prompt": { + "name": "prompt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "lifecycle": { + "name": "lifecycle", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'persistent'" + }, + "success_condition": { + "name": "success_condition", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "max_runs": { + "name": "max_runs", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "run_count": { + "name": "run_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "source_chat_id": { + "name": "source_chat_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_task_name": { + "name": "source_task_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_user_id": { + "name": "source_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_workspace_id": { + "name": "source_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "job_history": { + "name": "job_history", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_schedule_workflow_block_deployment_unique": { + "name": "workflow_schedule_workflow_block_deployment_unique", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workflow_schedule\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_schedule_workflow_deployment_idx": { + "name": "workflow_schedule_workflow_deployment_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_schedule_archived_at_idx": { + "name": "workflow_schedule_archived_at_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_schedule_workflow_id_workflow_id_fk": { + "name": "workflow_schedule_workflow_id_workflow_id_fk", + "tableFrom": "workflow_schedule", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_schedule_deployment_version_id_workflow_deployment_version_id_fk": { + "name": "workflow_schedule_deployment_version_id_workflow_deployment_version_id_fk", + "tableFrom": "workflow_schedule", + "tableTo": "workflow_deployment_version", + "columnsFrom": ["deployment_version_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_schedule_source_user_id_user_id_fk": { + "name": "workflow_schedule_source_user_id_user_id_fk", + "tableFrom": "workflow_schedule", + "tableTo": "user", + "columnsFrom": ["source_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_schedule_source_workspace_id_workspace_id_fk": { + "name": "workflow_schedule_source_workspace_id_workspace_id_fk", + "tableFrom": "workflow_schedule", + "tableTo": "workspace", + "columnsFrom": ["source_workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_subflows": { + "name": "workflow_subflows", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "config": { + "name": "config", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_subflows_workflow_id_idx": { + "name": "workflow_subflows_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_subflows_workflow_type_idx": { + "name": "workflow_subflows_workflow_type_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_subflows_workflow_id_workflow_id_fk": { + "name": "workflow_subflows_workflow_id_workflow_id_fk", + "tableFrom": "workflow_subflows", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace": { + "name": "workspace", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'#33C482'" + }, + "owner_id": { + "name": "owner_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "billed_account_user_id": { + "name": "billed_account_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "allow_personal_api_keys": { + "name": "allow_personal_api_keys", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "inbox_enabled": { + "name": "inbox_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "inbox_address": { + "name": "inbox_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "inbox_provider_id": { + "name": "inbox_provider_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workspace_owner_id_user_id_fk": { + "name": "workspace_owner_id_user_id_fk", + "tableFrom": "workspace", + "tableTo": "user", + "columnsFrom": ["owner_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_billed_account_user_id_user_id_fk": { + "name": "workspace_billed_account_user_id_user_id_fk", + "tableFrom": "workspace", + "tableTo": "user", + "columnsFrom": ["billed_account_user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_byok_keys": { + "name": "workspace_byok_keys", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "encrypted_api_key": { + "name": "encrypted_api_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_byok_provider_unique": { + "name": "workspace_byok_provider_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_byok_workspace_idx": { + "name": "workspace_byok_workspace_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_byok_keys_workspace_id_workspace_id_fk": { + "name": "workspace_byok_keys_workspace_id_workspace_id_fk", + "tableFrom": "workspace_byok_keys", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_byok_keys_created_by_user_id_fk": { + "name": "workspace_byok_keys_created_by_user_id_fk", + "tableFrom": "workspace_byok_keys", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_environment": { + "name": "workspace_environment", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "variables": { + "name": "variables", + "type": "json", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_environment_workspace_unique": { + "name": "workspace_environment_workspace_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_environment_workspace_id_workspace_id_fk": { + "name": "workspace_environment_workspace_id_workspace_id_fk", + "tableFrom": "workspace_environment", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_file": { + "name": "workspace_file", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "uploaded_by": { + "name": "uploaded_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "uploaded_at": { + "name": "uploaded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_file_workspace_id_idx": { + "name": "workspace_file_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_file_key_idx": { + "name": "workspace_file_key_idx", + "columns": [ + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_file_deleted_at_idx": { + "name": "workspace_file_deleted_at_idx", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_file_workspace_id_workspace_id_fk": { + "name": "workspace_file_workspace_id_workspace_id_fk", + "tableFrom": "workspace_file", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_file_uploaded_by_user_id_fk": { + "name": "workspace_file_uploaded_by_user_id_fk", + "tableFrom": "workspace_file", + "tableTo": "user", + "columnsFrom": ["uploaded_by"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "workspace_file_key_unique": { + "name": "workspace_file_key_unique", + "nullsNotDistinct": false, + "columns": ["key"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_files": { + "name": "workspace_files", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "context": { + "name": "context", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chat_id": { + "name": "chat_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "original_name": { + "name": "original_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content_type": { + "name": "content_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "uploaded_at": { + "name": "uploaded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_files_key_active_unique": { + "name": "workspace_files_key_active_unique", + "columns": [ + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workspace_files\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_key_idx": { + "name": "workspace_files_key_idx", + "columns": [ + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_user_id_idx": { + "name": "workspace_files_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_workspace_id_idx": { + "name": "workspace_files_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_context_idx": { + "name": "workspace_files_context_idx", + "columns": [ + { + "expression": "context", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_chat_id_idx": { + "name": "workspace_files_chat_id_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_deleted_at_idx": { + "name": "workspace_files_deleted_at_idx", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_files_user_id_user_id_fk": { + "name": "workspace_files_user_id_user_id_fk", + "tableFrom": "workspace_files", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_files_workspace_id_workspace_id_fk": { + "name": "workspace_files_workspace_id_workspace_id_fk", + "tableFrom": "workspace_files", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_files_chat_id_copilot_chats_id_fk": { + "name": "workspace_files_chat_id_copilot_chats_id_fk", + "tableFrom": "workspace_files", + "tableTo": "copilot_chats", + "columnsFrom": ["chat_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_invitation": { + "name": "workspace_invitation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "inviter_id": { + "name": "inviter_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'member'" + }, + "status": { + "name": "status", + "type": "workspace_invitation_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permissions": { + "name": "permissions", + "type": "permission_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'admin'" + }, + "org_invitation_id": { + "name": "org_invitation_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workspace_invitation_workspace_id_workspace_id_fk": { + "name": "workspace_invitation_workspace_id_workspace_id_fk", + "tableFrom": "workspace_invitation", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_invitation_inviter_id_user_id_fk": { + "name": "workspace_invitation_inviter_id_user_id_fk", + "tableFrom": "workspace_invitation", + "tableTo": "user", + "columnsFrom": ["inviter_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "workspace_invitation_token_unique": { + "name": "workspace_invitation_token_unique", + "nullsNotDistinct": false, + "columns": ["token"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_notification_delivery": { + "name": "workspace_notification_delivery", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "subscription_id": { + "name": "subscription_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "notification_delivery_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "last_attempt_at": { + "name": "last_attempt_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "next_attempt_at": { + "name": "next_attempt_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "response_status": { + "name": "response_status", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "response_body": { + "name": "response_body", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_notification_delivery_subscription_id_idx": { + "name": "workspace_notification_delivery_subscription_id_idx", + "columns": [ + { + "expression": "subscription_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_notification_delivery_execution_id_idx": { + "name": "workspace_notification_delivery_execution_id_idx", + "columns": [ + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_notification_delivery_status_idx": { + "name": "workspace_notification_delivery_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_notification_delivery_next_attempt_idx": { + "name": "workspace_notification_delivery_next_attempt_idx", + "columns": [ + { + "expression": "next_attempt_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_notification_delivery_subscription_id_workspace_notification_subscription_id_fk": { + "name": "workspace_notification_delivery_subscription_id_workspace_notification_subscription_id_fk", + "tableFrom": "workspace_notification_delivery", + "tableTo": "workspace_notification_subscription", + "columnsFrom": ["subscription_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_notification_delivery_workflow_id_workflow_id_fk": { + "name": "workspace_notification_delivery_workflow_id_workflow_id_fk", + "tableFrom": "workspace_notification_delivery", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_notification_subscription": { + "name": "workspace_notification_subscription", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "notification_type": { + "name": "notification_type", + "type": "notification_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "workflow_ids": { + "name": "workflow_ids", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "'{}'::text[]" + }, + "all_workflows": { + "name": "all_workflows", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "level_filter": { + "name": "level_filter", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY['info', 'error']::text[]" + }, + "trigger_filter": { + "name": "trigger_filter", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY['api', 'webhook', 'schedule', 'manual', 'chat']::text[]" + }, + "include_final_output": { + "name": "include_final_output", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "include_trace_spans": { + "name": "include_trace_spans", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "include_rate_limits": { + "name": "include_rate_limits", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "include_usage_data": { + "name": "include_usage_data", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "webhook_config": { + "name": "webhook_config", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "email_recipients": { + "name": "email_recipients", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "slack_config": { + "name": "slack_config", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "alert_config": { + "name": "alert_config", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "last_alert_at": { + "name": "last_alert_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_notification_workspace_id_idx": { + "name": "workspace_notification_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_notification_active_idx": { + "name": "workspace_notification_active_idx", + "columns": [ + { + "expression": "active", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_notification_type_idx": { + "name": "workspace_notification_type_idx", + "columns": [ + { + "expression": "notification_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_notification_subscription_workspace_id_workspace_id_fk": { + "name": "workspace_notification_subscription_workspace_id_workspace_id_fk", + "tableFrom": "workspace_notification_subscription", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_notification_subscription_created_by_user_id_fk": { + "name": "workspace_notification_subscription_created_by_user_id_fk", + "tableFrom": "workspace_notification_subscription", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.a2a_task_status": { + "name": "a2a_task_status", + "schema": "public", + "values": [ + "submitted", + "working", + "input-required", + "completed", + "failed", + "canceled", + "rejected", + "auth-required", + "unknown" + ] + }, + "public.billing_blocked_reason": { + "name": "billing_blocked_reason", + "schema": "public", + "values": ["payment_failed", "dispute"] + }, + "public.chat_type": { + "name": "chat_type", + "schema": "public", + "values": ["mothership", "copilot"] + }, + "public.credential_member_role": { + "name": "credential_member_role", + "schema": "public", + "values": ["admin", "member"] + }, + "public.credential_member_status": { + "name": "credential_member_status", + "schema": "public", + "values": ["active", "pending", "revoked"] + }, + "public.credential_set_invitation_status": { + "name": "credential_set_invitation_status", + "schema": "public", + "values": ["pending", "accepted", "expired", "cancelled"] + }, + "public.credential_set_member_status": { + "name": "credential_set_member_status", + "schema": "public", + "values": ["active", "pending", "revoked"] + }, + "public.credential_type": { + "name": "credential_type", + "schema": "public", + "values": ["oauth", "env_workspace", "env_personal"] + }, + "public.notification_delivery_status": { + "name": "notification_delivery_status", + "schema": "public", + "values": ["pending", "in_progress", "success", "failed"] + }, + "public.notification_type": { + "name": "notification_type", + "schema": "public", + "values": ["webhook", "email", "slack"] + }, + "public.permission_type": { + "name": "permission_type", + "schema": "public", + "values": ["admin", "write", "read"] + }, + "public.template_creator_type": { + "name": "template_creator_type", + "schema": "public", + "values": ["user", "organization"] + }, + "public.template_status": { + "name": "template_status", + "schema": "public", + "values": ["pending", "approved", "rejected"] + }, + "public.usage_log_category": { + "name": "usage_log_category", + "schema": "public", + "values": ["model", "fixed"] + }, + "public.usage_log_source": { + "name": "usage_log_source", + "schema": "public", + "values": ["workflow", "wand", "copilot", "workspace-chat", "mcp_copilot", "mothership_block"] + }, + "public.workspace_invitation_status": { + "name": "workspace_invitation_status", + "schema": "public", + "values": ["pending", "accepted", "rejected", "cancelled"] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} diff --git a/packages/db/migrations/meta/_journal.json b/packages/db/migrations/meta/_journal.json index 4065f5936ec..cbfddfa699e 100644 --- a/packages/db/migrations/meta/_journal.json +++ b/packages/db/migrations/meta/_journal.json @@ -1240,6 +1240,13 @@ "when": 1773698715278, "tag": "0177_wise_puma", "breakpoints": true + }, + { + "idx": 178, + "version": "7", + "when": 1774112405784, + "tag": "0178_clumsy_living_mummy", + "breakpoints": true } ] } diff --git a/packages/db/schema.ts b/packages/db/schema.ts index cf991202b46..b0f5190866b 100644 --- a/packages/db/schema.ts +++ b/packages/db/schema.ts @@ -33,6 +33,7 @@ export const user = pgTable('user', { id: text('id').primaryKey(), name: text('name').notNull(), email: text('email').notNull().unique(), + normalizedEmail: text('normalized_email').unique(), emailVerified: boolean('email_verified').notNull(), image: text('image'), createdAt: timestamp('created_at').notNull(), From 951c8fd5e98bd6ff1d9a7c653673ca77a57634ba Mon Sep 17 00:00:00 2001 From: Waleed Date: Sat, 21 Mar 2026 11:45:49 -0700 Subject: [PATCH 7/7] feat(integrations): add integrationType and tags classification to all blocks (#3702) * feat(integrations): add integrationType and tags classification to all blocks * improvement(integrations): replace generic api/oauth tags with use-case-oriented tags * lint * upgrade turbo --- .claude/commands/add-block.md | 10 +- .claude/commands/add-integration.md | 6 +- .../components/integration-grid.tsx | 140 +++- .../integrations/data/integrations.json | 672 +++++++++++++----- .../app/(landing)/integrations/data/types.ts | 2 + apps/sim/blocks/blocks/a2a.ts | 3 + apps/sim/blocks/blocks/agent.ts | 4 +- apps/sim/blocks/blocks/ahrefs.ts | 4 +- apps/sim/blocks/blocks/airtable.ts | 4 +- apps/sim/blocks/blocks/airweave.ts | 4 +- apps/sim/blocks/blocks/algolia.ts | 4 +- apps/sim/blocks/blocks/amplitude.ts | 4 +- apps/sim/blocks/blocks/api.ts | 3 + apps/sim/blocks/blocks/apify.ts | 3 + apps/sim/blocks/blocks/apollo.ts | 4 +- apps/sim/blocks/blocks/arxiv.ts | 3 + apps/sim/blocks/blocks/asana.ts | 4 +- apps/sim/blocks/blocks/ashby.ts | 4 +- apps/sim/blocks/blocks/attio.ts | 4 +- apps/sim/blocks/blocks/box.ts | 4 +- apps/sim/blocks/blocks/brandfetch.ts | 4 +- apps/sim/blocks/blocks/browser_use.ts | 4 +- apps/sim/blocks/blocks/calcom.ts | 4 +- apps/sim/blocks/blocks/calendly.ts | 4 +- apps/sim/blocks/blocks/circleback.ts | 3 + apps/sim/blocks/blocks/clay.ts | 4 +- apps/sim/blocks/blocks/clerk.ts | 3 + apps/sim/blocks/blocks/cloudflare.ts | 4 +- apps/sim/blocks/blocks/confluence.ts | 4 +- apps/sim/blocks/blocks/cursor.ts | 4 +- apps/sim/blocks/blocks/databricks.ts | 4 +- apps/sim/blocks/blocks/datadog.ts | 4 +- apps/sim/blocks/blocks/devin.ts | 4 +- apps/sim/blocks/blocks/discord.ts | 4 +- apps/sim/blocks/blocks/docusign.ts | 4 +- apps/sim/blocks/blocks/dropbox.ts | 4 +- apps/sim/blocks/blocks/dspy.ts | 3 + apps/sim/blocks/blocks/dub.ts | 4 +- apps/sim/blocks/blocks/duckduckgo.ts | 3 + apps/sim/blocks/blocks/dynamodb.ts | 3 + apps/sim/blocks/blocks/elasticsearch.ts | 4 +- apps/sim/blocks/blocks/elevenlabs.ts | 4 +- apps/sim/blocks/blocks/enrich.ts | 4 +- apps/sim/blocks/blocks/evernote.ts | 4 +- apps/sim/blocks/blocks/exa.ts | 4 +- apps/sim/blocks/blocks/fathom.ts | 4 +- apps/sim/blocks/blocks/file.ts | 5 + apps/sim/blocks/blocks/firecrawl.ts | 4 +- apps/sim/blocks/blocks/fireflies.ts | 6 +- apps/sim/blocks/blocks/gamma.ts | 4 +- apps/sim/blocks/blocks/github.ts | 6 +- apps/sim/blocks/blocks/gitlab.ts | 4 +- apps/sim/blocks/blocks/gmail.ts | 6 +- apps/sim/blocks/blocks/gong.ts | 4 +- apps/sim/blocks/blocks/google.ts | 4 +- apps/sim/blocks/blocks/google_ads.ts | 4 +- apps/sim/blocks/blocks/google_bigquery.ts | 4 +- apps/sim/blocks/blocks/google_books.ts | 4 +- apps/sim/blocks/blocks/google_calendar.ts | 6 +- apps/sim/blocks/blocks/google_contacts.ts | 4 +- apps/sim/blocks/blocks/google_docs.ts | 4 +- apps/sim/blocks/blocks/google_drive.ts | 4 +- apps/sim/blocks/blocks/google_forms.ts | 3 + apps/sim/blocks/blocks/google_groups.ts | 4 +- apps/sim/blocks/blocks/google_maps.ts | 3 + apps/sim/blocks/blocks/google_meet.ts | 4 +- apps/sim/blocks/blocks/google_pagespeed.ts | 4 +- apps/sim/blocks/blocks/google_sheets.ts | 6 +- apps/sim/blocks/blocks/google_slides.ts | 6 +- apps/sim/blocks/blocks/google_tasks.ts | 4 +- apps/sim/blocks/blocks/google_translate.ts | 4 +- apps/sim/blocks/blocks/google_vault.ts | 4 +- apps/sim/blocks/blocks/grafana.ts | 4 +- apps/sim/blocks/blocks/grain.ts | 4 +- apps/sim/blocks/blocks/greenhouse.ts | 4 +- apps/sim/blocks/blocks/greptile.ts | 4 +- apps/sim/blocks/blocks/hex.ts | 4 +- apps/sim/blocks/blocks/hubspot.ts | 4 +- apps/sim/blocks/blocks/huggingface.ts | 4 +- apps/sim/blocks/blocks/hunter.ts | 4 +- apps/sim/blocks/blocks/image_generator.ts | 4 +- apps/sim/blocks/blocks/imap.ts | 3 + apps/sim/blocks/blocks/incidentio.ts | 4 +- apps/sim/blocks/blocks/infisical.ts | 4 +- apps/sim/blocks/blocks/intercom.ts | 6 +- apps/sim/blocks/blocks/jina.ts | 4 +- apps/sim/blocks/blocks/jira.ts | 4 +- .../blocks/blocks/jira_service_management.ts | 4 +- apps/sim/blocks/blocks/kalshi.ts | 6 +- apps/sim/blocks/blocks/langsmith.ts | 4 +- apps/sim/blocks/blocks/lemlist.ts | 4 +- apps/sim/blocks/blocks/linear.ts | 4 +- apps/sim/blocks/blocks/linkedin.ts | 4 +- apps/sim/blocks/blocks/linkup.ts | 4 +- apps/sim/blocks/blocks/loops.ts | 4 +- apps/sim/blocks/blocks/luma.ts | 4 +- apps/sim/blocks/blocks/mailchimp.ts | 4 +- apps/sim/blocks/blocks/mailgun.ts | 3 + apps/sim/blocks/blocks/mcp.ts | 3 + apps/sim/blocks/blocks/mem0.ts | 4 +- apps/sim/blocks/blocks/microsoft_ad.ts | 4 +- apps/sim/blocks/blocks/microsoft_dataverse.ts | 4 +- apps/sim/blocks/blocks/microsoft_excel.ts | 6 +- apps/sim/blocks/blocks/microsoft_planner.ts | 4 +- apps/sim/blocks/blocks/microsoft_teams.ts | 4 +- apps/sim/blocks/blocks/mistral_parse.ts | 4 +- apps/sim/blocks/blocks/mongodb.ts | 3 + apps/sim/blocks/blocks/mysql.ts | 3 + apps/sim/blocks/blocks/neo4j.ts | 3 + apps/sim/blocks/blocks/notion.ts | 6 +- apps/sim/blocks/blocks/obsidian.ts | 4 +- apps/sim/blocks/blocks/okta.ts | 3 + apps/sim/blocks/blocks/onedrive.ts | 4 +- apps/sim/blocks/blocks/onepassword.ts | 4 +- apps/sim/blocks/blocks/openai.ts | 4 +- apps/sim/blocks/blocks/outlook.ts | 4 +- apps/sim/blocks/blocks/pagerduty.ts | 4 +- apps/sim/blocks/blocks/parallel.ts | 4 +- apps/sim/blocks/blocks/perplexity.ts | 4 +- apps/sim/blocks/blocks/pinecone.ts | 4 +- apps/sim/blocks/blocks/pipedrive.ts | 4 +- apps/sim/blocks/blocks/polymarket.ts | 3 + apps/sim/blocks/blocks/postgresql.ts | 3 + apps/sim/blocks/blocks/posthog.ts | 4 +- apps/sim/blocks/blocks/pulse.ts | 4 +- apps/sim/blocks/blocks/qdrant.ts | 4 +- apps/sim/blocks/blocks/rds.ts | 3 + apps/sim/blocks/blocks/reddit.ts | 4 +- apps/sim/blocks/blocks/redis.ts | 4 +- apps/sim/blocks/blocks/reducto.ts | 4 +- apps/sim/blocks/blocks/resend.ts | 4 +- apps/sim/blocks/blocks/revenuecat.ts | 4 +- apps/sim/blocks/blocks/rss.ts | 3 + apps/sim/blocks/blocks/s3.ts | 4 +- apps/sim/blocks/blocks/salesforce.ts | 4 +- apps/sim/blocks/blocks/search.ts | 3 + apps/sim/blocks/blocks/sendgrid.ts | 3 + apps/sim/blocks/blocks/sentry.ts | 4 +- apps/sim/blocks/blocks/serper.ts | 4 +- apps/sim/blocks/blocks/servicenow.ts | 3 + apps/sim/blocks/blocks/sftp.ts | 4 +- apps/sim/blocks/blocks/sharepoint.ts | 4 +- apps/sim/blocks/blocks/shopify.ts | 4 +- apps/sim/blocks/blocks/similarweb.ts | 4 +- apps/sim/blocks/blocks/slack.ts | 4 +- apps/sim/blocks/blocks/smtp.ts | 4 +- apps/sim/blocks/blocks/spotify.ts | 4 +- apps/sim/blocks/blocks/sqs.ts | 3 + apps/sim/blocks/blocks/ssh.ts | 4 +- apps/sim/blocks/blocks/stagehand.ts | 4 +- apps/sim/blocks/blocks/stripe.ts | 4 +- apps/sim/blocks/blocks/stt.ts | 4 +- apps/sim/blocks/blocks/supabase.ts | 4 +- apps/sim/blocks/blocks/tavily.ts | 4 +- apps/sim/blocks/blocks/telegram.ts | 4 +- apps/sim/blocks/blocks/textract.ts | 4 +- apps/sim/blocks/blocks/tinybird.ts | 4 +- apps/sim/blocks/blocks/translate.ts | 4 +- apps/sim/blocks/blocks/trello.ts | 4 +- apps/sim/blocks/blocks/tts.ts | 4 +- apps/sim/blocks/blocks/twilio.ts | 4 +- apps/sim/blocks/blocks/twilio_voice.ts | 4 +- apps/sim/blocks/blocks/typeform.ts | 4 +- apps/sim/blocks/blocks/upstash.ts | 4 +- apps/sim/blocks/blocks/vercel.ts | 4 +- apps/sim/blocks/blocks/video_generator.ts | 4 +- apps/sim/blocks/blocks/vision.ts | 4 +- apps/sim/blocks/blocks/wealthbox.ts | 4 +- apps/sim/blocks/blocks/webflow.ts | 4 +- apps/sim/blocks/blocks/whatsapp.ts | 4 +- apps/sim/blocks/blocks/wikipedia.ts | 3 + apps/sim/blocks/blocks/wordpress.ts | 4 +- apps/sim/blocks/blocks/workday.ts | 3 + apps/sim/blocks/blocks/x.ts | 4 +- apps/sim/blocks/blocks/youtube.ts | 4 +- apps/sim/blocks/blocks/zendesk.ts | 4 +- apps/sim/blocks/blocks/zep.ts | 4 +- apps/sim/blocks/blocks/zoom.ts | 4 +- apps/sim/blocks/types.ts | 76 ++ bun.lock | 28 +- package.json | 2 +- scripts/generate-docs.ts | 65 +- 182 files changed, 1324 insertions(+), 362 deletions(-) diff --git a/.claude/commands/add-block.md b/.claude/commands/add-block.md index 6d51062660d..e07600c2655 100644 --- a/.claude/commands/add-block.md +++ b/.claude/commands/add-block.md @@ -19,7 +19,7 @@ When the user asks you to create a block: ```typescript import { {ServiceName}Icon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { getScopesForService } from '@/lib/oauth/utils' export const {ServiceName}Block: BlockConfig = { @@ -29,6 +29,8 @@ export const {ServiceName}Block: BlockConfig = { longDescription: 'Detailed description for docs', docsLink: 'https://docs.sim.ai/tools/{service}', category: 'tools', // 'tools' | 'blocks' | 'triggers' + integrationType: IntegrationType.X, // Primary category (see IntegrationType enum) + tags: ['oauth', 'api'], // Cross-cutting tags (see IntegrationTag type) bgColor: '#HEXCOLOR', // Brand color icon: {ServiceName}Icon, @@ -629,7 +631,7 @@ export const registry: Record = { ```typescript import { ServiceIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { getScopesForService } from '@/lib/oauth/utils' export const ServiceBlock: BlockConfig = { @@ -639,6 +641,8 @@ export const ServiceBlock: BlockConfig = { longDescription: 'Full description for documentation...', docsLink: 'https://docs.sim.ai/tools/service', category: 'tools', + integrationType: IntegrationType.DeveloperTools, + tags: ['oauth', 'api'], bgColor: '#FF6B6B', icon: ServiceIcon, authMode: AuthMode.OAuth, @@ -796,6 +800,8 @@ All tool IDs referenced in `tools.access` and returned by `tools.config.tool` MU ## Checklist Before Finishing +- [ ] `integrationType` is set to the correct `IntegrationType` enum value +- [ ] `tags` array includes all applicable `IntegrationTag` values - [ ] All subBlocks have `id`, `title` (except switch), and `type` - [ ] Conditions use correct syntax (field, value, not, and) - [ ] DependsOn set for fields that need other values diff --git a/.claude/commands/add-integration.md b/.claude/commands/add-integration.md index c990f39a7b2..c0fb91e7fa9 100644 --- a/.claude/commands/add-integration.md +++ b/.claude/commands/add-integration.md @@ -113,7 +113,7 @@ export const {service}{Action}Tool: ToolConfig = { ```typescript import { {Service}Icon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { getScopesForService } from '@/lib/oauth/utils' export const {Service}Block: BlockConfig = { @@ -123,6 +123,8 @@ export const {Service}Block: BlockConfig = { longDescription: '...', docsLink: 'https://docs.sim.ai/tools/{service}', category: 'tools', + integrationType: IntegrationType.X, // Primary category (see IntegrationType enum) + tags: ['oauth', 'api'], // Cross-cutting tags (see IntegrationTag type) bgColor: '#HEXCOLOR', icon: {Service}Icon, authMode: AuthMode.OAuth, // or AuthMode.ApiKey @@ -410,6 +412,8 @@ If creating V2 versions (API-aligned outputs): ### Block - [ ] Created `blocks/blocks/{service}.ts` +- [ ] Set `integrationType` to the correct `IntegrationType` enum value +- [ ] Set `tags` array with all applicable `IntegrationTag` values - [ ] Defined operation dropdown with all operations - [ ] Added credential field with `requiredScopes: getScopesForService('{service}')` - [ ] Added conditional fields per operation diff --git a/apps/sim/app/(landing)/integrations/components/integration-grid.tsx b/apps/sim/app/(landing)/integrations/components/integration-grid.tsx index b06307162d4..61975a29513 100644 --- a/apps/sim/app/(landing)/integrations/components/integration-grid.tsx +++ b/apps/sim/app/(landing)/integrations/components/integration-grid.tsx @@ -6,54 +6,132 @@ import { blockTypeToIconMap } from '@/app/(landing)/integrations/data/icon-mappi import type { Integration } from '@/app/(landing)/integrations/data/types' import { IntegrationCard } from './integration-card' +const CATEGORY_LABELS: Record = { + ai: 'AI', + analytics: 'Analytics', + automation: 'Automation', + communication: 'Communication', + crm: 'CRM', + 'customer-support': 'Customer Support', + databases: 'Databases', + design: 'Design', + 'developer-tools': 'Developer Tools', + documents: 'Documents', + ecommerce: 'E-commerce', + email: 'Email', + 'file-storage': 'File Storage', + hr: 'HR', + media: 'Media', + productivity: 'Productivity', + 'sales-intelligence': 'Sales Intelligence', + search: 'Search', + security: 'Security', + social: 'Social', + other: 'Other', +} as const + interface IntegrationGridProps { integrations: Integration[] } export function IntegrationGrid({ integrations }: IntegrationGridProps) { const [query, setQuery] = useState('') + const [activeCategory, setActiveCategory] = useState(null) + + const availableCategories = useMemo(() => { + const counts = new Map() + for (const i of integrations) { + if (i.integrationType) { + counts.set(i.integrationType, (counts.get(i.integrationType) || 0) + 1) + } + } + return Array.from(counts.entries()) + .sort((a, b) => b[1] - a[1]) + .map(([key]) => key) + }, [integrations]) const filtered = useMemo(() => { + let results = integrations + + if (activeCategory) { + results = results.filter((i) => i.integrationType === activeCategory) + } + const q = query.trim().toLowerCase() - if (!q) return integrations - return integrations.filter( - (i) => - i.name.toLowerCase().includes(q) || - i.description.toLowerCase().includes(q) || - i.operations.some( - (op) => op.name.toLowerCase().includes(q) || op.description.toLowerCase().includes(q) - ) || - i.triggers.some((t) => t.name.toLowerCase().includes(q)) - ) - }, [integrations, query]) + if (q) { + results = results.filter( + (i) => + i.name.toLowerCase().includes(q) || + i.description.toLowerCase().includes(q) || + i.operations.some( + (op) => op.name.toLowerCase().includes(q) || op.description.toLowerCase().includes(q) + ) || + i.triggers.some((t) => t.name.toLowerCase().includes(q)) + ) + } + + return results + }, [integrations, query, activeCategory]) return (
-
-
+ + setQuery(e.target.value)} + className='pl-9' + aria-label='Search integrations' + /> +
+
+ +
+ + {availableCategories.map((cat) => ( + + ))}
{filtered.length === 0 ? (

- No integrations found for “{query}” + No integrations found + {query ? <> for “{query}” : null} + {activeCategory ? <> in {CATEGORY_LABELS[activeCategory] || activeCategory} : null}

) : (
diff --git a/apps/sim/app/(landing)/integrations/data/integrations.json b/apps/sim/app/(landing)/integrations/data/integrations.json index d1048bd260c..ee1bedb0da4 100644 --- a/apps/sim/app/(landing)/integrations/data/integrations.json +++ b/apps/sim/app/(landing)/integrations/data/integrations.json @@ -50,7 +50,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "security", + "tags": ["secrets-management", "identity"] }, { "type": "a2a", @@ -99,7 +101,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "developer-tools", + "tags": ["agentic", "automation"] }, { "type": "ahrefs", @@ -148,7 +152,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "analytics", + "tags": ["seo", "marketing", "data-analytics"] }, { "type": "airtable", @@ -203,7 +209,9 @@ ], "triggerCount": 1, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "databases", + "tags": ["spreadsheet", "automation"] }, { "type": "airweave", @@ -219,7 +227,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "search", + "tags": ["vector-search", "knowledge-base"] }, { "type": "algolia", @@ -296,7 +306,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "search", + "tags": ["vector-search", "knowledge-base"] }, { "type": "dynamodb", @@ -341,7 +353,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "databases", + "tags": ["cloud", "data-warehouse"] }, { "type": "rds", @@ -382,7 +396,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "databases", + "tags": ["cloud", "data-warehouse"] }, { "type": "sqs", @@ -403,7 +419,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "developer-tools", + "tags": ["cloud", "messaging", "automation"] }, { "type": "amplitude", @@ -464,7 +482,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "analytics", + "tags": ["data-analytics", "marketing"] }, { "type": "apify", @@ -489,7 +509,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "automation", + "tags": ["web-scraping", "automation", "data-analytics"] }, { "type": "apollo", @@ -606,7 +628,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "sales-intelligence", + "tags": ["enrichment", "sales-engagement"] }, { "type": "arxiv", @@ -635,7 +659,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "search", + "tags": ["document-processing", "knowledge-base"] }, { "type": "asana", @@ -676,7 +702,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "productivity", + "tags": ["project-management", "ticketing", "automation"] }, { "type": "ashby", @@ -836,7 +864,9 @@ ], "triggerCount": 6, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "hr", + "tags": ["hiring"] }, { "type": "attio", @@ -1104,7 +1134,9 @@ ], "triggerCount": 18, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "crm", + "tags": ["sales-engagement", "enrichment"] }, { "type": "textract_v2", @@ -1120,7 +1152,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "ai", + "tags": ["document-processing", "ocr", "cloud"] }, { "type": "microsoft_ad", @@ -1189,7 +1223,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "security", + "tags": ["identity", "microsoft-365"] }, { "type": "box", @@ -1266,7 +1302,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "file-storage", + "tags": ["cloud", "content-management", "e-signatures"] }, { "type": "brandfetch", @@ -1291,7 +1329,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "sales-intelligence", + "tags": ["enrichment", "marketing"] }, { "type": "browser_use", @@ -1307,7 +1347,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "automation", + "tags": ["web-scraping", "automation", "agentic"] }, { "type": "calcom", @@ -1446,7 +1488,9 @@ ], "triggerCount": 9, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "productivity", + "tags": ["scheduling", "calendar", "meeting"] }, { "type": "calendly", @@ -1512,7 +1556,9 @@ ], "triggerCount": 4, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "productivity", + "tags": ["scheduling", "calendar", "meeting"] }, { "type": "circleback", @@ -1544,7 +1590,9 @@ ], "triggerCount": 3, "authType": "none", - "category": "triggers" + "category": "triggers", + "integrationType": "ai", + "tags": ["meeting", "note-taking", "automation"] }, { "type": "clay", @@ -1560,7 +1608,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "sales-intelligence", + "tags": ["enrichment", "sales-engagement", "data-analytics"] }, { "type": "clerk", @@ -1621,7 +1671,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "security", + "tags": ["identity", "automation"] }, { "type": "cloudflare", @@ -1690,7 +1742,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "developer-tools", + "tags": ["cloud", "monitoring"] }, { "type": "confluence_v2", @@ -1972,7 +2026,9 @@ ], "triggerCount": 16, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "documents", + "tags": ["knowledge-base", "content-management", "note-taking"] }, { "type": "cursor_v2", @@ -2017,7 +2073,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "developer-tools", + "tags": ["agentic", "automation"] }, { "type": "databricks", @@ -2066,7 +2124,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "databases", + "tags": ["data-warehouse", "data-analytics", "cloud"] }, { "type": "datadog", @@ -2131,7 +2191,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "analytics", + "tags": ["monitoring", "incident-management", "error-tracking"] }, { "type": "devin", @@ -2164,7 +2226,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "developer-tools", + "tags": ["agentic", "automation"] }, { "type": "discord", @@ -2321,7 +2385,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "communication", + "tags": ["messaging", "webhooks", "automation"] }, { "type": "docusign", @@ -2370,7 +2436,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "documents", + "tags": ["e-signatures", "document-processing"] }, { "type": "dropbox", @@ -2427,7 +2495,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "file-storage", + "tags": ["cloud", "document-processing"] }, { "type": "dspy", @@ -2456,7 +2526,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "ai", + "tags": ["llm", "agentic", "automation"] }, { "type": "dub", @@ -2501,7 +2573,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "developer-tools", + "tags": ["link-management", "marketing", "data-analytics"] }, { "type": "duckduckgo", @@ -2517,7 +2591,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "search", + "tags": ["web-scraping", "seo"] }, { "type": "elasticsearch", @@ -2586,7 +2662,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "databases", + "tags": ["vector-search", "data-analytics"] }, { "type": "elevenlabs", @@ -2602,7 +2680,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "media", + "tags": ["text-to-speech"] }, { "type": "openai", @@ -2618,7 +2698,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "ai", + "tags": ["llm", "vector-search"] }, { "type": "enrich", @@ -2751,7 +2833,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "sales-intelligence", + "tags": ["enrichment", "data-analytics"] }, { "type": "evernote", @@ -2812,7 +2896,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "documents", + "tags": ["note-taking", "knowledge-base"] }, { "type": "exa", @@ -2849,7 +2935,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "search", + "tags": ["web-scraping", "enrichment"] }, { "type": "fathom", @@ -2897,7 +2985,9 @@ ], "triggerCount": 2, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "analytics", + "tags": ["meeting", "note-taking"] }, { "type": "file_v3", @@ -2913,7 +3003,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "file-storage", + "tags": ["document-processing"] }, { "type": "firecrawl", @@ -2954,7 +3046,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "automation", + "tags": ["web-scraping", "automation"] }, { "type": "fireflies_v2", @@ -3017,7 +3111,9 @@ ], "triggerCount": 1, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "media", + "tags": ["meeting", "speech-to-text", "note-taking"] }, { "type": "gamma", @@ -3054,7 +3150,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "design", + "tags": ["document-processing", "content-management"] }, { "type": "github_v2", @@ -3459,7 +3557,9 @@ ], "triggerCount": 11, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "developer-tools", + "tags": ["version-control", "ci-cd"] }, { "type": "gitlab", @@ -3552,7 +3652,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "developer-tools", + "tags": ["version-control", "ci-cd"] }, { "type": "gmail_v2", @@ -3617,7 +3719,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "email", + "tags": ["google-workspace", "messaging"] }, { "type": "gong", @@ -3706,7 +3810,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "sales-intelligence", + "tags": ["meeting", "sales-engagement", "speech-to-text"] }, { "type": "google_ads", @@ -3747,7 +3853,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "analytics", + "tags": ["marketing", "google-workspace", "data-analytics"] }, { "type": "google_bigquery", @@ -3784,7 +3892,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "databases", + "tags": ["data-warehouse", "google-workspace", "data-analytics"] }, { "type": "google_books", @@ -3809,7 +3919,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "search", + "tags": ["google-workspace", "knowledge-base", "content-management"] }, { "type": "google_calendar_v2", @@ -3866,7 +3978,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "productivity", + "tags": ["calendar", "scheduling", "google-workspace"] }, { "type": "google_contacts", @@ -3907,7 +4021,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "productivity", + "tags": ["google-workspace", "customer-support", "enrichment"] }, { "type": "google_docs", @@ -3936,7 +4052,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "documents", + "tags": ["google-workspace", "document-processing", "content-management"] }, { "type": "google_drive", @@ -4009,7 +4127,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "file-storage", + "tags": ["cloud", "google-workspace", "document-processing"] }, { "type": "google_forms", @@ -4068,7 +4188,9 @@ ], "triggerCount": 1, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "documents", + "tags": ["google-workspace", "forms", "data-analytics"] }, { "type": "google_groups", @@ -4149,7 +4271,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "communication", + "tags": ["google-workspace", "messaging", "identity"] }, { "type": "google_maps", @@ -4218,7 +4342,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "developer-tools", + "tags": ["google-workspace", "enrichment"] }, { "type": "google_meet", @@ -4259,7 +4385,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "communication", + "tags": ["meeting", "google-workspace", "scheduling"] }, { "type": "google_pagespeed", @@ -4275,7 +4403,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "analytics", + "tags": ["google-workspace", "seo", "monitoring"] }, { "type": "google_search", @@ -4291,7 +4421,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "search", + "tags": ["google-workspace", "web-scraping", "seo"] }, { "type": "google_sheets_v2", @@ -4352,7 +4484,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "documents", + "tags": ["spreadsheet", "google-workspace", "data-analytics"] }, { "type": "google_slides_v2", @@ -4425,7 +4559,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "documents", + "tags": ["google-workspace", "document-processing", "content-management"] }, { "type": "google_tasks", @@ -4466,7 +4602,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "productivity", + "tags": ["google-workspace", "project-management", "scheduling"] }, { "type": "google_translate", @@ -4491,7 +4629,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "ai", + "tags": ["google-workspace", "content-management", "automation"] }, { "type": "google_vault", @@ -4536,7 +4676,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "security", + "tags": ["google-workspace", "secrets-management", "document-processing"] }, { "type": "grafana", @@ -4629,7 +4771,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "analytics", + "tags": ["monitoring", "data-analytics"] }, { "type": "grain", @@ -4723,7 +4867,9 @@ ], "triggerCount": 8, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "media", + "tags": ["meeting", "note-taking"] }, { "type": "greenhouse", @@ -4784,7 +4930,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "hr", + "tags": ["hiring"] }, { "type": "greptile", @@ -4817,7 +4965,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "developer-tools", + "tags": ["version-control", "knowledge-base"] }, { "type": "hex", @@ -4898,7 +5048,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "analytics", + "tags": ["data-warehouse", "data-analytics"] }, { "type": "hubspot", @@ -5046,7 +5198,9 @@ ], "triggerCount": 18, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "crm", + "tags": ["marketing", "sales-engagement", "customer-support"] }, { "type": "huggingface", @@ -5062,7 +5216,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "ai", + "tags": ["llm", "agentic"] }, { "type": "hunter", @@ -5103,7 +5259,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "sales-intelligence", + "tags": ["enrichment", "sales-engagement"] }, { "type": "image_generator", @@ -5119,7 +5277,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "ai", + "tags": ["image-generation", "llm"] }, { "type": "imap", @@ -5141,7 +5301,9 @@ ], "triggerCount": 1, "authType": "none", - "category": "triggers" + "category": "triggers", + "integrationType": "email", + "tags": ["messaging", "automation"] }, { "type": "incidentio", @@ -5334,7 +5496,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "developer-tools", + "tags": ["incident-management", "monitoring"] }, { "type": "infisical", @@ -5371,7 +5535,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "security", + "tags": ["secrets-management"] }, { "type": "intercom_v2", @@ -5512,7 +5678,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "customer-support", + "tags": ["customer-support", "messaging"] }, { "type": "jina", @@ -5537,7 +5705,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "search", + "tags": ["web-scraping", "knowledge-base"] }, { "type": "jira", @@ -5681,7 +5851,9 @@ ], "triggerCount": 6, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "productivity", + "tags": ["project-management", "ticketing"] }, { "type": "jira_service_management", @@ -5782,7 +5954,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "customer-support", + "tags": ["customer-support", "ticketing", "incident-management"] }, { "type": "kalshi_v2", @@ -5867,7 +6041,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "analytics", + "tags": ["prediction-markets", "data-analytics"] }, { "type": "knowledge", @@ -5965,7 +6141,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "developer-tools", + "tags": ["monitoring", "llm", "data-analytics"] }, { "type": "lemlist", @@ -6040,7 +6218,9 @@ ], "triggerCount": 9, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "email", + "tags": ["sales-engagement", "email-marketing", "automation"] }, { "type": "linear", @@ -6445,7 +6625,9 @@ ], "triggerCount": 15, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "productivity", + "tags": ["project-management", "ticketing"] }, { "type": "linkedin", @@ -6470,7 +6652,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "social", + "tags": ["marketing", "sales-engagement", "enrichment"] }, { "type": "linkup", @@ -6486,7 +6670,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "search", + "tags": ["web-scraping", "enrichment"] }, { "type": "loops", @@ -6543,7 +6729,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "email", + "tags": ["email-marketing", "marketing", "automation"] }, { "type": "luma", @@ -6584,7 +6772,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "productivity", + "tags": ["events", "calendar", "scheduling"] }, { "type": "mailchimp", @@ -6893,7 +7083,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "email", + "tags": ["email-marketing", "marketing", "automation"] }, { "type": "mailgun", @@ -6942,7 +7134,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "email", + "tags": ["messaging", "email-marketing"] }, { "type": "mem0", @@ -6971,7 +7165,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "ai", + "tags": ["llm", "knowledge-base", "agentic"] }, { "type": "memory", @@ -7089,7 +7285,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "databases", + "tags": ["microsoft-365", "data-warehouse", "cloud"] }, { "type": "microsoft_excel_v2", @@ -7114,7 +7312,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "documents", + "tags": ["spreadsheet", "microsoft-365"] }, { "type": "microsoft_planner", @@ -7183,7 +7383,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "productivity", + "tags": ["project-management", "microsoft-365", "ticketing"] }, { "type": "microsoft_teams", @@ -7262,7 +7464,9 @@ ], "triggerCount": 1, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "communication", + "tags": ["messaging", "microsoft-365"] }, { "type": "mistral_parse_v3", @@ -7278,7 +7482,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "ai", + "tags": ["document-processing", "ocr"] }, { "type": "mongodb", @@ -7319,7 +7525,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "databases", + "tags": ["data-warehouse", "cloud"] }, { "type": "mysql", @@ -7360,7 +7568,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "databases", + "tags": ["data-warehouse", "data-analytics"] }, { "type": "neo4j", @@ -7405,7 +7615,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "databases", + "tags": ["data-warehouse", "data-analytics"] }, { "type": "notion_v2", @@ -7421,7 +7633,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "documents", + "tags": ["note-taking", "knowledge-base", "content-management"] }, { "type": "obsidian", @@ -7498,7 +7712,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "documents", + "tags": ["note-taking", "knowledge-base"] }, { "type": "okta", @@ -7587,7 +7803,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "security", + "tags": ["identity", "automation"] }, { "type": "onedrive", @@ -7628,7 +7846,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "file-storage", + "tags": ["microsoft-365", "cloud", "document-processing"] }, { "type": "outlook", @@ -7681,7 +7901,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "email", + "tags": ["microsoft-365", "messaging", "automation"] }, { "type": "pagerduty", @@ -7722,7 +7944,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "developer-tools", + "tags": ["incident-management", "monitoring"] }, { "type": "parallel_ai", @@ -7751,7 +7975,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "search", + "tags": ["web-scraping", "llm", "agentic"] }, { "type": "perplexity", @@ -7776,7 +8002,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "ai", + "tags": ["llm", "web-scraping", "agentic"] }, { "type": "pinecone", @@ -7813,7 +8041,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "databases", + "tags": ["vector-search", "knowledge-base"] }, { "type": "pipedrive", @@ -7902,7 +8132,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "crm", + "tags": ["sales-engagement", "project-management"] }, { "type": "polymarket", @@ -7999,7 +8231,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "analytics", + "tags": ["prediction-markets", "data-analytics"] }, { "type": "postgresql", @@ -8040,7 +8274,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "databases", + "tags": ["data-warehouse", "data-analytics"] }, { "type": "posthog", @@ -8229,7 +8465,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "analytics", + "tags": ["data-analytics", "monitoring"] }, { "type": "pulse_v2", @@ -8245,7 +8483,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "ai", + "tags": ["document-processing", "ocr"] }, { "type": "qdrant", @@ -8274,7 +8514,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "databases", + "tags": ["vector-search", "knowledge-base"] }, { "type": "reddit", @@ -8359,7 +8601,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "social", + "tags": ["content-management", "web-scraping"] }, { "type": "redis", @@ -8464,7 +8708,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "databases", + "tags": ["cloud", "data-warehouse"] }, { "type": "reducto_v2", @@ -8480,7 +8726,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "ai", + "tags": ["document-processing", "ocr"] }, { "type": "resend", @@ -8529,7 +8777,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "email", + "tags": ["email-marketing", "messaging"] }, { "type": "revenuecat", @@ -8586,7 +8836,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "ecommerce", + "tags": ["payments", "subscriptions"] }, { "type": "s3", @@ -8623,7 +8875,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "file-storage", + "tags": ["cloud", "data-warehouse"] }, { "type": "salesforce", @@ -8780,7 +9034,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "crm", + "tags": ["sales-engagement", "customer-support"] }, { "type": "search", @@ -8796,7 +9052,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "search", + "tags": ["web-scraping", "seo"] }, { "type": "sendgrid", @@ -8877,7 +9135,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "email", + "tags": ["email-marketing", "messaging"] }, { "type": "sentry", @@ -8942,7 +9202,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "developer-tools", + "tags": ["error-tracking", "monitoring"] }, { "type": "serper", @@ -8958,7 +9220,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "search", + "tags": ["web-scraping", "seo"] }, { "type": "servicenow", @@ -8991,7 +9255,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "customer-support", + "tags": ["customer-support", "ticketing", "incident-management"] }, { "type": "sftp", @@ -9032,7 +9298,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "file-storage", + "tags": ["cloud", "automation"] }, { "type": "sharepoint", @@ -9081,7 +9349,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "documents", + "tags": ["microsoft-365", "content-management", "document-processing"] }, { "type": "shopify", @@ -9182,7 +9452,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "ecommerce", + "tags": ["payments", "subscriptions"] }, { "type": "similarweb", @@ -9219,7 +9491,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "analytics", + "tags": ["marketing", "data-analytics", "seo"] }, { "type": "slack", @@ -9334,7 +9608,9 @@ ], "triggerCount": 1, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "communication", + "tags": ["messaging", "webhooks", "automation"] }, { "type": "smtp", @@ -9350,7 +9626,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "email", + "tags": ["email-marketing", "messaging"] }, { "type": "stt_v2", @@ -9366,7 +9644,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "ai", + "tags": ["speech-to-text", "document-processing"] }, { "type": "ssh", @@ -9435,7 +9715,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "developer-tools", + "tags": ["cloud", "automation"] }, { "type": "stagehand", @@ -9460,7 +9742,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "automation", + "tags": ["web-scraping", "automation", "agentic"] }, { "type": "stripe", @@ -9683,7 +9967,9 @@ ], "triggerCount": 1, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "ecommerce", + "tags": ["payments", "subscriptions", "webhooks"] }, { "type": "supabase", @@ -9788,7 +10074,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "databases", + "tags": ["cloud", "data-warehouse", "vector-search"] }, { "type": "tavily", @@ -9821,7 +10109,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "search", + "tags": ["web-scraping", "enrichment"] }, { "type": "telegram", @@ -9872,7 +10162,9 @@ ], "triggerCount": 1, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "communication", + "tags": ["messaging", "webhooks", "automation"] }, { "type": "tts", @@ -9888,7 +10180,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "ai", + "tags": ["text-to-speech", "llm"] }, { "type": "tinybird", @@ -9913,7 +10207,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "analytics", + "tags": ["data-warehouse", "data-analytics"] }, { "type": "translate", @@ -9929,7 +10225,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "ai", + "tags": ["document-processing", "llm"] }, { "type": "trello", @@ -9970,7 +10268,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "productivity", + "tags": ["project-management", "ticketing"] }, { "type": "twilio_sms", @@ -9986,7 +10286,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "communication", + "tags": ["messaging", "automation"] }, { "type": "twilio_voice", @@ -10021,7 +10323,9 @@ ], "triggerCount": 1, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "communication", + "tags": ["messaging", "text-to-speech"] }, { "type": "typeform", @@ -10076,7 +10380,9 @@ ], "triggerCount": 1, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "documents", + "tags": ["forms", "data-analytics"] }, { "type": "upstash", @@ -10157,7 +10463,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "databases", + "tags": ["cloud", "data-warehouse"] }, { "type": "vercel", @@ -10374,7 +10682,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "developer-tools", + "tags": ["cloud", "ci-cd"] }, { "type": "video_generator_v2", @@ -10390,7 +10700,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "ai", + "tags": ["video-generation", "llm"] }, { "type": "vision_v2", @@ -10406,7 +10718,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "ai", + "tags": ["llm", "document-processing", "ocr"] }, { "type": "wealthbox", @@ -10447,7 +10761,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "crm", + "tags": ["sales-engagement", "customer-support"] }, { "type": "webflow", @@ -10505,7 +10821,9 @@ ], "triggerCount": 4, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "design", + "tags": ["content-management", "seo"] }, { "type": "whatsapp", @@ -10527,7 +10845,9 @@ ], "triggerCount": 1, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "communication", + "tags": ["messaging", "automation"] }, { "type": "wikipedia", @@ -10560,7 +10880,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "search", + "tags": ["knowledge-base", "web-scraping"] }, { "type": "wordpress", @@ -10681,7 +11003,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "design", + "tags": ["content-management", "seo"] }, { "type": "workday", @@ -10738,7 +11062,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "hr", + "tags": ["hiring", "project-management"] }, { "type": "x", @@ -10867,7 +11193,9 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "social", + "tags": ["marketing", "messaging"] }, { "type": "youtube", @@ -10920,7 +11248,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "media", + "tags": ["google-workspace", "marketing", "content-management"] }, { "type": "zendesk", @@ -11041,7 +11371,9 @@ "triggers": [], "triggerCount": 0, "authType": "none", - "category": "tools" + "category": "tools", + "integrationType": "customer-support", + "tags": ["customer-support", "ticketing"] }, { "type": "zep", @@ -11094,7 +11426,9 @@ "triggers": [], "triggerCount": 0, "authType": "api-key", - "category": "tools" + "category": "tools", + "integrationType": "ai", + "tags": ["llm", "knowledge-base", "agentic"] }, { "type": "zoom", @@ -11151,6 +11485,8 @@ "triggers": [], "triggerCount": 0, "authType": "oauth", - "category": "tools" + "category": "tools", + "integrationType": "communication", + "tags": ["meeting", "calendar", "scheduling"] } ] diff --git a/apps/sim/app/(landing)/integrations/data/types.ts b/apps/sim/app/(landing)/integrations/data/types.ts index 125247ce61f..b1a17f7a2b2 100644 --- a/apps/sim/app/(landing)/integrations/data/types.ts +++ b/apps/sim/app/(landing)/integrations/data/types.ts @@ -34,4 +34,6 @@ export interface Integration { triggerCount: number authType: AuthType category: string + integrationType?: string + tags?: string[] } diff --git a/apps/sim/blocks/blocks/a2a.ts b/apps/sim/blocks/blocks/a2a.ts index b12905b4b78..44b70d3803d 100644 --- a/apps/sim/blocks/blocks/a2a.ts +++ b/apps/sim/blocks/blocks/a2a.ts @@ -1,5 +1,6 @@ import { A2AIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' import { normalizeFileInput } from '@/blocks/utils' import type { ToolResponse } from '@/tools/types' @@ -63,6 +64,8 @@ export const A2ABlock: BlockConfig = { 'Compatible with any A2A-compliant agent including LangGraph, Google ADK, and other Sim workflows.', docsLink: 'https://docs.sim.ai/blocks/a2a', category: 'tools', + integrationType: IntegrationType.DeveloperTools, + tags: ['agentic', 'automation'], bgColor: '#4151B5', icon: A2AIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/agent.ts b/apps/sim/blocks/blocks/agent.ts index 651d3d9295b..a5585816a61 100644 --- a/apps/sim/blocks/blocks/agent.ts +++ b/apps/sim/blocks/blocks/agent.ts @@ -2,7 +2,7 @@ import { createLogger } from '@sim/logger' import { AgentIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { getApiKeyCondition, getModelOptions, RESPONSE_FORMAT_WAND_CONFIG } from '@/blocks/utils' import { getBaseModelProviders, @@ -69,6 +69,8 @@ export const AgentBlock: BlockConfig = { `, docsLink: 'https://docs.sim.ai/blocks/agent', category: 'blocks', + integrationType: IntegrationType.AI, + tags: ['llm', 'agentic', 'automation'], bgColor: 'var(--brand-primary-hex)', icon: AgentIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/ahrefs.ts b/apps/sim/blocks/blocks/ahrefs.ts index 7624f10b007..02857936b5c 100644 --- a/apps/sim/blocks/blocks/ahrefs.ts +++ b/apps/sim/blocks/blocks/ahrefs.ts @@ -1,6 +1,6 @@ import { AhrefsIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { AhrefsResponse } from '@/tools/ahrefs/types' export const AhrefsBlock: BlockConfig = { @@ -12,6 +12,8 @@ export const AhrefsBlock: BlockConfig = { 'Integrate Ahrefs SEO tools into your workflow. Analyze domain ratings, backlinks, organic keywords, top pages, and more. Requires an Ahrefs Enterprise plan with API access.', docsLink: 'https://docs.ahrefs.com/docs/api/reference/introduction', category: 'tools', + integrationType: IntegrationType.Analytics, + tags: ['seo', 'marketing', 'data-analytics'], bgColor: '#E0E0E0', icon: AhrefsIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/airtable.ts b/apps/sim/blocks/blocks/airtable.ts index ced9b6d8f97..48e9b670bc4 100644 --- a/apps/sim/blocks/blocks/airtable.ts +++ b/apps/sim/blocks/blocks/airtable.ts @@ -1,7 +1,7 @@ import { AirtableIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { AirtableResponse } from '@/tools/airtable/types' import { getTrigger } from '@/triggers' @@ -14,6 +14,8 @@ export const AirtableBlock: BlockConfig = { 'Integrates Airtable into the workflow. Can list bases, list tables (with schema), and create, get, list, or update records. Can also be used in trigger mode to trigger a workflow when an update is made to an Airtable table.', docsLink: 'https://docs.sim.ai/tools/airtable', category: 'tools', + integrationType: IntegrationType.Databases, + tags: ['spreadsheet', 'automation'], bgColor: '#E0E0E0', icon: AirtableIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/airweave.ts b/apps/sim/blocks/blocks/airweave.ts index 3edf0335fa1..caa9c4097f6 100644 --- a/apps/sim/blocks/blocks/airweave.ts +++ b/apps/sim/blocks/blocks/airweave.ts @@ -1,6 +1,6 @@ import { AirweaveIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { AirweaveSearchResponse } from '@/tools/airweave/types' export const AirweaveBlock: BlockConfig = { @@ -12,6 +12,8 @@ export const AirweaveBlock: BlockConfig = { 'Search across your synced data sources using Airweave. Supports semantic search with hybrid, neural, or keyword retrieval strategies. Optionally generate AI-powered answers from search results.', docsLink: 'https://docs.airweave.ai', category: 'tools', + integrationType: IntegrationType.Search, + tags: ['vector-search', 'knowledge-base'], bgColor: '#6366F1', icon: AirweaveIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/algolia.ts b/apps/sim/blocks/blocks/algolia.ts index 0848d6175a0..f2d0d8f2640 100644 --- a/apps/sim/blocks/blocks/algolia.ts +++ b/apps/sim/blocks/blocks/algolia.ts @@ -1,6 +1,6 @@ import { AlgoliaIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' export const AlgoliaBlock: BlockConfig = { type: 'algolia', @@ -10,6 +10,8 @@ export const AlgoliaBlock: BlockConfig = { 'Integrate Algolia into your workflow. Search indices, manage records (add, update, delete, browse), configure index settings, and perform batch operations.', docsLink: 'https://docs.sim.ai/tools/algolia', category: 'tools', + integrationType: IntegrationType.Search, + tags: ['vector-search', 'knowledge-base'], bgColor: '#003DFF', icon: AlgoliaIcon, authMode: AuthMode.ApiKey, diff --git a/apps/sim/blocks/blocks/amplitude.ts b/apps/sim/blocks/blocks/amplitude.ts index e9cbf618342..689f5a9d0c5 100644 --- a/apps/sim/blocks/blocks/amplitude.ts +++ b/apps/sim/blocks/blocks/amplitude.ts @@ -1,5 +1,5 @@ import { AmplitudeIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' export const AmplitudeBlock: BlockConfig = { type: 'amplitude', @@ -9,6 +9,8 @@ export const AmplitudeBlock: BlockConfig = { 'Integrate Amplitude into your workflow to track events, identify users and groups, search for users, query analytics, and retrieve revenue data.', docsLink: 'https://docs.sim.ai/tools/amplitude', category: 'tools', + integrationType: IntegrationType.Analytics, + tags: ['data-analytics', 'marketing'], bgColor: '#1B1F3B', icon: AmplitudeIcon, authMode: AuthMode.ApiKey, diff --git a/apps/sim/blocks/blocks/api.ts b/apps/sim/blocks/blocks/api.ts index e12c1422ff1..8eafbb423e3 100644 --- a/apps/sim/blocks/blocks/api.ts +++ b/apps/sim/blocks/blocks/api.ts @@ -1,5 +1,6 @@ import { ApiIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' import type { RequestResponse } from '@/tools/http/types' export const ApiBlock: BlockConfig = { @@ -13,6 +14,8 @@ export const ApiBlock: BlockConfig = { - Curl the endpoint yourself before filling out the API block to make sure it's working IF you have the necessary authentication headers. Clarify with the user if you need any additional headers. `, category: 'blocks', + integrationType: IntegrationType.DeveloperTools, + tags: ['automation', 'webhooks'], bgColor: '#2F55FF', icon: ApiIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/apify.ts b/apps/sim/blocks/blocks/apify.ts index 39b92f7f2b3..bbcca0055b9 100644 --- a/apps/sim/blocks/blocks/apify.ts +++ b/apps/sim/blocks/blocks/apify.ts @@ -1,5 +1,6 @@ import { ApifyIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' import type { RunActorResult } from '@/tools/apify/types' export const ApifyBlock: BlockConfig = { @@ -10,6 +11,8 @@ export const ApifyBlock: BlockConfig = { 'Integrate Apify into your workflow. Run any Apify actor with custom input and retrieve results. Supports both synchronous and asynchronous execution with automatic dataset fetching.', docsLink: 'https://docs.sim.ai/tools/apify', category: 'tools', + integrationType: IntegrationType.Automation, + tags: ['web-scraping', 'automation', 'data-analytics'], bgColor: '#E0E0E0', icon: ApifyIcon, diff --git a/apps/sim/blocks/blocks/apollo.ts b/apps/sim/blocks/blocks/apollo.ts index 11e03b52acc..5383123dcb6 100644 --- a/apps/sim/blocks/blocks/apollo.ts +++ b/apps/sim/blocks/blocks/apollo.ts @@ -1,6 +1,6 @@ import { ApolloIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { ApolloResponse } from '@/tools/apollo/types' export const ApolloBlock: BlockConfig = { @@ -12,6 +12,8 @@ export const ApolloBlock: BlockConfig = { 'Integrates Apollo.io into the workflow. Search for people and companies, enrich contact data, manage your CRM contacts and accounts, add contacts to sequences, and create tasks.', docsLink: 'https://docs.sim.ai/tools/apollo', category: 'tools', + integrationType: IntegrationType.SalesIntelligence, + tags: ['enrichment', 'sales-engagement'], bgColor: '#EBF212', icon: ApolloIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/arxiv.ts b/apps/sim/blocks/blocks/arxiv.ts index b8946f0c9b2..c7bbbe1d905 100644 --- a/apps/sim/blocks/blocks/arxiv.ts +++ b/apps/sim/blocks/blocks/arxiv.ts @@ -1,5 +1,6 @@ import { ArxivIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' import type { ArxivResponse } from '@/tools/arxiv/types' export const ArxivBlock: BlockConfig = { @@ -10,6 +11,8 @@ export const ArxivBlock: BlockConfig = { 'Integrates ArXiv into the workflow. Can search for papers, get paper details, and get author papers. Does not require OAuth or an API key.', docsLink: 'https://docs.sim.ai/tools/arxiv', category: 'tools', + integrationType: IntegrationType.Search, + tags: ['document-processing', 'knowledge-base'], bgColor: '#E0E0E0', icon: ArxivIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/asana.ts b/apps/sim/blocks/blocks/asana.ts index a92c7384a8e..4da1b84f961 100644 --- a/apps/sim/blocks/blocks/asana.ts +++ b/apps/sim/blocks/blocks/asana.ts @@ -1,7 +1,7 @@ import { AsanaIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { AsanaResponse } from '@/tools/asana/types' export const AsanaBlock: BlockConfig = { @@ -12,6 +12,8 @@ export const AsanaBlock: BlockConfig = { longDescription: 'Integrate Asana into the workflow. Can read, write, and update tasks.', docsLink: 'https://docs.sim.ai/tools/asana', category: 'tools', + integrationType: IntegrationType.Productivity, + tags: ['project-management', 'ticketing', 'automation'], bgColor: '#E0E0E0', icon: AsanaIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/ashby.ts b/apps/sim/blocks/blocks/ashby.ts index 175979503b3..0659dcbeda3 100644 --- a/apps/sim/blocks/blocks/ashby.ts +++ b/apps/sim/blocks/blocks/ashby.ts @@ -1,5 +1,5 @@ import { AshbyIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' import { getTrigger } from '@/triggers' export const AshbyBlock: BlockConfig = { @@ -10,6 +10,8 @@ export const AshbyBlock: BlockConfig = { 'Integrate Ashby into the workflow. Manage candidates (list, get, create, update, search, tag), applications (list, get, create, change stage), jobs (list, get), job postings (list, get), offers (list, get), notes (list, create), interviews (list), and reference data (sources, tags, archive reasons, custom fields, departments, locations, openings, users).', docsLink: 'https://docs.sim.ai/tools/ashby', category: 'tools', + integrationType: IntegrationType.HR, + tags: ['hiring'], bgColor: '#5D4ED6', icon: AshbyIcon, authMode: AuthMode.ApiKey, diff --git a/apps/sim/blocks/blocks/attio.ts b/apps/sim/blocks/blocks/attio.ts index aebea95d363..21ee5ffdf82 100644 --- a/apps/sim/blocks/blocks/attio.ts +++ b/apps/sim/blocks/blocks/attio.ts @@ -1,6 +1,6 @@ import { AttioIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { AttioResponse } from '@/tools/attio/types' import { getTrigger } from '@/triggers' @@ -12,6 +12,8 @@ export const AttioBlock: BlockConfig = { 'Connect to Attio to manage CRM records (people, companies, custom objects), notes, tasks, lists, list entries, comments, workspace members, and webhooks.', docsLink: 'https://docs.sim.ai/tools/attio', category: 'tools', + integrationType: IntegrationType.CRM, + tags: ['sales-engagement', 'enrichment'], bgColor: '#1D1E20', icon: AttioIcon, authMode: AuthMode.OAuth, diff --git a/apps/sim/blocks/blocks/box.ts b/apps/sim/blocks/blocks/box.ts index a341b9e7cf6..27318f83531 100644 --- a/apps/sim/blocks/blocks/box.ts +++ b/apps/sim/blocks/blocks/box.ts @@ -1,7 +1,7 @@ import { BoxCompanyIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { normalizeFileInput } from '@/blocks/utils' export const BoxBlock: BlockConfig = { @@ -12,6 +12,8 @@ export const BoxBlock: BlockConfig = { 'Integrate Box into your workflow to manage files, folders, and e-signatures. Upload and download files, search content, create folders, send documents for e-signature, track signing status, and more.', docsLink: 'https://docs.sim.ai/tools/box', category: 'tools', + integrationType: IntegrationType.FileStorage, + tags: ['cloud', 'content-management', 'e-signatures'], bgColor: '#FFFFFF', icon: BoxCompanyIcon, authMode: AuthMode.OAuth, diff --git a/apps/sim/blocks/blocks/brandfetch.ts b/apps/sim/blocks/blocks/brandfetch.ts index 68bbcd1db30..6b1965b8bad 100644 --- a/apps/sim/blocks/blocks/brandfetch.ts +++ b/apps/sim/blocks/blocks/brandfetch.ts @@ -1,6 +1,6 @@ import { BrandfetchIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { BrandfetchGetBrandResponse, BrandfetchSearchResponse } from '@/tools/brandfetch/types' export const BrandfetchBlock: BlockConfig = { @@ -11,6 +11,8 @@ export const BrandfetchBlock: BlockConfig = { @@ -11,6 +11,8 @@ export const BrowserUseBlock: BlockConfig = { 'Integrate Browser Use into the workflow. Can navigate the web and perform actions as if a real user was interacting with the browser.', docsLink: 'https://docs.sim.ai/tools/browser_use', category: 'tools', + integrationType: IntegrationType.Automation, + tags: ['web-scraping', 'automation', 'agentic'], bgColor: '#181C1E', icon: BrowserUseIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/calcom.ts b/apps/sim/blocks/blocks/calcom.ts index 0a32aa854dc..2b08bac4165 100644 --- a/apps/sim/blocks/blocks/calcom.ts +++ b/apps/sim/blocks/blocks/calcom.ts @@ -1,6 +1,6 @@ import { CalComIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { ToolResponse } from '@/tools/types' import { getTrigger } from '@/triggers' @@ -14,6 +14,8 @@ export const CalComBlock: BlockConfig = { 'Integrate Cal.com into your workflow. Create and manage bookings, event types, schedules, and check availability slots. Supports creating, listing, rescheduling, and canceling bookings, as well as managing event types and schedules. Can also trigger workflows based on Cal.com webhook events (booking created, cancelled, rescheduled). Connect your Cal.com account via OAuth.', docsLink: 'https://docs.sim.ai/tools/calcom', category: 'tools', + integrationType: IntegrationType.Productivity, + tags: ['scheduling', 'calendar', 'meeting'], bgColor: '#FFFFFE', icon: CalComIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/calendly.ts b/apps/sim/blocks/blocks/calendly.ts index 4f4bfcce69e..aa99278402f 100644 --- a/apps/sim/blocks/blocks/calendly.ts +++ b/apps/sim/blocks/blocks/calendly.ts @@ -1,6 +1,6 @@ import { CalendlyIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { ToolResponse } from '@/tools/types' import { getTrigger } from '@/triggers' @@ -14,6 +14,8 @@ export const CalendlyBlock: BlockConfig = { 'Integrate Calendly into your workflow. Manage event types, scheduled events, invitees, and webhooks. Can also trigger workflows based on Calendly webhook events (invitee scheduled, invitee canceled, routing form submitted). Requires Personal Access Token.', docsLink: 'https://docs.sim.ai/tools/calendly', category: 'tools', + integrationType: IntegrationType.Productivity, + tags: ['scheduling', 'calendar', 'meeting'], bgColor: '#FFFFFF', icon: CalendlyIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/circleback.ts b/apps/sim/blocks/blocks/circleback.ts index b6fc448c878..519549cc701 100644 --- a/apps/sim/blocks/blocks/circleback.ts +++ b/apps/sim/blocks/blocks/circleback.ts @@ -1,5 +1,6 @@ import { CirclebackIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' import { getTrigger } from '@/triggers' export const CirclebackBlock: BlockConfig = { @@ -9,6 +10,8 @@ export const CirclebackBlock: BlockConfig = { longDescription: 'Receive meeting notes, action items, transcripts, and recordings when meetings are processed. Circleback uses webhooks to push data to your workflows.', category: 'triggers', + integrationType: IntegrationType.AI, + tags: ['meeting', 'note-taking', 'automation'], bgColor: 'linear-gradient(180deg, #E0F7FA 0%, #FFFFFF 100%)', docsLink: 'https://docs.sim.ai/tools/circleback', icon: CirclebackIcon, diff --git a/apps/sim/blocks/blocks/clay.ts b/apps/sim/blocks/blocks/clay.ts index 0d981c9f3e5..b662cb091b0 100644 --- a/apps/sim/blocks/blocks/clay.ts +++ b/apps/sim/blocks/blocks/clay.ts @@ -1,5 +1,5 @@ import { ClayIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' import type { ClayPopulateResponse } from '@/tools/clay/types' export const ClayBlock: BlockConfig = { @@ -10,6 +10,8 @@ export const ClayBlock: BlockConfig = { longDescription: 'Integrate Clay into the workflow. Can populate a table with data.', docsLink: 'https://docs.sim.ai/tools/clay', category: 'tools', + integrationType: IntegrationType.SalesIntelligence, + tags: ['enrichment', 'sales-engagement', 'data-analytics'], bgColor: '#E0E0E0', icon: ClayIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/clerk.ts b/apps/sim/blocks/blocks/clerk.ts index 246d50d4e65..a88d67be276 100644 --- a/apps/sim/blocks/blocks/clerk.ts +++ b/apps/sim/blocks/blocks/clerk.ts @@ -1,5 +1,6 @@ import { ClerkIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' import type { ClerkResponse } from '@/tools/clerk/types' export const ClerkBlock: BlockConfig = { @@ -10,6 +11,8 @@ export const ClerkBlock: BlockConfig = { 'Integrate Clerk authentication and user management into your workflow. Create, update, delete, and list users. Manage organizations and their memberships. Monitor and control user sessions.', docsLink: 'https://docs.sim.ai/tools/clerk', category: 'tools', + integrationType: IntegrationType.Security, + tags: ['identity', 'automation'], bgColor: '#131316', icon: ClerkIcon, diff --git a/apps/sim/blocks/blocks/cloudflare.ts b/apps/sim/blocks/blocks/cloudflare.ts index d1a264d7188..9ef661fc819 100644 --- a/apps/sim/blocks/blocks/cloudflare.ts +++ b/apps/sim/blocks/blocks/cloudflare.ts @@ -1,5 +1,5 @@ import { CloudflareIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' import type { CloudflareResponse } from '@/tools/cloudflare/types' export const CloudflareBlock: BlockConfig = { @@ -11,6 +11,8 @@ export const CloudflareBlock: BlockConfig = { 'Integrate Cloudflare into the workflow. Manage zones (domains), DNS records, SSL/TLS certificates, zone settings, DNS analytics, and cache purging via the Cloudflare API.', docsLink: 'https://docs.sim.ai/tools/cloudflare', category: 'tools', + integrationType: IntegrationType.DeveloperTools, + tags: ['cloud', 'monitoring'], bgColor: '#F5F6FA', icon: CloudflareIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/confluence.ts b/apps/sim/blocks/blocks/confluence.ts index ad52791c831..8d90cfda4ca 100644 --- a/apps/sim/blocks/blocks/confluence.ts +++ b/apps/sim/blocks/blocks/confluence.ts @@ -1,7 +1,7 @@ import { ConfluenceIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { normalizeFileInput } from '@/blocks/utils' import type { ConfluenceResponse } from '@/tools/confluence/types' import { getTrigger } from '@/triggers' @@ -16,6 +16,8 @@ export const ConfluenceBlock: BlockConfig = { 'Integrate Confluence into the workflow. Can read, create, update, delete pages, manage comments, attachments, labels, and search content.', docsLink: 'https://docs.sim.ai/tools/confluence', category: 'tools', + integrationType: IntegrationType.Documents, + tags: ['knowledge-base', 'content-management', 'note-taking'], bgColor: '#E0E0E0', icon: ConfluenceIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/cursor.ts b/apps/sim/blocks/blocks/cursor.ts index 3c96fc78e62..60ceec13e32 100644 --- a/apps/sim/blocks/blocks/cursor.ts +++ b/apps/sim/blocks/blocks/cursor.ts @@ -1,6 +1,6 @@ import { CursorIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { createVersionedToolSelector } from '@/blocks/utils' import type { CursorResponse } from '@/tools/cursor/types' @@ -12,6 +12,8 @@ export const CursorBlock: BlockConfig = { 'Interact with Cursor Cloud Agents API to launch AI agents that can work on your GitHub repositories. Supports launching agents, adding follow-up instructions, checking status, viewing conversations, and managing agent lifecycle.', docsLink: 'https://cursor.com/docs/cloud-agent/api/endpoints', category: 'tools', + integrationType: IntegrationType.DeveloperTools, + tags: ['agentic', 'automation'], bgColor: '#1E1E1E', icon: CursorIcon, authMode: AuthMode.ApiKey, diff --git a/apps/sim/blocks/blocks/databricks.ts b/apps/sim/blocks/blocks/databricks.ts index d4473fd41e7..3985fb9afcb 100644 --- a/apps/sim/blocks/blocks/databricks.ts +++ b/apps/sim/blocks/blocks/databricks.ts @@ -1,6 +1,6 @@ import { DatabricksIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { DatabricksResponse } from '@/tools/databricks/types' export const DatabricksBlock: BlockConfig = { @@ -12,6 +12,8 @@ export const DatabricksBlock: BlockConfig = { 'Connect to Databricks to execute SQL queries against SQL warehouses, trigger and monitor job runs, manage clusters, and retrieve run outputs. Requires a Personal Access Token and workspace host URL.', docsLink: 'https://docs.sim.ai/tools/databricks', category: 'tools', + integrationType: IntegrationType.Databases, + tags: ['data-warehouse', 'data-analytics', 'cloud'], bgColor: '#F9F7F4', icon: DatabricksIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/datadog.ts b/apps/sim/blocks/blocks/datadog.ts index ac06a5b87c3..c66ad2dc1e4 100644 --- a/apps/sim/blocks/blocks/datadog.ts +++ b/apps/sim/blocks/blocks/datadog.ts @@ -1,6 +1,6 @@ import { DatadogIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { DatadogResponse } from '@/tools/datadog/types' export const DatadogBlock: BlockConfig = { @@ -12,6 +12,8 @@ export const DatadogBlock: BlockConfig = { 'Integrate Datadog monitoring into workflows. Submit metrics, manage monitors, query logs, create events, handle downtimes, and more.', docsLink: 'https://docs.sim.ai/tools/datadog', category: 'tools', + integrationType: IntegrationType.Analytics, + tags: ['monitoring', 'incident-management', 'error-tracking'], bgColor: '#632CA6', icon: DatadogIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/devin.ts b/apps/sim/blocks/blocks/devin.ts index 8289fc3476c..291722e7d7d 100644 --- a/apps/sim/blocks/blocks/devin.ts +++ b/apps/sim/blocks/blocks/devin.ts @@ -1,6 +1,6 @@ import { DevinIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' export const DevinBlock: BlockConfig = { type: 'devin', @@ -17,6 +17,8 @@ export const DevinBlock: BlockConfig = { `, docsLink: 'https://docs.sim.ai/tools/devin', category: 'tools', + integrationType: IntegrationType.DeveloperTools, + tags: ['agentic', 'automation'], bgColor: '#12141A', icon: DevinIcon, authMode: AuthMode.ApiKey, diff --git a/apps/sim/blocks/blocks/discord.ts b/apps/sim/blocks/blocks/discord.ts index 0e245c9e821..992874e4e08 100644 --- a/apps/sim/blocks/blocks/discord.ts +++ b/apps/sim/blocks/blocks/discord.ts @@ -1,6 +1,6 @@ import { DiscordIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { normalizeFileInput } from '@/blocks/utils' import type { DiscordResponse } from '@/tools/discord/types' @@ -12,6 +12,8 @@ export const DiscordBlock: BlockConfig = { longDescription: 'Comprehensive Discord integration: messages, threads, channels, roles, members, invites, and webhooks.', category: 'tools', + integrationType: IntegrationType.Communication, + tags: ['messaging', 'webhooks', 'automation'], bgColor: '#5865F2', icon: DiscordIcon, docsLink: 'https://docs.sim.ai/tools/discord', diff --git a/apps/sim/blocks/blocks/docusign.ts b/apps/sim/blocks/blocks/docusign.ts index 3dd9cb11bff..d66c001f37f 100644 --- a/apps/sim/blocks/blocks/docusign.ts +++ b/apps/sim/blocks/blocks/docusign.ts @@ -1,7 +1,7 @@ import { DocuSignIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { normalizeFileInput } from '@/blocks/utils' import type { DocuSignResponse } from '@/tools/docusign/types' @@ -13,6 +13,8 @@ export const DocuSignBlock: BlockConfig = { 'Create and send envelopes for e-signature, use templates, check signing status, download signed documents, and manage recipients with DocuSign.', docsLink: 'https://docs.sim.ai/tools/docusign', category: 'tools', + integrationType: IntegrationType.Documents, + tags: ['e-signatures', 'document-processing'], bgColor: '#FFFFFF', icon: DocuSignIcon, authMode: AuthMode.OAuth, diff --git a/apps/sim/blocks/blocks/dropbox.ts b/apps/sim/blocks/blocks/dropbox.ts index cec6c26a853..12907877261 100644 --- a/apps/sim/blocks/blocks/dropbox.ts +++ b/apps/sim/blocks/blocks/dropbox.ts @@ -1,7 +1,7 @@ import { DropboxIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { normalizeFileInput } from '@/blocks/utils' import type { DropboxResponse } from '@/tools/dropbox/types' @@ -14,6 +14,8 @@ export const DropboxBlock: BlockConfig = { 'Integrate Dropbox into your workflow for file management, sharing, and collaboration. Upload files, download content, create folders, manage shared links, and more.', docsLink: 'https://docs.sim.ai/tools/dropbox', category: 'tools', + integrationType: IntegrationType.FileStorage, + tags: ['cloud', 'document-processing'], icon: DropboxIcon, bgColor: '#0061FF', subBlocks: [ diff --git a/apps/sim/blocks/blocks/dspy.ts b/apps/sim/blocks/blocks/dspy.ts index c2bf4a4b2e1..5cf823d99c8 100644 --- a/apps/sim/blocks/blocks/dspy.ts +++ b/apps/sim/blocks/blocks/dspy.ts @@ -1,5 +1,6 @@ import { DsPyIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' export const DSPyBlock: BlockConfig = { type: 'dspy', @@ -8,6 +9,8 @@ export const DSPyBlock: BlockConfig = { longDescription: 'Integrate with your self-hosted DSPy programs for LLM-powered predictions. Supports Predict, Chain of Thought, and ReAct agents. DSPy is the framework for programming—not prompting—language models.', category: 'tools', + integrationType: IntegrationType.AI, + tags: ['llm', 'agentic', 'automation'], bgColor: '#E0E0E0', icon: DsPyIcon, diff --git a/apps/sim/blocks/blocks/dub.ts b/apps/sim/blocks/blocks/dub.ts index 3e2e8fb1747..4894ab11523 100644 --- a/apps/sim/blocks/blocks/dub.ts +++ b/apps/sim/blocks/blocks/dub.ts @@ -1,6 +1,6 @@ import { DubIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { DubResponse } from '@/tools/dub/types' export const DubBlock: BlockConfig = { @@ -12,6 +12,8 @@ export const DubBlock: BlockConfig = { 'Create, manage, and track short links with Dub. Supports custom domains, UTM parameters, link analytics, and more.', docsLink: 'https://docs.sim.ai/tools/dub', category: 'tools', + integrationType: IntegrationType.DeveloperTools, + tags: ['link-management', 'marketing', 'data-analytics'], bgColor: '#181C1E', icon: DubIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/duckduckgo.ts b/apps/sim/blocks/blocks/duckduckgo.ts index 933e6b6a238..87d4d84a4fe 100644 --- a/apps/sim/blocks/blocks/duckduckgo.ts +++ b/apps/sim/blocks/blocks/duckduckgo.ts @@ -1,5 +1,6 @@ import { DuckDuckGoIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' import type { DuckDuckGoResponse } from '@/tools/duckduckgo/types' export const DuckDuckGoBlock: BlockConfig = { @@ -10,6 +11,8 @@ export const DuckDuckGoBlock: BlockConfig = { 'Search the web using DuckDuckGo Instant Answers API. Returns instant answers, abstracts, related topics, and more. Free to use without an API key.', docsLink: 'https://docs.sim.ai/tools/duckduckgo', category: 'tools', + integrationType: IntegrationType.Search, + tags: ['web-scraping', 'seo'], bgColor: '#FFFFFF', icon: DuckDuckGoIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/dynamodb.ts b/apps/sim/blocks/blocks/dynamodb.ts index 11e51c7b45f..628174f2099 100644 --- a/apps/sim/blocks/blocks/dynamodb.ts +++ b/apps/sim/blocks/blocks/dynamodb.ts @@ -1,5 +1,6 @@ import { DynamoDBIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' import type { DynamoDBIntrospectResponse, DynamoDBResponse } from '@/tools/dynamodb/types' export const DynamoDBBlock: BlockConfig = { @@ -10,6 +11,8 @@ export const DynamoDBBlock: BlockConfig = { @@ -12,6 +12,8 @@ export const ElasticsearchBlock: BlockConfig = { 'Integrate Elasticsearch into workflows for powerful search, indexing, and data management. Supports document CRUD operations, advanced search queries, bulk operations, index management, and cluster monitoring. Works with both self-hosted and Elastic Cloud deployments.', docsLink: 'https://docs.sim.ai/tools/elasticsearch', category: 'tools', + integrationType: IntegrationType.Databases, + tags: ['vector-search', 'data-analytics'], bgColor: '#E0E0E0', icon: ElasticsearchIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/elevenlabs.ts b/apps/sim/blocks/blocks/elevenlabs.ts index 58d79fe67ae..805a38b4a72 100644 --- a/apps/sim/blocks/blocks/elevenlabs.ts +++ b/apps/sim/blocks/blocks/elevenlabs.ts @@ -1,5 +1,5 @@ import { ElevenLabsIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' import type { ElevenLabsBlockResponse } from '@/tools/elevenlabs/types' export const ElevenLabsBlock: BlockConfig = { @@ -10,6 +10,8 @@ export const ElevenLabsBlock: BlockConfig = { longDescription: 'Integrate ElevenLabs into the workflow. Can convert text to speech.', docsLink: 'https://docs.sim.ai/tools/elevenlabs', category: 'tools', + integrationType: IntegrationType.Media, + tags: ['text-to-speech'], bgColor: '#181C1E', icon: ElevenLabsIcon, diff --git a/apps/sim/blocks/blocks/enrich.ts b/apps/sim/blocks/blocks/enrich.ts index 40081c16f04..90d594398df 100644 --- a/apps/sim/blocks/blocks/enrich.ts +++ b/apps/sim/blocks/blocks/enrich.ts @@ -1,6 +1,6 @@ import { EnrichSoIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' export const EnrichBlock: BlockConfig = { type: 'enrich', @@ -11,6 +11,8 @@ export const EnrichBlock: BlockConfig = { 'Access real-time B2B data intelligence with Enrich.so. Enrich profiles from email addresses, find work emails from LinkedIn, verify email deliverability, search for people and companies, and analyze LinkedIn post engagement.', docsLink: 'https://docs.enrich.so/', category: 'tools', + integrationType: IntegrationType.SalesIntelligence, + tags: ['enrichment', 'data-analytics'], bgColor: '#E5E5E6', icon: EnrichSoIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/evernote.ts b/apps/sim/blocks/blocks/evernote.ts index acc7fde5ccb..af80ad1cd82 100644 --- a/apps/sim/blocks/blocks/evernote.ts +++ b/apps/sim/blocks/blocks/evernote.ts @@ -1,6 +1,6 @@ import { EvernoteIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' export const EvernoteBlock: BlockConfig = { type: 'evernote', @@ -10,6 +10,8 @@ export const EvernoteBlock: BlockConfig = { 'Integrate with Evernote to manage notes, notebooks, and tags. Create, read, update, copy, search, and delete notes. Create and list notebooks and tags.', docsLink: 'https://docs.sim.ai/tools/evernote', category: 'tools', + integrationType: IntegrationType.Documents, + tags: ['note-taking', 'knowledge-base'], bgColor: '#E0E0E0', icon: EvernoteIcon, authMode: AuthMode.ApiKey, diff --git a/apps/sim/blocks/blocks/exa.ts b/apps/sim/blocks/blocks/exa.ts index 193fe9c292d..483dba64584 100644 --- a/apps/sim/blocks/blocks/exa.ts +++ b/apps/sim/blocks/blocks/exa.ts @@ -1,6 +1,6 @@ import { ExaAIIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { ExaResponse } from '@/tools/exa/types' export const ExaBlock: BlockConfig = { @@ -12,6 +12,8 @@ export const ExaBlock: BlockConfig = { 'Integrate Exa into the workflow. Can search, get contents, find similar links, answer a question, and perform research.', docsLink: 'https://docs.sim.ai/tools/exa', category: 'tools', + integrationType: IntegrationType.Search, + tags: ['web-scraping', 'enrichment'], bgColor: '#1F40ED', icon: ExaAIIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/fathom.ts b/apps/sim/blocks/blocks/fathom.ts index b6d8dd4db1b..7e8a83f2fe1 100644 --- a/apps/sim/blocks/blocks/fathom.ts +++ b/apps/sim/blocks/blocks/fathom.ts @@ -1,5 +1,5 @@ import { FathomIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' import type { FathomResponse } from '@/tools/fathom/types' import { getTrigger } from '@/triggers' import { fathomTriggerOptions } from '@/triggers/fathom/utils' @@ -14,6 +14,8 @@ export const FathomBlock: BlockConfig = { 'Integrate Fathom AI Notetaker into your workflow. List meetings, get transcripts and summaries, and manage team members and teams. Can also trigger workflows when new meeting content is ready.', docsLink: 'https://docs.sim.ai/tools/fathom', category: 'tools', + integrationType: IntegrationType.Analytics, + tags: ['meeting', 'note-taking'], bgColor: '#181C1E', icon: FathomIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/file.ts b/apps/sim/blocks/blocks/file.ts index f9b3058f254..9e6b14b7d9b 100644 --- a/apps/sim/blocks/blocks/file.ts +++ b/apps/sim/blocks/blocks/file.ts @@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger' import { DocumentIcon } from '@/components/icons' import { inferContextFromKey } from '@/lib/uploads/utils/file-utils' import type { BlockConfig, SubBlockType } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' import { createVersionedToolSelector, normalizeFileInput } from '@/blocks/utils' import type { FileParserOutput, FileParserV3Output } from '@/tools/file/types' @@ -53,6 +54,8 @@ export const FileBlock: BlockConfig = { `, docsLink: 'https://docs.sim.ai/tools/file', category: 'tools', + integrationType: IntegrationType.FileStorage, + tags: ['document-processing'], bgColor: '#40916C', icon: DocumentIcon, hideFromToolbar: true, @@ -252,6 +255,8 @@ export const FileV3Block: BlockConfig = { 'Upload files directly or import from external URLs to get UserFile objects for use in other blocks.', docsLink: 'https://docs.sim.ai/tools/file', category: 'tools', + integrationType: IntegrationType.FileStorage, + tags: ['document-processing'], bgColor: '#40916C', icon: DocumentIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/firecrawl.ts b/apps/sim/blocks/blocks/firecrawl.ts index add2d60ff55..51ce40ed124 100644 --- a/apps/sim/blocks/blocks/firecrawl.ts +++ b/apps/sim/blocks/blocks/firecrawl.ts @@ -1,6 +1,6 @@ import { FirecrawlIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { FirecrawlResponse } from '@/tools/firecrawl/types' export const FirecrawlBlock: BlockConfig = { @@ -12,6 +12,8 @@ export const FirecrawlBlock: BlockConfig = { 'Integrate Firecrawl into the workflow. Scrape pages, search the web, crawl entire sites, map URL structures, and extract structured data with AI.', docsLink: 'https://docs.sim.ai/tools/firecrawl', category: 'tools', + integrationType: IntegrationType.Automation, + tags: ['web-scraping', 'automation'], bgColor: '#181C1E', icon: FirecrawlIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/fireflies.ts b/apps/sim/blocks/blocks/fireflies.ts index 347ffb04f47..9812095fc47 100644 --- a/apps/sim/blocks/blocks/fireflies.ts +++ b/apps/sim/blocks/blocks/fireflies.ts @@ -1,7 +1,7 @@ import { FirefliesIcon } from '@/components/icons' import { resolveHttpsUrlFromFileInput } from '@/lib/uploads/utils/file-utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { normalizeFileInput } from '@/blocks/utils' import type { FirefliesResponse } from '@/tools/fireflies/types' import { getTrigger } from '@/triggers' @@ -17,6 +17,8 @@ export const FirefliesBlock: BlockConfig = { 'Integrate Fireflies.ai into the workflow. Manage meeting transcripts, add bot to live meetings, create soundbites, and more. Can also trigger workflows when transcriptions complete.', docsLink: 'https://docs.sim.ai/tools/fireflies', category: 'tools', + integrationType: IntegrationType.Media, + tags: ['meeting', 'speech-to-text', 'note-taking'], icon: FirefliesIcon, bgColor: '#100730', subBlocks: [ @@ -613,6 +615,8 @@ export const FirefliesV2Block: BlockConfig = { name: 'Fireflies', description: 'Interact with Fireflies.ai meeting transcripts and recordings', hideFromToolbar: false, + integrationType: IntegrationType.Media, + tags: ['meeting', 'speech-to-text', 'note-taking'], subBlocks: firefliesV2SubBlocks, tools: { ...FirefliesBlock.tools, diff --git a/apps/sim/blocks/blocks/gamma.ts b/apps/sim/blocks/blocks/gamma.ts index 27aad522213..5def6c2f201 100644 --- a/apps/sim/blocks/blocks/gamma.ts +++ b/apps/sim/blocks/blocks/gamma.ts @@ -1,5 +1,5 @@ import { GammaIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' import type { GammaResponse } from '@/tools/gamma/types' export const GammaBlock: BlockConfig = { @@ -10,6 +10,8 @@ export const GammaBlock: BlockConfig = { 'Integrate Gamma into the workflow. Can generate presentations, documents, webpages, and social posts from text, create from templates, check generation status, and browse themes and folders.', docsLink: 'https://docs.sim.ai/tools/gamma', category: 'tools', + integrationType: IntegrationType.Design, + tags: ['document-processing', 'content-management'], bgColor: '#002253', icon: GammaIcon, authMode: AuthMode.ApiKey, diff --git a/apps/sim/blocks/blocks/github.ts b/apps/sim/blocks/blocks/github.ts index 0d8f1dbf247..4ce959f28e7 100644 --- a/apps/sim/blocks/blocks/github.ts +++ b/apps/sim/blocks/blocks/github.ts @@ -1,6 +1,6 @@ import { GithubIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { createVersionedToolSelector } from '@/blocks/utils' import type { GitHubResponse } from '@/tools/github/types' import { getTrigger } from '@/triggers' @@ -14,6 +14,8 @@ export const GitHubBlock: BlockConfig = { 'Integrate Github into the workflow. Can get get PR details, create PR comment, get repository info, and get latest commit. Can be used in trigger mode to trigger a workflow when a PR is created, commented on, or a commit is pushed.', docsLink: 'https://docs.sim.ai/tools/github', category: 'tools', + integrationType: IntegrationType.DeveloperTools, + tags: ['version-control', 'ci-cd'], bgColor: '#181C1E', icon: GithubIcon, triggerAllowed: true, @@ -2023,6 +2025,8 @@ export const GitHubV2Block: BlockConfig = { type: 'github_v2', name: 'GitHub', hideFromToolbar: false, + integrationType: IntegrationType.DeveloperTools, + tags: ['version-control', 'ci-cd'], tools: { ...GitHubBlock.tools, access: (GitHubBlock.tools?.access || []).map((toolId) => `${toolId}_v2`), diff --git a/apps/sim/blocks/blocks/gitlab.ts b/apps/sim/blocks/blocks/gitlab.ts index 9d25f8fe1e2..845ffa4f07e 100644 --- a/apps/sim/blocks/blocks/gitlab.ts +++ b/apps/sim/blocks/blocks/gitlab.ts @@ -1,6 +1,6 @@ import { GitLabIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { GitLabResponse } from '@/tools/gitlab/types' export const GitLabBlock: BlockConfig = { @@ -13,6 +13,8 @@ export const GitLabBlock: BlockConfig = { 'Integrate GitLab into the workflow. Can manage projects, issues, merge requests, pipelines, and add comments. Supports all core GitLab DevOps operations.', docsLink: 'https://docs.sim.ai/tools/gitlab', category: 'tools', + integrationType: IntegrationType.DeveloperTools, + tags: ['version-control', 'ci-cd'], icon: GitLabIcon, bgColor: '#E0E0E0', subBlocks: [ diff --git a/apps/sim/blocks/blocks/gmail.ts b/apps/sim/blocks/blocks/gmail.ts index fb210593a1c..ca9f6eda697 100644 --- a/apps/sim/blocks/blocks/gmail.ts +++ b/apps/sim/blocks/blocks/gmail.ts @@ -1,7 +1,7 @@ import { GmailIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { createVersionedToolSelector, normalizeFileInput } from '@/blocks/utils' import type { GmailToolResponse } from '@/tools/gmail/types' import { getTrigger } from '@/triggers' @@ -46,6 +46,8 @@ export const GmailBlock: BlockConfig = { 'Integrate Gmail into the workflow. Can send, read, search, and move emails. Can be used in trigger mode to trigger a workflow when a new email is received.', docsLink: 'https://docs.sim.ai/tools/gmail', category: 'tools', + integrationType: IntegrationType.Email, + tags: ['google-workspace', 'messaging'], bgColor: '#E0E0E0', icon: GmailIcon, hideFromToolbar: true, @@ -553,6 +555,8 @@ export const GmailV2Block: BlockConfig = { type: 'gmail_v2', name: 'Gmail', hideFromToolbar: false, + integrationType: IntegrationType.Email, + tags: ['google-workspace', 'messaging'], tools: { ...GmailBlock.tools, access: [ diff --git a/apps/sim/blocks/blocks/gong.ts b/apps/sim/blocks/blocks/gong.ts index 5623efe4080..33adaf28742 100644 --- a/apps/sim/blocks/blocks/gong.ts +++ b/apps/sim/blocks/blocks/gong.ts @@ -1,5 +1,5 @@ import { GongIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' import type { GongResponse } from '@/tools/gong/types' export const GongBlock: BlockConfig = { @@ -11,6 +11,8 @@ export const GongBlock: BlockConfig = { 'Integrate Gong into your workflow. Access call recordings, transcripts, user data, activity stats, scorecards, trackers, library content, coaching metrics, and more via the Gong API.', docsLink: 'https://docs.sim.ai/tools/gong', category: 'tools', + integrationType: IntegrationType.SalesIntelligence, + tags: ['meeting', 'sales-engagement', 'speech-to-text'], bgColor: '#8039DF', icon: GongIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/google.ts b/apps/sim/blocks/blocks/google.ts index 2cc817a7020..c7370af563b 100644 --- a/apps/sim/blocks/blocks/google.ts +++ b/apps/sim/blocks/blocks/google.ts @@ -1,6 +1,6 @@ import { GoogleIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { GoogleSearchResponse } from '@/tools/google/types' export const GoogleSearchBlock: BlockConfig = { @@ -11,6 +11,8 @@ export const GoogleSearchBlock: BlockConfig = { longDescription: 'Integrate Google Search into the workflow. Can search the web.', docsLink: 'https://docs.sim.ai/tools/google_search', category: 'tools', + integrationType: IntegrationType.Search, + tags: ['google-workspace', 'web-scraping', 'seo'], bgColor: '#E0E0E0', icon: GoogleIcon, diff --git a/apps/sim/blocks/blocks/google_ads.ts b/apps/sim/blocks/blocks/google_ads.ts index d482c72fed4..8e20e428951 100644 --- a/apps/sim/blocks/blocks/google_ads.ts +++ b/apps/sim/blocks/blocks/google_ads.ts @@ -1,7 +1,7 @@ import { GoogleAdsIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' export const GoogleAdsBlock: BlockConfig = { type: 'google_ads', @@ -11,6 +11,8 @@ export const GoogleAdsBlock: BlockConfig = { 'Connect to Google Ads to list accessible accounts, list campaigns, view ad group details, get performance metrics, and run custom GAQL queries.', docsLink: 'https://docs.sim.ai/tools/google_ads', category: 'tools', + integrationType: IntegrationType.Analytics, + tags: ['marketing', 'google-workspace', 'data-analytics'], bgColor: '#E0E0E0', icon: GoogleAdsIcon, authMode: AuthMode.OAuth, diff --git a/apps/sim/blocks/blocks/google_bigquery.ts b/apps/sim/blocks/blocks/google_bigquery.ts index 44eb3d30a8a..ee6d7014d18 100644 --- a/apps/sim/blocks/blocks/google_bigquery.ts +++ b/apps/sim/blocks/blocks/google_bigquery.ts @@ -1,7 +1,7 @@ import { GoogleBigQueryIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' export const GoogleBigQueryBlock: BlockConfig = { type: 'google_bigquery', @@ -11,6 +11,8 @@ export const GoogleBigQueryBlock: BlockConfig = { 'Connect to Google BigQuery to run SQL queries, list datasets and tables, get table metadata, and insert rows.', docsLink: 'https://docs.sim.ai/tools/google_bigquery', category: 'tools', + integrationType: IntegrationType.Databases, + tags: ['data-warehouse', 'google-workspace', 'data-analytics'], bgColor: '#E0E0E0', icon: GoogleBigQueryIcon, authMode: AuthMode.OAuth, diff --git a/apps/sim/blocks/blocks/google_books.ts b/apps/sim/blocks/blocks/google_books.ts index 1b36cd7e4ae..033fd12948b 100644 --- a/apps/sim/blocks/blocks/google_books.ts +++ b/apps/sim/blocks/blocks/google_books.ts @@ -1,6 +1,6 @@ import { GoogleBooksIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' export const GoogleBooksBlock: BlockConfig = { type: 'google_books', @@ -11,6 +11,8 @@ export const GoogleBooksBlock: BlockConfig = { 'Search for books using the Google Books API. Find volumes by title, author, ISBN, or keywords, and retrieve detailed information about specific books including descriptions, ratings, and publication details.', docsLink: 'https://docs.sim.ai/tools/google_books', category: 'tools', + integrationType: IntegrationType.Search, + tags: ['google-workspace', 'knowledge-base', 'content-management'], bgColor: '#E0E0E0', icon: GoogleBooksIcon, diff --git a/apps/sim/blocks/blocks/google_calendar.ts b/apps/sim/blocks/blocks/google_calendar.ts index 24a35e1fbf4..22b5acd29c3 100644 --- a/apps/sim/blocks/blocks/google_calendar.ts +++ b/apps/sim/blocks/blocks/google_calendar.ts @@ -1,7 +1,7 @@ import { GoogleCalendarIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { createVersionedToolSelector } from '@/blocks/utils' import type { GoogleCalendarResponse } from '@/tools/google_calendar/types' @@ -14,6 +14,8 @@ export const GoogleCalendarBlock: BlockConfig = { 'Integrate Google Calendar into the workflow. Can create, read, update, and list calendar events.', docsLink: 'https://docs.sim.ai/tools/google_calendar', category: 'tools', + integrationType: IntegrationType.Productivity, + tags: ['calendar', 'scheduling', 'google-workspace'], bgColor: '#E0E0E0', icon: GoogleCalendarIcon, hideFromToolbar: true, @@ -648,6 +650,8 @@ export const GoogleCalendarV2Block: BlockConfig = { type: 'google_calendar_v2', name: 'Google Calendar', hideFromToolbar: false, + integrationType: IntegrationType.Productivity, + tags: ['calendar', 'scheduling', 'google-workspace'], tools: { ...GoogleCalendarBlock.tools, access: [ diff --git a/apps/sim/blocks/blocks/google_contacts.ts b/apps/sim/blocks/blocks/google_contacts.ts index 629b0a60018..5ba85d7dbbf 100644 --- a/apps/sim/blocks/blocks/google_contacts.ts +++ b/apps/sim/blocks/blocks/google_contacts.ts @@ -1,7 +1,7 @@ import { GoogleContactsIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { GoogleContactsResponse } from '@/tools/google_contacts/types' export const GoogleContactsBlock: BlockConfig = { @@ -13,6 +13,8 @@ export const GoogleContactsBlock: BlockConfig = { 'Integrate Google Contacts into the workflow. Can create, read, update, delete, list, and search contacts.', docsLink: 'https://docs.sim.ai/tools/google_contacts', category: 'tools', + integrationType: IntegrationType.Productivity, + tags: ['google-workspace', 'customer-support', 'enrichment'], bgColor: '#E0E0E0', icon: GoogleContactsIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/google_docs.ts b/apps/sim/blocks/blocks/google_docs.ts index ac9098395e3..d103a467965 100644 --- a/apps/sim/blocks/blocks/google_docs.ts +++ b/apps/sim/blocks/blocks/google_docs.ts @@ -1,7 +1,7 @@ import { GoogleDocsIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { GoogleDocsResponse } from '@/tools/google_docs/types' export const GoogleDocsBlock: BlockConfig = { @@ -13,6 +13,8 @@ export const GoogleDocsBlock: BlockConfig = { 'Integrate Google Docs into the workflow. Can read, write, and create documents.', docsLink: 'https://docs.sim.ai/tools/google_docs', category: 'tools', + integrationType: IntegrationType.Documents, + tags: ['google-workspace', 'document-processing', 'content-management'], bgColor: '#E0E0E0', icon: GoogleDocsIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/google_drive.ts b/apps/sim/blocks/blocks/google_drive.ts index 362d1c80426..cf9b988e9a0 100644 --- a/apps/sim/blocks/blocks/google_drive.ts +++ b/apps/sim/blocks/blocks/google_drive.ts @@ -1,7 +1,7 @@ import { GoogleDriveIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { normalizeFileInput } from '@/blocks/utils' import type { GoogleDriveResponse } from '@/tools/google_drive/types' @@ -14,6 +14,8 @@ export const GoogleDriveBlock: BlockConfig = { 'Integrate Google Drive into the workflow. Can create, upload, download, copy, move, delete, share files and manage permissions.', docsLink: 'https://docs.sim.ai/tools/google_drive', category: 'tools', + integrationType: IntegrationType.FileStorage, + tags: ['cloud', 'google-workspace', 'document-processing'], bgColor: '#E0E0E0', icon: GoogleDriveIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/google_forms.ts b/apps/sim/blocks/blocks/google_forms.ts index bf26311b387..a5bbf82952a 100644 --- a/apps/sim/blocks/blocks/google_forms.ts +++ b/apps/sim/blocks/blocks/google_forms.ts @@ -1,6 +1,7 @@ import { GoogleFormsIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' import { getTrigger } from '@/triggers' export const GoogleFormsBlock: BlockConfig = { @@ -11,6 +12,8 @@ export const GoogleFormsBlock: BlockConfig = { 'Integrate Google Forms into your workflow. Read form structure, get responses, create forms, update content, and manage notification watches.', docsLink: 'https://docs.sim.ai/tools/google_forms', category: 'tools', + integrationType: IntegrationType.Documents, + tags: ['google-workspace', 'forms', 'data-analytics'], bgColor: '#E0E0E0', icon: GoogleFormsIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/google_groups.ts b/apps/sim/blocks/blocks/google_groups.ts index c44830f3b79..98a2e19ec07 100644 --- a/apps/sim/blocks/blocks/google_groups.ts +++ b/apps/sim/blocks/blocks/google_groups.ts @@ -1,7 +1,7 @@ import { GoogleGroupsIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' export const GoogleGroupsBlock: BlockConfig = { type: 'google_groups', @@ -12,6 +12,8 @@ export const GoogleGroupsBlock: BlockConfig = { 'Connect to Google Workspace to create, update, and manage groups and their members using the Admin SDK Directory API.', docsLink: 'https://developers.google.com/admin-sdk/directory/v1/guides/manage-groups', category: 'tools', + integrationType: IntegrationType.Communication, + tags: ['google-workspace', 'messaging', 'identity'], bgColor: '#E8F0FE', icon: GoogleGroupsIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/google_maps.ts b/apps/sim/blocks/blocks/google_maps.ts index 5a582250e86..24676cb10ff 100644 --- a/apps/sim/blocks/blocks/google_maps.ts +++ b/apps/sim/blocks/blocks/google_maps.ts @@ -1,5 +1,6 @@ import { GoogleMapsIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' export const GoogleMapsBlock: BlockConfig = { type: 'google_maps', @@ -9,6 +10,8 @@ export const GoogleMapsBlock: BlockConfig = { 'Integrate Google Maps Platform APIs into your workflow. Supports geocoding addresses to coordinates, reverse geocoding, getting directions between locations, calculating distance matrices, searching for places, retrieving place details, elevation data, and timezone information.', docsLink: 'https://docs.sim.ai/tools/google_maps', category: 'tools', + integrationType: IntegrationType.DeveloperTools, + tags: ['google-workspace', 'enrichment'], bgColor: '#E0E0E0', icon: GoogleMapsIcon, diff --git a/apps/sim/blocks/blocks/google_meet.ts b/apps/sim/blocks/blocks/google_meet.ts index 28fa1d7f03e..9484359b1aa 100644 --- a/apps/sim/blocks/blocks/google_meet.ts +++ b/apps/sim/blocks/blocks/google_meet.ts @@ -1,7 +1,7 @@ import { GoogleMeetIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { GoogleMeetResponse } from '@/tools/google_meet/types' export const GoogleMeetBlock: BlockConfig = { @@ -12,6 +12,8 @@ export const GoogleMeetBlock: BlockConfig = { 'Integrate Google Meet into your workflow. Create meeting spaces, get space details, end conferences, list conference records, and view participants.', docsLink: 'https://docs.sim.ai/tools/google_meet', category: 'tools', + integrationType: IntegrationType.Communication, + tags: ['meeting', 'google-workspace', 'scheduling'], bgColor: '#E0E0E0', icon: GoogleMeetIcon, authMode: AuthMode.OAuth, diff --git a/apps/sim/blocks/blocks/google_pagespeed.ts b/apps/sim/blocks/blocks/google_pagespeed.ts index eca3a30996e..fada86e3183 100644 --- a/apps/sim/blocks/blocks/google_pagespeed.ts +++ b/apps/sim/blocks/blocks/google_pagespeed.ts @@ -1,5 +1,5 @@ import { GooglePagespeedIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' import type { GooglePagespeedAnalyzeResponse } from '@/tools/google_pagespeed/types' export const GooglePagespeedBlock: BlockConfig = { @@ -10,6 +10,8 @@ export const GooglePagespeedBlock: BlockConfig = 'Analyze web pages for performance, accessibility, SEO, and best practices using Google PageSpeed Insights API powered by Lighthouse.', docsLink: 'https://docs.sim.ai/tools/google_pagespeed', category: 'tools', + integrationType: IntegrationType.Analytics, + tags: ['google-workspace', 'seo', 'monitoring'], bgColor: '#E0E0E0', icon: GooglePagespeedIcon, authMode: AuthMode.ApiKey, diff --git a/apps/sim/blocks/blocks/google_sheets.ts b/apps/sim/blocks/blocks/google_sheets.ts index 31f9aab66e7..eeb41cd0536 100644 --- a/apps/sim/blocks/blocks/google_sheets.ts +++ b/apps/sim/blocks/blocks/google_sheets.ts @@ -1,7 +1,7 @@ import { GoogleSheetsIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { createVersionedToolSelector } from '@/blocks/utils' import type { GoogleSheetsResponse, GoogleSheetsV2Response } from '@/tools/google_sheets/types' @@ -16,6 +16,8 @@ export const GoogleSheetsBlock: BlockConfig = { 'Integrate Google Sheets into the workflow. Can read, write, append, and update data.', docsLink: 'https://docs.sim.ai/tools/google_sheets', category: 'tools', + integrationType: IntegrationType.Documents, + tags: ['spreadsheet', 'google-workspace', 'data-analytics'], bgColor: '#E0E0E0', icon: GoogleSheetsIcon, subBlocks: [ @@ -302,6 +304,8 @@ export const GoogleSheetsV2Block: BlockConfig = { 'Integrate Google Sheets into the workflow with explicit sheet selection. Can read, write, append, update, clear data, create spreadsheets, get spreadsheet info, and copy sheets.', docsLink: 'https://docs.sim.ai/tools/google_sheets', category: 'tools', + integrationType: IntegrationType.Documents, + tags: ['spreadsheet', 'google-workspace', 'data-analytics'], bgColor: '#E0E0E0', icon: GoogleSheetsIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/google_slides.ts b/apps/sim/blocks/blocks/google_slides.ts index 9fc8fdbf1d4..fb2d6fca536 100644 --- a/apps/sim/blocks/blocks/google_slides.ts +++ b/apps/sim/blocks/blocks/google_slides.ts @@ -2,7 +2,7 @@ import { GoogleSlidesIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import { resolveHttpsUrlFromFileInput } from '@/lib/uploads/utils/file-utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { normalizeFileInput } from '@/blocks/utils' import type { GoogleSlidesResponse } from '@/tools/google_slides/types' @@ -16,6 +16,8 @@ export const GoogleSlidesBlock: BlockConfig = { 'Integrate Google Slides into the workflow. Can read, write, create presentations, replace text, add slides, add images, get thumbnails, get page details, delete objects, duplicate objects, reorder slides, create tables, create shapes, and insert text.', docsLink: 'https://docs.sim.ai/tools/google_slides', category: 'tools', + integrationType: IntegrationType.Documents, + tags: ['google-workspace', 'document-processing', 'content-management'], bgColor: '#E0E0E0', icon: GoogleSlidesIcon, subBlocks: [ @@ -955,6 +957,8 @@ export const GoogleSlidesV2Block: BlockConfig = { name: 'Google Slides', description: 'Read, write, and create presentations', hideFromToolbar: false, + integrationType: IntegrationType.Documents, + tags: ['google-workspace', 'document-processing', 'content-management'], subBlocks: googleSlidesV2SubBlocks, tools: { access: GoogleSlidesBlock.tools!.access, diff --git a/apps/sim/blocks/blocks/google_tasks.ts b/apps/sim/blocks/blocks/google_tasks.ts index cd930ecb21e..12569327ad1 100644 --- a/apps/sim/blocks/blocks/google_tasks.ts +++ b/apps/sim/blocks/blocks/google_tasks.ts @@ -1,7 +1,7 @@ import { GoogleTasksIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { GoogleTasksResponse } from '@/tools/google_tasks/types' export const GoogleTasksBlock: BlockConfig = { @@ -12,6 +12,8 @@ export const GoogleTasksBlock: BlockConfig = { 'Integrate Google Tasks into your workflow. Create, read, update, delete, and list tasks and task lists.', docsLink: 'https://docs.sim.ai/tools/google_tasks', category: 'tools', + integrationType: IntegrationType.Productivity, + tags: ['google-workspace', 'project-management', 'scheduling'], bgColor: '#E0E0E0', icon: GoogleTasksIcon, authMode: AuthMode.OAuth, diff --git a/apps/sim/blocks/blocks/google_translate.ts b/apps/sim/blocks/blocks/google_translate.ts index 2eaeb2bb22f..86d6cf131c8 100644 --- a/apps/sim/blocks/blocks/google_translate.ts +++ b/apps/sim/blocks/blocks/google_translate.ts @@ -1,5 +1,5 @@ import { GoogleTranslateIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' const SUPPORTED_LANGUAGES = [ { label: 'Afrikaans', id: 'af' }, @@ -145,6 +145,8 @@ export const GoogleTranslateBlock: BlockConfig = { 'Translate and detect languages using the Google Cloud Translation API. Supports auto-detection of the source language.', docsLink: 'https://docs.sim.ai/tools/google_translate', category: 'tools', + integrationType: IntegrationType.AI, + tags: ['google-workspace', 'content-management', 'automation'], bgColor: '#E0E0E0', icon: GoogleTranslateIcon, authMode: AuthMode.ApiKey, diff --git a/apps/sim/blocks/blocks/google_vault.ts b/apps/sim/blocks/blocks/google_vault.ts index 1cbb334e698..7ca1ed44851 100644 --- a/apps/sim/blocks/blocks/google_vault.ts +++ b/apps/sim/blocks/blocks/google_vault.ts @@ -1,7 +1,7 @@ import { GoogleVaultIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' export const GoogleVaultBlock: BlockConfig = { type: 'google_vault', @@ -12,6 +12,8 @@ export const GoogleVaultBlock: BlockConfig = { 'Connect Google Vault to create exports, list exports, and manage holds within matters.', docsLink: 'https://developers.google.com/vault', category: 'tools', + integrationType: IntegrationType.Security, + tags: ['google-workspace', 'secrets-management', 'document-processing'], bgColor: '#E8F0FE', icon: GoogleVaultIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/grafana.ts b/apps/sim/blocks/blocks/grafana.ts index fd71cfa7d1b..4ef7f36810a 100644 --- a/apps/sim/blocks/blocks/grafana.ts +++ b/apps/sim/blocks/blocks/grafana.ts @@ -1,6 +1,6 @@ import { GrafanaIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { GrafanaResponse } from '@/tools/grafana/types' export const GrafanaBlock: BlockConfig = { @@ -12,6 +12,8 @@ export const GrafanaBlock: BlockConfig = { 'Integrate Grafana into workflows. Manage dashboards, alerts, annotations, data sources, folders, and monitor health status.', docsLink: 'https://docs.sim.ai/tools/grafana', category: 'tools', + integrationType: IntegrationType.Analytics, + tags: ['monitoring', 'data-analytics'], bgColor: '#E0E0E0', icon: GrafanaIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/grain.ts b/apps/sim/blocks/blocks/grain.ts index aa0a6236824..2a4684bdf88 100644 --- a/apps/sim/blocks/blocks/grain.ts +++ b/apps/sim/blocks/blocks/grain.ts @@ -1,6 +1,6 @@ import { GrainIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { getTrigger } from '@/triggers' import { grainTriggerOptions } from '@/triggers/grain/utils' @@ -13,6 +13,8 @@ export const GrainBlock: BlockConfig = { longDescription: 'Integrate Grain into your workflow. Access meeting recordings, transcripts, highlights, and AI-generated summaries. Can also trigger workflows based on Grain webhook events.', category: 'tools', + integrationType: IntegrationType.Media, + tags: ['meeting', 'note-taking'], docsLink: 'https://docs.sim.ai/tools/grain', icon: GrainIcon, bgColor: '#F6FAF9', diff --git a/apps/sim/blocks/blocks/greenhouse.ts b/apps/sim/blocks/blocks/greenhouse.ts index 5478756faa7..4df4963fca4 100644 --- a/apps/sim/blocks/blocks/greenhouse.ts +++ b/apps/sim/blocks/blocks/greenhouse.ts @@ -1,5 +1,5 @@ import { GreenhouseIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' import type { GreenhouseResponse } from '@/tools/greenhouse/types' export const GreenhouseBlock: BlockConfig = { @@ -10,6 +10,8 @@ export const GreenhouseBlock: BlockConfig = { 'Integrate Greenhouse into the workflow. List and retrieve candidates, jobs, applications, users, departments, offices, and job stages from your Greenhouse ATS account.', docsLink: 'https://docs.sim.ai/tools/greenhouse', category: 'tools', + integrationType: IntegrationType.HR, + tags: ['hiring'], bgColor: '#469776', icon: GreenhouseIcon, authMode: AuthMode.ApiKey, diff --git a/apps/sim/blocks/blocks/greptile.ts b/apps/sim/blocks/blocks/greptile.ts index 05b2e68b4c3..76cb142cf3c 100644 --- a/apps/sim/blocks/blocks/greptile.ts +++ b/apps/sim/blocks/blocks/greptile.ts @@ -1,6 +1,6 @@ import { GreptileIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { GreptileResponse } from '@/tools/greptile/types' export const GreptileBlock: BlockConfig = { @@ -12,6 +12,8 @@ export const GreptileBlock: BlockConfig = { 'Query and search codebases using natural language with Greptile. Get AI-generated answers about your code, find relevant files, and understand complex codebases.', docsLink: 'https://docs.sim.ai/tools/greptile', category: 'tools', + integrationType: IntegrationType.DeveloperTools, + tags: ['version-control', 'knowledge-base'], bgColor: '#e5e5e5', icon: GreptileIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/hex.ts b/apps/sim/blocks/blocks/hex.ts index f3ea6a2cb89..4da74a5f32f 100644 --- a/apps/sim/blocks/blocks/hex.ts +++ b/apps/sim/blocks/blocks/hex.ts @@ -1,6 +1,6 @@ import { HexIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { HexResponse } from '@/tools/hex/types' export const HexBlock: BlockConfig = { @@ -11,6 +11,8 @@ export const HexBlock: BlockConfig = { 'Integrate Hex into your workflow. Run projects, check run status, manage collections and groups, list users, and view data connections. Requires a Hex API token.', docsLink: 'https://docs.sim.ai/tools/hex', category: 'tools', + integrationType: IntegrationType.Analytics, + tags: ['data-warehouse', 'data-analytics'], bgColor: '#14151A', icon: HexIcon, authMode: AuthMode.ApiKey, diff --git a/apps/sim/blocks/blocks/hubspot.ts b/apps/sim/blocks/blocks/hubspot.ts index 24bf1a39819..ecacf1d588e 100644 --- a/apps/sim/blocks/blocks/hubspot.ts +++ b/apps/sim/blocks/blocks/hubspot.ts @@ -1,7 +1,7 @@ import { HubspotIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { HubSpotResponse } from '@/tools/hubspot/types' import { getTrigger } from '@/triggers' import { hubspotAllTriggerOptions } from '@/triggers/hubspot/utils' @@ -15,6 +15,8 @@ export const HubSpotBlock: BlockConfig = { 'Integrate HubSpot into your workflow. Manage contacts, companies, deals, tickets, and other CRM objects with powerful automation capabilities. Can be used in trigger mode to start workflows when contacts are created, deleted, or updated.', docsLink: 'https://docs.sim.ai/tools/hubspot', category: 'tools', + integrationType: IntegrationType.CRM, + tags: ['marketing', 'sales-engagement', 'customer-support'], bgColor: '#FF7A59', icon: HubspotIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/huggingface.ts b/apps/sim/blocks/blocks/huggingface.ts index c02f4a9bf30..9333d0d5902 100644 --- a/apps/sim/blocks/blocks/huggingface.ts +++ b/apps/sim/blocks/blocks/huggingface.ts @@ -1,6 +1,6 @@ import { HuggingFaceIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { HuggingFaceChatResponse } from '@/tools/huggingface/types' export const HuggingFaceBlock: BlockConfig = { @@ -12,6 +12,8 @@ export const HuggingFaceBlock: BlockConfig = { 'Integrate Hugging Face into the workflow. Can generate completions using the Hugging Face Inference API.', docsLink: 'https://docs.sim.ai/tools/huggingface', category: 'tools', + integrationType: IntegrationType.AI, + tags: ['llm', 'agentic'], bgColor: '#0B0F19', icon: HuggingFaceIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/hunter.ts b/apps/sim/blocks/blocks/hunter.ts index f713227916b..614ab7dd391 100644 --- a/apps/sim/blocks/blocks/hunter.ts +++ b/apps/sim/blocks/blocks/hunter.ts @@ -1,5 +1,5 @@ import { HunterIOIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' import type { HunterResponse } from '@/tools/hunter/types' export const HunterBlock: BlockConfig = { @@ -11,6 +11,8 @@ export const HunterBlock: BlockConfig = { 'Integrate Hunter into the workflow. Can search domains, find email addresses, verify email addresses, discover companies, find companies, and count email addresses.', docsLink: 'https://docs.sim.ai/tools/hunter', category: 'tools', + integrationType: IntegrationType.SalesIntelligence, + tags: ['enrichment', 'sales-engagement'], bgColor: '#E0E0E0', icon: HunterIOIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/image_generator.ts b/apps/sim/blocks/blocks/image_generator.ts index e2efad69d59..517e25bf7a7 100644 --- a/apps/sim/blocks/blocks/image_generator.ts +++ b/apps/sim/blocks/blocks/image_generator.ts @@ -1,5 +1,5 @@ import { ImageIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' import type { DalleResponse } from '@/tools/openai/types' export const ImageGeneratorBlock: BlockConfig = { @@ -11,6 +11,8 @@ export const ImageGeneratorBlock: BlockConfig = { 'Integrate Image Generator into the workflow. Can generate images using DALL-E 3 or GPT Image.', docsLink: 'https://docs.sim.ai/tools/image_generator', category: 'tools', + integrationType: IntegrationType.AI, + tags: ['image-generation', 'llm'], bgColor: '#4D5FFF', icon: ImageIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/imap.ts b/apps/sim/blocks/blocks/imap.ts index e23727b20c0..8217e372de6 100644 --- a/apps/sim/blocks/blocks/imap.ts +++ b/apps/sim/blocks/blocks/imap.ts @@ -1,5 +1,6 @@ import { MailServerIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' import { getTrigger } from '@/triggers' export const ImapBlock: BlockConfig = { @@ -9,6 +10,8 @@ export const ImapBlock: BlockConfig = { longDescription: 'Connect to any email server via IMAP protocol to trigger workflows when new emails are received. Supports Gmail, Outlook, Yahoo, and any other IMAP-compatible email provider.', category: 'triggers', + integrationType: IntegrationType.Email, + tags: ['messaging', 'automation'], bgColor: '#6366F1', icon: MailServerIcon, triggerAllowed: true, diff --git a/apps/sim/blocks/blocks/incidentio.ts b/apps/sim/blocks/blocks/incidentio.ts index cd3de03573e..ad8c19949d6 100644 --- a/apps/sim/blocks/blocks/incidentio.ts +++ b/apps/sim/blocks/blocks/incidentio.ts @@ -1,6 +1,6 @@ import { IncidentioIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { IncidentioResponse } from '@/tools/incidentio/types' export const IncidentioBlock: BlockConfig = { @@ -12,6 +12,8 @@ export const IncidentioBlock: BlockConfig = { 'Integrate incident.io into the workflow. Manage incidents, actions, follow-ups, workflows, schedules, escalations, custom fields, and more.', docsLink: 'https://docs.sim.ai/tools/incidentio', category: 'tools', + integrationType: IntegrationType.DeveloperTools, + tags: ['incident-management', 'monitoring'], bgColor: '#E0E0E0', icon: IncidentioIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/infisical.ts b/apps/sim/blocks/blocks/infisical.ts index adfb69c02d3..94909db1b6e 100644 --- a/apps/sim/blocks/blocks/infisical.ts +++ b/apps/sim/blocks/blocks/infisical.ts @@ -1,6 +1,6 @@ import { InfisicalIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { InfisicalResponse } from '@/tools/infisical/types' export const InfisicalBlock: BlockConfig = { @@ -11,6 +11,8 @@ export const InfisicalBlock: BlockConfig = { 'Integrate Infisical into your workflow. List, get, create, update, and delete secrets across project environments.', docsLink: 'https://docs.sim.ai/tools/infisical', category: 'tools', + integrationType: IntegrationType.Security, + tags: ['secrets-management'], bgColor: '#F7FE62', icon: InfisicalIcon, authMode: AuthMode.ApiKey, diff --git a/apps/sim/blocks/blocks/intercom.ts b/apps/sim/blocks/blocks/intercom.ts index 6919679b640..21b8124324a 100644 --- a/apps/sim/blocks/blocks/intercom.ts +++ b/apps/sim/blocks/blocks/intercom.ts @@ -1,6 +1,6 @@ import { IntercomIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { createVersionedToolSelector } from '@/blocks/utils' export const IntercomBlock: BlockConfig = { @@ -13,6 +13,8 @@ export const IntercomBlock: BlockConfig = { docsLink: 'https://docs.sim.ai/tools/intercom', authMode: AuthMode.ApiKey, category: 'tools', + integrationType: IntegrationType.CustomerSupport, + tags: ['customer-support', 'messaging'], bgColor: '#E0E0E0', icon: IntercomIcon, subBlocks: [ @@ -1404,6 +1406,8 @@ export const IntercomV2Block: BlockConfig = { ...IntercomBlock, type: 'intercom_v2', name: 'Intercom', + integrationType: IntegrationType.CustomerSupport, + tags: ['customer-support', 'messaging'], hideFromToolbar: false, tools: { ...IntercomBlock.tools, diff --git a/apps/sim/blocks/blocks/jina.ts b/apps/sim/blocks/blocks/jina.ts index 4f9be7884c9..2a71e96eaa7 100644 --- a/apps/sim/blocks/blocks/jina.ts +++ b/apps/sim/blocks/blocks/jina.ts @@ -1,5 +1,5 @@ import { JinaAIIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' import type { ReadUrlResponse, SearchResponse } from '@/tools/jina/types' export const JinaBlock: BlockConfig = { @@ -11,6 +11,8 @@ export const JinaBlock: BlockConfig = { 'Integrate Jina AI into the workflow. Search the web and get LLM-friendly results, or extract clean content from specific URLs with advanced parsing options.', docsLink: 'https://docs.sim.ai/tools/jina', category: 'tools', + integrationType: IntegrationType.Search, + tags: ['web-scraping', 'knowledge-base'], bgColor: '#333333', icon: JinaAIIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/jira.ts b/apps/sim/blocks/blocks/jira.ts index 82f118cf213..092677ab904 100644 --- a/apps/sim/blocks/blocks/jira.ts +++ b/apps/sim/blocks/blocks/jira.ts @@ -1,7 +1,7 @@ import { JiraIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { normalizeFileInput } from '@/blocks/utils' import type { JiraResponse } from '@/tools/jira/types' import { getTrigger } from '@/triggers' @@ -16,6 +16,8 @@ export const JiraBlock: BlockConfig = { 'Integrate Jira into the workflow. Can read, write, and update issues. Can also trigger workflows based on Jira webhook events.', docsLink: 'https://docs.sim.ai/tools/jira', category: 'tools', + integrationType: IntegrationType.Productivity, + tags: ['project-management', 'ticketing'], bgColor: '#E0E0E0', icon: JiraIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/jira_service_management.ts b/apps/sim/blocks/blocks/jira_service_management.ts index b74fbe4a134..d78251cb3c0 100644 --- a/apps/sim/blocks/blocks/jira_service_management.ts +++ b/apps/sim/blocks/blocks/jira_service_management.ts @@ -1,7 +1,7 @@ import { JiraServiceManagementIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { JsmResponse } from '@/tools/jsm/types' export const JiraServiceManagementBlock: BlockConfig = { @@ -13,6 +13,8 @@ export const JiraServiceManagementBlock: BlockConfig = { 'Integrate with Jira Service Management for IT service management. Create and manage service requests, handle customers and organizations, track SLAs, and manage queues.', docsLink: 'https://docs.sim.ai/tools/jira-service-management', category: 'tools', + integrationType: IntegrationType.CustomerSupport, + tags: ['customer-support', 'ticketing', 'incident-management'], bgColor: '#E0E0E0', icon: JiraServiceManagementIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/kalshi.ts b/apps/sim/blocks/blocks/kalshi.ts index d013c93c28d..8293dbba418 100644 --- a/apps/sim/blocks/blocks/kalshi.ts +++ b/apps/sim/blocks/blocks/kalshi.ts @@ -1,6 +1,6 @@ import { KalshiIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { createVersionedToolSelector } from '@/blocks/utils' export const KalshiBlock: BlockConfig = { @@ -12,6 +12,8 @@ export const KalshiBlock: BlockConfig = { docsLink: 'https://docs.sim.ai/tools/kalshi', authMode: AuthMode.ApiKey, category: 'tools', + integrationType: IntegrationType.Analytics, + tags: ['prediction-markets', 'data-analytics'], hideFromToolbar: true, bgColor: '#09C285', icon: KalshiIcon, @@ -707,6 +709,8 @@ export const KalshiV2Block: BlockConfig = { description: 'Access prediction markets and trade on Kalshi', longDescription: 'Integrate Kalshi prediction markets into the workflow. Can get markets, market, events, event, balance, positions, orders, orderbook, trades, candlesticks, fills, series, exchange status, and place/cancel/amend trades.', + integrationType: IntegrationType.Analytics, + tags: ['prediction-markets', 'data-analytics'], hideFromToolbar: false, tools: { ...KalshiBlock.tools, diff --git a/apps/sim/blocks/blocks/langsmith.ts b/apps/sim/blocks/blocks/langsmith.ts index 0a09606bf80..96773f8fc7b 100644 --- a/apps/sim/blocks/blocks/langsmith.ts +++ b/apps/sim/blocks/blocks/langsmith.ts @@ -1,5 +1,5 @@ import { LangsmithIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' import type { LangsmithResponse } from '@/tools/langsmith/types' export const LangsmithBlock: BlockConfig = { @@ -10,6 +10,8 @@ export const LangsmithBlock: BlockConfig = { 'Send run data to LangSmith to trace executions, attach metadata, and monitor workflow performance.', docsLink: 'https://docs.sim.ai/tools/langsmith', category: 'tools', + integrationType: IntegrationType.DeveloperTools, + tags: ['monitoring', 'llm', 'data-analytics'], bgColor: '#181C1E', icon: LangsmithIcon, authMode: AuthMode.ApiKey, diff --git a/apps/sim/blocks/blocks/lemlist.ts b/apps/sim/blocks/blocks/lemlist.ts index 9758b7e1ad3..c917e95e51d 100644 --- a/apps/sim/blocks/blocks/lemlist.ts +++ b/apps/sim/blocks/blocks/lemlist.ts @@ -1,5 +1,5 @@ import { LemlistIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' import type { LemlistResponse } from '@/tools/lemlist/types' import { getTrigger } from '@/triggers' @@ -12,6 +12,8 @@ export const LemlistBlock: BlockConfig = { 'Integrate Lemlist into your workflow. Retrieve campaign activities and replies, get lead information, and send emails through the Lemlist inbox.', docsLink: 'https://docs.sim.ai/tools/lemlist', category: 'tools', + integrationType: IntegrationType.Email, + tags: ['sales-engagement', 'email-marketing', 'automation'], bgColor: '#316BFF', icon: LemlistIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/linear.ts b/apps/sim/blocks/blocks/linear.ts index e1a922daacc..504cb6b5ffa 100644 --- a/apps/sim/blocks/blocks/linear.ts +++ b/apps/sim/blocks/blocks/linear.ts @@ -1,7 +1,7 @@ import { LinearIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { normalizeFileInput } from '@/blocks/utils' import type { LinearResponse } from '@/tools/linear/types' import { getTrigger } from '@/triggers' @@ -16,6 +16,8 @@ export const LinearBlock: BlockConfig = { 'Integrate Linear into the workflow. Can manage issues, comments, projects, labels, workflow states, cycles, attachments, and more. Can also trigger workflows based on Linear webhook events.', docsLink: 'https://docs.sim.ai/tools/linear', category: 'tools', + integrationType: IntegrationType.Productivity, + tags: ['project-management', 'ticketing'], icon: LinearIcon, bgColor: '#5E6AD2', subBlocks: [ diff --git a/apps/sim/blocks/blocks/linkedin.ts b/apps/sim/blocks/blocks/linkedin.ts index 87fd163b3c1..3098124b7b7 100644 --- a/apps/sim/blocks/blocks/linkedin.ts +++ b/apps/sim/blocks/blocks/linkedin.ts @@ -1,7 +1,7 @@ import { LinkedInIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { LinkedInResponse } from '@/tools/linkedin/types' export const LinkedInBlock: BlockConfig = { @@ -13,6 +13,8 @@ export const LinkedInBlock: BlockConfig = { 'Integrate LinkedIn into workflows. Share posts to your personal feed and access your LinkedIn profile information.', docsLink: 'https://docs.sim.ai/tools/linkedin', category: 'tools', + integrationType: IntegrationType.Social, + tags: ['marketing', 'sales-engagement', 'enrichment'], bgColor: '#0072B1', icon: LinkedInIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/linkup.ts b/apps/sim/blocks/blocks/linkup.ts index c9cfc4953e4..b1aead7b07f 100644 --- a/apps/sim/blocks/blocks/linkup.ts +++ b/apps/sim/blocks/blocks/linkup.ts @@ -1,5 +1,5 @@ import { LinkupIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' import type { LinkupSearchToolResponse } from '@/tools/linkup/types' export const LinkupBlock: BlockConfig = { @@ -10,6 +10,8 @@ export const LinkupBlock: BlockConfig = { longDescription: 'Integrate Linkup into the workflow. Can search the web.', docsLink: 'https://docs.sim.ai/tools/linkup', category: 'tools', + integrationType: IntegrationType.Search, + tags: ['web-scraping', 'enrichment'], bgColor: '#D6D3C7', icon: LinkupIcon, diff --git a/apps/sim/blocks/blocks/loops.ts b/apps/sim/blocks/blocks/loops.ts index 02a49ea7647..ec7b9d9b53d 100644 --- a/apps/sim/blocks/blocks/loops.ts +++ b/apps/sim/blocks/blocks/loops.ts @@ -1,6 +1,6 @@ import { LoopsIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { LoopsResponse } from '@/tools/loops/types' export const LoopsBlock: BlockConfig = { @@ -12,6 +12,8 @@ export const LoopsBlock: BlockConfig = { 'Integrate Loops into the workflow. Create and manage contacts, send transactional emails, and trigger event-based automations.', docsLink: 'https://docs.sim.ai/tools/loops', category: 'tools', + integrationType: IntegrationType.Email, + tags: ['email-marketing', 'marketing', 'automation'], bgColor: '#FAFAF9', icon: LoopsIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/luma.ts b/apps/sim/blocks/blocks/luma.ts index aa640b00813..f7fc2d615b9 100644 --- a/apps/sim/blocks/blocks/luma.ts +++ b/apps/sim/blocks/blocks/luma.ts @@ -1,5 +1,5 @@ import { LumaIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' export const LumaBlock: BlockConfig = { type: 'luma', @@ -9,6 +9,8 @@ export const LumaBlock: BlockConfig = { 'Integrate Luma into the workflow. Can create events, update events, get event details, list calendar events, get guest lists, and add guests to events.', docsLink: 'https://docs.sim.ai/tools/luma', category: 'tools', + integrationType: IntegrationType.Productivity, + tags: ['events', 'calendar', 'scheduling'], bgColor: '#FFFFFF', icon: LumaIcon, authMode: AuthMode.ApiKey, diff --git a/apps/sim/blocks/blocks/mailchimp.ts b/apps/sim/blocks/blocks/mailchimp.ts index 147e61e575c..0834f9bb2fe 100644 --- a/apps/sim/blocks/blocks/mailchimp.ts +++ b/apps/sim/blocks/blocks/mailchimp.ts @@ -1,6 +1,6 @@ import { MailchimpIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' export const MailchimpBlock: BlockConfig = { type: 'mailchimp', @@ -11,6 +11,8 @@ export const MailchimpBlock: BlockConfig = { docsLink: 'https://docs.sim.ai/tools/mailchimp', authMode: AuthMode.ApiKey, category: 'tools', + integrationType: IntegrationType.Email, + tags: ['email-marketing', 'marketing', 'automation'], bgColor: '#FFE01B', icon: MailchimpIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/mailgun.ts b/apps/sim/blocks/blocks/mailgun.ts index 4fdee43095d..5d06a21c218 100644 --- a/apps/sim/blocks/blocks/mailgun.ts +++ b/apps/sim/blocks/blocks/mailgun.ts @@ -1,5 +1,6 @@ import { MailgunIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' import type { SendMessageResult } from '@/tools/mailgun/types' export const MailgunBlock: BlockConfig = { @@ -10,6 +11,8 @@ export const MailgunBlock: BlockConfig = { 'Integrate Mailgun into your workflow. Send transactional emails, manage mailing lists and members, view domain information, and track email events. Supports text and HTML emails, tags for tracking, and comprehensive list management.', docsLink: 'https://docs.sim.ai/tools/mailgun', category: 'tools', + integrationType: IntegrationType.Email, + tags: ['messaging', 'email-marketing'], bgColor: '#E0E0E0', icon: MailgunIcon, diff --git a/apps/sim/blocks/blocks/mcp.ts b/apps/sim/blocks/blocks/mcp.ts index 1d80d052da3..0b5d4da8db6 100644 --- a/apps/sim/blocks/blocks/mcp.ts +++ b/apps/sim/blocks/blocks/mcp.ts @@ -1,6 +1,7 @@ import { McpIcon } from '@/components/icons' import { createMcpToolId } from '@/lib/mcp/shared' import type { BlockConfig } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' import type { ToolResponse } from '@/tools/types' export interface McpResponse extends ToolResponse { @@ -15,6 +16,8 @@ export const McpBlock: BlockConfig = { 'Integrate MCP into the workflow. Can execute tools from MCP servers. Requires MCP servers in workspace settings.', docsLink: 'https://docs.sim.ai/mcp', category: 'tools', + integrationType: IntegrationType.DeveloperTools, + tags: ['agentic', 'automation', 'llm'], bgColor: '#181C1E', icon: McpIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/mem0.ts b/apps/sim/blocks/blocks/mem0.ts index 3384b93b0cb..8904e9593e2 100644 --- a/apps/sim/blocks/blocks/mem0.ts +++ b/apps/sim/blocks/blocks/mem0.ts @@ -1,5 +1,5 @@ import { Mem0Icon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' import type { Mem0Response } from '@/tools/mem0/types' export const Mem0Block: BlockConfig = { @@ -11,6 +11,8 @@ export const Mem0Block: BlockConfig = { bgColor: '#181C1E', icon: Mem0Icon, category: 'tools', + integrationType: IntegrationType.AI, + tags: ['llm', 'knowledge-base', 'agentic'], docsLink: 'https://docs.sim.ai/tools/mem0', subBlocks: [ { diff --git a/apps/sim/blocks/blocks/microsoft_ad.ts b/apps/sim/blocks/blocks/microsoft_ad.ts index be5265efaa2..bc6d0cf34e3 100644 --- a/apps/sim/blocks/blocks/microsoft_ad.ts +++ b/apps/sim/blocks/blocks/microsoft_ad.ts @@ -1,7 +1,7 @@ import { AzureIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { MicrosoftAdResponse } from '@/tools/microsoft_ad/types' export const MicrosoftAdBlock: BlockConfig = { @@ -12,6 +12,8 @@ export const MicrosoftAdBlock: BlockConfig = { 'Integrate Azure Active Directory into your workflows. List, create, update, and delete users and groups. Manage group memberships programmatically.', docsLink: 'https://docs.sim.ai/tools/microsoft_ad', category: 'tools', + integrationType: IntegrationType.Security, + tags: ['identity', 'microsoft-365'], bgColor: '#0078D4', icon: AzureIcon, authMode: AuthMode.OAuth, diff --git a/apps/sim/blocks/blocks/microsoft_dataverse.ts b/apps/sim/blocks/blocks/microsoft_dataverse.ts index 531973197fa..336b76e5df7 100644 --- a/apps/sim/blocks/blocks/microsoft_dataverse.ts +++ b/apps/sim/blocks/blocks/microsoft_dataverse.ts @@ -1,7 +1,7 @@ import { MicrosoftDataverseIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { normalizeFileInput } from '@/blocks/utils' import type { DataverseResponse } from '@/tools/microsoft_dataverse/types' @@ -14,6 +14,8 @@ export const MicrosoftDataverseBlock: BlockConfig = { 'Integrate Microsoft Dataverse into your workflow. Create, read, update, delete, upsert, associate, query, search, and execute actions and functions against Dataverse tables using the Web API. Supports bulk operations, FetchXML, file uploads, and relevance search. Works with Dynamics 365, Power Platform, and custom Dataverse environments.', docsLink: 'https://docs.sim.ai/tools/microsoft_dataverse', category: 'tools', + integrationType: IntegrationType.Databases, + tags: ['microsoft-365', 'data-warehouse', 'cloud'], bgColor: '#E0E0E0', icon: MicrosoftDataverseIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/microsoft_excel.ts b/apps/sim/blocks/blocks/microsoft_excel.ts index 1329b6edcde..4b04368742c 100644 --- a/apps/sim/blocks/blocks/microsoft_excel.ts +++ b/apps/sim/blocks/blocks/microsoft_excel.ts @@ -1,7 +1,7 @@ import { MicrosoftExcelIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { createVersionedToolSelector } from '@/blocks/utils' import type { MicrosoftExcelResponse, @@ -18,6 +18,8 @@ export const MicrosoftExcelBlock: BlockConfig = { 'Integrate Microsoft Excel into the workflow. Can read, write, update, add to table, and create new worksheets.', docsLink: 'https://docs.sim.ai/tools/microsoft_excel', category: 'tools', + integrationType: IntegrationType.Documents, + tags: ['spreadsheet', 'microsoft-365'], bgColor: '#E0E0E0', icon: MicrosoftExcelIcon, subBlocks: [ @@ -338,6 +340,8 @@ export const MicrosoftExcelV2Block: BlockConfig = { 'Integrate Microsoft Excel into the workflow with explicit sheet selection. Can read and write data in specific sheets.', docsLink: 'https://docs.sim.ai/tools/microsoft_excel', category: 'tools', + integrationType: IntegrationType.Documents, + tags: ['spreadsheet', 'microsoft-365'], bgColor: '#E0E0E0', icon: MicrosoftExcelIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/microsoft_planner.ts b/apps/sim/blocks/blocks/microsoft_planner.ts index 1a0d57d9be9..cfa7c8bf08b 100644 --- a/apps/sim/blocks/blocks/microsoft_planner.ts +++ b/apps/sim/blocks/blocks/microsoft_planner.ts @@ -1,7 +1,7 @@ import { MicrosoftPlannerIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { MicrosoftPlannerResponse } from '@/tools/microsoft_planner/types' interface MicrosoftPlannerBlockParams { @@ -35,6 +35,8 @@ export const MicrosoftPlannerBlock: BlockConfig = { 'Integrate Microsoft Planner into the workflow. Manage tasks, plans, buckets, and task details including checklists and references.', docsLink: 'https://docs.sim.ai/tools/microsoft_planner', category: 'tools', + integrationType: IntegrationType.Productivity, + tags: ['project-management', 'microsoft-365', 'ticketing'], bgColor: '#E0E0E0', icon: MicrosoftPlannerIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/microsoft_teams.ts b/apps/sim/blocks/blocks/microsoft_teams.ts index 7b382374c8d..65869e81a9a 100644 --- a/apps/sim/blocks/blocks/microsoft_teams.ts +++ b/apps/sim/blocks/blocks/microsoft_teams.ts @@ -1,7 +1,7 @@ import { MicrosoftTeamsIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { normalizeFileInput } from '@/blocks/utils' import type { MicrosoftTeamsResponse } from '@/tools/microsoft_teams/types' import { getTrigger } from '@/triggers' @@ -15,6 +15,8 @@ export const MicrosoftTeamsBlock: BlockConfig = { 'Integrate Microsoft Teams into the workflow. Read, write, update, and delete chat and channel messages. Reply to messages, add reactions, and list team/channel members. Can be used in trigger mode to trigger a workflow when a message is sent to a chat or channel. To mention users in messages, wrap their name in `` tags: `userName`', docsLink: 'https://docs.sim.ai/tools/microsoft_teams', category: 'tools', + integrationType: IntegrationType.Communication, + tags: ['messaging', 'microsoft-365'], triggerAllowed: true, bgColor: '#E0E0E0', icon: MicrosoftTeamsIcon, diff --git a/apps/sim/blocks/blocks/mistral_parse.ts b/apps/sim/blocks/blocks/mistral_parse.ts index d7bb020a1b3..2ee52dbcf82 100644 --- a/apps/sim/blocks/blocks/mistral_parse.ts +++ b/apps/sim/blocks/blocks/mistral_parse.ts @@ -1,5 +1,5 @@ import { MistralIcon } from '@/components/icons' -import { AuthMode, type BlockConfig, type SubBlockType } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType, type SubBlockType } from '@/blocks/types' import { createVersionedToolSelector, normalizeFileInput } from '@/blocks/utils' import type { MistralParserOutput } from '@/tools/mistral/types' @@ -12,6 +12,8 @@ export const MistralParseBlock: BlockConfig = { longDescription: `Integrate Mistral Parse into the workflow. Can extract text from uploaded PDF documents, or from a URL.`, docsLink: 'https://docs.sim.ai/tools/mistral_parse', category: 'tools', + integrationType: IntegrationType.AI, + tags: ['document-processing', 'ocr'], bgColor: '#000000', icon: MistralIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/mongodb.ts b/apps/sim/blocks/blocks/mongodb.ts index aa567e30e3d..cf1398f295e 100644 --- a/apps/sim/blocks/blocks/mongodb.ts +++ b/apps/sim/blocks/blocks/mongodb.ts @@ -1,5 +1,6 @@ import { MongoDBIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' import type { MongoDBIntrospectResponse, MongoDBResponse } from '@/tools/mongodb/types' export const MongoDBBlock: BlockConfig = { @@ -10,6 +11,8 @@ export const MongoDBBlock: BlockConfig = { @@ -10,6 +11,8 @@ export const MySQLBlock: BlockConfig = { 'Integrate MySQL into the workflow. Can query, insert, update, delete, and execute raw SQL.', docsLink: 'https://docs.sim.ai/tools/mysql', category: 'tools', + integrationType: IntegrationType.Databases, + tags: ['data-warehouse', 'data-analytics'], bgColor: '#E0E0E0', icon: MySQLIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/neo4j.ts b/apps/sim/blocks/blocks/neo4j.ts index 2624e5e0bb3..df502c237ce 100644 --- a/apps/sim/blocks/blocks/neo4j.ts +++ b/apps/sim/blocks/blocks/neo4j.ts @@ -1,5 +1,6 @@ import { Neo4jIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' import type { Neo4jIntrospectResponse, Neo4jResponse } from '@/tools/neo4j/types' export const Neo4jBlock: BlockConfig = { @@ -10,6 +11,8 @@ export const Neo4jBlock: BlockConfig = 'Integrate Neo4j graph database into the workflow. Can query, create, merge, update, and delete nodes and relationships.', docsLink: 'https://docs.sim.ai/tools/neo4j', category: 'tools', + integrationType: IntegrationType.Databases, + tags: ['data-warehouse', 'data-analytics'], bgColor: '#FFFFFF', icon: Neo4jIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/notion.ts b/apps/sim/blocks/blocks/notion.ts index f222565fdf4..82fae4c2c3f 100644 --- a/apps/sim/blocks/blocks/notion.ts +++ b/apps/sim/blocks/blocks/notion.ts @@ -1,6 +1,6 @@ import { NotionIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { createVersionedToolSelector } from '@/blocks/utils' import type { NotionResponse } from '@/tools/notion/types' @@ -15,6 +15,8 @@ export const NotionBlock: BlockConfig = { 'Integrate with Notion into the workflow. Can read page, read database, create page, create database, append content, query database, and search workspace.', docsLink: 'https://docs.sim.ai/tools/notion', category: 'tools', + integrationType: IntegrationType.Documents, + tags: ['note-taking', 'knowledge-base', 'content-management'], bgColor: '#181C1E', icon: NotionIcon, subBlocks: [ @@ -429,6 +431,8 @@ export const NotionV2Block: BlockConfig = { 'Integrate with Notion into the workflow. Can read page, read database, create page, create database, append content, query database, and search workspace.', docsLink: 'https://docs.sim.ai/tools/notion', category: 'tools', + integrationType: IntegrationType.Documents, + tags: ['note-taking', 'knowledge-base', 'content-management'], bgColor: '#181C1E', icon: NotionIcon, hideFromToolbar: false, diff --git a/apps/sim/blocks/blocks/obsidian.ts b/apps/sim/blocks/blocks/obsidian.ts index 533c80fc654..57711412610 100644 --- a/apps/sim/blocks/blocks/obsidian.ts +++ b/apps/sim/blocks/blocks/obsidian.ts @@ -1,6 +1,6 @@ import { ObsidianIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' export const ObsidianBlock: BlockConfig = { type: 'obsidian', @@ -10,6 +10,8 @@ export const ObsidianBlock: BlockConfig = { 'Read, create, update, search, and delete notes in your Obsidian vault. Manage periodic notes, execute commands, and patch content at specific locations. Requires the Obsidian Local REST API plugin.', docsLink: 'https://docs.sim.ai/tools/obsidian', category: 'tools', + integrationType: IntegrationType.Documents, + tags: ['note-taking', 'knowledge-base'], bgColor: '#0F0F0F', icon: ObsidianIcon, authMode: AuthMode.ApiKey, diff --git a/apps/sim/blocks/blocks/okta.ts b/apps/sim/blocks/blocks/okta.ts index e0b284c1bb6..8961846d606 100644 --- a/apps/sim/blocks/blocks/okta.ts +++ b/apps/sim/blocks/blocks/okta.ts @@ -1,5 +1,6 @@ import { OktaIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' import type { OktaResponse } from '@/tools/okta/types' export const OktaBlock: BlockConfig = { @@ -10,6 +11,8 @@ export const OktaBlock: BlockConfig = { 'Integrate Okta identity management into your workflow. List, create, update, activate, suspend, and delete users. Reset passwords. Manage groups and group membership.', docsLink: 'https://docs.sim.ai/tools/okta', category: 'tools', + integrationType: IntegrationType.Security, + tags: ['identity', 'automation'], bgColor: '#191919', icon: OktaIcon, diff --git a/apps/sim/blocks/blocks/onedrive.ts b/apps/sim/blocks/blocks/onedrive.ts index b8d54b5e300..4ecc27b97aa 100644 --- a/apps/sim/blocks/blocks/onedrive.ts +++ b/apps/sim/blocks/blocks/onedrive.ts @@ -2,7 +2,7 @@ import { createLogger } from '@sim/logger' import { MicrosoftOneDriveIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { normalizeFileInput } from '@/blocks/utils' import type { OneDriveResponse } from '@/tools/onedrive/types' import { normalizeExcelValuesForToolParams } from '@/tools/onedrive/utils' @@ -18,6 +18,8 @@ export const OneDriveBlock: BlockConfig = { 'Integrate OneDrive into the workflow. Can create text and Excel files, upload files, download files, list files, and delete files or folders.', docsLink: 'https://docs.sim.ai/tools/onedrive', category: 'tools', + integrationType: IntegrationType.FileStorage, + tags: ['microsoft-365', 'cloud', 'document-processing'], bgColor: '#E0E0E0', icon: MicrosoftOneDriveIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/onepassword.ts b/apps/sim/blocks/blocks/onepassword.ts index 7407c7f9277..80e5b4adef1 100644 --- a/apps/sim/blocks/blocks/onepassword.ts +++ b/apps/sim/blocks/blocks/onepassword.ts @@ -1,5 +1,5 @@ import { OnePasswordIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' export const OnePasswordBlock: BlockConfig = { type: 'onepassword', @@ -9,6 +9,8 @@ export const OnePasswordBlock: BlockConfig = { 'Access and manage secrets stored in 1Password vaults using the Connect API or Service Account SDK. List vaults, retrieve items with their fields and secrets, create new items, update existing ones, delete items, and resolve secret references.', docsLink: 'https://docs.sim.ai/tools/onepassword', category: 'tools', + integrationType: IntegrationType.Security, + tags: ['secrets-management', 'identity'], bgColor: '#E0E0E0', icon: OnePasswordIcon, authMode: AuthMode.ApiKey, diff --git a/apps/sim/blocks/blocks/openai.ts b/apps/sim/blocks/blocks/openai.ts index 2585804b296..5069ab13864 100644 --- a/apps/sim/blocks/blocks/openai.ts +++ b/apps/sim/blocks/blocks/openai.ts @@ -1,6 +1,6 @@ import { OpenAIIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' export const OpenAIBlock: BlockConfig = { type: 'openai', @@ -9,6 +9,8 @@ export const OpenAIBlock: BlockConfig = { authMode: AuthMode.ApiKey, longDescription: 'Integrate Embeddings into the workflow. Can generate embeddings from text.', category: 'tools', + integrationType: IntegrationType.AI, + tags: ['llm', 'vector-search'], docsLink: 'https://docs.sim.ai/tools/openai', bgColor: '#10a37f', icon: OpenAIIcon, diff --git a/apps/sim/blocks/blocks/outlook.ts b/apps/sim/blocks/blocks/outlook.ts index 2635a5be659..ead70e9e7c4 100644 --- a/apps/sim/blocks/blocks/outlook.ts +++ b/apps/sim/blocks/blocks/outlook.ts @@ -1,7 +1,7 @@ import { OutlookIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { normalizeFileInput } from '@/blocks/utils' import type { OutlookResponse } from '@/tools/outlook/types' import { getTrigger } from '@/triggers' @@ -15,6 +15,8 @@ export const OutlookBlock: BlockConfig = { 'Integrate Outlook into the workflow. Can read, draft, send, forward, and move email messages. Can be used in trigger mode to trigger a workflow when a new email is received.', docsLink: 'https://docs.sim.ai/tools/outlook', category: 'tools', + integrationType: IntegrationType.Email, + tags: ['microsoft-365', 'messaging', 'automation'], triggerAllowed: true, bgColor: '#E0E0E0', icon: OutlookIcon, diff --git a/apps/sim/blocks/blocks/pagerduty.ts b/apps/sim/blocks/blocks/pagerduty.ts index 34e1336bb92..5cb6a4e88cc 100644 --- a/apps/sim/blocks/blocks/pagerduty.ts +++ b/apps/sim/blocks/blocks/pagerduty.ts @@ -1,5 +1,5 @@ import { PagerDutyIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' export const PagerDutyBlock: BlockConfig = { type: 'pagerduty', @@ -9,6 +9,8 @@ export const PagerDutyBlock: BlockConfig = { 'Integrate PagerDuty into your workflow to list, create, and update incidents, add notes, list services, and check on-call schedules.', docsLink: 'https://docs.sim.ai/tools/pagerduty', category: 'tools', + integrationType: IntegrationType.DeveloperTools, + tags: ['incident-management', 'monitoring'], bgColor: '#06AC38', icon: PagerDutyIcon, authMode: AuthMode.ApiKey, diff --git a/apps/sim/blocks/blocks/parallel.ts b/apps/sim/blocks/blocks/parallel.ts index 65fdc052c69..b57dac65632 100644 --- a/apps/sim/blocks/blocks/parallel.ts +++ b/apps/sim/blocks/blocks/parallel.ts @@ -1,5 +1,5 @@ import { ParallelIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' import type { ToolResponse } from '@/tools/types' export const ParallelBlock: BlockConfig = { @@ -11,6 +11,8 @@ export const ParallelBlock: BlockConfig = { 'Integrate Parallel AI into the workflow. Can search the web, extract information from URLs, and conduct deep research.', docsLink: 'https://docs.sim.ai/tools/parallel-ai', category: 'tools', + integrationType: IntegrationType.Search, + tags: ['web-scraping', 'llm', 'agentic'], bgColor: '#E0E0E0', icon: ParallelIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/perplexity.ts b/apps/sim/blocks/blocks/perplexity.ts index eb88fe81b4c..7a1050e94b0 100644 --- a/apps/sim/blocks/blocks/perplexity.ts +++ b/apps/sim/blocks/blocks/perplexity.ts @@ -1,5 +1,5 @@ import { PerplexityIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' import type { PerplexityChatResponse, PerplexitySearchResponse } from '@/tools/perplexity/types' type PerplexityResponse = PerplexityChatResponse | PerplexitySearchResponse @@ -13,6 +13,8 @@ export const PerplexityBlock: BlockConfig = { authMode: AuthMode.ApiKey, docsLink: 'https://docs.sim.ai/tools/perplexity', category: 'tools', + integrationType: IntegrationType.AI, + tags: ['llm', 'web-scraping', 'agentic'], bgColor: '#20808D', // Perplexity turquoise color icon: PerplexityIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/pinecone.ts b/apps/sim/blocks/blocks/pinecone.ts index c89b67c20a0..59459a80413 100644 --- a/apps/sim/blocks/blocks/pinecone.ts +++ b/apps/sim/blocks/blocks/pinecone.ts @@ -1,6 +1,6 @@ import { PineconeIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { PineconeResponse } from '@/tools/pinecone/types' export const PineconeBlock: BlockConfig = { @@ -12,6 +12,8 @@ export const PineconeBlock: BlockConfig = { 'Integrate Pinecone into the workflow. Can generate embeddings, upsert text, search with text, fetch vectors, and search with vectors.', docsLink: 'https://docs.sim.ai/tools/pinecone', category: 'tools', + integrationType: IntegrationType.Databases, + tags: ['vector-search', 'knowledge-base'], bgColor: '#0D1117', icon: PineconeIcon, diff --git a/apps/sim/blocks/blocks/pipedrive.ts b/apps/sim/blocks/blocks/pipedrive.ts index 7b62906f93e..4d7b8606663 100644 --- a/apps/sim/blocks/blocks/pipedrive.ts +++ b/apps/sim/blocks/blocks/pipedrive.ts @@ -1,7 +1,7 @@ import { PipedriveIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { PipedriveResponse } from '@/tools/pipedrive/types' export const PipedriveBlock: BlockConfig = { @@ -13,6 +13,8 @@ export const PipedriveBlock: BlockConfig = { 'Integrate Pipedrive into your workflow. Manage deals, contacts, sales pipeline, projects, activities, files, and communications with powerful CRM capabilities.', docsLink: 'https://docs.sim.ai/tools/pipedrive', category: 'tools', + integrationType: IntegrationType.CRM, + tags: ['sales-engagement', 'project-management'], bgColor: '#2E6936', icon: PipedriveIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/polymarket.ts b/apps/sim/blocks/blocks/polymarket.ts index dd92a405714..62eb55ce2fe 100644 --- a/apps/sim/blocks/blocks/polymarket.ts +++ b/apps/sim/blocks/blocks/polymarket.ts @@ -1,5 +1,6 @@ import { PolymarketIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' export const PolymarketBlock: BlockConfig = { type: 'polymarket', @@ -9,6 +10,8 @@ export const PolymarketBlock: BlockConfig = { 'Integrate Polymarket prediction markets into the workflow. Can get markets, market, events, event, tags, series, orderbook, price, midpoint, price history, last trade price, spread, tick size, positions, trades, activity, leaderboard, holders, and search.', docsLink: 'https://docs.sim.ai/tools/polymarket', category: 'tools', + integrationType: IntegrationType.Analytics, + tags: ['prediction-markets', 'data-analytics'], bgColor: '#4C82FB', icon: PolymarketIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/postgresql.ts b/apps/sim/blocks/blocks/postgresql.ts index 2f375733345..53bf028ed6c 100644 --- a/apps/sim/blocks/blocks/postgresql.ts +++ b/apps/sim/blocks/blocks/postgresql.ts @@ -1,5 +1,6 @@ import { PostgresIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' import type { PostgresResponse } from '@/tools/postgresql/types' export const PostgreSQLBlock: BlockConfig = { @@ -10,6 +11,8 @@ export const PostgreSQLBlock: BlockConfig = { 'Integrate PostgreSQL into the workflow. Can query, insert, update, delete, and execute raw SQL.', docsLink: 'https://docs.sim.ai/tools/postgresql', category: 'tools', + integrationType: IntegrationType.Databases, + tags: ['data-warehouse', 'data-analytics'], bgColor: '#336791', icon: PostgresIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/posthog.ts b/apps/sim/blocks/blocks/posthog.ts index fef1f8aa5df..9e4f147a9ca 100644 --- a/apps/sim/blocks/blocks/posthog.ts +++ b/apps/sim/blocks/blocks/posthog.ts @@ -1,6 +1,6 @@ import { PosthogIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { PostHogResponse } from '@/tools/posthog/types' export const PostHogBlock: BlockConfig = { @@ -12,6 +12,8 @@ export const PostHogBlock: BlockConfig = { 'Integrate PostHog into your workflow. Track events, manage feature flags, analyze user behavior, run experiments, create surveys, and access session recordings.', docsLink: 'https://docs.sim.ai/tools/posthog', category: 'tools', + integrationType: IntegrationType.Analytics, + tags: ['data-analytics', 'monitoring'], bgColor: '#E0E0E0', icon: PosthogIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/pulse.ts b/apps/sim/blocks/blocks/pulse.ts index fda29aa162e..41b6a74571b 100644 --- a/apps/sim/blocks/blocks/pulse.ts +++ b/apps/sim/blocks/blocks/pulse.ts @@ -1,5 +1,5 @@ import { PulseIcon } from '@/components/icons' -import { AuthMode, type BlockConfig, type SubBlockType } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType, type SubBlockType } from '@/blocks/types' import { createVersionedToolSelector, normalizeFileInput } from '@/blocks/utils' import type { PulseParserOutput } from '@/tools/pulse/types' @@ -13,6 +13,8 @@ export const PulseBlock: BlockConfig = { 'Integrate Pulse into the workflow. Extract text from PDF documents, images, and Office files via URL or upload.', docsLink: 'https://docs.sim.ai/tools/pulse', category: 'tools', + integrationType: IntegrationType.AI, + tags: ['document-processing', 'ocr'], bgColor: '#E0E0E0', icon: PulseIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/qdrant.ts b/apps/sim/blocks/blocks/qdrant.ts index 9d0de09c32e..71ec14c2168 100644 --- a/apps/sim/blocks/blocks/qdrant.ts +++ b/apps/sim/blocks/blocks/qdrant.ts @@ -1,6 +1,6 @@ import { QdrantIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { QdrantResponse } from '@/tools/qdrant/types' export const QdrantBlock: BlockConfig = { @@ -11,6 +11,8 @@ export const QdrantBlock: BlockConfig = { longDescription: 'Integrate Qdrant into the workflow. Can upsert, search, and fetch points.', docsLink: 'https://qdrant.tech/documentation/', category: 'tools', + integrationType: IntegrationType.Databases, + tags: ['vector-search', 'knowledge-base'], bgColor: '#1A223F', icon: QdrantIcon, diff --git a/apps/sim/blocks/blocks/rds.ts b/apps/sim/blocks/blocks/rds.ts index 1bf54787c28..71ac6822e85 100644 --- a/apps/sim/blocks/blocks/rds.ts +++ b/apps/sim/blocks/blocks/rds.ts @@ -1,5 +1,6 @@ import { RDSIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' import type { RdsIntrospectResponse, RdsResponse } from '@/tools/rds/types' export const RDSBlock: BlockConfig = { @@ -10,6 +11,8 @@ export const RDSBlock: BlockConfig = { 'Integrate Amazon RDS Aurora Serverless into the workflow using the Data API. Can query, insert, update, delete, and execute raw SQL without managing database connections.', docsLink: 'https://docs.sim.ai/tools/rds', category: 'tools', + integrationType: IntegrationType.Databases, + tags: ['cloud', 'data-warehouse'], bgColor: 'linear-gradient(45deg, #2E27AD 0%, #527FFF 100%)', icon: RDSIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/reddit.ts b/apps/sim/blocks/blocks/reddit.ts index d2ddb1d908e..a9e44008065 100644 --- a/apps/sim/blocks/blocks/reddit.ts +++ b/apps/sim/blocks/blocks/reddit.ts @@ -1,7 +1,7 @@ import { RedditIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { RedditResponse } from '@/tools/reddit/types' export const RedditBlock: BlockConfig = { @@ -13,6 +13,8 @@ export const RedditBlock: BlockConfig = { 'Integrate Reddit into workflows. Read posts, comments, and search content. Submit posts, vote, reply, edit, manage messages, and access user and subreddit info.', docsLink: 'https://docs.sim.ai/tools/reddit', category: 'tools', + integrationType: IntegrationType.Social, + tags: ['content-management', 'web-scraping'], bgColor: '#FF5700', icon: RedditIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/redis.ts b/apps/sim/blocks/blocks/redis.ts index 1b105dac5f3..8149fb4c6da 100644 --- a/apps/sim/blocks/blocks/redis.ts +++ b/apps/sim/blocks/blocks/redis.ts @@ -1,6 +1,6 @@ import { RedisIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { RedisCommandResponse, RedisDeleteResponse, @@ -81,6 +81,8 @@ export const RedisBlock: BlockConfig = { 'Connect to any Redis instance to perform key-value, hash, list, and utility operations via a direct connection.', docsLink: 'https://docs.sim.ai/tools/redis', category: 'tools', + integrationType: IntegrationType.Databases, + tags: ['cloud', 'data-warehouse'], bgColor: '#FF4438', authMode: AuthMode.ApiKey, icon: RedisIcon, diff --git a/apps/sim/blocks/blocks/reducto.ts b/apps/sim/blocks/blocks/reducto.ts index d0c6ed7ce3f..cd666fa739c 100644 --- a/apps/sim/blocks/blocks/reducto.ts +++ b/apps/sim/blocks/blocks/reducto.ts @@ -1,5 +1,5 @@ import { ReductoIcon } from '@/components/icons' -import { AuthMode, type BlockConfig, type SubBlockType } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType, type SubBlockType } from '@/blocks/types' import { createVersionedToolSelector, normalizeFileInput } from '@/blocks/utils' import type { ReductoParserOutput } from '@/tools/reducto/types' @@ -12,6 +12,8 @@ export const ReductoBlock: BlockConfig = { longDescription: `Integrate Reducto Parse into the workflow. Can extract text from uploaded PDF documents, or from a URL.`, docsLink: 'https://docs.sim.ai/tools/reducto', category: 'tools', + integrationType: IntegrationType.AI, + tags: ['document-processing', 'ocr'], bgColor: '#5c0c5c', icon: ReductoIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/resend.ts b/apps/sim/blocks/blocks/resend.ts index 75a06bcfaaa..db3b77506a9 100644 --- a/apps/sim/blocks/blocks/resend.ts +++ b/apps/sim/blocks/blocks/resend.ts @@ -1,6 +1,6 @@ import { ResendIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' export const ResendBlock: BlockConfig = { type: 'resend', @@ -10,6 +10,8 @@ export const ResendBlock: BlockConfig = { 'Integrate Resend into your workflow. Send emails, retrieve email status, manage contacts, and view domains. Requires API Key.', docsLink: 'https://docs.sim.ai/tools/resend', category: 'tools', + integrationType: IntegrationType.Email, + tags: ['email-marketing', 'messaging'], bgColor: '#181C1E', icon: ResendIcon, authMode: AuthMode.ApiKey, diff --git a/apps/sim/blocks/blocks/revenuecat.ts b/apps/sim/blocks/blocks/revenuecat.ts index b6e645c42b5..c99b5cf6917 100644 --- a/apps/sim/blocks/blocks/revenuecat.ts +++ b/apps/sim/blocks/blocks/revenuecat.ts @@ -1,6 +1,6 @@ import { RevenueCatIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { RevenueCatResponse } from '@/tools/revenuecat/types' export const RevenueCatBlock: BlockConfig = { @@ -12,6 +12,8 @@ export const RevenueCatBlock: BlockConfig = { 'Integrate RevenueCat into the workflow. Manage subscribers, entitlements, offerings, and Google Play subscriptions. Retrieve customer subscription status, grant or revoke promotional entitlements, record purchases, update subscriber attributes, and manage Google Play subscription billing.', docsLink: 'https://docs.sim.ai/tools/revenuecat', category: 'tools', + integrationType: IntegrationType.Ecommerce, + tags: ['payments', 'subscriptions'], bgColor: '#F25A5A', icon: RevenueCatIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/rss.ts b/apps/sim/blocks/blocks/rss.ts index d91f8a6b82a..8f1214e4837 100644 --- a/apps/sim/blocks/blocks/rss.ts +++ b/apps/sim/blocks/blocks/rss.ts @@ -1,5 +1,6 @@ import { RssIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' import { getTrigger } from '@/triggers' export const RssBlock: BlockConfig = { @@ -9,6 +10,8 @@ export const RssBlock: BlockConfig = { longDescription: 'Subscribe to any RSS or Atom feed and automatically trigger your workflow when new content is published. Perfect for monitoring blogs, news sites, podcasts, and any content that publishes an RSS feed.', category: 'triggers', + integrationType: IntegrationType.Search, + tags: ['content-management', 'automation'], bgColor: '#F97316', icon: RssIcon, triggerAllowed: true, diff --git a/apps/sim/blocks/blocks/s3.ts b/apps/sim/blocks/blocks/s3.ts index 30fabd9d3e5..5e93cdef6e9 100644 --- a/apps/sim/blocks/blocks/s3.ts +++ b/apps/sim/blocks/blocks/s3.ts @@ -1,6 +1,6 @@ import { S3Icon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { normalizeFileInput } from '@/blocks/utils' import type { S3Response } from '@/tools/s3/types' @@ -13,6 +13,8 @@ export const S3Block: BlockConfig = { 'Integrate S3 into the workflow. Upload files, download objects, list bucket contents, delete objects, and copy objects between buckets. Requires AWS access key and secret access key.', docsLink: 'https://docs.sim.ai/tools/s3', category: 'tools', + integrationType: IntegrationType.FileStorage, + tags: ['cloud', 'data-warehouse'], bgColor: 'linear-gradient(45deg, #1B660F 0%, #6CAE3E 100%)', icon: S3Icon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/salesforce.ts b/apps/sim/blocks/blocks/salesforce.ts index f6bbd422e63..53a9d67adae 100644 --- a/apps/sim/blocks/blocks/salesforce.ts +++ b/apps/sim/blocks/blocks/salesforce.ts @@ -1,7 +1,7 @@ import { SalesforceIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { SalesforceResponse } from '@/tools/salesforce/types' export const SalesforceBlock: BlockConfig = { @@ -13,6 +13,8 @@ export const SalesforceBlock: BlockConfig = { 'Integrate Salesforce into your workflow. Manage accounts, contacts, leads, opportunities, cases, and tasks with powerful automation capabilities.', docsLink: 'https://docs.sim.ai/tools/salesforce', category: 'tools', + integrationType: IntegrationType.CRM, + tags: ['sales-engagement', 'customer-support'], bgColor: '#E0E0E0', icon: SalesforceIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/search.ts b/apps/sim/blocks/blocks/search.ts index 9ec8dbe4822..70f82ab211b 100644 --- a/apps/sim/blocks/blocks/search.ts +++ b/apps/sim/blocks/blocks/search.ts @@ -1,5 +1,6 @@ import { SearchIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' export const SearchBlock: BlockConfig = { type: 'search', @@ -9,6 +10,8 @@ export const SearchBlock: BlockConfig = { bgColor: '#3B82F6', icon: SearchIcon, category: 'tools', + integrationType: IntegrationType.Search, + tags: ['web-scraping', 'seo'], docsLink: 'https://docs.sim.ai/tools/search', subBlocks: [ { diff --git a/apps/sim/blocks/blocks/sendgrid.ts b/apps/sim/blocks/blocks/sendgrid.ts index 29a58c2564e..37c151702b0 100644 --- a/apps/sim/blocks/blocks/sendgrid.ts +++ b/apps/sim/blocks/blocks/sendgrid.ts @@ -1,5 +1,6 @@ import { SendgridIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' import { normalizeFileInput } from '@/blocks/utils' import type { SendMailResult } from '@/tools/sendgrid/types' @@ -11,6 +12,8 @@ export const SendGridBlock: BlockConfig = { 'Integrate SendGrid into your workflow. Send transactional emails, manage marketing contacts and lists, and work with email templates. Supports dynamic templates, attachments, and comprehensive contact management.', docsLink: 'https://docs.sim.ai/tools/sendgrid', category: 'tools', + integrationType: IntegrationType.Email, + tags: ['email-marketing', 'messaging'], bgColor: '#1A82E2', icon: SendgridIcon, diff --git a/apps/sim/blocks/blocks/sentry.ts b/apps/sim/blocks/blocks/sentry.ts index 8afe64d9607..19d3b5be4cf 100644 --- a/apps/sim/blocks/blocks/sentry.ts +++ b/apps/sim/blocks/blocks/sentry.ts @@ -1,6 +1,6 @@ import { SentryIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { SentryResponse } from '@/tools/sentry/types' export const SentryBlock: BlockConfig = { @@ -12,6 +12,8 @@ export const SentryBlock: BlockConfig = { 'Integrate Sentry into the workflow. Monitor issues, manage projects, track events, and coordinate releases across your applications.', docsLink: 'https://docs.sim.ai/tools/sentry', category: 'tools', + integrationType: IntegrationType.DeveloperTools, + tags: ['error-tracking', 'monitoring'], bgColor: '#E0E0E0', icon: SentryIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/serper.ts b/apps/sim/blocks/blocks/serper.ts index 202de8ef70b..b857dbe58a5 100644 --- a/apps/sim/blocks/blocks/serper.ts +++ b/apps/sim/blocks/blocks/serper.ts @@ -1,6 +1,6 @@ import { SerperIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { SearchResponse } from '@/tools/serper/types' export const SerperBlock: BlockConfig = { @@ -11,6 +11,8 @@ export const SerperBlock: BlockConfig = { longDescription: 'Integrate Serper into the workflow. Can search the web.', docsLink: 'https://docs.sim.ai/tools/serper', category: 'tools', + integrationType: IntegrationType.Search, + tags: ['web-scraping', 'seo'], bgColor: '#2B3543', icon: SerperIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/servicenow.ts b/apps/sim/blocks/blocks/servicenow.ts index 2a260d88c09..14376584725 100644 --- a/apps/sim/blocks/blocks/servicenow.ts +++ b/apps/sim/blocks/blocks/servicenow.ts @@ -1,5 +1,6 @@ import { ServiceNowIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' import type { ServiceNowResponse } from '@/tools/servicenow/types' export const ServiceNowBlock: BlockConfig = { @@ -10,6 +11,8 @@ export const ServiceNowBlock: BlockConfig = { 'Integrate ServiceNow into your workflow. Create, read, update, and delete records in any ServiceNow table including incidents, tasks, change requests, users, and more.', docsLink: 'https://docs.sim.ai/tools/servicenow', category: 'tools', + integrationType: IntegrationType.CustomerSupport, + tags: ['customer-support', 'ticketing', 'incident-management'], bgColor: '#032D42', icon: ServiceNowIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/sftp.ts b/apps/sim/blocks/blocks/sftp.ts index 0a868644d3e..18b3bd43f11 100644 --- a/apps/sim/blocks/blocks/sftp.ts +++ b/apps/sim/blocks/blocks/sftp.ts @@ -1,6 +1,6 @@ import { SftpIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { normalizeFileInput } from '@/blocks/utils' import type { SftpUploadResult } from '@/tools/sftp/types' @@ -12,6 +12,8 @@ export const SftpBlock: BlockConfig = { 'Upload, download, list, and manage files on remote servers via SFTP. Supports both password and private key authentication for secure file transfers.', docsLink: 'https://docs.sim.ai/tools/sftp', category: 'tools', + integrationType: IntegrationType.FileStorage, + tags: ['cloud', 'automation'], bgColor: '#2D3748', icon: SftpIcon, authMode: AuthMode.ApiKey, diff --git a/apps/sim/blocks/blocks/sharepoint.ts b/apps/sim/blocks/blocks/sharepoint.ts index 85ac2c34ba4..8813654588d 100644 --- a/apps/sim/blocks/blocks/sharepoint.ts +++ b/apps/sim/blocks/blocks/sharepoint.ts @@ -2,7 +2,7 @@ import { createLogger } from '@sim/logger' import { MicrosoftSharepointIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { normalizeFileInput } from '@/blocks/utils' import type { SharepointResponse } from '@/tools/sharepoint/types' @@ -17,6 +17,8 @@ export const SharepointBlock: BlockConfig = { 'Integrate SharePoint into the workflow. Read/create pages, list sites, and work with lists (read, create, update items). Requires OAuth.', docsLink: 'https://docs.sim.ai/tools/sharepoint', category: 'tools', + integrationType: IntegrationType.Documents, + tags: ['microsoft-365', 'content-management', 'document-processing'], bgColor: '#E0E0E0', icon: MicrosoftSharepointIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/shopify.ts b/apps/sim/blocks/blocks/shopify.ts index 7c4d12e7379..d21d414c8c5 100644 --- a/apps/sim/blocks/blocks/shopify.ts +++ b/apps/sim/blocks/blocks/shopify.ts @@ -1,7 +1,7 @@ import { ShopifyIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' interface ShopifyResponse { success: boolean @@ -18,6 +18,8 @@ export const ShopifyBlock: BlockConfig = { 'Integrate Shopify into your workflow. Manage products, orders, customers, and inventory. Create, read, update, and delete products. List and manage orders. Handle customer data and adjust inventory levels.', docsLink: 'https://docs.sim.ai/tools/shopify', category: 'tools', + integrationType: IntegrationType.Ecommerce, + tags: ['payments', 'subscriptions'], icon: ShopifyIcon, bgColor: '#FFFFFF', subBlocks: [ diff --git a/apps/sim/blocks/blocks/similarweb.ts b/apps/sim/blocks/blocks/similarweb.ts index 432b3a47125..a2af1b178f1 100644 --- a/apps/sim/blocks/blocks/similarweb.ts +++ b/apps/sim/blocks/blocks/similarweb.ts @@ -1,6 +1,6 @@ import { SimilarwebIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' export const SimilarwebBlock: BlockConfig = { type: 'similarweb', @@ -10,6 +10,8 @@ export const SimilarwebBlock: BlockConfig = { 'Access comprehensive website analytics including traffic estimates, engagement metrics, rankings, and traffic sources using the Similarweb API.', docsLink: 'https://developers.similarweb.com/docs/similarweb-web-traffic-api', category: 'tools', + integrationType: IntegrationType.Analytics, + tags: ['marketing', 'data-analytics', 'seo'], bgColor: '#000922', icon: SimilarwebIcon, authMode: AuthMode.ApiKey, diff --git a/apps/sim/blocks/blocks/slack.ts b/apps/sim/blocks/blocks/slack.ts index a455c8f0392..23edef24d9f 100644 --- a/apps/sim/blocks/blocks/slack.ts +++ b/apps/sim/blocks/blocks/slack.ts @@ -1,7 +1,7 @@ import { SlackIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { normalizeFileInput } from '@/blocks/utils' import type { SlackResponse } from '@/tools/slack/types' import { getTrigger } from '@/triggers' @@ -16,6 +16,8 @@ export const SlackBlock: BlockConfig = { 'Integrate Slack into the workflow. Can send, update, and delete messages, send ephemeral messages visible only to a specific user, open/update/push modal views, publish Home tab views, create canvases, read messages, and add or remove reactions. Requires Bot Token instead of OAuth in advanced mode. Can be used in trigger mode to trigger a workflow when a message is sent to a channel.', docsLink: 'https://docs.sim.ai/tools/slack', category: 'tools', + integrationType: IntegrationType.Communication, + tags: ['messaging', 'webhooks', 'automation'], bgColor: '#611f69', icon: SlackIcon, triggerAllowed: true, diff --git a/apps/sim/blocks/blocks/smtp.ts b/apps/sim/blocks/blocks/smtp.ts index 6537beb5c95..43aeb757135 100644 --- a/apps/sim/blocks/blocks/smtp.ts +++ b/apps/sim/blocks/blocks/smtp.ts @@ -1,6 +1,6 @@ import { SmtpIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { normalizeFileInput } from '@/blocks/utils' import type { SmtpSendMailResult } from '@/tools/smtp/types' @@ -12,6 +12,8 @@ export const SmtpBlock: BlockConfig = { 'Send emails using any SMTP server (Gmail, Outlook, custom servers, etc.). Configure SMTP connection settings and send emails with full control over content, recipients, and attachments.', docsLink: 'https://docs.sim.ai/tools/smtp', category: 'tools', + integrationType: IntegrationType.Email, + tags: ['email-marketing', 'messaging'], bgColor: '#2D3748', icon: SmtpIcon, authMode: AuthMode.ApiKey, diff --git a/apps/sim/blocks/blocks/spotify.ts b/apps/sim/blocks/blocks/spotify.ts index 61d0670f49e..2c4de8e7f22 100644 --- a/apps/sim/blocks/blocks/spotify.ts +++ b/apps/sim/blocks/blocks/spotify.ts @@ -1,6 +1,6 @@ import { SpotifyIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { normalizeFileInput } from '@/blocks/utils' import type { ToolResponse } from '@/tools/types' @@ -13,6 +13,8 @@ export const SpotifyBlock: BlockConfig = { 'Integrate Spotify into your workflow. Search for tracks, albums, artists, and playlists. Manage playlists, access your library, control playback, browse podcasts and audiobooks.', docsLink: 'https://docs.sim.ai/tools/spotify', category: 'tools', + integrationType: IntegrationType.Media, + tags: ['content-management', 'automation'], hideFromToolbar: true, bgColor: '#000000', icon: SpotifyIcon, diff --git a/apps/sim/blocks/blocks/sqs.ts b/apps/sim/blocks/blocks/sqs.ts index 72f6ccacdc4..cc65c3f038a 100644 --- a/apps/sim/blocks/blocks/sqs.ts +++ b/apps/sim/blocks/blocks/sqs.ts @@ -1,5 +1,6 @@ import { SQSIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' import type { SqsResponse } from '@/tools/sqs/types' export const SQSBlock: BlockConfig = { @@ -9,6 +10,8 @@ export const SQSBlock: BlockConfig = { longDescription: 'Integrate Amazon SQS into the workflow. Can send messages to SQS queues.', docsLink: 'https://docs.sim.ai/tools/sqs', category: 'tools', + integrationType: IntegrationType.DeveloperTools, + tags: ['cloud', 'messaging', 'automation'], bgColor: 'linear-gradient(45deg, #2E27AD 0%, #527FFF 100%)', icon: SQSIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/ssh.ts b/apps/sim/blocks/blocks/ssh.ts index eb7e975d213..6e80f4a88ca 100644 --- a/apps/sim/blocks/blocks/ssh.ts +++ b/apps/sim/blocks/blocks/ssh.ts @@ -1,6 +1,6 @@ import { SshIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { SSHResponse } from '@/tools/ssh/types' export const SSHBlock: BlockConfig = { @@ -12,6 +12,8 @@ export const SSHBlock: BlockConfig = { 'Execute commands, transfer files, and manage remote servers via SSH. Supports password and private key authentication for secure server access.', docsLink: 'https://docs.sim.ai/tools/ssh', category: 'tools', + integrationType: IntegrationType.DeveloperTools, + tags: ['cloud', 'automation'], bgColor: '#000000', icon: SshIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/stagehand.ts b/apps/sim/blocks/blocks/stagehand.ts index c5764533602..118a2104857 100644 --- a/apps/sim/blocks/blocks/stagehand.ts +++ b/apps/sim/blocks/blocks/stagehand.ts @@ -1,5 +1,5 @@ import { StagehandIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' import type { ToolResponse } from '@/tools/types' export interface StagehandExtractResponse extends ToolResponse { @@ -35,6 +35,8 @@ export const StagehandBlock: BlockConfig = { 'Integrate Stagehand into the workflow. Can extract structured data from webpages or run an autonomous agent to perform tasks.', docsLink: 'https://docs.sim.ai/tools/stagehand', category: 'tools', + integrationType: IntegrationType.Automation, + tags: ['web-scraping', 'automation', 'agentic'], bgColor: '#FFC83C', icon: StagehandIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/stripe.ts b/apps/sim/blocks/blocks/stripe.ts index 9377e56ef76..1ffd43ab495 100644 --- a/apps/sim/blocks/blocks/stripe.ts +++ b/apps/sim/blocks/blocks/stripe.ts @@ -1,6 +1,6 @@ import { StripeIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { StripeResponse } from '@/tools/stripe/types' import { getTrigger } from '@/triggers' @@ -13,6 +13,8 @@ export const StripeBlock: BlockConfig = { 'Integrates Stripe into the workflow. Manage payment intents, customers, subscriptions, invoices, charges, products, prices, and events. Can be used in trigger mode to trigger a workflow when a Stripe event occurs.', docsLink: 'https://docs.sim.ai/tools/stripe', category: 'tools', + integrationType: IntegrationType.Ecommerce, + tags: ['payments', 'subscriptions', 'webhooks'], bgColor: '#635BFF', icon: StripeIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/stt.ts b/apps/sim/blocks/blocks/stt.ts index dd22afb291f..1f6a3820fcd 100644 --- a/apps/sim/blocks/blocks/stt.ts +++ b/apps/sim/blocks/blocks/stt.ts @@ -1,5 +1,5 @@ import { STTIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' import { createVersionedToolSelector, normalizeFileInput } from '@/blocks/utils' import type { SttBlockResponse } from '@/tools/stt/types' @@ -13,6 +13,8 @@ export const SttBlock: BlockConfig = { 'Transcribe audio and video files to text using leading AI providers. Supports multiple languages, timestamps, and speaker diarization.', docsLink: 'https://docs.sim.ai/tools/stt', category: 'tools', + integrationType: IntegrationType.AI, + tags: ['speech-to-text', 'document-processing'], bgColor: '#181C1E', icon: STTIcon, diff --git a/apps/sim/blocks/blocks/supabase.ts b/apps/sim/blocks/blocks/supabase.ts index 84ec3c0e3b8..2ef6b973ad7 100644 --- a/apps/sim/blocks/blocks/supabase.ts +++ b/apps/sim/blocks/blocks/supabase.ts @@ -1,6 +1,6 @@ import { createLogger } from '@sim/logger' import { SupabaseIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' import { normalizeFileInput } from '@/blocks/utils' import type { SupabaseResponse } from '@/tools/supabase/types' @@ -15,6 +15,8 @@ export const SupabaseBlock: BlockConfig = { 'Integrate Supabase into the workflow. Supports database operations (query, insert, update, delete, upsert), full-text search, RPC functions, row counting, vector search, and complete storage management (upload, download, list, move, copy, delete files and buckets).', docsLink: 'https://docs.sim.ai/tools/supabase', category: 'tools', + integrationType: IntegrationType.Databases, + tags: ['cloud', 'data-warehouse', 'vector-search'], bgColor: '#1C1C1C', icon: SupabaseIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/tavily.ts b/apps/sim/blocks/blocks/tavily.ts index 11731b6ab1f..549a67c3db9 100644 --- a/apps/sim/blocks/blocks/tavily.ts +++ b/apps/sim/blocks/blocks/tavily.ts @@ -1,6 +1,6 @@ import { TavilyIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { TavilyResponse } from '@/tools/tavily/types' export const TavilyBlock: BlockConfig = { @@ -11,6 +11,8 @@ export const TavilyBlock: BlockConfig = { longDescription: 'Integrate Tavily into the workflow. Can search the web and extract content from specific URLs. Requires API Key.', category: 'tools', + integrationType: IntegrationType.Search, + tags: ['web-scraping', 'enrichment'], docsLink: 'https://docs.sim.ai/tools/tavily', bgColor: '#0066FF', icon: TavilyIcon, diff --git a/apps/sim/blocks/blocks/telegram.ts b/apps/sim/blocks/blocks/telegram.ts index ce4076d3849..8e720f2c68f 100644 --- a/apps/sim/blocks/blocks/telegram.ts +++ b/apps/sim/blocks/blocks/telegram.ts @@ -1,6 +1,6 @@ import { TelegramIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { normalizeFileInput } from '@/blocks/utils' import type { TelegramResponse } from '@/tools/telegram/types' import { getTrigger } from '@/triggers' @@ -14,6 +14,8 @@ export const TelegramBlock: BlockConfig = { 'Integrate Telegram into the workflow. Can send and delete messages. Can be used in trigger mode to trigger a workflow when a message is sent to a chat.', docsLink: 'https://docs.sim.ai/tools/telegram', category: 'tools', + integrationType: IntegrationType.Communication, + tags: ['messaging', 'webhooks', 'automation'], bgColor: '#E0E0E0', icon: TelegramIcon, triggerAllowed: true, diff --git a/apps/sim/blocks/blocks/textract.ts b/apps/sim/blocks/blocks/textract.ts index a2eea305049..e21d646ee9a 100644 --- a/apps/sim/blocks/blocks/textract.ts +++ b/apps/sim/blocks/blocks/textract.ts @@ -1,5 +1,5 @@ import { TextractIcon } from '@/components/icons' -import { AuthMode, type BlockConfig, type SubBlockType } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType, type SubBlockType } from '@/blocks/types' import { createVersionedToolSelector, normalizeFileInput } from '@/blocks/utils' import type { TextractParserOutput } from '@/tools/textract/types' @@ -12,6 +12,8 @@ export const TextractBlock: BlockConfig = { longDescription: `Integrate AWS Textract into your workflow to extract text, tables, forms, and key-value pairs from documents. Single-page mode supports JPEG, PNG, and single-page PDF. Multi-page mode supports multi-page PDF and TIFF.`, docsLink: 'https://docs.sim.ai/tools/textract', category: 'tools', + integrationType: IntegrationType.AI, + tags: ['document-processing', 'ocr', 'cloud'], bgColor: 'linear-gradient(135deg, #055F4E 0%, #56C0A7 100%)', icon: TextractIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/tinybird.ts b/apps/sim/blocks/blocks/tinybird.ts index 436543de76f..e1b1e08d4da 100644 --- a/apps/sim/blocks/blocks/tinybird.ts +++ b/apps/sim/blocks/blocks/tinybird.ts @@ -1,6 +1,6 @@ import { TinybirdIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { TinybirdResponse } from '@/tools/tinybird/types' export const TinybirdBlock: BlockConfig = { @@ -12,6 +12,8 @@ export const TinybirdBlock: BlockConfig = { 'Interact with Tinybird using the Events API to stream JSON or NDJSON events, or use the Query API to execute SQL queries against Pipes and Data Sources.', docsLink: 'https://www.tinybird.co/docs/api-reference', category: 'tools', + integrationType: IntegrationType.Analytics, + tags: ['data-warehouse', 'data-analytics'], bgColor: '#2EF598', icon: TinybirdIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/translate.ts b/apps/sim/blocks/blocks/translate.ts index a47a2e06ef4..b29079be194 100644 --- a/apps/sim/blocks/blocks/translate.ts +++ b/apps/sim/blocks/blocks/translate.ts @@ -1,5 +1,5 @@ import { TranslateIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' import { getModelOptions, getProviderCredentialSubBlocks, @@ -17,6 +17,8 @@ export const TranslateBlock: BlockConfig = { longDescription: 'Integrate Translate into the workflow. Can translate text to any language.', docsLink: 'https://docs.sim.ai/tools/translate', category: 'tools', + integrationType: IntegrationType.AI, + tags: ['document-processing', 'llm'], bgColor: '#FF4B4B', icon: TranslateIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/trello.ts b/apps/sim/blocks/blocks/trello.ts index 0e4180d557a..c0d9511bfcc 100644 --- a/apps/sim/blocks/blocks/trello.ts +++ b/apps/sim/blocks/blocks/trello.ts @@ -1,7 +1,7 @@ import { TrelloIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { ToolResponse } from '@/tools/types' /** @@ -21,6 +21,8 @@ export const TrelloBlock: BlockConfig = { 'Integrate with Trello to manage boards and cards. List boards, list cards, create cards, update cards, get actions, and add comments.', docsLink: 'https://docs.sim.ai/tools/trello', category: 'tools', + integrationType: IntegrationType.Productivity, + tags: ['project-management', 'ticketing'], bgColor: '#0052CC', icon: TrelloIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/tts.ts b/apps/sim/blocks/blocks/tts.ts index eebc8acd3e5..c6fea970e79 100644 --- a/apps/sim/blocks/blocks/tts.ts +++ b/apps/sim/blocks/blocks/tts.ts @@ -1,5 +1,5 @@ import { TTSIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' import type { TtsBlockResponse } from '@/tools/tts/types' export const TtsBlock: BlockConfig = { @@ -11,6 +11,8 @@ export const TtsBlock: BlockConfig = { 'Generate natural-sounding speech from text using state-of-the-art AI voices from OpenAI, Deepgram, ElevenLabs, Cartesia, Google Cloud, Azure, and PlayHT. Supports multiple voices, languages, and audio formats.', docsLink: 'https://docs.sim.ai/tools/tts', category: 'tools', + integrationType: IntegrationType.AI, + tags: ['text-to-speech', 'llm'], bgColor: '#181C1E', icon: TTSIcon, diff --git a/apps/sim/blocks/blocks/twilio.ts b/apps/sim/blocks/blocks/twilio.ts index 8f5db2d9b08..2b620559977 100644 --- a/apps/sim/blocks/blocks/twilio.ts +++ b/apps/sim/blocks/blocks/twilio.ts @@ -1,6 +1,6 @@ import { TwilioIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { TwilioSMSBlockOutput } from '@/tools/twilio/types' export const TwilioSMSBlock: BlockConfig = { @@ -10,6 +10,8 @@ export const TwilioSMSBlock: BlockConfig = { authMode: AuthMode.ApiKey, longDescription: 'Integrate Twilio into the workflow. Can send SMS messages.', category: 'tools', + integrationType: IntegrationType.Communication, + tags: ['messaging', 'automation'], docsLink: 'https://docs.sim.ai/tools/twilio', bgColor: '#F22F46', // Twilio brand color icon: TwilioIcon, diff --git a/apps/sim/blocks/blocks/twilio_voice.ts b/apps/sim/blocks/blocks/twilio_voice.ts index b9692c1089c..3a4c4b85bf0 100644 --- a/apps/sim/blocks/blocks/twilio_voice.ts +++ b/apps/sim/blocks/blocks/twilio_voice.ts @@ -1,6 +1,6 @@ import { TwilioIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { ToolResponse } from '@/tools/types' import { getTrigger } from '@/triggers' @@ -12,6 +12,8 @@ export const TwilioVoiceBlock: BlockConfig = { longDescription: 'Integrate Twilio Voice into the workflow. Make outbound calls and retrieve call recordings.', category: 'tools', + integrationType: IntegrationType.Communication, + tags: ['messaging', 'text-to-speech'], docsLink: 'https://docs.sim.ai/tools/twilio_voice', bgColor: '#F22F46', // Twilio brand color icon: TwilioIcon, diff --git a/apps/sim/blocks/blocks/typeform.ts b/apps/sim/blocks/blocks/typeform.ts index f0c0a58de68..cb707c349b3 100644 --- a/apps/sim/blocks/blocks/typeform.ts +++ b/apps/sim/blocks/blocks/typeform.ts @@ -1,6 +1,6 @@ import { TypeformIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { TypeformResponse } from '@/tools/typeform/types' import { getTrigger } from '@/triggers' @@ -13,6 +13,8 @@ export const TypeformBlock: BlockConfig = { 'Integrate Typeform into the workflow. Can retrieve responses, download files, and get form insights. Can be used in trigger mode to trigger a workflow when a form is submitted. Requires API Key.', docsLink: 'https://docs.sim.ai/tools/typeform', category: 'tools', + integrationType: IntegrationType.Documents, + tags: ['forms', 'data-analytics'], bgColor: '#262627', // Typeform brand color icon: TypeformIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/upstash.ts b/apps/sim/blocks/blocks/upstash.ts index e5afc6e7baf..040377d9625 100644 --- a/apps/sim/blocks/blocks/upstash.ts +++ b/apps/sim/blocks/blocks/upstash.ts @@ -1,6 +1,6 @@ import { UpstashIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { UpstashRedisCommandResponse, UpstashRedisDeleteResponse, @@ -46,6 +46,8 @@ export const UpstashBlock: BlockConfig = { 'Connect to Upstash Redis to perform key-value, hash, list, and utility operations via the REST API.', docsLink: 'https://docs.sim.ai/tools/upstash', category: 'tools', + integrationType: IntegrationType.Databases, + tags: ['cloud', 'data-warehouse'], bgColor: '#181C1E', authMode: AuthMode.ApiKey, icon: UpstashIcon, diff --git a/apps/sim/blocks/blocks/vercel.ts b/apps/sim/blocks/blocks/vercel.ts index c49e37d0172..0a89cc24c34 100644 --- a/apps/sim/blocks/blocks/vercel.ts +++ b/apps/sim/blocks/blocks/vercel.ts @@ -1,6 +1,6 @@ import { VercelIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' export const VercelBlock: BlockConfig = { type: 'vercel', @@ -10,6 +10,8 @@ export const VercelBlock: BlockConfig = { 'Integrate with Vercel to manage deployments, projects, domains, DNS records, environment variables, aliases, edge configs, teams, and more.', docsLink: 'https://docs.sim.ai/tools/vercel', category: 'tools', + integrationType: IntegrationType.DeveloperTools, + tags: ['cloud', 'ci-cd'], bgColor: '#171717', icon: VercelIcon, authMode: AuthMode.ApiKey, diff --git a/apps/sim/blocks/blocks/video_generator.ts b/apps/sim/blocks/blocks/video_generator.ts index 55c5a247203..cc7141f3371 100644 --- a/apps/sim/blocks/blocks/video_generator.ts +++ b/apps/sim/blocks/blocks/video_generator.ts @@ -1,5 +1,5 @@ import { VideoIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' import { normalizeFileInput } from '@/blocks/utils' import type { VideoBlockResponse } from '@/tools/video/types' @@ -13,6 +13,8 @@ export const VideoGeneratorBlock: BlockConfig = { 'Generate high-quality videos from text prompts using leading AI providers. Supports multiple models, aspect ratios, resolutions, and provider-specific features like world consistency, camera controls, and audio generation.', docsLink: 'https://docs.sim.ai/tools/video-generator', category: 'tools', + integrationType: IntegrationType.AI, + tags: ['video-generation', 'llm'], bgColor: '#181C1E', icon: VideoIcon, diff --git a/apps/sim/blocks/blocks/vision.ts b/apps/sim/blocks/blocks/vision.ts index 6c35fd613a0..46c910ad8f4 100644 --- a/apps/sim/blocks/blocks/vision.ts +++ b/apps/sim/blocks/blocks/vision.ts @@ -1,6 +1,6 @@ import { EyeIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { createVersionedToolSelector, normalizeFileInput } from '@/blocks/utils' import type { VisionResponse } from '@/tools/vision/types' @@ -30,6 +30,8 @@ export const VisionBlock: BlockConfig = { longDescription: 'Integrate Vision into the workflow. Can analyze images with vision models.', docsLink: 'https://docs.sim.ai/tools/vision', category: 'tools', + integrationType: IntegrationType.AI, + tags: ['llm', 'document-processing', 'ocr'], bgColor: '#4D5FFF', icon: EyeIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/wealthbox.ts b/apps/sim/blocks/blocks/wealthbox.ts index 0a70229ead6..abdb86bca24 100644 --- a/apps/sim/blocks/blocks/wealthbox.ts +++ b/apps/sim/blocks/blocks/wealthbox.ts @@ -1,7 +1,7 @@ import { WealthboxIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { WealthboxResponse } from '@/tools/wealthbox/types' export const WealthboxBlock: BlockConfig = { @@ -13,6 +13,8 @@ export const WealthboxBlock: BlockConfig = { 'Integrate Wealthbox into the workflow. Can read and write notes, read and write contacts, and read and write tasks.', docsLink: 'https://docs.sim.ai/tools/wealthbox', category: 'tools', + integrationType: IntegrationType.CRM, + tags: ['sales-engagement', 'customer-support'], bgColor: '#E0E0E0', icon: WealthboxIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/webflow.ts b/apps/sim/blocks/blocks/webflow.ts index 6c2afb6577f..db6e7978cb3 100644 --- a/apps/sim/blocks/blocks/webflow.ts +++ b/apps/sim/blocks/blocks/webflow.ts @@ -1,7 +1,7 @@ import { WebflowIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { WebflowResponse } from '@/tools/webflow/types' import { getTrigger } from '@/triggers' @@ -14,6 +14,8 @@ export const WebflowBlock: BlockConfig = { 'Integrates Webflow CMS into the workflow. Can create, get, list, update, or delete items in Webflow CMS collections. Manage your Webflow content programmatically. Can be used in trigger mode to trigger workflows when collection items change or forms are submitted.', docsLink: 'https://docs.sim.ai/tools/webflow', category: 'tools', + integrationType: IntegrationType.Design, + tags: ['content-management', 'seo'], triggerAllowed: true, bgColor: '#E0E0E0', icon: WebflowIcon, diff --git a/apps/sim/blocks/blocks/whatsapp.ts b/apps/sim/blocks/blocks/whatsapp.ts index 2a709f3594d..c42ea29d3d3 100644 --- a/apps/sim/blocks/blocks/whatsapp.ts +++ b/apps/sim/blocks/blocks/whatsapp.ts @@ -1,6 +1,6 @@ import { WhatsAppIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { WhatsAppResponse } from '@/tools/whatsapp/types' import { getTrigger } from '@/triggers' @@ -12,6 +12,8 @@ export const WhatsAppBlock: BlockConfig = { longDescription: 'Integrate WhatsApp into the workflow. Can send messages.', docsLink: 'https://docs.sim.ai/tools/whatsapp', category: 'tools', + integrationType: IntegrationType.Communication, + tags: ['messaging', 'automation'], bgColor: '#25D366', icon: WhatsAppIcon, triggerAllowed: true, diff --git a/apps/sim/blocks/blocks/wikipedia.ts b/apps/sim/blocks/blocks/wikipedia.ts index 9fbcea81434..2965d4083a4 100644 --- a/apps/sim/blocks/blocks/wikipedia.ts +++ b/apps/sim/blocks/blocks/wikipedia.ts @@ -1,5 +1,6 @@ import { WikipediaIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' import type { WikipediaResponse } from '@/tools/wikipedia/types' export const WikipediaBlock: BlockConfig = { @@ -10,6 +11,8 @@ export const WikipediaBlock: BlockConfig = { 'Integrate Wikipedia into the workflow. Can get page summary, search pages, get page content, and get random page.', docsLink: 'https://docs.sim.ai/tools/wikipedia', category: 'tools', + integrationType: IntegrationType.Search, + tags: ['knowledge-base', 'web-scraping'], bgColor: '#000000', icon: WikipediaIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/wordpress.ts b/apps/sim/blocks/blocks/wordpress.ts index 305f0be30cb..58ea0629dcf 100644 --- a/apps/sim/blocks/blocks/wordpress.ts +++ b/apps/sim/blocks/blocks/wordpress.ts @@ -1,7 +1,7 @@ import { WordpressIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import { normalizeFileInput } from '@/blocks/utils' import type { WordPressResponse } from '@/tools/wordpress/types' @@ -14,6 +14,8 @@ export const WordPressBlock: BlockConfig = { 'Integrate with WordPress to create, update, and manage posts, pages, media, comments, categories, tags, and users. Supports WordPress.com sites via OAuth and self-hosted WordPress sites using Application Passwords authentication.', docsLink: 'https://docs.sim.ai/tools/wordpress', category: 'tools', + integrationType: IntegrationType.Design, + tags: ['content-management', 'seo'], bgColor: '#21759B', icon: WordpressIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/workday.ts b/apps/sim/blocks/blocks/workday.ts index b55e4e7fc0f..76d54900afb 100644 --- a/apps/sim/blocks/blocks/workday.ts +++ b/apps/sim/blocks/blocks/workday.ts @@ -1,5 +1,6 @@ import { WorkdayIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' +import { IntegrationType } from '@/blocks/types' export const WorkdayBlock: BlockConfig = { type: 'workday', @@ -9,6 +10,8 @@ export const WorkdayBlock: BlockConfig = { 'Integrate Workday HRIS into your workflow. Create pre-hires, hire employees, manage worker profiles, assign onboarding plans, handle job changes, retrieve compensation data, and process terminations.', docsLink: 'https://docs.sim.ai/tools/workday', category: 'tools', + integrationType: IntegrationType.HR, + tags: ['hiring', 'project-management'], bgColor: '#F5F0EB', icon: WorkdayIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/x.ts b/apps/sim/blocks/blocks/x.ts index e1d93077ece..d68e16249ee 100644 --- a/apps/sim/blocks/blocks/x.ts +++ b/apps/sim/blocks/blocks/x.ts @@ -1,7 +1,7 @@ import { xIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' export const XBlock: BlockConfig = { type: 'x', @@ -12,6 +12,8 @@ export const XBlock: BlockConfig = { 'Integrate X into the workflow. Search tweets, manage bookmarks, follow/block/mute users, like and retweet, view trends, and more.', docsLink: 'https://docs.sim.ai/tools/x', category: 'tools', + integrationType: IntegrationType.Social, + tags: ['marketing', 'messaging'], bgColor: '#000000', icon: xIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/youtube.ts b/apps/sim/blocks/blocks/youtube.ts index 243c80ef40d..856f4f5c22f 100644 --- a/apps/sim/blocks/blocks/youtube.ts +++ b/apps/sim/blocks/blocks/youtube.ts @@ -1,6 +1,6 @@ import { YouTubeIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { YouTubeResponse } from '@/tools/youtube/types' export const YouTubeBlock: BlockConfig = { @@ -12,6 +12,8 @@ export const YouTubeBlock: BlockConfig = { 'Integrate YouTube into the workflow. Can search for videos, get trending videos, get video details, get video categories, get channel information, get all videos from a channel, get channel playlists, get playlist items, and get video comments.', docsLink: 'https://docs.sim.ai/tools/youtube', category: 'tools', + integrationType: IntegrationType.Media, + tags: ['google-workspace', 'marketing', 'content-management'], bgColor: '#FF0000', icon: YouTubeIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/zendesk.ts b/apps/sim/blocks/blocks/zendesk.ts index bdd504e8069..1a994a6d4fa 100644 --- a/apps/sim/blocks/blocks/zendesk.ts +++ b/apps/sim/blocks/blocks/zendesk.ts @@ -1,6 +1,6 @@ import { ZendeskIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' export const ZendeskBlock: BlockConfig = { type: 'zendesk', @@ -11,6 +11,8 @@ export const ZendeskBlock: BlockConfig = { docsLink: 'https://docs.sim.ai/tools/zendesk', authMode: AuthMode.ApiKey, category: 'tools', + integrationType: IntegrationType.CustomerSupport, + tags: ['customer-support', 'ticketing'], bgColor: '#E0E0E0', icon: ZendeskIcon, subBlocks: [ diff --git a/apps/sim/blocks/blocks/zep.ts b/apps/sim/blocks/blocks/zep.ts index bd3f43f66aa..a944fe5956d 100644 --- a/apps/sim/blocks/blocks/zep.ts +++ b/apps/sim/blocks/blocks/zep.ts @@ -1,5 +1,5 @@ import { ZepIcon } from '@/components/icons' -import { AuthMode, type BlockConfig } from '@/blocks/types' +import { AuthMode, type BlockConfig, IntegrationType } from '@/blocks/types' import type { ZepResponse } from '@/tools/zep/types' export const ZepBlock: BlockConfig = { @@ -12,6 +12,8 @@ export const ZepBlock: BlockConfig = { bgColor: '#E8E8E8', icon: ZepIcon, category: 'tools', + integrationType: IntegrationType.AI, + tags: ['llm', 'knowledge-base', 'agentic'], docsLink: 'https://docs.sim.ai/tools/zep', subBlocks: [ { diff --git a/apps/sim/blocks/blocks/zoom.ts b/apps/sim/blocks/blocks/zoom.ts index 4d9ecbd21dd..5c77ac856ed 100644 --- a/apps/sim/blocks/blocks/zoom.ts +++ b/apps/sim/blocks/blocks/zoom.ts @@ -1,7 +1,7 @@ import { ZoomIcon } from '@/components/icons' import { getScopesForService } from '@/lib/oauth/utils' import type { BlockConfig } from '@/blocks/types' -import { AuthMode } from '@/blocks/types' +import { AuthMode, IntegrationType } from '@/blocks/types' import type { ZoomResponse } from '@/tools/zoom/types' export const ZoomBlock: BlockConfig = { @@ -13,6 +13,8 @@ export const ZoomBlock: BlockConfig = { 'Integrate Zoom into workflows. Create, list, update, and delete Zoom meetings. Get meeting details, invitations, recordings, and participants. Manage cloud recordings programmatically.', docsLink: 'https://docs.sim.ai/tools/zoom', category: 'tools', + integrationType: IntegrationType.Communication, + tags: ['meeting', 'calendar', 'scheduling'], bgColor: '#2D8CFF', icon: ZoomIcon, subBlocks: [ diff --git a/apps/sim/blocks/types.ts b/apps/sim/blocks/types.ts index 1ff68892ee1..0e02b26a17e 100644 --- a/apps/sim/blocks/types.ts +++ b/apps/sim/blocks/types.ts @@ -16,6 +16,80 @@ export type PrimitiveValueType = export type BlockCategory = 'blocks' | 'tools' | 'triggers' +export enum IntegrationType { + AI = 'ai', + Analytics = 'analytics', + Automation = 'automation', + Communication = 'communication', + CRM = 'crm', + CustomerSupport = 'customer-support', + Databases = 'databases', + Design = 'design', + DeveloperTools = 'developer-tools', + Documents = 'documents', + Ecommerce = 'ecommerce', + Email = 'email', + FileStorage = 'file-storage', + HR = 'hr', + Media = 'media', + Other = 'other', + Productivity = 'productivity', + SalesIntelligence = 'sales-intelligence', + Search = 'search', + Security = 'security', + Social = 'social', +} + +export type IntegrationTag = + | 'marketing' + | 'automation' + | 'webhooks' + | 'vector-search' + | 'meeting' + | 'calendar' + | 'scheduling' + | 'incident-management' + | 'monitoring' + | 'error-tracking' + | 'prediction-markets' + | 'document-processing' + | 'ocr' + | 'text-to-speech' + | 'speech-to-text' + | 'image-generation' + | 'video-generation' + | 'cloud' + | 'google-workspace' + | 'microsoft-365' + | 'data-warehouse' + | 'data-analytics' + | 'customer-support' + | 'project-management' + | 'ticketing' + | 'payments' + | 'subscriptions' + | 'enrichment' + | 'web-scraping' + | 'llm' + | 'messaging' + | 'version-control' + | 'ci-cd' + | 'note-taking' + | 'spreadsheet' + | 'seo' + | 'email-marketing' + | 'e-signatures' + | 'identity' + | 'secrets-management' + | 'hiring' + | 'sales-engagement' + | 'agentic' + | 'knowledge-base' + | 'content-management' + | 'forms' + | 'link-management' + | 'events' + // Authentication modes for sub-blocks and summaries export enum AuthMode { OAuth = 'oauth', @@ -351,6 +425,8 @@ export interface BlockConfig { name: string description: string category: BlockCategory + integrationType?: IntegrationType + tags?: IntegrationTag[] longDescription?: string bestPractices?: string docsLink?: string diff --git a/bun.lock b/bun.lock index cd5dc2f1e00..c55505f0ec9 100644 --- a/bun.lock +++ b/bun.lock @@ -10,7 +10,7 @@ "glob": "13.0.0", "husky": "9.1.7", "lint-staged": "16.0.0", - "turbo": "2.8.17", + "turbo": "2.8.20", }, }, "apps/docs": { @@ -1461,6 +1461,18 @@ "@trigger.dev/sdk": ["@trigger.dev/sdk@4.1.2", "", { "dependencies": { "@opentelemetry/api": "1.9.0", "@opentelemetry/semantic-conventions": "1.36.0", "@trigger.dev/core": "4.1.2", "chalk": "^5.2.0", "cronstrue": "^2.21.0", "debug": "^4.3.4", "evt": "^2.4.13", "slug": "^6.0.0", "ulid": "^2.3.0", "uncrypto": "^0.1.3", "uuid": "^9.0.0", "ws": "^8.11.0" }, "peerDependencies": { "ai": "^4.2.0 || ^5.0.0", "zod": "^3.0.0 || ^4.0.0" }, "optionalPeers": ["ai"] }, "sha512-BQLcskVAlUvOM4jN91PNpXtcmgjsHOL8IFes3aEt/fnBfnDRzRNIUlO+H4KkBy5/66pAOgODLmevMSCKd0keYw=="], + "@turbo/darwin-64": ["@turbo/darwin-64@2.8.20", "", { "os": "darwin", "cpu": "x64" }, "sha512-FQ9EX1xMU5nbwjxXxM3yU88AQQ6Sqc6S44exPRroMcx9XZHqqppl5ymJF0Ig/z3nvQNwDmz1Gsnvxubo+nXWjQ=="], + + "@turbo/darwin-arm64": ["@turbo/darwin-arm64@2.8.20", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Gpyh9ATFGThD6/s9L95YWY54cizg/VRWl2B67h0yofG8BpHf67DFAh9nuJVKG7bY0+SBJDAo5cMur+wOl9YOYw=="], + + "@turbo/linux-64": ["@turbo/linux-64@2.8.20", "", { "os": "linux", "cpu": "x64" }, "sha512-p2QxWUYyYUgUFG0b0kR+pPi8t7c9uaVlRtjTTI1AbCvVqkpjUfCcReBn6DgG/Hu8xrWdKLuyQFaLYFzQskZbcA=="], + + "@turbo/linux-arm64": ["@turbo/linux-arm64@2.8.20", "", { "os": "linux", "cpu": "arm64" }, "sha512-Gn5yjlZGLRZWarLWqdQzv0wMqyBNIdq1QLi48F1oY5Lo9kiohuf7BPQWtWxeNVS2NgJ1+nb/DzK1JduYC4AWOA=="], + + "@turbo/windows-64": ["@turbo/windows-64@2.8.20", "", { "os": "win32", "cpu": "x64" }, "sha512-vyaDpYk/8T6Qz5V/X+ihKvKFEZFUoC0oxYpC1sZanK6gaESJlmV3cMRT3Qhcg4D2VxvtC2Jjs9IRkrZGL+exLw=="], + + "@turbo/windows-arm64": ["@turbo/windows-arm64@2.8.20", "", { "os": "win32", "cpu": "arm64" }, "sha512-voicVULvUV5yaGXo0Iue13BcHGYW3u0VgqSbfQwBaHbpj1zLjYV4KIe+7fYIo6DO8FVUJzxFps3ODCQG/Wy2Qw=="], + "@tweenjs/tween.js": ["@tweenjs/tween.js@23.1.3", "", {}, "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA=="], "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], @@ -3539,19 +3551,7 @@ "tunnel-agent": ["tunnel-agent@0.6.0", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w=="], - "turbo": ["turbo@2.8.17", "", { "optionalDependencies": { "turbo-darwin-64": "2.8.17", "turbo-darwin-arm64": "2.8.17", "turbo-linux-64": "2.8.17", "turbo-linux-arm64": "2.8.17", "turbo-windows-64": "2.8.17", "turbo-windows-arm64": "2.8.17" }, "bin": { "turbo": "bin/turbo" } }, "sha512-YwPsNSqU2f/RXU/+Kcb7cPkPZARxom4+me7LKEdN5jsvy2tpfze3zDZ4EiGrJnvOm9Avu9rK0aaYsP7qZ3iz7A=="], - - "turbo-darwin-64": ["turbo-darwin-64@2.8.17", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZFkv2hv7zHpAPEXBF6ouRRXshllOavYc+jjcrYyVHvxVTTwJWsBZwJ/gpPzmOKGvkSjsEyDO5V6aqqtZzwVF+Q=="], - - "turbo-darwin-arm64": ["turbo-darwin-arm64@2.8.17", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5DXqhQUt24ycEryXDfMNKEkW5TBHs+QmU23a2qxXwwFDaJsWcPo2obEhBxxdEPOv7qmotjad+09RGeWCcJ9JDw=="], - - "turbo-linux-64": ["turbo-linux-64@2.8.17", "", { "os": "linux", "cpu": "x64" }, "sha512-KLUbz6w7F73D/Ihh51hVagrKR0/CTsPEbRkvXLXvoND014XJ4BCrQUqSxlQ4/hu+nqp1v5WlM85/h3ldeyujuA=="], - - "turbo-linux-arm64": ["turbo-linux-arm64@2.8.17", "", { "os": "linux", "cpu": "arm64" }, "sha512-pJK67XcNJH40lTAjFu7s/rUlobgVXyB3A3lDoq+/JccB3hf+SysmkpR4Itlc93s8LEaFAI4mamhFuTV17Z6wOg=="], - - "turbo-windows-64": ["turbo-windows-64@2.8.17", "", { "os": "win32", "cpu": "x64" }, "sha512-EijeQ6zszDMmGZLP2vT2RXTs/GVi9rM0zv2/G4rNu2SSRSGFapgZdxgW4b5zUYLVaSkzmkpWlGfPfj76SW9yUg=="], - - "turbo-windows-arm64": ["turbo-windows-arm64@2.8.17", "", { "os": "win32", "cpu": "arm64" }, "sha512-crpfeMPkfECd4V1PQ/hMoiyVcOy04+bWedu/if89S15WhOalHZ2BYUi6DOJhZrszY+mTT99OwpOsj4wNfb/GHQ=="], + "turbo": ["turbo@2.8.20", "", { "optionalDependencies": { "@turbo/darwin-64": "2.8.20", "@turbo/darwin-arm64": "2.8.20", "@turbo/linux-64": "2.8.20", "@turbo/linux-arm64": "2.8.20", "@turbo/windows-64": "2.8.20", "@turbo/windows-arm64": "2.8.20" }, "bin": { "turbo": "bin/turbo" } }, "sha512-Rb4qk5YT8RUwwdXtkLpkVhNEe/lor6+WV7S5tTlLpxSz6MjV5Qi8jGNn4gS6NAvrYGA/rNrE6YUQM85sCZUDbQ=="], "tweetnacl": ["tweetnacl@0.14.5", "", {}, "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA=="], diff --git a/package.json b/package.json index a3644a06b83..ac3b5cc61ba 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "glob": "13.0.0", "husky": "9.1.7", "lint-staged": "16.0.0", - "turbo": "2.8.17" + "turbo": "2.8.20" }, "lint-staged": { "*.{js,jsx,ts,tsx,json,css,scss}": [ diff --git a/scripts/generate-docs.ts b/scripts/generate-docs.ts index 2619b2c9a63..ddbad423d35 100755 --- a/scripts/generate-docs.ts +++ b/scripts/generate-docs.ts @@ -79,6 +79,8 @@ interface IntegrationEntry { triggerCount: number authType: 'oauth' | 'api-key' | 'none' category: string + integrationType?: string + tags?: string[] } /** @@ -592,6 +594,8 @@ async function writeIntegrationsJson(iconMapping: Record): Promi triggerCount: triggers.length, authType, category: config.category, + ...(config.integrationType ? { integrationType: config.integrationType } : {}), + ...(config.tags ? { tags: config.tags } : {}), }) } } @@ -759,9 +763,18 @@ function extractBlockConfigFromContent( const triggerIds = extractTriggersAvailable(blockContent) const docsLink = extractStringPropertyFromContent(blockContent, 'docsLink', true) || - (baseConfig as any)?.docsLink || + baseConfig?.docsLink || `https://docs.sim.ai/tools/${stripVersionSuffix(blockType)}` + const integrationType = + extractEnumPropertyFromContent(blockContent, 'integrationType') || + baseConfig?.integrationType || + null + const tags = + extractArrayPropertyFromContent(blockContent, 'tags') || + baseConfig?.tags || + null + return { type: blockType, name, @@ -777,6 +790,8 @@ function extractBlockConfigFromContent( operations: operations.length > 0 ? operations : (baseConfig as any)?.operations || [], triggerIds: triggerIds.length > 0 ? triggerIds : (baseConfig as any)?.triggerIds || [], docsLink, + ...(integrationType ? { integrationType } : {}), + ...(tags ? { tags } : {}), } } catch (error) { console.error(`Error extracting block configuration for ${blockName}:`, error) @@ -841,6 +856,54 @@ function extractStringPropertyFromContent( return null } +/** + * Extract an enum property value from block content. + * Matches patterns like `integrationType: IntegrationType.DeveloperTools` + * and returns the string value (e.g., 'developer-tools'). + */ +function extractEnumPropertyFromContent(content: string, propName: string): string | null { + const match = content.match(new RegExp(`${propName}\\s*:\\s*IntegrationType\\.(\\w+)`)) + if (!match) return null + const enumKey = match[1] + // Convert enum key to kebab-case value (e.g., DeveloperTools -> developer-tools) + const ENUM_MAP: Record = { + AI: 'ai', + Analytics: 'analytics', + Automation: 'automation', + Communication: 'communication', + CRM: 'crm', + CustomerSupport: 'customer-support', + Databases: 'databases', + Design: 'design', + DeveloperTools: 'developer-tools', + Documents: 'documents', + Ecommerce: 'ecommerce', + Email: 'email', + FileStorage: 'file-storage', + HR: 'hr', + Media: 'media', + Other: 'other', + Productivity: 'productivity', + SalesIntelligence: 'sales-intelligence', + Search: 'search', + Security: 'security', + Social: 'social', + } + return ENUM_MAP[enumKey] || enumKey.toLowerCase() +} + +/** + * Extract a string array property from block content. + * Matches patterns like `tags: ['api', 'oauth', 'webhooks']` + */ +function extractArrayPropertyFromContent(content: string, propName: string): string[] | null { + const match = content.match(new RegExp(`${propName}\\s*:\\s*\\[([^\\]]+)\\]`)) + if (!match) return null + const items = match[1].match(/'([^']+)'|"([^"]+)"/g) + if (!items) return null + return items.map((item) => item.replace(/['"]/g, '')) +} + function extractIconNameFromContent(content: string): string | null { const iconMatch = content.match(/icon\s*:\s*(\w+Icon)/) return iconMatch ? iconMatch[1] : null