@nuxtagentic/integrations 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/LICENSE.md +9 -0
  2. package/README.md +175 -2
  3. package/client.ts +124 -0
  4. package/module.ts +44 -0
  5. package/package.json +52 -3
  6. package/runtime/assets/logos/discord.svg +1 -0
  7. package/runtime/assets/logos/github.svg +1 -0
  8. package/runtime/assets/logos/gmail.svg +1 -0
  9. package/runtime/assets/logos/googleads.svg +1 -0
  10. package/runtime/assets/logos/googleanalytics.svg +1 -0
  11. package/runtime/assets/logos/googlecalendar.svg +1 -0
  12. package/runtime/assets/logos/googledrive.svg +1 -0
  13. package/runtime/assets/logos/googlesearchconsole.svg +1 -0
  14. package/runtime/assets/logos/hubspot.svg +1 -0
  15. package/runtime/assets/logos/intercom.svg +1 -0
  16. package/runtime/assets/logos/linear.svg +1 -0
  17. package/runtime/assets/logos/mcp.svg +1 -0
  18. package/runtime/assets/logos/meta.svg +1 -0
  19. package/runtime/assets/logos/notion.svg +1 -0
  20. package/runtime/assets/logos/reddit.svg +1 -0
  21. package/runtime/assets/logos/sentry.svg +1 -0
  22. package/runtime/assets/logos/shopify.svg +1 -0
  23. package/runtime/assets/logos/slack.svg +1 -0
  24. package/runtime/assets/logos/stripe.svg +1 -0
  25. package/runtime/assets/logos/tiktok-dark.svg +1 -0
  26. package/runtime/assets/logos/tiktok.svg +1 -0
  27. package/runtime/assets/logos/vercel.svg +1 -0
  28. package/runtime/assets/logos/x.svg +1 -0
  29. package/runtime/components/IntegrationCard.vue +82 -0
  30. package/runtime/components/IntegrationCatalog.vue +130 -0
  31. package/runtime/components/IntegrationConnectionPanel.vue +589 -0
  32. package/runtime/components/IntegrationLogo.vue +41 -0
  33. package/runtime/pages/integrations.vue +481 -0
  34. package/runtime/server/api/integrations/approvals/[id].post.ts +69 -0
  35. package/runtime/server/api/integrations/catalog/[provider]/action.post.ts +35 -0
  36. package/runtime/server/api/integrations/catalog/[provider]/connection.post.ts +242 -0
  37. package/runtime/server/api/integrations/catalog/[provider]/tools.get.ts +40 -0
  38. package/runtime/server/api/integrations/catalog/index.get.ts +48 -0
  39. package/runtime/server/api/integrations/catalog/tools.get.ts +27 -0
  40. package/runtime/server/plugins/connect-maintenance.ts +30 -0
  41. package/runtime/server/utils/approval-continuation.ts +37 -0
  42. package/runtime/server/utils/google-mcp.ts +296 -0
  43. package/runtime/server/utils/integration-adapters.ts +836 -0
  44. package/runtime/server/utils/integration-context.ts +510 -0
  45. package/runtime/server/utils/integration-crypto.ts +13 -0
  46. package/runtime/server/utils/request-body.ts +38 -0
  47. package/runtime/shared/agent.ts +14 -0
  48. package/runtime/shared/catalog.ts +566 -0
  49. package/runtime/shared/google-mcp.ts +8 -0
  50. package/runtime/workspace.ts +15 -0
  51. package/schema.ts +179 -0
