@growthub/cli 0.14.10 → 0.14.11
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-custom-workspace-starter-v1/apps/workspace/app/api/workspace/add-ons/[providerId]/callback/route.js +35 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/add-ons/[providerId]/failure/route.js +35 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/add-ons/[providerId]/schedule/route.js +423 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/add-ons/providers/[providerId]/connect/route.js +78 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/add-ons/providers/[providerId]/credentials/route.js +276 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/add-ons/providers/[providerId]/products/[productId]/resources/route.js +173 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/add-ons/providers/[providerId]/products/sync/route.js +347 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/add-ons/providers/[providerId]/sync/route.js +293 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/add-ons/upstash/provider/connect/route.js +7 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/add-ons/upstash/provider/sync/route.js +7 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/add-ons/upstash/sync/route.js +197 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/apps/route.js +1 -1
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/metadata-graph/route.js +1 -49
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/sandbox-run/route.js +3 -20
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/test-api-record/route.js +3 -20
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/workflow/publish/route.js +407 -290
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/workflows/[providerId]/route.js +209 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/components/WorkspaceAddOnsMarketplace.jsx +806 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/ApiRegistryActionCard.jsx +141 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/CeoCockpit.jsx +15 -3
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/HelperSidecar.jsx +42 -5
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationGraphCanvas.jsx +5 -1
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationNodeConfigPanel.jsx +86 -20
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/ScheduleCockpit.jsx +363 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/helper-commands.js +8 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/globals.css +322 -1
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/page.jsx +2 -2
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/settings/add-ons/add-ons-client.jsx +197 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/settings/add-ons/page.jsx +23 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/settings/settings-shell.jsx +1 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workflows/WorkflowSurface.jsx +734 -61
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workspace-rail.jsx +15 -10
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/env-status.js +2 -7
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-graph-runner.js +2 -19
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/sandbox-serverless-flow.js +8 -4
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/schedule-cockpit-console.js +287 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/scheduler-orchestration.js +449 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/server-secrets.js +77 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/serverless-readiness.js +583 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-add-on-callback.js +63 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-add-on-scheduler.js +519 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-add-ons.js +957 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-config.js +607 -63
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-data-model.js +21 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-operator-auth.js +32 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/public/integrations/upstash/provider.png +0 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/public/integrations/upstash/qstash.png +0 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/public/integrations/upstash/redis.png +0 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/public/integrations/upstash/search.png +0 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/public/integrations/upstash/vector.png +0 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/scripts/scheduler-ingress-smoke.mjs +26 -0
- package/package.json +1 -1
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { readWorkspaceConfig, writeWorkspaceConfig } from "@/lib/workspace-config";
|
|
3
|
+
import {
|
|
4
|
+
getUpstashProduct,
|
|
5
|
+
listUpstashProductReadiness,
|
|
6
|
+
UPSTASH_REGION_OPTIONS,
|
|
7
|
+
withUpstashProductRegistry
|
|
8
|
+
} from "@/lib/workspace-add-ons";
|
|
9
|
+
import { appendOutcomeReceipt } from "@/lib/workspace-outcome-receipts";
|
|
10
|
+
import { readEnvVar, resolveRequiredEnv } from "@/lib/server-secrets";
|
|
11
|
+
|
|
12
|
+
const PROBE_TIMEOUT_MS = 8000;
|
|
13
|
+
|
|
14
|
+
function jsonError(message, status = 400, extra = {}) {
|
|
15
|
+
return NextResponse.json({ error: message, ...extra }, { status });
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function clean(value) {
|
|
19
|
+
return String(value == null ? "" : value).trim();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Canonical concrete-key read — same contract as readiness + schedule runtime.
|
|
23
|
+
function envValue(key) {
|
|
24
|
+
return clean(readEnvVar(key, process.env)?.value || "");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function selectedQstashRegion(region) {
|
|
28
|
+
return UPSTASH_REGION_OPTIONS.find((option) => option.id === region) || UPSTASH_REGION_OPTIONS[0];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function fetchWithTimeout(url, init = {}) {
|
|
32
|
+
const controller = new AbortController();
|
|
33
|
+
const timeout = setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS);
|
|
34
|
+
try {
|
|
35
|
+
return await fetch(url, { ...init, signal: controller.signal, cache: "no-store" });
|
|
36
|
+
} finally {
|
|
37
|
+
clearTimeout(timeout);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function readProbeText(response) {
|
|
42
|
+
try {
|
|
43
|
+
return clean(await response.text()).slice(0, 240);
|
|
44
|
+
} catch {
|
|
45
|
+
return "";
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function safeUrl(baseUrl, path) {
|
|
50
|
+
const base = clean(baseUrl).replace(/\/+$/, "");
|
|
51
|
+
const suffix = clean(path).startsWith("/") ? clean(path) : `/${clean(path)}`;
|
|
52
|
+
return `${base}${suffix}`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function probeJsonPaths({ baseUrl, token, paths, label }) {
|
|
56
|
+
let last = null;
|
|
57
|
+
for (const path of paths) {
|
|
58
|
+
const url = safeUrl(baseUrl, path);
|
|
59
|
+
const response = await fetchWithTimeout(url, {
|
|
60
|
+
method: "GET",
|
|
61
|
+
headers: { authorization: `Bearer ${token}` },
|
|
62
|
+
});
|
|
63
|
+
const text = await readProbeText(response);
|
|
64
|
+
last = { status: response.status, path, text };
|
|
65
|
+
if (response.ok) {
|
|
66
|
+
return {
|
|
67
|
+
ok: true,
|
|
68
|
+
baseUrl,
|
|
69
|
+
testedAt: new Date().toISOString(),
|
|
70
|
+
proof: `${label} probe ${path} returned HTTP ${response.status}`,
|
|
71
|
+
summary: `${label} sync verified with a read-only REST probe (${path}).`,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const details = last ? `${last.path} returned HTTP ${last.status}` : "no endpoint returned";
|
|
76
|
+
return {
|
|
77
|
+
ok: false,
|
|
78
|
+
baseUrl,
|
|
79
|
+
testedAt: new Date().toISOString(),
|
|
80
|
+
proof: `${label} probe failed: ${details}`,
|
|
81
|
+
summary: `${label} REST probe failed: ${details}.`,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function probeUpstashProduct(productId, region) {
|
|
86
|
+
const product = getUpstashProduct(productId);
|
|
87
|
+
if (!product) {
|
|
88
|
+
return { ok: false, status: 400, error: "unknown Upstash product" };
|
|
89
|
+
}
|
|
90
|
+
const readiness = listUpstashProductReadiness(process.env).find((item) => item.productId === product.productId);
|
|
91
|
+
const requiredEnv = resolveRequiredEnv(product.requiredEnv, process.env);
|
|
92
|
+
if (!readiness?.configured || !requiredEnv.ok) {
|
|
93
|
+
return {
|
|
94
|
+
ok: false,
|
|
95
|
+
status: 422,
|
|
96
|
+
error: `${product.label} provider credentials are not connected`,
|
|
97
|
+
missingEnv: requiredEnv.missing.length ? requiredEnv.missing : (readiness?.missingEnv || product.requiredEnv),
|
|
98
|
+
resolvedEnv: requiredEnv.resolvedKeys,
|
|
99
|
+
summary: `${product.label} provider credentials are not connected. Complete provider setup, then sync again.`,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const probe = product.probe || {};
|
|
104
|
+
if (!probe.baseUrlEnv || !probe.tokenEnv || !Array.isArray(probe.paths) || !probe.paths.length) {
|
|
105
|
+
return { ok: false, status: 400, error: "unsupported Upstash product probe" };
|
|
106
|
+
}
|
|
107
|
+
const regionOption = selectedQstashRegion(region);
|
|
108
|
+
const configuredUrl = envValue(probe.baseUrlEnv) || (probe.fallbackRegionBaseUrl ? regionOption.baseUrl : "");
|
|
109
|
+
const result = await probeJsonPaths({
|
|
110
|
+
baseUrl: configuredUrl,
|
|
111
|
+
token: envValue(probe.tokenEnv),
|
|
112
|
+
paths: probe.paths,
|
|
113
|
+
label: product.label,
|
|
114
|
+
});
|
|
115
|
+
return {
|
|
116
|
+
...result,
|
|
117
|
+
resolvedEnv: requiredEnv.resolvedKeys,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async function POST(request) {
|
|
122
|
+
let body = {};
|
|
123
|
+
try {
|
|
124
|
+
body = await request.json();
|
|
125
|
+
} catch {
|
|
126
|
+
return jsonError("invalid json body", 400);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const productId = clean(body.productId || "upstash-qstash");
|
|
130
|
+
const region = clean(body.region || "us-east-1");
|
|
131
|
+
const plan = clean(body.plan || "free");
|
|
132
|
+
const product = getUpstashProduct(productId);
|
|
133
|
+
if (!product) return jsonError("unknown Upstash product", 400, { productId });
|
|
134
|
+
|
|
135
|
+
const syncResult = await probeUpstashProduct(product.productId, region);
|
|
136
|
+
if (!syncResult.ok) {
|
|
137
|
+
await appendOutcomeReceipt({
|
|
138
|
+
kind: "workspace-add-on-sync",
|
|
139
|
+
lane: "server-authoritative",
|
|
140
|
+
outcomeStatus: "blocked",
|
|
141
|
+
actor: "workspace-marketplace",
|
|
142
|
+
objectRefs: [{ objectId: "api-registry", objectType: "api-registry", rowName: product.label }],
|
|
143
|
+
summary: syncResult.summary || syncResult.error || `${product.label} sync failed`,
|
|
144
|
+
policyVerdict: { ok: false, violationCodes: syncResult.missingEnv?.length ? ["provider_product_not_connected"] : ["provider_probe_failed"] },
|
|
145
|
+
nextActions: syncResult.missingEnv?.length
|
|
146
|
+
? [`Complete ${product.label} setup from the provider marketplace flow, then sync again.`]
|
|
147
|
+
: [`Open the ${product.label} provider console, verify the product connection, then retry sync.`]
|
|
148
|
+
});
|
|
149
|
+
return jsonError(syncResult.error || syncResult.summary || "Upstash sync failed", syncResult.status || 502, {
|
|
150
|
+
productId: product.productId,
|
|
151
|
+
missingEnv: syncResult.missingEnv || [],
|
|
152
|
+
sync: {
|
|
153
|
+
ok: false,
|
|
154
|
+
proof: syncResult.proof || "",
|
|
155
|
+
summary: syncResult.summary || "",
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const currentConfig = await readWorkspaceConfig();
|
|
161
|
+
const nextConfig = withUpstashProductRegistry(currentConfig, {
|
|
162
|
+
productId: product.productId,
|
|
163
|
+
region,
|
|
164
|
+
plan,
|
|
165
|
+
syncResult,
|
|
166
|
+
});
|
|
167
|
+
const persisted = await writeWorkspaceConfig({ dataModel: nextConfig.dataModel });
|
|
168
|
+
const { receipt } = await appendOutcomeReceipt({
|
|
169
|
+
kind: "workspace-add-on-sync",
|
|
170
|
+
lane: "server-authoritative",
|
|
171
|
+
outcomeStatus: "published",
|
|
172
|
+
actor: "workspace-marketplace",
|
|
173
|
+
objectRefs: [{ objectId: "api-registry", objectType: "api-registry", rowName: product.label }],
|
|
174
|
+
changedFields: ["dataModel.api-registry"],
|
|
175
|
+
policyVerdict: { ok: true },
|
|
176
|
+
schemaVerdict: { ok: true },
|
|
177
|
+
summary: `${product.label} installed after provider sync probe.`,
|
|
178
|
+
nextActions: product.productId === "upstash-qstash"
|
|
179
|
+
? ["Workflow Canvas can now bind QStash/Workflow from the installed product card."]
|
|
180
|
+
: ["Use this workspace add-on from the relevant data/retrieval surfaces."]
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
return NextResponse.json({
|
|
184
|
+
ok: true,
|
|
185
|
+
productId: product.productId,
|
|
186
|
+
workspaceConfig: persisted,
|
|
187
|
+
sync: {
|
|
188
|
+
ok: true,
|
|
189
|
+
proof: syncResult.proof,
|
|
190
|
+
summary: syncResult.summary,
|
|
191
|
+
testedAt: syncResult.testedAt,
|
|
192
|
+
},
|
|
193
|
+
receiptId: receipt.receiptId,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export { POST };
|
|
@@ -68,7 +68,7 @@ function safeRuntime(warnings) {
|
|
|
68
68
|
|
|
69
69
|
// Mirrors the CLI probe (cli/src/commands/workspace-surface.ts) so detection
|
|
70
70
|
// lives inside the artifact too — the bridge roadmap Item 4 called for.
|
|
71
|
-
const KNOWN_APP_DIRS = ["apps/workspace"];
|
|
71
|
+
const KNOWN_APP_DIRS = ["apps/workspace", "apps/agency-portal", "apps/portal", "studio", "app", "src"];
|
|
72
72
|
|
|
73
73
|
function detectFramework(absPath) {
|
|
74
74
|
try {
|
|
@@ -35,11 +35,6 @@ import { readWorkspaceConfig, readWorkspaceSourceRecords } from "@/lib/workspace
|
|
|
35
35
|
import { buildWorkspaceMetadataStore } from "@/lib/workspace-metadata-store";
|
|
36
36
|
import { buildWorkspaceMetadataGraph } from "@/lib/workspace-metadata-graph";
|
|
37
37
|
import { selectStaleMetadataGroups } from "@/lib/workspace-metadata-selectors";
|
|
38
|
-
import { deriveBlastRadius } from "@/lib/workspace-metadata-impact";
|
|
39
|
-
import { deriveStaleSurfaces } from "@/lib/workspace-stale-surfaces";
|
|
40
|
-
import { deriveWorkflowImpact } from "@/lib/workspace-workflow-impact";
|
|
41
|
-
import { deriveProvenanceLineage } from "@/lib/workspace-provenance-lineage";
|
|
42
|
-
import { deriveAppReadiness } from "@/lib/workspace-app-readiness";
|
|
43
38
|
|
|
44
39
|
const ENVELOPE_KIND = "growthub-workspace-metadata-graph-v1";
|
|
45
40
|
const ENVELOPE_VERSION = 1;
|
|
@@ -116,17 +111,10 @@ async function GET(request) {
|
|
|
116
111
|
// Optional stale-group selector via query params.
|
|
117
112
|
let staleGroups = [];
|
|
118
113
|
let staleReasons = [];
|
|
119
|
-
// Parse all causal query params from one URL read.
|
|
120
|
-
let impactId = "";
|
|
121
|
-
let lineageId = "";
|
|
122
|
-
let lineageDirection = "both";
|
|
123
114
|
try {
|
|
124
115
|
const url = request && request.url ? new URL(request.url) : null;
|
|
125
116
|
const staleKind = url ? (url.searchParams.get("staleKind") || "").trim() : "";
|
|
126
117
|
const staleId = url ? (url.searchParams.get("staleId") || "").trim() : "";
|
|
127
|
-
impactId = url ? (url.searchParams.get("impactId") || "").trim() : "";
|
|
128
|
-
lineageId = url ? (url.searchParams.get("lineageId") || "").trim() : "";
|
|
129
|
-
lineageDirection = url ? (url.searchParams.get("lineageDirection") || "both").trim() : "both";
|
|
130
118
|
if (staleKind && staleId) {
|
|
131
119
|
const result = selectStaleMetadataGroups(metadataStore, { kind: staleKind, id: staleId });
|
|
132
120
|
staleGroups = Array.isArray(result?.groups) ? result.groups : [];
|
|
@@ -136,30 +124,6 @@ async function GET(request) {
|
|
|
136
124
|
warnings.push(`Failed to compute stale groups: ${error?.message || "unknown error"}`);
|
|
137
125
|
}
|
|
138
126
|
|
|
139
|
-
// Causal derivations over the same read-only graph (Mutation → Law →
|
|
140
|
-
// Intelligence). All pure, all bounded, all secret-free. `staleSurfaces` is
|
|
141
|
-
// the unconditional freshness baseline (timestamps already in the graph);
|
|
142
|
-
// `impact` and `lineage` are computed on demand for one node.
|
|
143
|
-
let staleSurfaces = null;
|
|
144
|
-
let readiness = null;
|
|
145
|
-
let impact = null;
|
|
146
|
-
let lineage = null;
|
|
147
|
-
try {
|
|
148
|
-
staleSurfaces = deriveStaleSurfaces(graph);
|
|
149
|
-
readiness = deriveAppReadiness(graph);
|
|
150
|
-
if (impactId) {
|
|
151
|
-
impact = {
|
|
152
|
-
blastRadius: deriveBlastRadius(graph, impactId),
|
|
153
|
-
workflowImpact: deriveWorkflowImpact(graph, impactId)
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
if (lineageId) {
|
|
157
|
-
lineage = deriveProvenanceLineage(graph, lineageId, { direction: lineageDirection });
|
|
158
|
-
}
|
|
159
|
-
} catch (error) {
|
|
160
|
-
warnings.push(`Failed to compute causal derivations: ${error?.message || "unknown error"}`);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
127
|
return NextResponse.json({
|
|
164
128
|
kind: ENVELOPE_KIND,
|
|
165
129
|
version: ENVELOPE_VERSION,
|
|
@@ -199,11 +163,6 @@ async function GET(request) {
|
|
|
199
163
|
groups: staleGroups,
|
|
200
164
|
reasons: staleReasons
|
|
201
165
|
},
|
|
202
|
-
// Causal intelligence layer — read-only derivations over `graph` above.
|
|
203
|
-
staleSurfaces,
|
|
204
|
-
readiness,
|
|
205
|
-
...(impact ? { impact } : {}),
|
|
206
|
-
...(lineage ? { lineage } : {}),
|
|
207
166
|
warnings,
|
|
208
167
|
selectors: {
|
|
209
168
|
// Manifest of selectors the route honours. Only `selectStaleMetadataGroups`
|
|
@@ -211,14 +170,7 @@ async function GET(request) {
|
|
|
211
170
|
// selectors are exposed as importable helpers for server-side consumers
|
|
212
171
|
// and the read-only inspector; they are NOT toggled through query
|
|
213
172
|
// params in V1.
|
|
214
|
-
httpEnabled: [
|
|
215
|
-
"selectStaleMetadataGroups",
|
|
216
|
-
"deriveStaleSurfaces",
|
|
217
|
-
"deriveBlastRadius",
|
|
218
|
-
"deriveWorkflowImpact",
|
|
219
|
-
"deriveProvenanceLineage",
|
|
220
|
-
"deriveAppReadiness"
|
|
221
|
-
],
|
|
173
|
+
httpEnabled: ["selectStaleMetadataGroups"],
|
|
222
174
|
helperOnly: [
|
|
223
175
|
"selectWidgetRequiredFields",
|
|
224
176
|
"selectWorkflowNodeInputSchema",
|
|
@@ -88,26 +88,9 @@ import {
|
|
|
88
88
|
validateRunInputsEnvelope,
|
|
89
89
|
summarizeRunInputs
|
|
90
90
|
} from "@/lib/orchestration-run-inputs";
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
.trim()
|
|
95
|
-
.replace(/[^a-z0-9]+/gi, "_")
|
|
96
|
-
.replace(/^_+|_+$/g, "")
|
|
97
|
-
.toUpperCase();
|
|
98
|
-
return Array.from(new Set([
|
|
99
|
-
token,
|
|
100
|
-
token ? `${token}_API_KEY` : "",
|
|
101
|
-
token ? `${token}_TOKEN` : ""
|
|
102
|
-
].filter(Boolean)));
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
function readServerSecret(authRef) {
|
|
106
|
-
for (const key of envKeyCandidates(authRef)) {
|
|
107
|
-
if (process.env[key]) return { key, value: process.env[key] };
|
|
108
|
-
}
|
|
109
|
-
return null;
|
|
110
|
-
}
|
|
91
|
+
// Single canonical secret resolver — shared with the serverless add-on lane so
|
|
92
|
+
// both run lanes resolve stored env tokens identically (no copy-pasted logic).
|
|
93
|
+
import { readServerSecret } from "@/lib/server-secrets";
|
|
111
94
|
|
|
112
95
|
function coerceBoolean(value) {
|
|
113
96
|
if (value === true || value === false) return value;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { NextResponse } from "next/server";
|
|
2
2
|
import { readWorkspaceConfig } from "@/lib/workspace-config";
|
|
3
|
+
import { readServerSecret } from "@/lib/server-secrets";
|
|
3
4
|
|
|
4
5
|
const DEFAULT_TIMEOUT_MS = 15000;
|
|
5
6
|
|
|
@@ -18,25 +19,7 @@ function buildUrl(record) {
|
|
|
18
19
|
return `${baseUrl.replace(/\/+$/, "")}/${endpoint.replace(/^\/+/, "")}`;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
const token = String(ref || "")
|
|
23
|
-
.trim()
|
|
24
|
-
.replace(/[^a-z0-9]+/gi, "_")
|
|
25
|
-
.replace(/^_+|_+$/g, "")
|
|
26
|
-
.toUpperCase();
|
|
27
|
-
return Array.from(new Set([
|
|
28
|
-
token,
|
|
29
|
-
token ? `${token}_API_KEY` : "",
|
|
30
|
-
token ? `${token}_TOKEN` : "",
|
|
31
|
-
].filter(Boolean)));
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function readServerSecret(authRef) {
|
|
35
|
-
for (const key of envKeyCandidates(authRef)) {
|
|
36
|
-
if (process.env[key]) return process.env[key];
|
|
37
|
-
}
|
|
38
|
-
return "";
|
|
39
|
-
}
|
|
22
|
+
// Secret resolution uses the single canonical resolver from lib/server-secrets.js.
|
|
40
23
|
|
|
41
24
|
function findRegistryRecord(workspaceConfig, registryId) {
|
|
42
25
|
const id = String(registryId || "").trim();
|
|
@@ -86,7 +69,7 @@ async function POST(request) {
|
|
|
86
69
|
|
|
87
70
|
const method = normalizeMethod(record.method);
|
|
88
71
|
const authRef = record.authRef || record.integrationId || dataSourceRecord?.registryId;
|
|
89
|
-
const secret = readServerSecret(authRef);
|
|
72
|
+
const secret = readServerSecret(authRef)?.value || "";
|
|
90
73
|
const controller = new AbortController();
|
|
91
74
|
const timeout = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT_MS);
|
|
92
75
|
|