@growthub/cli 0.9.3 → 0.9.5
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/growthub-agency-portal-starter-v1/apps/agency-portal/growthub.config.json +112 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/apps/agency-portal/package.json +1 -1
- package/assets/worker-kits/growthub-agency-portal-starter-v1/bundles/growthub-agency-portal-starter-v1.json +1 -0
- package/assets/worker-kits/growthub-agency-portal-starter-v1/kit.json +2 -0
- package/assets/worker-kits/growthub-creative-video-pipeline-v1/apps/creative-video-pipeline/package.json +1 -1
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/SKILL.md +35 -1
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/.env.example +41 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/README.md +38 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/settings/integrations/route.js +13 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/route.js +91 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/globals.css +912 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/layout.jsx +14 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/page.jsx +23 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/settings/integrations/page.jsx +105 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workspace-builder.jsx +680 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/growthub.config.json +53 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/jsconfig.json +8 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/auth/index.js +21 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/env.js +28 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/integrations/growthub-connection-normalizer.js +95 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/integrations/index.js +198 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/payments/index.js +13 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/persistence/index.js +13 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/persistence/postgres.js +16 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/persistence/provider-managed.js +16 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/persistence/qstash-kv.js +16 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/domain/integrations.js +185 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/domain/portal.js +150 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-config.js +232 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/next.config.js +10 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/package-lock.json +976 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/package.json +17 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/postcss.config.mjs +3 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/vercel.json +5 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/bundles/growthub-custom-workspace-starter-v1.json +13 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/docs/adapter-contracts.md +86 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/docs/vercel-serverless-deployment.md +46 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/growthub.config.json +49 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/helpers/check-self-improving-health.sh +60 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/helpers/promote-capability.mjs +37 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/helpers/propose-capability.mjs +38 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/kit.json +45 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/templates/deployment-handoff.md +61 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/templates/supabase-setup-plan.md +26 -0
- package/dist/index.js +2903 -1596
- package/package.json +2 -1
package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/growthub.config.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "workspace-builder-default",
|
|
3
|
+
"name": "Workspace Builder",
|
|
4
|
+
"description": "Default no-code composition for the official Growthub Custom Workspace Starter. The interface starts as a configurable dashboard-builder shell and can be customized by editing this file or by future governed UI controls.",
|
|
5
|
+
"capabilities": [
|
|
6
|
+
"dashboards",
|
|
7
|
+
"canvas",
|
|
8
|
+
"widgets",
|
|
9
|
+
"bindings",
|
|
10
|
+
"integrations",
|
|
11
|
+
"settings"
|
|
12
|
+
],
|
|
13
|
+
"pipelines": [],
|
|
14
|
+
"integrations": [],
|
|
15
|
+
"dashboards": [
|
|
16
|
+
{
|
|
17
|
+
"id": "untitled-dashboard",
|
|
18
|
+
"name": "Untitled",
|
|
19
|
+
"createdBy": "Workspace owner",
|
|
20
|
+
"updatedAt": "new",
|
|
21
|
+
"status": "draft"
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"widgetTypes": [
|
|
25
|
+
{ "kind": "chart", "label": "Chart", "icon": "C" },
|
|
26
|
+
{ "kind": "view", "label": "View", "icon": "V" },
|
|
27
|
+
{ "kind": "iframe", "label": "iFrame", "icon": "I" },
|
|
28
|
+
{ "kind": "rich-text", "label": "Rich Text", "icon": "T" }
|
|
29
|
+
],
|
|
30
|
+
"canvas": {
|
|
31
|
+
"id": "workspace-canvas",
|
|
32
|
+
"name": "Tab 1",
|
|
33
|
+
"scope": "workspace",
|
|
34
|
+
"layout": {
|
|
35
|
+
"columns": 12,
|
|
36
|
+
"rowHeight": 64,
|
|
37
|
+
"gap": 16,
|
|
38
|
+
"responsive": true
|
|
39
|
+
},
|
|
40
|
+
"widgets": [],
|
|
41
|
+
"bindings": {
|
|
42
|
+
"chatToCanvas": true,
|
|
43
|
+
"workflowOutputsToArtifacts": true,
|
|
44
|
+
"sessionContext": true,
|
|
45
|
+
"configDrivenCanvas": true
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"provenance": {
|
|
49
|
+
"createdBy": "cli",
|
|
50
|
+
"mirrors": "growthub-agency-portal-starter-v1",
|
|
51
|
+
"note": "Shipped with growthub-custom-workspace-starter-v1; safe to edit inside a governed fork and validate through the starter export smoke path."
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -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-custom-workspace-starter-v1/apps/workspace/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,198 @@
|
|
|
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
|
+
const merged = mergeBridgeRows(normalizeGrowthubBridgePayload(payload));
|
|
61
|
+
return applyApiKeyOverlays(merged, config);
|
|
62
|
+
}
|
|
63
|
+
function applyApiKeyOverlays(integrations, config) {
|
|
64
|
+
if (!config.dataSources.hasWindsorApiKey) return integrations;
|
|
65
|
+
const windsorOverlay = {
|
|
66
|
+
status: "connected",
|
|
67
|
+
isConnected: true,
|
|
68
|
+
isActive: true,
|
|
69
|
+
authPath: "byo-api-key",
|
|
70
|
+
setupMode: "bring-your-own-key",
|
|
71
|
+
authType: "api_token",
|
|
72
|
+
category: "api_key",
|
|
73
|
+
secretEnvName: "WINDSOR_API_KEY",
|
|
74
|
+
connectionMetadata: { source: "workspace-env", secretEnvName: "WINDSOR_API_KEY" }
|
|
75
|
+
};
|
|
76
|
+
return integrations.map((item) => {
|
|
77
|
+
if (item.provider === "windsor-ai") return { ...item, ...windsorOverlay };
|
|
78
|
+
if (item.provider === "google-sheets") return { ...item, ...windsorOverlay, secretEnvName: undefined, connectionMetadata: { source: "windsor-blended-data" } };
|
|
79
|
+
return item;
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function readBringYourOwnRows() {
|
|
83
|
+
const raw = process.env.AGENCY_PORTAL_BYO_CONNECTIONS_JSON;
|
|
84
|
+
const rows = [];
|
|
85
|
+
if (process.env.WINDSOR_API_KEY) {
|
|
86
|
+
rows.push({
|
|
87
|
+
id: "windsor-ai",
|
|
88
|
+
provider: "windsor-ai",
|
|
89
|
+
name: "Windsor AI",
|
|
90
|
+
label: "Windsor AI",
|
|
91
|
+
category: "api_key",
|
|
92
|
+
authType: "api_token",
|
|
93
|
+
status: "connected",
|
|
94
|
+
isConnected: true,
|
|
95
|
+
isActive: true,
|
|
96
|
+
authPath: "byo-api-key",
|
|
97
|
+
setupMode: "bring-your-own-key",
|
|
98
|
+
secretEnvName: "WINDSOR_API_KEY",
|
|
99
|
+
connectionMetadata: {
|
|
100
|
+
source: "workspace-env",
|
|
101
|
+
secretEnvName: "WINDSOR_API_KEY"
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
if (!raw) return rows;
|
|
106
|
+
try {
|
|
107
|
+
const parsed = JSON.parse(raw);
|
|
108
|
+
return [...rows, ...normalizeGrowthubBridgePayload(parsed)];
|
|
109
|
+
} catch {
|
|
110
|
+
return rows;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function mergeBringYourOwnRows(rows) {
|
|
114
|
+
const merged = mergeBridgeRows(rows);
|
|
115
|
+
return merged.map((item) => {
|
|
116
|
+
const row = rows.find((candidate) => {
|
|
117
|
+
const provider = candidate.provider || candidate.id;
|
|
118
|
+
return provider === item.provider || candidate.id === item.id;
|
|
119
|
+
});
|
|
120
|
+
if (!row) return item;
|
|
121
|
+
return {
|
|
122
|
+
...item,
|
|
123
|
+
authPath: "byo-api-key",
|
|
124
|
+
setupMode: "bring-your-own-key",
|
|
125
|
+
secretEnvName: typeof row.secretEnvName === "string" ? row.secretEnvName : void 0,
|
|
126
|
+
status: row.status || "connected"
|
|
127
|
+
};
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
function mergeBridgeRows(rows) {
|
|
131
|
+
const seenProviders = /* @__PURE__ */ new Set();
|
|
132
|
+
const merged = agencyPortalIntegrationCatalog.map((catalogItem) => {
|
|
133
|
+
const row = rows.find((item) => {
|
|
134
|
+
const provider = item.provider || item.id;
|
|
135
|
+
return provider === catalogItem.provider || item.id === catalogItem.id;
|
|
136
|
+
});
|
|
137
|
+
if (!row) return catalogItem;
|
|
138
|
+
seenProviders.add(row.provider || row.id || catalogItem.provider);
|
|
139
|
+
return {
|
|
140
|
+
...catalogItem,
|
|
141
|
+
label: row.label || row.name || catalogItem.label,
|
|
142
|
+
name: row.name || row.label || catalogItem.name,
|
|
143
|
+
icon: row.icon || catalogItem.icon,
|
|
144
|
+
description: row.description || catalogItem.description,
|
|
145
|
+
category: row.category || catalogItem.category,
|
|
146
|
+
authType: row.authType || catalogItem.authType,
|
|
147
|
+
isConnected: row.isConnected ?? (row.status === "connected" ? true : catalogItem.isConnected),
|
|
148
|
+
isActive: row.isActive ?? (row.status === "connected" ? true : catalogItem.isActive),
|
|
149
|
+
authPath: row.authPath || catalogItem.authPath,
|
|
150
|
+
setupMode: row.setupMode || catalogItem.setupMode,
|
|
151
|
+
status: row.status || (row.isConnected || row.isActive ? "connected" : catalogItem.status),
|
|
152
|
+
connectionId: row.connectionId,
|
|
153
|
+
accountId: row.accountId,
|
|
154
|
+
secretEnvName: row.secretEnvName,
|
|
155
|
+
connectionMetadata: row.connectionMetadata || row.metadata,
|
|
156
|
+
metadata: row.metadata || row.connectionMetadata
|
|
157
|
+
};
|
|
158
|
+
});
|
|
159
|
+
const discoveredRows = rows.filter((row) => {
|
|
160
|
+
const provider = row.provider || row.id;
|
|
161
|
+
if (!provider) return false;
|
|
162
|
+
if (seenProviders.has(provider)) return false;
|
|
163
|
+
return !agencyPortalIntegrationCatalog.some((item) => item.provider === provider || item.id === row.id);
|
|
164
|
+
});
|
|
165
|
+
return [...merged, ...discoveredRows.map(toDiscoveredIntegration)];
|
|
166
|
+
}
|
|
167
|
+
function toDiscoveredIntegration(row) {
|
|
168
|
+
const provider = row.provider || row.id || "unknown-provider";
|
|
169
|
+
const label = row.label || row.name || provider;
|
|
170
|
+
const isDataPipeline = ["windsor-ai", "google-sheets", "google-analytics", "shopify", "meta-ads"].includes(provider);
|
|
171
|
+
const isConnected = row.isConnected ?? row.status === "connected";
|
|
172
|
+
return {
|
|
173
|
+
id: row.id || provider,
|
|
174
|
+
label,
|
|
175
|
+
name: row.name || label,
|
|
176
|
+
icon: row.icon || label.slice(0, 1).toUpperCase(),
|
|
177
|
+
provider,
|
|
178
|
+
description: row.description || "Connected through the Growthub account bridge.",
|
|
179
|
+
category: row.category || "mcp_connector",
|
|
180
|
+
authType: row.authType || "oauth_first_party",
|
|
181
|
+
isConnected,
|
|
182
|
+
isActive: row.isActive ?? isConnected,
|
|
183
|
+
lane: isDataPipeline ? "data-source" : "workspace-integration",
|
|
184
|
+
objectType: isDataPipeline ? "data-pipeline" : "mcp-connection",
|
|
185
|
+
status: row.status || (isConnected ? "connected" : "needs-connection"),
|
|
186
|
+
authPath: row.authPath || "growthub-mcp-bridge",
|
|
187
|
+
setupMode: row.setupMode || "hosted-authority",
|
|
188
|
+
connectionId: row.connectionId,
|
|
189
|
+
accountId: row.accountId,
|
|
190
|
+
secretEnvName: row.secretEnvName,
|
|
191
|
+
connectionMetadata: row.connectionMetadata || row.metadata,
|
|
192
|
+
metadata: row.metadata || row.connectionMetadata
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
export {
|
|
196
|
+
describeIntegrationAdapter,
|
|
197
|
+
listAgencyPortalIntegrations
|
|
198
|
+
};
|
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
function describeProviderManagedAdapter() {
|
|
2
|
+
return {
|
|
3
|
+
id: "provider-managed",
|
|
4
|
+
label: "Provider Managed",
|
|
5
|
+
requiredEnv: [],
|
|
6
|
+
mode: "external",
|
|
7
|
+
notes: [
|
|
8
|
+
"Use when a deployment provider owns persistence.",
|
|
9
|
+
"Document provider-specific environment variables in the fork journal.",
|
|
10
|
+
"Do not promote provider-specific names into the worker-kit manifest."
|
|
11
|
+
]
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
describeProviderManagedAdapter
|
|
16
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
function describeQstashKvAdapter() {
|
|
2
|
+
return {
|
|
3
|
+
id: "qstash-kv",
|
|
4
|
+
label: "Qstash KV",
|
|
5
|
+
requiredEnv: ["QSTASH_KV_REST_URL", "QSTASH_KV_REST_TOKEN"],
|
|
6
|
+
mode: "kv",
|
|
7
|
+
notes: [
|
|
8
|
+
"Use HTTP-first KV for serverless-friendly deployments.",
|
|
9
|
+
"Model relational portal records as namespaced documents and secondary indexes.",
|
|
10
|
+
"Keep queue and storage concerns separated from the domain capability map."
|
|
11
|
+
]
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
describeQstashKvAdapter
|
|
16
|
+
};
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
const dataSources = [
|
|
2
|
+
{
|
|
3
|
+
id: "windsor-ai",
|
|
4
|
+
label: "Windsor AI",
|
|
5
|
+
name: "Windsor AI",
|
|
6
|
+
icon: "W",
|
|
7
|
+
provider: "windsor-ai",
|
|
8
|
+
description: "Primary blended marketing data source for cross-channel reporting.",
|
|
9
|
+
category: "mcp_connector",
|
|
10
|
+
authType: "oauth_first_party",
|
|
11
|
+
isConnected: false,
|
|
12
|
+
isActive: false,
|
|
13
|
+
lane: "data-source",
|
|
14
|
+
objectType: "data-pipeline",
|
|
15
|
+
status: "needs-connection",
|
|
16
|
+
authPath: "growthub-mcp-bridge",
|
|
17
|
+
setupMode: "hosted-authority"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: "google-sheets-blended-data",
|
|
21
|
+
label: "Google Sheets blended data",
|
|
22
|
+
name: "Google Sheets blended data",
|
|
23
|
+
icon: "G",
|
|
24
|
+
provider: "google-sheets",
|
|
25
|
+
description: "Windsor AI blended data destination for spreadsheet-backed reporting workflows.",
|
|
26
|
+
category: "mcp_connector",
|
|
27
|
+
authType: "oauth_first_party",
|
|
28
|
+
isConnected: false,
|
|
29
|
+
isActive: false,
|
|
30
|
+
lane: "data-source",
|
|
31
|
+
objectType: "data-pipeline",
|
|
32
|
+
status: "needs-connection",
|
|
33
|
+
authPath: "growthub-mcp-bridge",
|
|
34
|
+
setupMode: "hosted-authority"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: "google-analytics",
|
|
38
|
+
label: "Google Analytics",
|
|
39
|
+
name: "Google Analytics",
|
|
40
|
+
icon: "G",
|
|
41
|
+
provider: "google-analytics",
|
|
42
|
+
description: "First-party Growthub connection for analytics properties and account metrics.",
|
|
43
|
+
category: "mcp_connector",
|
|
44
|
+
authType: "oauth_first_party",
|
|
45
|
+
isConnected: false,
|
|
46
|
+
isActive: false,
|
|
47
|
+
lane: "data-source",
|
|
48
|
+
objectType: "data-pipeline",
|
|
49
|
+
status: "needs-connection",
|
|
50
|
+
authPath: "growthub-mcp-bridge",
|
|
51
|
+
setupMode: "hosted-authority"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: "shopify",
|
|
55
|
+
label: "Shopify",
|
|
56
|
+
name: "Shopify",
|
|
57
|
+
icon: "S",
|
|
58
|
+
provider: "shopify",
|
|
59
|
+
description: "Commerce data source resolved through the Growthub MCP connection store.",
|
|
60
|
+
category: "mcp_connector",
|
|
61
|
+
authType: "oauth_first_party",
|
|
62
|
+
isConnected: false,
|
|
63
|
+
isActive: false,
|
|
64
|
+
lane: "data-source",
|
|
65
|
+
objectType: "data-pipeline",
|
|
66
|
+
status: "needs-connection",
|
|
67
|
+
authPath: "growthub-mcp-bridge",
|
|
68
|
+
setupMode: "hosted-authority"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: "meta-ads",
|
|
72
|
+
label: "Meta Facebook and Instagram",
|
|
73
|
+
name: "Meta Facebook and Instagram",
|
|
74
|
+
icon: "M",
|
|
75
|
+
provider: "meta-ads",
|
|
76
|
+
description: "First-party Meta account access for Facebook and Instagram performance data.",
|
|
77
|
+
category: "mcp_connector",
|
|
78
|
+
authType: "oauth_first_party",
|
|
79
|
+
isConnected: false,
|
|
80
|
+
isActive: false,
|
|
81
|
+
lane: "data-source",
|
|
82
|
+
objectType: "data-pipeline",
|
|
83
|
+
status: "needs-connection",
|
|
84
|
+
authPath: "growthub-mcp-bridge",
|
|
85
|
+
setupMode: "hosted-authority"
|
|
86
|
+
}
|
|
87
|
+
];
|
|
88
|
+
const workspaceIntegrations = [
|
|
89
|
+
{
|
|
90
|
+
id: "asana",
|
|
91
|
+
label: "Asana",
|
|
92
|
+
name: "Asana",
|
|
93
|
+
icon: "A",
|
|
94
|
+
provider: "asana",
|
|
95
|
+
description: "Project and task operations available through the connected Growthub account.",
|
|
96
|
+
category: "mcp_connector",
|
|
97
|
+
authType: "oauth_first_party",
|
|
98
|
+
isConnected: false,
|
|
99
|
+
isActive: false,
|
|
100
|
+
lane: "workspace-integration",
|
|
101
|
+
objectType: "mcp-connection",
|
|
102
|
+
status: "needs-connection",
|
|
103
|
+
authPath: "growthub-mcp-bridge",
|
|
104
|
+
setupMode: "hosted-authority"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
id: "slack",
|
|
108
|
+
label: "Slack",
|
|
109
|
+
name: "Slack",
|
|
110
|
+
icon: "S",
|
|
111
|
+
provider: "slack",
|
|
112
|
+
description: "Team messaging and notification workflows without app-local Slack secrets.",
|
|
113
|
+
category: "mcp_connector",
|
|
114
|
+
authType: "oauth_first_party",
|
|
115
|
+
isConnected: false,
|
|
116
|
+
isActive: false,
|
|
117
|
+
lane: "workspace-integration",
|
|
118
|
+
objectType: "mcp-connection",
|
|
119
|
+
status: "needs-connection",
|
|
120
|
+
authPath: "growthub-mcp-bridge",
|
|
121
|
+
setupMode: "hosted-authority"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
id: "go-high-level",
|
|
125
|
+
label: "GoHighLevel",
|
|
126
|
+
name: "GoHighLevel",
|
|
127
|
+
icon: "G",
|
|
128
|
+
provider: "go-high-level",
|
|
129
|
+
description: "CRM and social account access delegated through Growthub connection authority.",
|
|
130
|
+
category: "mcp_connector",
|
|
131
|
+
authType: "oauth_first_party",
|
|
132
|
+
isConnected: false,
|
|
133
|
+
isActive: false,
|
|
134
|
+
lane: "workspace-integration",
|
|
135
|
+
objectType: "mcp-connection",
|
|
136
|
+
status: "needs-connection",
|
|
137
|
+
authPath: "growthub-mcp-bridge",
|
|
138
|
+
setupMode: "hosted-authority"
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
id: "google-drive",
|
|
142
|
+
label: "Google Drive",
|
|
143
|
+
name: "Google Drive",
|
|
144
|
+
icon: "G",
|
|
145
|
+
provider: "google-drive",
|
|
146
|
+
description: "Document and knowledge-base access resolved through the user's connected account.",
|
|
147
|
+
category: "mcp_connector",
|
|
148
|
+
authType: "oauth_first_party",
|
|
149
|
+
isConnected: false,
|
|
150
|
+
isActive: false,
|
|
151
|
+
lane: "workspace-integration",
|
|
152
|
+
objectType: "mcp-connection",
|
|
153
|
+
status: "needs-connection",
|
|
154
|
+
authPath: "growthub-mcp-bridge",
|
|
155
|
+
setupMode: "hosted-authority"
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
id: "notion",
|
|
159
|
+
label: "Notion",
|
|
160
|
+
name: "Notion",
|
|
161
|
+
icon: "N",
|
|
162
|
+
provider: "notion",
|
|
163
|
+
description: "Workspace knowledge and project content access through the Growthub bridge.",
|
|
164
|
+
category: "mcp_connector",
|
|
165
|
+
authType: "oauth_first_party",
|
|
166
|
+
isConnected: false,
|
|
167
|
+
isActive: false,
|
|
168
|
+
lane: "workspace-integration",
|
|
169
|
+
objectType: "mcp-connection",
|
|
170
|
+
status: "needs-connection",
|
|
171
|
+
authPath: "growthub-mcp-bridge",
|
|
172
|
+
setupMode: "hosted-authority"
|
|
173
|
+
}
|
|
174
|
+
];
|
|
175
|
+
const agencyPortalIntegrationCatalog = [...dataSources, ...workspaceIntegrations];
|
|
176
|
+
function groupIntegrationsByLane(integrations) {
|
|
177
|
+
return {
|
|
178
|
+
dataSources: integrations.filter((item) => item.lane === "data-source"),
|
|
179
|
+
workspaceIntegrations: integrations.filter((item) => item.lane === "workspace-integration")
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
export {
|
|
183
|
+
agencyPortalIntegrationCatalog,
|
|
184
|
+
groupIntegrationsByLane
|
|
185
|
+
};
|