@@ -0,0 +1,130 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+ import type { IntegrationConnection } from '../../client'
4
+ import {
5
+ INTEGRATION_CATALOG,
6
+ INTEGRATION_CATEGORIES,
7
+ type IntegrationDefinition,
8
+ } from '../shared/catalog'
9
+ import IntegrationCard from './IntegrationCard.vue'
10
+
11
+ const tab = defineModel<string>('tab', { required: true })
12
+ const category = defineModel<string>('category', { required: true })
13
+ const search = defineModel<string>('search', { required: true })
14
+ const { connections, loading, error } = defineProps<{
15
+ connections: IntegrationConnection[]
16
+ loading?: boolean
17
+ error?: boolean
18
+ }>()
19
+ defineEmits<{ select: [integration: IntegrationDefinition, event: MouseEvent] }>()
20
+
21
+ const connectionsOf = (provider: string) =>
22
+ connections.filter((entry) => entry.provider === provider)
23
+ const isConnected = (provider: string) => connectionsOf(provider).some((entry) => entry.enabled)
24
+ const filteredCatalog = computed(() => {
25
+ const query = search.value.trim().toLowerCase()
26
+ return INTEGRATION_CATALOG.filter(
27
+ (entry) =>
28
+ (category.value === 'All' || entry.category === category.value) &&
29
+ `${entry.name} ${entry.category} ${entry.description}`.toLowerCase().includes(query),
30
+ )
31
+ })
32
+ const visible = computed(() =>
33
+ filteredCatalog.value.filter(
34
+ (entry) => tab.value === 'all' || (tab.value === 'connected') === isConnected(entry.id),
35
+ ),
36
+ )
37
+ const tabs = computed(() => {
38
+ const total = filteredCatalog.value.length
39
+ const connectedCount = filteredCatalog.value.filter((entry) => isConnected(entry.id)).length
40
+ return [
41
+ { label: 'All', value: 'all', count: total },
42
+ { label: 'Connected', value: 'connected', count: connectedCount },
43
+ { label: 'Available', value: 'available', count: total - connectedCount },
44
+ ]
45
+ })
46
+ const emptyMessage = computed(() => {
47
+ if (!filteredCatalog.value.length) {
48
+ return 'No integrations match your filters.'
49
+ }
50
+ return tab.value === 'connected'
51
+ ? 'No connected integrations here yet. Choose Available to connect an app.'
52
+ : 'All integrations here are connected. Choose Connected to manage them.'
53
+ })
54
+ </script>
55
+
56
+ <template>
57
+ <div class="flex flex-col gap-5">
58
+ <div class="flex flex-wrap items-center gap-3">
59
+ <UTabs
60
+ :model-value="tab"
61
+ :items="tabs"
62
+ :content="false"
63
+ color="neutral"
64
+ variant="pill"
65
+ aria-label="Integration status"
66
+ class="w-full sm:w-[350px]"
67
+ :ui="{
68
+ root: 'gap-0',
69
+ list: 'h-9 rounded-lg border border-(--gray-500) bg-(--gray-200) p-0.5',
70
+ trigger:
71
+ 'flex-auto cursor-pointer gap-2 rounded-md px-2 py-0 text-[13px] font-normal data-[state=active]:text-highlighted sm:px-3',
72
+ indicator: 'inset-y-0.5 rounded-md bg-(--gray-400) shadow-none ring-0',
73
+ }"
74
+ @update:model-value="tab = String($event)"
75
+ >
76
+ <template #trailing="{ item }">
77
+ <span class="text-xs text-dimmed tabular-nums group-data-[state=active]:text-muted">
78
+ {{ item.count }}
79
+ </span>
80
+ </template>
81
+ </UTabs>
82
+ <UInput
83
+ v-model="search"
84
+ icon="i-lucide-search"
85
+ placeholder="Search integrations"
86
+ aria-label="Search integrations"
87
+ class="w-full sm:ms-auto sm:w-60"
88
+ :ui="{ base: 'h-9 rounded-lg bg-transparent text-[13px]', leadingIcon: 'size-3.5' }"
89
+ />
90
+ </div>
91
+ <div class="flex flex-wrap gap-1.5">
92
+ <UButton
93
+ v-for="item in INTEGRATION_CATEGORIES"
94
+ :key="item"
95
+ :label="item"
96
+ color="neutral"
97
+ :variant="category === item ? 'soft' : 'ghost'"
98
+ class="h-7 rounded-full px-3 text-[13px] font-normal"
99
+ :class="category === item ? 'bg-(--gray-400) text-highlighted ring ring-(--gray-500)' : ''"
100
+ :aria-pressed="category === item"
101
+ @click="category = item"
102
+ />
103
+ </div>
104
+ <div
105
+ v-if="loading"
106
+ class="flex items-center gap-2 text-sm text-muted"
107
+ >
108
+ <UIcon
109
+ name="i-lucide-loader-circle"
110
+ class="size-4 animate-spin"
111
+ />
112
+ Loading connections…
113
+ </div>
114
+ <div class="grid grid-cols-[repeat(auto-fill,minmax(min(260px,100%),1fr))] gap-3">
115
+ <IntegrationCard
116
+ v-for="entry in visible"
117
+ :key="entry.id"
118
+ :integration="entry"
119
+ :connections="connectionsOf(entry.id)"
120
+ @select="$emit('select', entry, $event)"
121
+ />
122
+ </div>
123
+ <p
124
+ v-if="!loading && !error && !visible.length"
125
+ class="mt-6 text-center text-sm text-dimmed"
126
+ >
127
+ {{ emptyMessage }}
128
+ </p>
129
+ </div>
130
+ </template>