@growthub/cli 0.14.9 → 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.
Files changed (61) hide show
  1. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/add-ons/[providerId]/callback/route.js +35 -0
  2. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/add-ons/[providerId]/failure/route.js +35 -0
  3. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/add-ons/[providerId]/schedule/route.js +423 -0
  4. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/add-ons/providers/[providerId]/connect/route.js +78 -0
  5. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/add-ons/providers/[providerId]/credentials/route.js +276 -0
  6. 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
  7. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/add-ons/providers/[providerId]/products/sync/route.js +347 -0
  8. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/add-ons/providers/[providerId]/sync/route.js +293 -0
  9. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/add-ons/upstash/provider/connect/route.js +7 -0
  10. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/add-ons/upstash/provider/sync/route.js +7 -0
  11. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/add-ons/upstash/sync/route.js +197 -0
  12. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/apps/route.js +1 -1
  13. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/patch/preflight/route.js +38 -0
  14. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/sandbox-run/route.js +3 -20
  15. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/test-api-record/route.js +3 -20
  16. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/workflow/publish/route.js +407 -290
  17. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/workflows/[providerId]/route.js +209 -0
  18. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/components/WorkspaceAddOnsMarketplace.jsx +806 -0
  19. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/ApiRegistryActionCard.jsx +141 -0
  20. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/CeoCockpit.jsx +15 -3
  21. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/HelperSidecar.jsx +42 -5
  22. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationGraphCanvas.jsx +5 -1
  23. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationNodeConfigPanel.jsx +86 -20
  24. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/ScheduleCockpit.jsx +363 -0
  25. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/helper-commands.js +8 -0
  26. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/globals.css +322 -1
  27. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/page.jsx +2 -2
  28. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/settings/add-ons/add-ons-client.jsx +197 -0
  29. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/settings/add-ons/page.jsx +23 -0
  30. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/settings/settings-shell.jsx +1 -0
  31. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workflows/WorkflowSurface.jsx +734 -61
  32. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workspace-rail.jsx +15 -10
  33. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/env-status.js +2 -7
  34. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-graph-runner.js +29 -19
  35. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/sandbox-serverless-flow.js +8 -4
  36. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/schedule-cockpit-console.js +287 -0
  37. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/scheduler-orchestration.js +449 -0
  38. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/server-secrets.js +77 -0
  39. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/serverless-readiness.js +583 -0
  40. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-add-on-callback.js +63 -0
  41. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-add-on-scheduler.js +519 -0
  42. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-add-ons.js +957 -0
  43. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-app-readiness.js +212 -0
  44. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-config.js +607 -63
  45. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-contract-compliance.js +168 -0
  46. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-data-model.js +21 -0
  47. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-operator-auth.js +32 -0
  48. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-patch-impact.js +133 -0
  49. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-provenance-lineage.js +214 -0
  50. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-stale-surfaces.js +217 -0
  51. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-workflow-impact.js +170 -0
  52. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/public/integrations/upstash/provider.png +0 -0
  53. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/public/integrations/upstash/qstash.png +0 -0
  54. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/public/integrations/upstash/redis.png +0 -0
  55. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/public/integrations/upstash/search.png +0 -0
  56. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/public/integrations/upstash/vector.png +0 -0
  57. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/scripts/scheduler-ingress-smoke.mjs +26 -0
  58. package/assets/worker-kits/growthub-custom-workspace-starter-v1/kit.json +6 -0
  59. package/assets/worker-kits/growthub-custom-workspace-starter-v1/skills/governed-workspace-mutation/SKILL.md +3 -1
  60. package/dist/index.js +3024 -4191
  61. 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,6 +35,38 @@ import {
35
35
  } from "@/lib/workspace-patch-policy";
36
36
  import { evaluateAppScope, requireAppScope } from "@/lib/workspace-app-registry";
37
37
  import { appendOutcomeReceipt } from "@/lib/workspace-outcome-receipts";
