@growthub/cli 0.7.9 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/worker-kits/creative-strategist-v1/SKILL.md +95 -0
- package/assets/worker-kits/creative-strategist-v1/bundles/creative-strategist-v1.json +12 -2
- package/assets/worker-kits/creative-strategist-v1/helpers/README.md +29 -0
- package/assets/worker-kits/creative-strategist-v1/helpers/extract-muse-frames.sh +81 -0
- package/assets/worker-kits/creative-strategist-v1/helpers/grep-hooks.sh +62 -0
- package/assets/worker-kits/creative-strategist-v1/kit.json +20 -2
- package/assets/worker-kits/creative-strategist-v1/skills/README.md +23 -0
- package/assets/worker-kits/creative-strategist-v1/skills/frame-analysis/SKILL.md +88 -0
- package/assets/worker-kits/creative-strategist-v1/templates/project.md +48 -0
- package/assets/worker-kits/creative-strategist-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/creative-strategist-v1/workers/creative-strategist/CLAUDE.md +22 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/.env.example +53 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/QUICKSTART.md +98 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/SKILL.md +89 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/.env.example +25 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/README.md +36 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/app/api/settings/integrations/route.js +13 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/app/api/workspace/route.js +27 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/app/globals.css +237 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/app/layout.jsx +14 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/app/page.jsx +165 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/app/settings/integrations/page.jsx +134 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/adapters/auth/index.js +21 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/adapters/env.js +28 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/adapters/integrations/growthub-connection-normalizer.js +95 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/adapters/integrations/index.js +178 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/adapters/payments/index.js +13 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/adapters/persistence/index.js +13 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/adapters/persistence/postgres.js +16 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/adapters/persistence/provider-managed.js +16 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/adapters/persistence/qstash-kv.js +16 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/domain/integrations.js +185 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/domain/portal.js +16 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/next.config.js +10 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/package-lock.json +976 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/package.json +17 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/postcss.config.mjs +3 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/vercel.json +5 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/brands/NEW-CLIENT.md +10 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/brands/_template/brand-kit.md +27 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/brands/growthub/brand-kit.md +25 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/bundles/growthub-agency-portal-starter-v1.json +65 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/docs/adapter-contracts.md +79 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/docs/fork-sync-integration.md +32 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/docs/governed-workspace-primitives.md +182 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/docs/starter-kit-overview.md +30 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/docs/vercel-serverless-deployment.md +46 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/docs/vite-ui-shell-guide.md +24 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/examples/portal-brief-sample.md +44 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/examples/workspace-sample.md +10 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/growthub-meta/README.md +11 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/growthub-meta/kit-standard.md +16 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/helpers/README.md +49 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/kit.json +156 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/output/README.md +13 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/output-standards.md +25 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/runtime-assumptions.md +15 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/setup/check-deps.sh +20 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/setup/verify-env.mjs +92 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/skills/README.md +55 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/skills.md +133 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/studio/index.html +12 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/studio/package-lock.json +1677 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/studio/package.json +20 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/studio/serve.mjs +42 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/studio/src/App.jsx +162 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/studio/src/app.css +138 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/studio/src/main.jsx +10 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/studio/vite.config.js +8 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/templates/agent-contract.md +9 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/templates/client-onboarding-plan.md +56 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/templates/deployment-handoff.md +61 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/templates/deployment-plan.md +22 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/templates/portal-brief.md +65 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/templates/project.md +55 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/templates/supabase-setup-plan.md +26 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/templates/workspace-brief.md +11 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/validation-checklist.md +32 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/workers/agency-portal-operator/CLAUDE.md +75 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/SKILL.md +89 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/bundles/growthub-ai-website-cloner-v1.json +9 -2
- package/assets/worker-kits/growthub-ai-website-cloner-v1/helpers/README.md +29 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/kit.json +14 -2
- package/assets/worker-kits/growthub-ai-website-cloner-v1/skills/README.md +23 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/templates/project.md +48 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/growthub-ai-website-cloner-v1/workers/ai-website-cloner-operator/CLAUDE.md +22 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/SKILL.md +122 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/bundles/growthub-custom-workspace-starter-v1.json +14 -2
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/docs/governed-workspace-primitives.md +182 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/helpers/README.md +44 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/kit.json +16 -2
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/skills/README.md +55 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/templates/project.md +55 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/workers/custom-workspace-operator/CLAUDE.md +24 -2
- package/assets/worker-kits/growthub-email-marketing-v1/SKILL.md +90 -0
- package/assets/worker-kits/growthub-email-marketing-v1/bundles/growthub-email-marketing-v1.json +9 -2
- package/assets/worker-kits/growthub-email-marketing-v1/helpers/README.md +29 -0
- package/assets/worker-kits/growthub-email-marketing-v1/kit.json +14 -2
- package/assets/worker-kits/growthub-email-marketing-v1/skills/README.md +23 -0
- package/assets/worker-kits/growthub-email-marketing-v1/templates/project.md +48 -0
- package/assets/worker-kits/growthub-email-marketing-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/growthub-email-marketing-v1/workers/email-marketing-strategist/CLAUDE.md +22 -0
- package/assets/worker-kits/growthub-geo-seo-v1/SKILL.md +90 -0
- package/assets/worker-kits/growthub-geo-seo-v1/bundles/growthub-geo-seo-v1.json +12 -3
- package/assets/worker-kits/growthub-geo-seo-v1/helpers/README.md +29 -0
- package/assets/worker-kits/growthub-geo-seo-v1/kit.json +23 -5
- package/assets/worker-kits/growthub-geo-seo-v1/skills/README.md +23 -0
- package/assets/worker-kits/growthub-geo-seo-v1/templates/project.md +48 -0
- package/assets/worker-kits/growthub-geo-seo-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/growthub-geo-seo-v1/workers/geo-seo-operator/CLAUDE.md +22 -0
- package/assets/worker-kits/growthub-hyperframes-studio-v1/SKILL.md +89 -0
- package/assets/worker-kits/growthub-hyperframes-studio-v1/bundles/growthub-hyperframes-studio-v1.json +6 -1
- package/assets/worker-kits/growthub-hyperframes-studio-v1/helpers/README.md +29 -0
- package/assets/worker-kits/growthub-hyperframes-studio-v1/kit.json +14 -2
- package/assets/worker-kits/growthub-hyperframes-studio-v1/skills/README.md +23 -0
- package/assets/worker-kits/growthub-hyperframes-studio-v1/templates/project.md +48 -0
- package/assets/worker-kits/growthub-hyperframes-studio-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/growthub-hyperframes-studio-v1/workers/hyperframes-studio-operator/CLAUDE.md +22 -0
- package/assets/worker-kits/growthub-marketing-skills-v1/SKILL.md +90 -0
- package/assets/worker-kits/growthub-marketing-skills-v1/bundles/growthub-marketing-skills-v1.json +12 -3
- package/assets/worker-kits/growthub-marketing-skills-v1/helpers/README.md +29 -0
- package/assets/worker-kits/growthub-marketing-skills-v1/kit.json +23 -5
- package/assets/worker-kits/growthub-marketing-skills-v1/skills/README.md +23 -0
- package/assets/worker-kits/growthub-marketing-skills-v1/templates/project.md +48 -0
- package/assets/worker-kits/growthub-marketing-skills-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/growthub-marketing-skills-v1/workers/marketing-operator/CLAUDE.md +22 -0
- package/assets/worker-kits/growthub-open-higgsfield-studio-v1/SKILL.md +89 -0
- package/assets/worker-kits/growthub-open-higgsfield-studio-v1/bundles/growthub-open-higgsfield-studio-v1.json +9 -2
- package/assets/worker-kits/growthub-open-higgsfield-studio-v1/helpers/README.md +29 -0
- package/assets/worker-kits/growthub-open-higgsfield-studio-v1/kit.json +14 -2
- package/assets/worker-kits/growthub-open-higgsfield-studio-v1/skills/README.md +23 -0
- package/assets/worker-kits/growthub-open-higgsfield-studio-v1/templates/project.md +48 -0
- package/assets/worker-kits/growthub-open-higgsfield-studio-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/growthub-open-higgsfield-studio-v1/workers/open-higgsfield-studio-operator/CLAUDE.md +22 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/SKILL.md +89 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/bundles/growthub-open-montage-studio-v1.json +9 -2
- package/assets/worker-kits/growthub-open-montage-studio-v1/helpers/README.md +29 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/kit.json +14 -2
- package/assets/worker-kits/growthub-open-montage-studio-v1/skills/README.md +23 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/templates/project.md +48 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/growthub-open-montage-studio-v1/workers/open-montage-studio-operator/CLAUDE.md +22 -0
- package/assets/worker-kits/growthub-postiz-social-v1/SKILL.md +90 -0
- package/assets/worker-kits/growthub-postiz-social-v1/bundles/growthub-postiz-social-v1.json +9 -2
- package/assets/worker-kits/growthub-postiz-social-v1/helpers/README.md +29 -0
- package/assets/worker-kits/growthub-postiz-social-v1/kit.json +14 -2
- package/assets/worker-kits/growthub-postiz-social-v1/skills/README.md +23 -0
- package/assets/worker-kits/growthub-postiz-social-v1/templates/project.md +48 -0
- package/assets/worker-kits/growthub-postiz-social-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/growthub-postiz-social-v1/workers/postiz-social-operator/CLAUDE.md +22 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/SKILL.md +89 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/bundles/growthub-twenty-crm-v1.json +9 -2
- package/assets/worker-kits/growthub-twenty-crm-v1/helpers/README.md +29 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/kit.json +14 -2
- package/assets/worker-kits/growthub-twenty-crm-v1/skills/README.md +23 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/templates/project.md +48 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/growthub-twenty-crm-v1/workers/twenty-crm-operator/CLAUDE.md +22 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/SKILL.md +89 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/bundles/growthub-video-use-studio-v1.json +6 -1
- package/assets/worker-kits/growthub-video-use-studio-v1/helpers/README.md +29 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/kit.json +14 -2
- package/assets/worker-kits/growthub-video-use-studio-v1/skills/README.md +23 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/templates/project.md +48 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/growthub-video-use-studio-v1/workers/video-use-studio-operator/CLAUDE.md +22 -0
- package/assets/worker-kits/growthub-zernio-social-v1/SKILL.md +90 -0
- package/assets/worker-kits/growthub-zernio-social-v1/bundles/growthub-zernio-social-v1.json +9 -2
- package/assets/worker-kits/growthub-zernio-social-v1/helpers/README.md +29 -0
- package/assets/worker-kits/growthub-zernio-social-v1/kit.json +14 -2
- package/assets/worker-kits/growthub-zernio-social-v1/skills/README.md +23 -0
- package/assets/worker-kits/growthub-zernio-social-v1/templates/project.md +48 -0
- package/assets/worker-kits/growthub-zernio-social-v1/templates/self-eval.md +67 -0
- package/assets/worker-kits/growthub-zernio-social-v1/workers/zernio-social-operator/CLAUDE.md +22 -0
- package/dist/index.js +970 -241
- package/package.json +2 -2
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { describeAuthAdapter } from "@/lib/adapters/auth";
|
|
2
|
+
import { readAdapterConfig } from "@/lib/adapters/env";
|
|
3
|
+
import { describePaymentAdapter } from "@/lib/adapters/payments";
|
|
4
|
+
import { describePersistenceAdapter } from "@/lib/adapters/persistence";
|
|
5
|
+
import { portalCapabilities } from "@/lib/domain/portal";
|
|
6
|
+
import Link from "next/link";
|
|
7
|
+
const nav = [
|
|
8
|
+
...portalCapabilities.map((item) => ({ href: `#${item.id}`, label: item.label })),
|
|
9
|
+
{ href: "/settings/integrations", label: "Integrations" }
|
|
10
|
+
];
|
|
11
|
+
const quickActions = [
|
|
12
|
+
"Client onboarding",
|
|
13
|
+
"Publish report",
|
|
14
|
+
"Sync Windsor data",
|
|
15
|
+
"Review open tasks"
|
|
16
|
+
];
|
|
17
|
+
function Home() {
|
|
18
|
+
const config = readAdapterConfig();
|
|
19
|
+
const persistence = describePersistenceAdapter();
|
|
20
|
+
const auth = describeAuthAdapter();
|
|
21
|
+
const payments = describePaymentAdapter();
|
|
22
|
+
return <main className="shell">
|
|
23
|
+
<aside className="sidebar">
|
|
24
|
+
<div className="brand">
|
|
25
|
+
<span className="brand-mark">GH</span>
|
|
26
|
+
<span>Agency Portal</span>
|
|
27
|
+
</div>
|
|
28
|
+
<nav className="nav">
|
|
29
|
+
{nav.map((item, index) => <Link className={index === 0 ? "active" : ""} href={item.href} key={item.href}>{item.label}</Link>)}
|
|
30
|
+
</nav>
|
|
31
|
+
<div className="sidebar-footer">
|
|
32
|
+
<span className="status-dot" />
|
|
33
|
+
Governed worker kit
|
|
34
|
+
</div>
|
|
35
|
+
</aside>
|
|
36
|
+
|
|
37
|
+
<section className="main">
|
|
38
|
+
<div className="utility-bar">
|
|
39
|
+
<div>
|
|
40
|
+
<strong>Production workspace</strong>
|
|
41
|
+
<span>Local customization, Vercel deployment, bridge-ready integrations.</span>
|
|
42
|
+
</div>
|
|
43
|
+
<div className="utility-actions">
|
|
44
|
+
<Link href="/settings/integrations">Integrations</Link>
|
|
45
|
+
<span className="pill">v1 kit</span>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<div className="page-heading">
|
|
50
|
+
<div>
|
|
51
|
+
<p className="eyebrow">Growthub Local + Vercel</p>
|
|
52
|
+
<h1>Composable Agency Workspace</h1>
|
|
53
|
+
<p>
|
|
54
|
+
A production starter for agency portals with local-first Vite operation, Vercel
|
|
55
|
+
deployment, thin adapter contracts, Windsor data pipelines, and Growthub MCP
|
|
56
|
+
connection authority.
|
|
57
|
+
</p>
|
|
58
|
+
</div>
|
|
59
|
+
<span className="badge">deploy: {config.deployTarget}</span>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<section className="hero-grid" id="dashboard">
|
|
63
|
+
<article className="hero-card wide">
|
|
64
|
+
<p className="card-label">Monthly Revenue</p>
|
|
65
|
+
<strong>$0</strong>
|
|
66
|
+
<div className="progress"><span style={{ width: "0%" }} /></div>
|
|
67
|
+
<p className="muted">Connect persistence to populate invoices, retainers, and margin reporting.</p>
|
|
68
|
+
</article>
|
|
69
|
+
<article className="hero-card">
|
|
70
|
+
<p className="card-label">MCP Connections</p>
|
|
71
|
+
<strong>{config.integrationAdapter}</strong>
|
|
72
|
+
<p className="muted">Growthub bridge and BYO API key paths normalize into one object model.</p>
|
|
73
|
+
</article>
|
|
74
|
+
<article className="hero-card">
|
|
75
|
+
<p className="card-label">Client Results</p>
|
|
76
|
+
<strong>Windsor</strong>
|
|
77
|
+
<p className="muted">First-class Windsor AI and Google Sheets blended data pipeline support.</p>
|
|
78
|
+
</article>
|
|
79
|
+
</section>
|
|
80
|
+
|
|
81
|
+
<section className="ops-strip" aria-label="Setup paths">
|
|
82
|
+
<article>
|
|
83
|
+
<span>01</span>
|
|
84
|
+
<strong>Local Vite shell</strong>
|
|
85
|
+
<p>Use the same portal frame for agent-led local customization.</p>
|
|
86
|
+
</article>
|
|
87
|
+
<article>
|
|
88
|
+
<span>02</span>
|
|
89
|
+
<strong>Vercel app</strong>
|
|
90
|
+
<p>Deploy the Next app without binding persistence to a single provider.</p>
|
|
91
|
+
</article>
|
|
92
|
+
<article>
|
|
93
|
+
<span>03</span>
|
|
94
|
+
<strong>Growthub bridge</strong>
|
|
95
|
+
<p>Resolve hosted MCP accounts when the user connects Growthub authority.</p>
|
|
96
|
+
</article>
|
|
97
|
+
<article>
|
|
98
|
+
<span>04</span>
|
|
99
|
+
<strong>BYO keys</strong>
|
|
100
|
+
<p>Support Windsor and external provider keys through the same object contract.</p>
|
|
101
|
+
</article>
|
|
102
|
+
</section>
|
|
103
|
+
|
|
104
|
+
<section className="grid compact-grid">
|
|
105
|
+
{portalCapabilities.map((capability) => <article className="card" id={capability.id} key={capability.id}>
|
|
106
|
+
<h3>{capability.label}</h3>
|
|
107
|
+
<div className="metric">{capability.metric}</div>
|
|
108
|
+
<p>{capability.description}</p>
|
|
109
|
+
</article>)}
|
|
110
|
+
</section>
|
|
111
|
+
|
|
112
|
+
<section className="adapter" aria-label="Adapter contracts">
|
|
113
|
+
<article className="card">
|
|
114
|
+
<h3>Persistence</h3>
|
|
115
|
+
<p><strong>{persistence.label}</strong></p>
|
|
116
|
+
<p>Postgres, Qstash KV, or provider-managed.</p>
|
|
117
|
+
</article>
|
|
118
|
+
<article className="card">
|
|
119
|
+
<h3>Auth</h3>
|
|
120
|
+
<p><strong>{auth.id}</strong></p>
|
|
121
|
+
<p>{auth.requiredEnv.length ? auth.requiredEnv.join(", ") : "provider-defined"}</p>
|
|
122
|
+
</article>
|
|
123
|
+
<article className="card">
|
|
124
|
+
<h3>Payments</h3>
|
|
125
|
+
<p><strong>{payments.id}</strong></p>
|
|
126
|
+
<p>{payments.enabled ? "enabled" : "disabled"}</p>
|
|
127
|
+
</article>
|
|
128
|
+
<article className="card">
|
|
129
|
+
<h3>Integrations</h3>
|
|
130
|
+
<p><strong>{config.integrationAdapter}</strong></p>
|
|
131
|
+
<p><Link href="/settings/integrations">Open setup surface</Link></p>
|
|
132
|
+
</article>
|
|
133
|
+
<article className="card">
|
|
134
|
+
<h3>Worker API</h3>
|
|
135
|
+
<p><code>GET /api/workspace</code></p>
|
|
136
|
+
<p>Adapter and capability metadata for agents.</p>
|
|
137
|
+
</article>
|
|
138
|
+
</section>
|
|
139
|
+
|
|
140
|
+
<section className="results-panel" id="client-results">
|
|
141
|
+
<div>
|
|
142
|
+
<p className="eyebrow">Client Results</p>
|
|
143
|
+
<h2>Windsor AI + blended data ready</h2>
|
|
144
|
+
<p>
|
|
145
|
+
Windsor is a data pipeline object, not a database choice. Google Sheets blended
|
|
146
|
+
exports, GA4, Shopify, and Meta data stay composable through the integrations surface.
|
|
147
|
+
</p>
|
|
148
|
+
</div>
|
|
149
|
+
<div className="results-metrics">
|
|
150
|
+
<span>Meta</span>
|
|
151
|
+
<span>Shopify</span>
|
|
152
|
+
<span>GA4</span>
|
|
153
|
+
<span>Sheets</span>
|
|
154
|
+
</div>
|
|
155
|
+
</section>
|
|
156
|
+
</section>
|
|
157
|
+
|
|
158
|
+
<aside className="quick-actions" aria-label="Quick actions">
|
|
159
|
+
{quickActions.map((action) => <button type="button" key={action}>{action}</button>)}
|
|
160
|
+
</aside>
|
|
161
|
+
</main>;
|
|
162
|
+
}
|
|
163
|
+
export {
|
|
164
|
+
Home as default
|
|
165
|
+
};
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { describeIntegrationAdapter, listAgencyPortalIntegrations } from "@/lib/adapters/integrations";
|
|
2
|
+
import { portalCapabilities } from "@/lib/domain/portal";
|
|
3
|
+
import { groupIntegrationsByLane } from "@/lib/domain/integrations";
|
|
4
|
+
import Link from "next/link";
|
|
5
|
+
const nav = [
|
|
6
|
+
...portalCapabilities.map((item) => ({ href: `/#${item.id}`, label: item.label })),
|
|
7
|
+
{ href: "/settings/integrations", label: "Integrations" }
|
|
8
|
+
];
|
|
9
|
+
async function IntegrationsSettingsPage() {
|
|
10
|
+
const adapter = describeIntegrationAdapter();
|
|
11
|
+
const grouped = groupIntegrationsByLane(await listAgencyPortalIntegrations());
|
|
12
|
+
const allIntegrations = [...grouped.dataSources, ...grouped.workspaceIntegrations];
|
|
13
|
+
const connectedCount = allIntegrations.filter((item) => item.isConnected).length;
|
|
14
|
+
return <main className="shell">
|
|
15
|
+
<aside className="sidebar">
|
|
16
|
+
<div className="brand">
|
|
17
|
+
<span className="brand-mark">GH</span>
|
|
18
|
+
<span>Agency Portal</span>
|
|
19
|
+
</div>
|
|
20
|
+
<nav className="nav">
|
|
21
|
+
{nav.map((item) => <Link className={item.href === "/settings/integrations" ? "active" : ""} key={item.href} href={item.href}>
|
|
22
|
+
{item.label}
|
|
23
|
+
</Link>)}
|
|
24
|
+
</nav>
|
|
25
|
+
<div className="sidebar-footer">
|
|
26
|
+
<span className="status-dot" />
|
|
27
|
+
{connectedCount} connected
|
|
28
|
+
</div>
|
|
29
|
+
</aside>
|
|
30
|
+
|
|
31
|
+
<section className="main">
|
|
32
|
+
<div className="utility-bar">
|
|
33
|
+
<div>
|
|
34
|
+
<strong>Integration setup</strong>
|
|
35
|
+
<span>Growthub bridge, BYO API keys, and Windsor data pipelines normalize into one worker-kit object model.</span>
|
|
36
|
+
</div>
|
|
37
|
+
<div className="utility-actions">
|
|
38
|
+
<span className="pill">{adapter.authority}</span>
|
|
39
|
+
<span className="pill">{adapter.source}</span>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<div className="page-heading">
|
|
44
|
+
<span className="eyebrow">Settings</span>
|
|
45
|
+
<h1>Integrations</h1>
|
|
46
|
+
<p>
|
|
47
|
+
Configure the portal through the hosted Growthub auth bridge or through explicit bring-your-own credentials.
|
|
48
|
+
Data pipeline objects stay separate from workspace integrations while sharing one normalized surface.
|
|
49
|
+
</p>
|
|
50
|
+
<span className="badge">{adapter.label}</span>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<section className="setup-grid" aria-label="Integration setup paths">
|
|
54
|
+
<article className="setup-card">
|
|
55
|
+
<span>01</span>
|
|
56
|
+
<strong>Growthub Bridge</strong>
|
|
57
|
+
<p>Uses the authenticated Growthub account to resolve already-connected MCP accounts for this portal.</p>
|
|
58
|
+
<code>GROWTHUB_BRIDGE_ACCESS_TOKEN</code>
|
|
59
|
+
</article>
|
|
60
|
+
<article className="setup-card">
|
|
61
|
+
<span>02</span>
|
|
62
|
+
<strong>BYO API Key</strong>
|
|
63
|
+
<p>Supports direct provider keys without binding the kit to a database, vendor, or hosted account.</p>
|
|
64
|
+
<code>AGENCY_PORTAL_BYO_CONNECTIONS_JSON</code>
|
|
65
|
+
</article>
|
|
66
|
+
<article className="setup-card">
|
|
67
|
+
<span>03</span>
|
|
68
|
+
<strong>Windsor Data</strong>
|
|
69
|
+
<p>First-class reporting pipeline for blended Meta, Shopify, GA4, and Google Sheets data sources.</p>
|
|
70
|
+
<code>WINDSOR_API_KEY</code>
|
|
71
|
+
</article>
|
|
72
|
+
</section>
|
|
73
|
+
|
|
74
|
+
<section className="integration-board">
|
|
75
|
+
<div className="integration-toolbar">
|
|
76
|
+
<div>
|
|
77
|
+
<strong>Connection authority</strong>
|
|
78
|
+
<p>{adapter.description}</p>
|
|
79
|
+
</div>
|
|
80
|
+
<code>GET /api/settings/integrations</code>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
<IntegrationPanel
|
|
84
|
+
title="Data pipeline objects"
|
|
85
|
+
intro="Meta, Shopify, GA4, Windsor AI, and Google Sheets blended data feed reporting and analytics workflows."
|
|
86
|
+
items={grouped.dataSources}
|
|
87
|
+
/>
|
|
88
|
+
<IntegrationPanel
|
|
89
|
+
title="MCP connection integrations"
|
|
90
|
+
intro="Asana, Slack, GHL, Google Drive, and Notion are operational integrations resolved through MCP connection authority or explicit BYO setup."
|
|
91
|
+
items={grouped.workspaceIntegrations}
|
|
92
|
+
/>
|
|
93
|
+
</section>
|
|
94
|
+
</section>
|
|
95
|
+
</main>;
|
|
96
|
+
}
|
|
97
|
+
function IntegrationPanel({
|
|
98
|
+
title,
|
|
99
|
+
intro,
|
|
100
|
+
items
|
|
101
|
+
}) {
|
|
102
|
+
const connected = items.filter((item) => item.isConnected).length;
|
|
103
|
+
return <article className="integration-section">
|
|
104
|
+
<div className="section-heading">
|
|
105
|
+
<div>
|
|
106
|
+
<h2>{title}</h2>
|
|
107
|
+
<p className="panel-copy">{intro}</p>
|
|
108
|
+
</div>
|
|
109
|
+
<span className="badge">{connected}/{items.length} connected</span>
|
|
110
|
+
</div>
|
|
111
|
+
<div className="integration-list">
|
|
112
|
+
{items.map((item) => <article className="integration-card" key={item.id}>
|
|
113
|
+
<div className="integration-card-top">
|
|
114
|
+
<div className="provider-mark">{item.label.slice(0, 1)}</div>
|
|
115
|
+
<div>
|
|
116
|
+
<strong>{item.label}</strong>
|
|
117
|
+
<p>{item.description}</p>
|
|
118
|
+
</div>
|
|
119
|
+
<span className={`status ${item.status}`}>{item.status}</span>
|
|
120
|
+
</div>
|
|
121
|
+
<div className="integration-card-meta">
|
|
122
|
+
<span>{item.provider}</span>
|
|
123
|
+
<span>{item.objectType}</span>
|
|
124
|
+
<span>{item.authPath}</span>
|
|
125
|
+
<span>{item.setupMode}</span>
|
|
126
|
+
{item.secretEnvName ? <span>{item.secretEnvName}</span> : null}
|
|
127
|
+
</div>
|
|
128
|
+
</article>)}
|
|
129
|
+
</div>
|
|
130
|
+
</article>;
|
|
131
|
+
}
|
|
132
|
+
export {
|
|
133
|
+
IntegrationsSettingsPage as default
|
|
134
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { readAdapterConfig } from "../env";
|
|
2
|
+
function describeAuthAdapter() {
|
|
3
|
+
const { authAdapter } = readAdapterConfig();
|
|
4
|
+
if (authAdapter === "oidc") {
|
|
5
|
+
return {
|
|
6
|
+
id: "oidc",
|
|
7
|
+
requiredEnv: ["AUTH_SECRET", "AUTH_ISSUER", "AUTH_CLIENT_ID", "AUTH_CLIENT_SECRET"],
|
|
8
|
+
notes: ["Default portable auth contract for Vercel and local serverless use."]
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
if (authAdapter === "clerk") {
|
|
12
|
+
return { id: "clerk", requiredEnv: [], notes: ["Configure Clerk-specific env in the deployment target."] };
|
|
13
|
+
}
|
|
14
|
+
if (authAdapter === "authjs") {
|
|
15
|
+
return { id: "authjs", requiredEnv: ["AUTH_SECRET"], notes: ["Use Auth.js provider configuration in app code."] };
|
|
16
|
+
}
|
|
17
|
+
return { id: "provider-managed", requiredEnv: [], notes: ["Auth is managed outside the kit contract."] };
|
|
18
|
+
}
|
|
19
|
+
export {
|
|
20
|
+
describeAuthAdapter
|
|
21
|
+
};
|
package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/lib/adapters/env.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
function readAdapterConfig() {
|
|
2
|
+
return {
|
|
3
|
+
deployTarget: "vercel",
|
|
4
|
+
dataAdapter: readEnum("AGENCY_PORTAL_DATA_ADAPTER", ["postgres", "qstash-kv", "provider-managed"], "provider-managed"),
|
|
5
|
+
authAdapter: readEnum("AGENCY_PORTAL_AUTH_ADAPTER", ["oidc", "clerk", "authjs", "provider-managed"], "provider-managed"),
|
|
6
|
+
paymentAdapter: readEnum("AGENCY_PORTAL_PAYMENT_ADAPTER", ["none", "stripe", "polar"], "none"),
|
|
7
|
+
integrationAdapter: readEnum("AGENCY_PORTAL_INTEGRATION_ADAPTER", ["growthub-bridge", "byo-api-key", "static"], "static"),
|
|
8
|
+
reportingAdapter: process.env.AGENCY_PORTAL_REPORTING_ADAPTER || void 0,
|
|
9
|
+
growthubBridge: {
|
|
10
|
+
baseUrl: process.env.GROWTHUB_BRIDGE_BASE_URL || void 0,
|
|
11
|
+
integrationsPath: process.env.GROWTHUB_BRIDGE_INTEGRATIONS_PATH || "/api/mcp/accounts",
|
|
12
|
+
userId: process.env.GROWTHUB_BRIDGE_USER_ID || void 0,
|
|
13
|
+
hasAccessToken: Boolean(process.env.GROWTHUB_BRIDGE_ACCESS_TOKEN)
|
|
14
|
+
},
|
|
15
|
+
dataSources: {
|
|
16
|
+
hasWindsorApiKey: Boolean(process.env.WINDSOR_API_KEY)
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function readEnum(key, allowed, fallback) {
|
|
21
|
+
const value = process.env[key];
|
|
22
|
+
if (!value) return fallback;
|
|
23
|
+
if (allowed.includes(value)) return value;
|
|
24
|
+
throw new Error(`${key} must be one of: ${allowed.join(", ")}`);
|
|
25
|
+
}
|
|
26
|
+
export {
|
|
27
|
+
readAdapterConfig
|
|
28
|
+
};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
const providerAliases = {
|
|
2
|
+
ga4: "google-analytics",
|
|
3
|
+
google_analytics: "google-analytics",
|
|
4
|
+
google_drive: "google-drive",
|
|
5
|
+
ghl: "go-high-level",
|
|
6
|
+
gohighlevel: "go-high-level",
|
|
7
|
+
meta: "meta-ads",
|
|
8
|
+
meta_ads: "meta-ads"
|
|
9
|
+
};
|
|
10
|
+
function normalizeProviderId(provider) {
|
|
11
|
+
const normalized = provider.trim().toLowerCase().replaceAll("_", "-");
|
|
12
|
+
return providerAliases[normalized] || normalized;
|
|
13
|
+
}
|
|
14
|
+
function isHostedRecord(row) {
|
|
15
|
+
return "provider" in row && ("ready" in row || "connectedAt" in row || "scopes" in row || "handle" in row);
|
|
16
|
+
}
|
|
17
|
+
function normalizeHostedIntegration(row) {
|
|
18
|
+
const provider = normalizeProviderId(row.provider);
|
|
19
|
+
const ready = row.ready !== false;
|
|
20
|
+
return {
|
|
21
|
+
id: provider,
|
|
22
|
+
provider,
|
|
23
|
+
label: row.label,
|
|
24
|
+
name: row.label,
|
|
25
|
+
status: ready ? "connected" : "needs-connection",
|
|
26
|
+
isConnected: ready,
|
|
27
|
+
isActive: ready,
|
|
28
|
+
authPath: "growthub-mcp-bridge",
|
|
29
|
+
setupMode: "hosted-authority",
|
|
30
|
+
connectionMetadata: {
|
|
31
|
+
source: "growthub-cli-profile",
|
|
32
|
+
connectedAt: row.connectedAt,
|
|
33
|
+
scopes: row.scopes,
|
|
34
|
+
handle: row.handle
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function normalizeMcpAccount(account) {
|
|
39
|
+
const provider = normalizeProviderId(account.provider);
|
|
40
|
+
const isActive = account.isActive === true;
|
|
41
|
+
const isVerified = account.isVerified === true;
|
|
42
|
+
const isConnected = isActive;
|
|
43
|
+
return {
|
|
44
|
+
id: provider,
|
|
45
|
+
provider,
|
|
46
|
+
label: account.connectionName || void 0,
|
|
47
|
+
name: account.connectionName || void 0,
|
|
48
|
+
authType: normalizeConnectionType(account.connectionType),
|
|
49
|
+
status: isConnected ? "connected" : "needs-connection",
|
|
50
|
+
isConnected,
|
|
51
|
+
isActive,
|
|
52
|
+
connectionId: account.id,
|
|
53
|
+
authPath: "growthub-mcp-bridge",
|
|
54
|
+
setupMode: "hosted-authority",
|
|
55
|
+
connectionMetadata: {
|
|
56
|
+
source: "growthub-mcp-accounts",
|
|
57
|
+
accountId: account.id,
|
|
58
|
+
connectionName: account.connectionName,
|
|
59
|
+
connectionType: account.connectionType,
|
|
60
|
+
isVerified,
|
|
61
|
+
appSlug: account.appSlug,
|
|
62
|
+
createdAt: account.createdAt,
|
|
63
|
+
updatedAt: account.updatedAt,
|
|
64
|
+
metadata: account.metadata || void 0
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function normalizeConnectionType(connectionType) {
|
|
69
|
+
if (connectionType === "api_token" || connectionType === "api_key") return "api_token";
|
|
70
|
+
if (connectionType === "webhook") return "webhook";
|
|
71
|
+
return "oauth_first_party";
|
|
72
|
+
}
|
|
73
|
+
function normalizeBridgeRow(row) {
|
|
74
|
+
if (isHostedRecord(row)) return normalizeHostedIntegration(row);
|
|
75
|
+
const provider = normalizeProviderId(row.provider || row.id || "");
|
|
76
|
+
return {
|
|
77
|
+
...row,
|
|
78
|
+
id: row.id || provider,
|
|
79
|
+
provider
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function normalizeGrowthubBridgePayload(payload) {
|
|
83
|
+
if (Array.isArray(payload)) {
|
|
84
|
+
return payload.map(normalizeBridgeRow);
|
|
85
|
+
}
|
|
86
|
+
return [
|
|
87
|
+
...(payload.integrations || []).map(normalizeBridgeRow),
|
|
88
|
+
...(payload.accounts || []).map(normalizeMcpAccount),
|
|
89
|
+
...(payload.dataSources || []).map(normalizeBridgeRow),
|
|
90
|
+
...(payload.workspaceIntegrations || []).map(normalizeBridgeRow)
|
|
91
|
+
];
|
|
92
|
+
}
|
|
93
|
+
export {
|
|
94
|
+
normalizeGrowthubBridgePayload
|
|
95
|
+
};
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { readAdapterConfig } from "@/lib/adapters/env";
|
|
2
|
+
import {
|
|
3
|
+
agencyPortalIntegrationCatalog
|
|
4
|
+
} from "@/lib/domain/integrations";
|
|
5
|
+
import {
|
|
6
|
+
normalizeGrowthubBridgePayload
|
|
7
|
+
} from "./growthub-connection-normalizer";
|
|
8
|
+
function describeIntegrationAdapter() {
|
|
9
|
+
const config = readAdapterConfig();
|
|
10
|
+
if (config.integrationAdapter === "growthub-bridge") {
|
|
11
|
+
return {
|
|
12
|
+
id: "growthub-bridge",
|
|
13
|
+
label: "Growthub MCP bridge",
|
|
14
|
+
requiredEnv: ["GROWTHUB_BRIDGE_BASE_URL", "GROWTHUB_BRIDGE_ACCESS_TOKEN"],
|
|
15
|
+
authority: "growthub-gh-app"
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
if (config.integrationAdapter === "byo-api-key") {
|
|
19
|
+
return {
|
|
20
|
+
id: "byo-api-key",
|
|
21
|
+
label: "Bring your own API key",
|
|
22
|
+
requiredEnv: ["AGENCY_PORTAL_BYO_CONNECTIONS_JSON"],
|
|
23
|
+
authority: "workspace-env"
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
id: "static",
|
|
28
|
+
label: "Static starter catalog",
|
|
29
|
+
requiredEnv: [],
|
|
30
|
+
authority: "local-catalog"
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
async function listAgencyPortalIntegrations() {
|
|
34
|
+
const config = readAdapterConfig();
|
|
35
|
+
if (config.integrationAdapter !== "growthub-bridge") {
|
|
36
|
+
if (config.integrationAdapter === "byo-api-key") {
|
|
37
|
+
return mergeBringYourOwnRows(readBringYourOwnRows());
|
|
38
|
+
}
|
|
39
|
+
return agencyPortalIntegrationCatalog;
|
|
40
|
+
}
|
|
41
|
+
if (!config.growthubBridge.baseUrl || !process.env.GROWTHUB_BRIDGE_ACCESS_TOKEN) {
|
|
42
|
+
return agencyPortalIntegrationCatalog;
|
|
43
|
+
}
|
|
44
|
+
const url = new URL(config.growthubBridge.integrationsPath, config.growthubBridge.baseUrl);
|
|
45
|
+
const headers = {
|
|
46
|
+
accept: "application/json",
|
|
47
|
+
authorization: `Bearer ${process.env.GROWTHUB_BRIDGE_ACCESS_TOKEN}`
|
|
48
|
+
};
|
|
49
|
+
if (config.growthubBridge.userId) {
|
|
50
|
+
headers["x-user-id"] = config.growthubBridge.userId;
|
|
51
|
+
}
|
|
52
|
+
const response = await fetch(url, {
|
|
53
|
+
headers,
|
|
54
|
+
next: { revalidate: 30 }
|
|
55
|
+
});
|
|
56
|
+
if (!response.ok) {
|
|
57
|
+
return agencyPortalIntegrationCatalog;
|
|
58
|
+
}
|
|
59
|
+
const payload = await response.json();
|
|
60
|
+
return mergeBridgeRows(normalizeGrowthubBridgePayload(payload));
|
|
61
|
+
}
|
|
62
|
+
function readBringYourOwnRows() {
|
|
63
|
+
const raw = process.env.AGENCY_PORTAL_BYO_CONNECTIONS_JSON;
|
|
64
|
+
const rows = [];
|
|
65
|
+
if (process.env.WINDSOR_API_KEY) {
|
|
66
|
+
rows.push({
|
|
67
|
+
id: "windsor-ai",
|
|
68
|
+
provider: "windsor-ai",
|
|
69
|
+
name: "Windsor AI",
|
|
70
|
+
label: "Windsor AI",
|
|
71
|
+
category: "api_key",
|
|
72
|
+
authType: "api_token",
|
|
73
|
+
status: "connected",
|
|
74
|
+
isConnected: true,
|
|
75
|
+
isActive: true,
|
|
76
|
+
authPath: "byo-api-key",
|
|
77
|
+
setupMode: "bring-your-own-key",
|
|
78
|
+
secretEnvName: "WINDSOR_API_KEY",
|
|
79
|
+
connectionMetadata: {
|
|
80
|
+
source: "workspace-env",
|
|
81
|
+
secretEnvName: "WINDSOR_API_KEY"
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
if (!raw) return rows;
|
|
86
|
+
try {
|
|
87
|
+
const parsed = JSON.parse(raw);
|
|
88
|
+
return [...rows, ...normalizeGrowthubBridgePayload(parsed)];
|
|
89
|
+
} catch {
|
|
90
|
+
return rows;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function mergeBringYourOwnRows(rows) {
|
|
94
|
+
const merged = mergeBridgeRows(rows);
|
|
95
|
+
return merged.map((item) => {
|
|
96
|
+
const row = rows.find((candidate) => {
|
|
97
|
+
const provider = candidate.provider || candidate.id;
|
|
98
|
+
return provider === item.provider || candidate.id === item.id;
|
|
99
|
+
});
|
|
100
|
+
if (!row) return item;
|
|
101
|
+
return {
|
|
102
|
+
...item,
|
|
103
|
+
authPath: "byo-api-key",
|
|
104
|
+
setupMode: "bring-your-own-key",
|
|
105
|
+
secretEnvName: typeof row.secretEnvName === "string" ? row.secretEnvName : void 0,
|
|
106
|
+
status: row.status || "connected"
|
|
107
|
+
};
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
function mergeBridgeRows(rows) {
|
|
111
|
+
const seenProviders = /* @__PURE__ */ new Set();
|
|
112
|
+
const merged = agencyPortalIntegrationCatalog.map((catalogItem) => {
|
|
113
|
+
const row = rows.find((item) => {
|
|
114
|
+
const provider = item.provider || item.id;
|
|
115
|
+
return provider === catalogItem.provider || item.id === catalogItem.id;
|
|
116
|
+
});
|
|
117
|
+
if (!row) return catalogItem;
|
|
118
|
+
seenProviders.add(row.provider || row.id || catalogItem.provider);
|
|
119
|
+
return {
|
|
120
|
+
...catalogItem,
|
|
121
|
+
label: row.label || row.name || catalogItem.label,
|
|
122
|
+
name: row.name || row.label || catalogItem.name,
|
|
123
|
+
icon: row.icon || catalogItem.icon,
|
|
124
|
+
description: row.description || catalogItem.description,
|
|
125
|
+
category: row.category || catalogItem.category,
|
|
126
|
+
authType: row.authType || catalogItem.authType,
|
|
127
|
+
isConnected: row.isConnected ?? (row.status === "connected" ? true : catalogItem.isConnected),
|
|
128
|
+
isActive: row.isActive ?? (row.status === "connected" ? true : catalogItem.isActive),
|
|
129
|
+
authPath: row.authPath || catalogItem.authPath,
|
|
130
|
+
setupMode: row.setupMode || catalogItem.setupMode,
|
|
131
|
+
status: row.status || (row.isConnected || row.isActive ? "connected" : catalogItem.status),
|
|
132
|
+
connectionId: row.connectionId,
|
|
133
|
+
accountId: row.accountId,
|
|
134
|
+
secretEnvName: row.secretEnvName,
|
|
135
|
+
connectionMetadata: row.connectionMetadata || row.metadata,
|
|
136
|
+
metadata: row.metadata || row.connectionMetadata
|
|
137
|
+
};
|
|
138
|
+
});
|
|
139
|
+
const discoveredRows = rows.filter((row) => {
|
|
140
|
+
const provider = row.provider || row.id;
|
|
141
|
+
if (!provider) return false;
|
|
142
|
+
if (seenProviders.has(provider)) return false;
|
|
143
|
+
return !agencyPortalIntegrationCatalog.some((item) => item.provider === provider || item.id === row.id);
|
|
144
|
+
});
|
|
145
|
+
return [...merged, ...discoveredRows.map(toDiscoveredIntegration)];
|
|
146
|
+
}
|
|
147
|
+
function toDiscoveredIntegration(row) {
|
|
148
|
+
const provider = row.provider || row.id || "unknown-provider";
|
|
149
|
+
const label = row.label || row.name || provider;
|
|
150
|
+
const isDataPipeline = ["windsor-ai", "google-sheets", "google-analytics", "shopify", "meta-ads"].includes(provider);
|
|
151
|
+
const isConnected = row.isConnected ?? row.status === "connected";
|
|
152
|
+
return {
|
|
153
|
+
id: row.id || provider,
|
|
154
|
+
label,
|
|
155
|
+
name: row.name || label,
|
|
156
|
+
icon: row.icon || label.slice(0, 1).toUpperCase(),
|
|
157
|
+
provider,
|
|
158
|
+
description: row.description || "Connected through the Growthub account bridge.",
|
|
159
|
+
category: row.category || "mcp_connector",
|
|
160
|
+
authType: row.authType || "oauth_first_party",
|
|
161
|
+
isConnected,
|
|
162
|
+
isActive: row.isActive ?? isConnected,
|
|
163
|
+
lane: isDataPipeline ? "data-source" : "workspace-integration",
|
|
164
|
+
objectType: isDataPipeline ? "data-pipeline" : "mcp-connection",
|
|
165
|
+
status: row.status || (isConnected ? "connected" : "needs-connection"),
|
|
166
|
+
authPath: row.authPath || "growthub-mcp-bridge",
|
|
167
|
+
setupMode: row.setupMode || "hosted-authority",
|
|
168
|
+
connectionId: row.connectionId,
|
|
169
|
+
accountId: row.accountId,
|
|
170
|
+
secretEnvName: row.secretEnvName,
|
|
171
|
+
connectionMetadata: row.connectionMetadata || row.metadata,
|
|
172
|
+
metadata: row.metadata || row.connectionMetadata
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
export {
|
|
176
|
+
describeIntegrationAdapter,
|
|
177
|
+
listAgencyPortalIntegrations
|
|
178
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { readAdapterConfig } from "../env";
|
|
2
|
+
function describePaymentAdapter() {
|
|
3
|
+
const { paymentAdapter } = readAdapterConfig();
|
|
4
|
+
if (paymentAdapter === "none") return { id: "none", requiredEnv: [], enabled: false };
|
|
5
|
+
return {
|
|
6
|
+
id: paymentAdapter,
|
|
7
|
+
requiredEnv: ["PAYMENT_SECRET_KEY", "PAYMENT_WEBHOOK_SECRET"],
|
|
8
|
+
enabled: true
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
describePaymentAdapter
|
|
13
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { readAdapterConfig } from "../env";
|
|
2
|
+
import { describePostgresAdapter } from "./postgres";
|
|
3
|
+
import { describeProviderManagedAdapter } from "./provider-managed";
|
|
4
|
+
import { describeQstashKvAdapter } from "./qstash-kv";
|
|
5
|
+
function describePersistenceAdapter() {
|
|
6
|
+
const config = readAdapterConfig();
|
|
7
|
+
if (config.dataAdapter === "postgres") return describePostgresAdapter();
|
|
8
|
+
if (config.dataAdapter === "qstash-kv") return describeQstashKvAdapter();
|
|
9
|
+
return describeProviderManagedAdapter();
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
describePersistenceAdapter
|
|
13
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
function describePostgresAdapter() {
|
|
2
|
+
return {
|
|
3
|
+
id: "postgres",
|
|
4
|
+
label: "Postgres",
|
|
5
|
+
requiredEnv: ["DATABASE_URL"],
|
|
6
|
+
mode: "sql",
|
|
7
|
+
notes: [
|
|
8
|
+
"Use any Postgres-compatible provider.",
|
|
9
|
+
"Keep provider-specific pooling, SSL, and migration tooling outside the kit contract.",
|
|
10
|
+
"Application repositories should depend on this descriptor, not a provider SDK directly."
|
|
11
|
+
]
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
describePostgresAdapter
|
|
16
|
+
};
|