38
+ import { readWorkspaceSourceRecords } from "@/lib/workspace-config";
39
+ import { buildWorkspaceMetadataStore } from "@/lib/workspace-metadata-store";
40
+ import { buildWorkspaceMetadataGraph } from "@/lib/workspace-metadata-graph";
41
+ import { derivePatchImpact } from "@/lib/workspace-patch-impact";
42
+
43
+ /**
44
+ * Report the blast radius of a proposed patch BEFORE the write — the S1
45
+ * spine's intended preflight consumption. Builds the metadata graph from the
46
+ * MERGED config (what the workspace becomes if this patch lands), maps the
47
+ * patched dataModel objects / dashboards to their graph node ids, and runs the
48
+ * pure `deriveStaleSurfaces` seed path over them. Pure, additive, never
49
+ * throws — on any failure the preflight verdict is unaffected and `impact`
50
+ * is simply omitted.
51
+ */
52
+ async function computePatchImpact(currentConfig, mergedConfig, patch) {
53
+ try {
54
+ if (!patch || typeof patch !== "object" || Array.isArray(patch)) return null;
55
+ let sourceRecords = {};
56
+ try { sourceRecords = (await readWorkspaceSourceRecords()) || {}; } catch { sourceRecords = {}; }
57
+ // Build BOTH graphs so the impact deriver can report not just added/modified
58
+ // (on the merged graph) but also REMOVED objects/dashboards (whose downstream
59
+ // lived in the current graph). One shared, unit-tested deriver does the diff.
60
+ const buildGraph = (cfg) => buildWorkspaceMetadataGraph(buildWorkspaceMetadataStore({ workspaceConfig: cfg || {}, workspaceSourceRecords: sourceRecords }));
61
+ const currentGraph = buildGraph(currentConfig);
62
+ const mergedGraph = buildGraph(mergedConfig);
63
+ const impact = derivePatchImpact(currentGraph, mergedGraph, currentConfig || {}, mergedConfig || {});
64
+ if (!impact.total && !impact.removed.length) return null;
65
+ return impact;
66
+ } catch {
67
+ return null;
68
+ }
69
+ }
38
70
 
39
71
  async function POST(request) {
40
72
  let patch;
@@ -66,12 +98,14 @@ async function POST(request) {
66
98
  // PATCH about the merged result. Skipped when the body is not a plain
67
99
  // object (policy already reports that).
68
100
  let schema = { ok: true, errors: [] };
101
+ let mergedConfig = null;
69
102
  if (patch && typeof patch === "object" && !Array.isArray(patch)) {
70
103
  const sanitized = {};
71
104
  for (const key of WORKSPACE_PATCH_ALLOWED_FIELDS) {
72
105
  if (Object.prototype.hasOwnProperty.call(patch, key)) sanitized[key] = patch[key];
73
106
  }
74
107
  const merged = applyWorkspaceConfigPatch(currentConfig || {}, sanitized);
108
+ mergedConfig = merged;
75
109
  try {
76
110
  validateWorkspaceConfig({
77
111
  dashboards: merged.dashboards,
@@ -103,6 +137,9 @@ async function POST(request) {
103
137
  }
104
138
  }
105
139
 
140
+ // Blast radius of this patch BEFORE the write (additive; never blocks).
141
+ const impact = await computePatchImpact(currentConfig, mergedConfig, patch);
142
+
106
143
  const persistence = describePersistenceMode();
107
144
  const ok = policy.ok && schema.ok && (appScopeVerdict ? appScopeVerdict.allowed : true);
108
145
  const repairPlan = repairPlanForViolations(policy.violations);
@@ -140,6 +177,7 @@ async function POST(request) {
140
177
  schema,
141
178
  repairPlan,
142
179
  ...(appScopeVerdict ? { appScopeVerdict } : {}),
180
+ ...(impact ? { impact } : {}),
143
181
  ...(safeNextStep ? { safeNextStep } : {}),
144
182
  persistence: {
145
183
  mode: persistence.mode,
@@ -88,26 +88,9 @@ import {
88
88
  validateRunInputsEnvelope,
89
89
  summarizeRunInputs
90
90
  } from "@/lib/orchestration-run-inputs";
91
-
92
- function envKeyCandidates(ref) {
93
- const token = String(ref || "")
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
- function envKeyCandidates(ref) {
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