@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.
Files changed (52) 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/metadata-graph/route.js +1 -49
  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 +2 -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-config.js +607 -63
  44. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-data-model.js +21 -0
  45. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-operator-auth.js +32 -0
  46. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/public/integrations/upstash/provider.png +0 -0
  47. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/public/integrations/upstash/qstash.png +0 -0
  48. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/public/integrations/upstash/redis.png +0 -0
  49. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/public/integrations/upstash/search.png +0 -0
  50. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/public/integrations/upstash/vector.png +0 -0
  51. package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/scripts/scheduler-ingress-smoke.mjs +26 -0
  52. package/package.json +1 -1
@@ -5125,6 +5125,160 @@ body.workspace-rail-collapsed .workspace-builder.dm-workflow-page {
5125
5125
  .dm-workflow-upgrade-panel-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 10px 14px 0; }
5126
5126
  .dm-workflow-upgrade-panel-head .dm-api-action-card-eyebrow { margin: 0; }
5127
5127
  .dm-workflow-upgrade-panel .dm-api-action-card { margin: 8px; box-shadow: none; }
5128
+ .dm-workflow-schedule-backdrop { position: fixed; inset: 0; z-index: 60; display: grid; place-items: center; padding: 24px; background: rgba(15, 23, 42, .28); }
5129
+ .dm-workflow-schedule-modal { width: min(560px, 100%); max-height: min(760px, calc(100vh - 48px)); display: grid; grid-template-rows: auto minmax(0, 1fr) auto; overflow: hidden; border: 1px solid #d1d5db; border-radius: 8px; background: #fff; box-shadow: 0 24px 80px rgba(15,23,42,.22); }
5130
+ .dm-workflow-schedule-modal header,
5131
+ .dm-workflow-schedule-modal footer { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 16px; border-bottom: 1px solid #edf0f3; }
5132
+ .dm-workflow-schedule-modal footer { justify-content: flex-end; border-top: 1px solid #edf0f3; border-bottom: 0; background: #fafafa; }
5133
+ .dm-workflow-schedule-modal h3 { margin: 2px 0 0; font-size: 16px; color: #111827; }
5134
+ .dm-workflow-schedule-body { display: grid; gap: 12px; padding: 16px; overflow: auto; }
5135
+ .dm-marketplace-field textarea { width: 100%; border: 1px solid #e5e7eb; border-radius: 6px; padding: 10px; background: #fff; color: #111827; font: inherit; resize: vertical; box-sizing: border-box; }
5136
+ .dm-marketplace-field textarea:focus { outline: none; border-color: #9ca3af; box-shadow: 0 0 0 3px rgba(17,24,39,.06); }
5137
+ .dm-workflow-schedule-error { margin: 0; border: 1px solid #fecaca; border-radius: 6px; background: #fef2f2; color: #991b1b; padding: 10px; font-size: 12px; line-height: 1.4; }
5138
+ .dm-marketplace-backdrop { position: fixed; inset: 0; z-index: 90; display: grid; place-items: center; padding: 24px; background: rgba(15,23,42,.28); }
5139
+ .dm-marketplace-modal { position: relative; width: min(1040px, calc(100vw - 48px)); max-height: min(820px, calc(100vh - 48px)); overflow: hidden; display: flex; flex-direction: column; border: 1px solid #e5e7eb; border-radius: 8px; background: #fff; box-shadow: 0 24px 80px rgba(15,23,42,.24); }
5140
+ .dm-marketplace-page { position: relative; min-height: 680px; overflow: hidden; display: flex; flex-direction: column; border: 1px solid #e5e7eb; border-radius: 8px; background: #fff; box-shadow: 0 2px 8px rgba(15,23,42,.06); }
5141
+ .dm-marketplace-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; padding: 22px 24px 18px; border-bottom: 1px solid #edf0f3; }
5142
+ .dm-marketplace-header h2 { margin: 2px 0 0; font-size: 24px; line-height: 1.15; color: #111827; }
5143
+ .dm-marketplace-breadcrumbs { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-bottom: 18px; color: #4b5563; font-size: 12px; }
5144
+ .dm-marketplace-breadcrumbs svg { transform: rotate(-90deg); color: #9ca3af; }
5145
+ .dm-marketplace-breadcrumbs strong { color: #111827; font-weight: 500; }
5146
+ .dm-marketplace-breadcrumbs button { border: 0; padding: 0; background: transparent; color: #2563eb; font: inherit; cursor: pointer; }
5147
+ .dm-marketplace-provider-title { display: flex; align-items: center; gap: 12px; }
5148
+ .dm-marketplace-provider-title p { margin: 5px 0 0; color: #4b5563; font-size: 13px; }
5149
+ .dm-marketplace-subtitle { margin: 5px 0 0; color: #4b5563; font-size: 13px; }
5150
+ .dm-marketplace-provider-mark { width: 34px; height: 34px; display: inline-flex; align-items: center; justify-content: center; border-radius: 999px; background: #030712; color: #34d399; font-weight: 800; box-shadow: inset 0 0 0 2px #34d399; }
5151
+ .dm-marketplace-provider-actions { display: flex; align-items: center; gap: 8px; }
5152
+ .dm-marketplace-provider-actions a,
5153
+ .dm-marketplace-provider-actions button { display: inline-flex; align-items: center; gap: 6px; text-decoration: none; white-space: nowrap; }
5154
+ .dm-marketplace-layout { display: grid; grid-template-columns: 220px minmax(0, 1fr); min-height: 0; flex: 1; }
5155
+ .dm-marketplace-sidebar { padding: 16px 12px; border-right: 1px solid #edf0f3; display: grid; gap: 6px; align-content: start; background: #fafafa; }
5156
+ .dm-marketplace-sidebar button { display: flex; align-items: center; gap: 10px; width: 100%; border: 0; border-radius: 6px; padding: 10px 12px; background: transparent; color: #374151; font-size: 14px; font-weight: 650; cursor: pointer; text-align: left; }
5157
+ .dm-marketplace-sidebar button:hover,
5158
+ .dm-marketplace-sidebar button.is-active { background: #ecebea; color: #111827; }
5159
+ .dm-marketplace-setup-nav { margin-top: 14px; padding: 12px; border-top: 1px solid #e5e7eb; color: #64748b; font-size: 11px; text-transform: uppercase; letter-spacing: .08em; }
5160
+ .dm-marketplace-setup-nav ol { display: grid; gap: 8px; margin: 10px 0 0; padding: 0; list-style: none; text-transform: none; letter-spacing: 0; font-size: 12px; }
5161
+ .dm-marketplace-setup-nav li { display: flex; align-items: center; gap: 8px; color: #64748b; }
5162
+ .dm-marketplace-setup-nav li::before { content: ""; width: 8px; height: 8px; border: 1px solid #cbd5e1; border-radius: 999px; background: #fff; }
5163
+ .dm-marketplace-setup-nav li.is-active { color: #111827; font-weight: 700; }
5164
+ .dm-marketplace-setup-nav li.is-active::before { border-color: #111827; background: #111827; }
5165
+ .dm-marketplace-content { min-width: 0; overflow-y: auto; padding: 18px 22px 24px; display: grid; gap: 14px; align-content: start; }
5166
+ .dm-marketplace-error { border: 1px solid #fecaca; border-radius: 7px; padding: 10px 12px; background: #fef2f2; color: #991b1b; font-size: 13px; line-height: 1.35; }
5167
+ .dm-marketplace-search-row { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: 10px; align-items: center; }
5168
+ .dm-marketplace-search { min-width: 0; display: flex; align-items: center; gap: 8px; height: 38px; padding: 0 12px; border: 1px solid #bfdbfe; border-radius: 7px; color: #111827; box-shadow: 0 0 0 2px rgba(59,130,246,.12); }
5169
+ .dm-marketplace-filter { height: 38px; display: inline-flex; align-items: center; gap: 8px; border: 1px solid #e5e7eb; border-radius: 7px; padding: 0 12px; background: #fff; color: #6b7280; cursor: pointer; }
5170
+ .dm-marketplace-install-card { border: 1px solid #e5e7eb; border-radius: 8px; background: #fff; box-shadow: 0 2px 8px rgba(15,23,42,.06); overflow: hidden; }
5171
+ .dm-marketplace-provider-layout { display: grid; grid-template-columns: minmax(0, 1fr) 280px; gap: 28px; align-items: start; }
5172
+ .dm-marketplace-provider-main { display: grid; gap: 24px; }
5173
+ .dm-marketplace-details { display: grid; gap: 0; }
5174
+ .dm-marketplace-details h3,
5175
+ .dm-marketplace-overview h3 { margin: 0 0 10px; font-size: 16px; color: #111827; }
5176
+ .dm-marketplace-details div { min-height: 42px; display: grid; grid-template-columns: minmax(0, .85fr) minmax(0, 1fr); gap: 12px; align-items: center; border-bottom: 1px solid #e5e7eb; font-size: 12px; }
5177
+ .dm-marketplace-details span { color: #111827; }
5178
+ .dm-marketplace-details strong { color: #111827; font-weight: 500; text-align: right; }
5179
+ .dm-marketplace-details a { display: inline-flex; justify-content: flex-end; align-items: center; gap: 4px; color: #2563eb; text-decoration: none; text-align: right; }
5180
+ .dm-marketplace-overview { display: grid; gap: 6px; }
5181
+ .dm-marketplace-overview p { margin: 0; color: #4b5563; font-size: 13px; line-height: 1.5; }
5182
+ .dm-marketplace-products { display: grid; gap: 10px; }
5183
+ .dm-marketplace-products h3 { margin: 8px 0 0; font-size: 16px; color: #111827; }
5184
+ .dm-marketplace-product-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 14px; }
5185
+ .dm-marketplace-provider-grid { display: grid; grid-template-columns: minmax(0, 520px); gap: 12px; }
5186
+ .dm-marketplace-provider-card { min-height: 124px; display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 14px; align-items: center; border: 1px solid #e5e7eb; border-radius: 8px; background: #fff; padding: 18px; cursor: pointer; text-align: left; }
5187
+ .dm-marketplace-provider-card:hover { border-color: #cbd5e1; box-shadow: 0 8px 24px rgba(15,23,42,.08); }
5188
+ .dm-marketplace-provider-card strong { display: block; color: #111827; font-size: 15px; }
5189
+ .dm-marketplace-provider-card p { margin: 4px 0 0; color: #4b5563; font-size: 13px; }
5190
+ .dm-marketplace-provider-card small { display: block; margin-top: 12px; color: #64748b; font-size: 12px; }
5191
+ .dm-marketplace-product-card { min-height: 116px; display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 12px; align-items: start; border: 1px solid #e5e7eb; border-radius: 8px; background: #fff; padding: 14px; }
5192
+ .dm-marketplace-product-card.is-muted { background: #fcfcfc; }
5193
+ .dm-marketplace-product-card strong { display: block; font-size: 13px; color: #111827; }
5194
+ .dm-marketplace-product-card p { margin: 3px 0 0; font-size: 12px; color: #4b5563; }
5195
+ .dm-marketplace-product-card small { display: block; margin-top: 22px; color: #4b5563; font-size: 12px; }
5196
+ .dm-marketplace-card-actions { display: grid; justify-items: end; gap: 8px; }
5197
+ .dm-marketplace-gear { opacity: 0; transform: translateY(-2px); transition: opacity .14s ease, transform .14s ease; }
5198
+ .dm-marketplace-product-card:hover .dm-marketplace-gear,
5199
+ .dm-marketplace-gear:focus-visible { opacity: 1; transform: translateY(0); }
5200
+ .dm-marketplace-product-head { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 12px; align-items: center; padding: 16px; border-bottom: 1px solid #edf0f3; }
5201
+ .dm-marketplace-product-head h3 { margin: 0; font-size: 15px; color: #111827; }
5202
+ .dm-marketplace-product-head p { margin: 3px 0 0; font-size: 12px; line-height: 1.35; color: #4b5563; }
5203
+ .dm-marketplace-product-icon { width: 34px; height: 34px; display: inline-flex; align-items: center; justify-content: center; border-radius: 8px; overflow: hidden; font-weight: 800; color: #fff; }
5204
+ .dm-marketplace-product-icon img { width: 100%; height: 100%; object-fit: cover; display: block; }
5205
+ .dm-marketplace-product-icon.is-upstash { background: #7c3aed; }
5206
+ .dm-marketplace-product-icon.is-provider { border-radius: 999px; background: #030712; }
5207
+ .dm-marketplace-product-icon.is-custom { background: #111827; }
5208
+ .dm-marketplace-product-icon.is-redis { background: #dc2626; }
5209
+ .dm-marketplace-product-icon.is-search { background: #eab308; }
5210
+ .dm-marketplace-product-icon.is-vector { background: #ea580c; }
5211
+ .dm-marketplace-config { padding: 16px; display: grid; gap: 12px; }
5212
+ .dm-marketplace-section-title { margin: 0; display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 700; color: #111827; }
5213
+ .dm-marketplace-field { display: grid; gap: 7px; font-size: 12px; color: #4b5563; }
5214
+ .dm-marketplace-field select,
5215
+ .dm-marketplace-field input { height: 38px; width: 100%; border: 1px solid #e5e7eb; border-radius: 6px; padding: 0 10px; background: #fff; color: #111827; font: inherit; box-sizing: border-box; }
5216
+ .dm-marketplace-field input:focus,
5217
+ .dm-marketplace-field select:focus { outline: none; border-color: #9ca3af; box-shadow: 0 0 0 3px rgba(17,24,39,.06); }
5218
+ .dm-marketplace-credential-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
5219
+ @media (max-width: 760px) { .dm-marketplace-credential-grid { grid-template-columns: 1fr; } }
5220
+ .dm-marketplace-install-choice { display: grid; gap: 10px; border: 1px solid #e5e7eb; border-radius: 7px; padding: 12px; background: #fff; }
5221
+ .dm-marketplace-install-choice strong { display: block; color: #111827; font-size: 13px; }
5222
+ .dm-marketplace-install-choice span { display: block; margin-top: 3px; color: #64748b; font-size: 12px; line-height: 1.4; }
5223
+ .dm-marketplace-toggle { display: inline-flex; align-items: center; gap: 8px; font-size: 12px; color: #4b5563; }
5224
+ .dm-marketplace-toggle input { width: 34px; height: 20px; }
5225
+ .dm-marketplace-resource-divider { display: flex; align-items: center; gap: 10px; color: #64748b; font-size: 12px; font-weight: 650; }
5226
+ .dm-marketplace-resource-divider::before,
5227
+ .dm-marketplace-resource-divider::after { content: ""; height: 1px; flex: 1 1 auto; background: #e5e7eb; }
5228
+ .dm-marketplace-resource-divider span { white-space: nowrap; }
5229
+ .dm-marketplace-plan-list { display: grid; gap: 8px; padding-top: 6px; }
5230
+ .dm-marketplace-plan { min-height: 54px; display: flex; align-items: center; justify-content: space-between; gap: 10px; border: 1px solid #e5e7eb; border-radius: 6px; background: #fff; padding: 10px; color: #374151; cursor: pointer; text-align: left; }
5231
+ .dm-marketplace-plan.is-selected { border-color: #c7d2fe; background: #f8fafc; color: #111827; }
5232
+ .dm-marketplace-plan:disabled { color: #9ca3af; cursor: not-allowed; }
5233
+ .dm-marketplace-plan b { color: #111827; }
5234
+ .dm-marketplace-radio { width: 13px; height: 13px; flex: 0 0 auto; border: 1px solid #9ca3af; border-radius: 999px; }
5235
+ .dm-marketplace-env { display: flex; align-items: center; justify-content: space-between; gap: 10px; border: 1px solid #e5e7eb; border-radius: 6px; background: #f8fafc; color: #334155; padding: 10px; font-size: 12px; }
5236
+ .dm-marketplace-env.is-ready { border-color: #bbf7d0; background: #f0fdf4; color: #166534; }
5237
+ .dm-marketplace-env code { color: inherit; word-break: break-all; }
5238
+ .dm-marketplace-config-summary { display: grid; gap: 6px; border: 1px solid #e5e7eb; border-radius: 7px; padding: 10px; background: #fafafa; }
5239
+ .dm-marketplace-config-summary div { display: grid; grid-template-columns: 92px minmax(0, 1fr); gap: 8px; align-items: start; font-size: 12px; }
5240
+ .dm-marketplace-config-summary span { color: #64748b; }
5241
+ .dm-marketplace-config-summary code { color: #111827; white-space: normal; word-break: break-word; }
5242
+ .dm-marketplace-install-drawer { position: absolute; inset: 0 0 0 auto; z-index: 2; width: min(430px, 100%); padding: 14px; background: rgba(255,255,255,.84); box-shadow: -16px 0 50px rgba(15,23,42,.16); backdrop-filter: blur(2px); overflow-y: auto; }
5243
+ .dm-marketplace-modal .dm-marketplace-install-drawer { position: absolute; }
5244
+ .dm-marketplace-drawer-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 14px 16px; border-bottom: 1px solid #edf0f3; }
5245
+ .dm-marketplace-drawer-head h3 { margin: 0; font-size: 16px; color: #111827; }
5246
+ .dm-marketplace-provision-steps { display: grid; gap: 10px; padding: 12px 16px; border-top: 1px solid #edf0f3; }
5247
+ .dm-marketplace-provision-steps div { border: 1px solid #e5e7eb; border-radius: 7px; padding: 12px; color: #9ca3af; font-size: 13px; font-weight: 650; }
5248
+ .dm-marketplace-provision-steps div.is-active { color: #111827; border-color: #d1d5db; background: #fafafa; }
5249
+ .dm-marketplace-provision-steps div.is-complete { color: #374151; border-color: #d1d5db; background: #f8fafc; }
5250
+ .dm-marketplace-provision-steps .dm-marketplace-step-action-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 8px 8px 8px 12px; }
5251
+ .dm-marketplace-step-action-row .dm-btn-primary-sm { min-height: 34px; white-space: nowrap; }
5252
+ .dm-marketplace-adapters { padding: 16px; display: grid; gap: 8px; }
5253
+ .dm-marketplace-adapter { display: grid; grid-template-columns: minmax(0, .8fr) minmax(0, 1fr); gap: 10px; align-items: center; border: 1px solid #e5e7eb; border-radius: 6px; padding: 10px; background: #fff; }
5254
+ .dm-marketplace-adapter.is-ready { border-color: #bbf7d0; background: #f8fffb; }
5255
+ .dm-marketplace-adapter div { display: grid; gap: 2px; }
5256
+ .dm-marketplace-adapter strong { font-size: 13px; color: #111827; }
5257
+ .dm-marketplace-adapter span,
5258
+ .dm-marketplace-adapter code { font-size: 11px; color: #64748b; }
5259
+ .dm-marketplace-adapter code { text-align: right; white-space: normal; word-break: break-word; }
5260
+ .dm-marketplace-actions { display: flex; justify-content: flex-end; gap: 8px; padding: 14px 16px; border-top: 1px solid #edf0f3; background: #fafafa; }
5261
+ .dm-marketplace-console-link { margin-right: auto; display: inline-flex; align-items: center; gap: 6px; text-decoration: none; }
5262
+ .dm-marketplace-create-new-btn { justify-content: center; }
5263
+ .dm-marketplace-primary-link { text-decoration: none; justify-content: center; }
5264
+ @media (min-width: 761px) {
5265
+ .dm-marketplace-page { min-height: min(760px, calc(100vh - 112px)); height: min(920px, calc(100vh - 112px)); }
5266
+ }
5267
+ @media (max-width: 760px) {
5268
+ .dm-marketplace-backdrop { padding: 10px; align-items: stretch; }
5269
+ .dm-marketplace-modal { width: 100%; max-height: calc(100vh - 20px); }
5270
+ .dm-marketplace-layout { grid-template-columns: 1fr; }
5271
+ .dm-marketplace-sidebar { grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); border-right: 0; border-bottom: 1px solid #edf0f3; }
5272
+ .dm-marketplace-setup-nav { grid-column: 1 / -1; }
5273
+ .dm-marketplace-provider-actions { flex-wrap: wrap; justify-content: flex-start; }
5274
+ .dm-marketplace-provider-layout { grid-template-columns: 1fr; }
5275
+ .dm-marketplace-search-row { grid-template-columns: 1fr; }
5276
+ .dm-marketplace-product-grid { grid-template-columns: 1fr; }
5277
+ .dm-marketplace-adapter,
5278
+ .dm-marketplace-product-head { grid-template-columns: auto minmax(0, 1fr); }
5279
+ .dm-marketplace-product-head .dm-db-status { grid-column: 1 / -1; justify-self: start; }
5280
+ .dm-marketplace-adapter code { text-align: left; }
5281
+ }
5128
5282
 
5129
5283
  .dm-api-review-banner {
5130
5284
  display: grid;
@@ -5201,7 +5355,31 @@ body.workspace-rail-collapsed .workspace-builder.dm-workflow-page {
5201
5355
  .dm-orchestration-config__fieldmap,
5202
5356
  .dm-orchestration-config__payload { display: grid; gap: 8px; }
5203
5357
  .dm-orchestration-config__fieldmap-row,
5204
- .dm-orchestration-config__payload-row { display: grid; grid-template-columns: 1fr 1fr auto; gap: 6px; align-items: center; }
5358
+ .dm-orchestration-config__payload-row { display: grid; grid-template-columns: minmax(112px, .72fr) minmax(0, 1fr) auto; gap: 6px; align-items: center; min-width: 0; }
5359
+ .dm-orchestration-config__payload-row > input {
5360
+ min-width: 0;
5361
+ width: 100%;
5362
+ height: 34px;
5363
+ border: 1px solid #cbd5e1;
5364
+ border-radius: 6px;
5365
+ background: #fff;
5366
+ color: #111827;
5367
+ font: inherit;
5368
+ font-size: 12px;
5369
+ padding: 7px 9px;
5370
+ box-sizing: border-box;
5371
+ }
5372
+ .dm-orchestration-config__payload-row > input:focus {
5373
+ outline: none;
5374
+ border-color: #64748b;
5375
+ box-shadow: 0 0 0 3px rgba(100, 116, 139, .12);
5376
+ }
5377
+ .dm-orchestration-config__payload-row > .dm-btn-ghost {
5378
+ height: 34px;
5379
+ min-width: 70px;
5380
+ justify-content: center;
5381
+ white-space: nowrap;
5382
+ }
5205
5383
  .dm-orchestration-config__advanced-json summary { cursor: pointer; font-size: 11px; font-weight: 650; color: #374151; }
5206
5384
  .dm-orchestration-preview { margin: 0; padding: 10px; background: #f9fafb; border: 1px solid #e5e7eb; border-radius: 5px; font-size: 10px; overflow: auto; max-height: 160px; white-space: pre-wrap; word-break: break-word; }
5207
5385
  .dm-orchestration-preview > span { display: block; font-size: 10px; font-weight: 700; text-transform: uppercase; color: #6b7280; margin-bottom: 6px; }
@@ -5808,6 +5986,24 @@ body.workspace-rail-collapsed .workspace-builder.dm-workflow-page {
5808
5986
  border-color: #64748b;
5809
5987
  box-shadow: 0 0 0 3px rgba(100, 116, 139, .12);
5810
5988
  }
5989
+
5990
+ .dm-workflow-orchestration .dm-input-mode-select .dm-select-option.selected {
5991
+ background: #f5f5f5;
5992
+ color: #111827;
5993
+ }
5994
+
5995
+ .dm-workflow-orchestration .dm-input-mode-select {
5996
+ z-index: 130;
5997
+ }
5998
+
5999
+ .dm-workflow-orchestration .dm-input-mode-select .dm-select-option {
6000
+ grid-template-columns: 18px minmax(0, 1fr);
6001
+ align-items: center;
6002
+ }
6003
+
6004
+ .dm-workflow-orchestration .dm-input-mode-select .dm-select-option svg {
6005
+ color: #64748b;
6006
+ }
5811
6007
  .dm-workflow-orchestration .dm-orchestration-config__field input:disabled,
5812
6008
  .dm-workflow-orchestration .dm-orchestration-config__field textarea:disabled,
5813
6009
  .dm-workflow-orchestration .dm-orchestration-config__field select:disabled {
@@ -9447,3 +9643,128 @@ body.workspace-rail-collapsed .workspace-builder.workspace-lens-page,
9447
9643
  .dm-db-empty-state strong { font-size: 15px; color: var(--dm-ink); font-weight: 650; }
9448
9644
  .dm-db-empty-state span { font-size: 12.5px; color: var(--dm-muted); max-width: 360px; }
9449
9645
  .dm-db-empty-actions { display: inline-flex; gap: 8px; margin-top: 8px; }
9646
+
9647
+ /* Input-node serverless schedule fields — shown below the config panel only
9648
+ when Input mode = serverless schedule. Inherits the sidecar field styles. */
9649
+ .dm-trigger-schedule-config {
9650
+ display: flex;
9651
+ flex-direction: column;
9652
+ gap: 10px;
9653
+ margin-top: 12px;
9654
+ padding: 0;
9655
+ border: 0;
9656
+ background: transparent;
9657
+ min-height: 0;
9658
+ }
9659
+ .dm-workflow-schedule-state {
9660
+ display: grid;
9661
+ gap: 5px;
9662
+ margin: 0;
9663
+ padding: 0;
9664
+ }
9665
+ .dm-workflow-schedule-state div {
9666
+ display: grid;
9667
+ grid-template-columns: 86px minmax(0, 1fr);
9668
+ gap: 8px;
9669
+ align-items: baseline;
9670
+ min-width: 0;
9671
+ }
9672
+ .dm-workflow-schedule-state dt {
9673
+ color: #64748b;
9674
+ font-size: 10px;
9675
+ font-weight: 700;
9676
+ line-height: 1.25;
9677
+ margin: 0;
9678
+ text-transform: uppercase;
9679
+ }
9680
+ .dm-workflow-schedule-state dd {
9681
+ min-width: 0;
9682
+ margin: 0;
9683
+ color: #111827;
9684
+ font-size: 12px;
9685
+ line-height: 1.35;
9686
+ overflow-wrap: anywhere;
9687
+ }
9688
+ .dm-workflow-schedule-last-run {
9689
+ display: flex;
9690
+ align-items: center;
9691
+ justify-content: space-between;
9692
+ gap: 10px;
9693
+ min-height: 30px;
9694
+ padding: 0;
9695
+ color: #475569;
9696
+ }
9697
+ .dm-workflow-schedule-last-run span { font-size: 11px; font-weight: 650; color: #475569; }
9698
+ .dm-workflow-schedule-last-run strong { color: #111827; font-size: 12px; font-weight: 650; }
9699
+ .dm-workflow-schedule-submit {
9700
+ width: 100%;
9701
+ justify-content: center;
9702
+ }
9703
+ .dm-workflow-schedule-actions {
9704
+ display: grid;
9705
+ grid-template-columns: repeat(3, minmax(0, 1fr));
9706
+ gap: 8px;
9707
+ }
9708
+ .dm-workflow-schedule-actions .dm-btn-outline {
9709
+ justify-content: center;
9710
+ min-width: 0;
9711
+ }
9712
+ .dm-btn-outline.is-danger {
9713
+ border-color: #fecaca;
9714
+ color: #991b1b;
9715
+ }
9716
+ .dm-btn-outline.is-danger:hover:not(:disabled) {
9717
+ border-color: #fca5a5;
9718
+ background: #fef2f2;
9719
+ }
9720
+
9721
+ .dm-workflow-orchestration .dm-orchestration-config__field select {
9722
+ border-color: #cbd5e1;
9723
+ background: #fff;
9724
+ color: #111827;
9725
+ box-shadow: none;
9726
+ }
9727
+
9728
+ .dm-workflow-orchestration .dm-orchestration-config__field select:focus {
9729
+ outline: none;
9730
+ border-color: #64748b;
9731
+ box-shadow: 0 0 0 3px rgba(100, 116, 139, .12);
9732
+ }
9733
+
9734
+ /* ------------------------------------------------------------------ *
9735
+ * Serverless-readiness flagging — ultrathin orange only. *
9736
+ * The color IS the guidance: a flagged node gets an ultrathin orange *
9737
+ * border (nothing else added), and ONLY the exact main field(s) / *
9738
+ * delta-tag shield(s) the readiness scan mapped get a light-orange *
9739
+ * fill. No badges, no copy — handled atomically under the hood. *
9740
+ * ------------------------------------------------------------------ */
9741
+ .dm-orchestration-node--readiness { border-color: #f59e0b; box-shadow: 0 0 0 1px rgba(245, 158, 11, 0.55); }
9742
+ .dm-orchestration-node--readiness.is-warning { border-color: #fbbf24; box-shadow: 0 0 0 1px rgba(251, 191, 36, 0.42); }
9743
+ .dm-orchestration-node--readiness:hover { border-color: #f59e0b; }
9744
+ .dm-orchestration-node--readiness.dm-orchestration-node--selected { border-color: #f59e0b; box-shadow: 0 0 0 1px #f59e0b, 0 2px 8px rgba(245, 158, 11, 0.16); }
9745
+
9746
+ .dm-orchestration-config__field.dm-field--readiness input,
9747
+ .dm-orchestration-config__field.dm-field--readiness textarea,
9748
+ .dm-orchestration-config__field.dm-field--readiness select { border-color: #f59e0b; background: #fffbeb; }
9749
+ .dm-orchestration-config__field.dm-field--readiness.is-warning input,
9750
+ .dm-orchestration-config__field.dm-field--readiness.is-warning textarea,
9751
+ .dm-orchestration-config__field.dm-field--readiness.is-warning select { border-color: #fcd34d; background: #fffdf5; }
9752
+
9753
+ .dm-orchestration-config__payload.dm-field--readiness { border-radius: 6px; padding: 6px; background: #fffbeb; box-shadow: inset 0 0 0 1px rgba(245, 158, 11, 0.4); }
9754
+ .dm-orchestration-config__payload.dm-field--readiness.is-warning { background: #fffdf5; box-shadow: inset 0 0 0 1px rgba(252, 211, 77, 0.45); }
9755
+
9756
+ /* ------------------------------------------------------------------ *
9757
+ * Schedule cockpit (/schedule) — sidecar operations surface. Reuses *
9758
+ * the swarm/CEO card grammar; only the search/filter/tag chrome is new.*
9759
+ * ------------------------------------------------------------------ */
9760
+ .dm-schedule-search { display: flex; align-items: center; gap: 6px; padding: 6px 9px; border: 1px solid #e5e7eb; border-radius: 6px; background: #fff; color: #6b7280; margin-bottom: 8px; }
9761
+ .dm-schedule-search input { flex: 1; min-width: 0; border: 0; outline: none; font-size: 12px; color: #111827; background: transparent; }
9762
+ .dm-schedule-filters { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
9763
+ .dm-schedule-filter { border: 1px solid #e5e7eb; border-radius: 999px; padding: 3px 10px; font-size: 11px; font-weight: 600; color: #475569; background: #fff; cursor: pointer; }
9764
+ .dm-schedule-filter:hover { border-color: #cbd5e1; }
9765
+ .dm-schedule-filter.is-active { border-color: #2563eb; color: #1d4ed8; background: #eff6ff; }
9766
+ .dm-schedule-tags { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }
9767
+ .dm-schedule-tag { font-size: 10px; font-weight: 600; line-height: 1.4; padding: 1px 7px; border-radius: 999px; border: 1px solid #e5e7eb; color: #475569; background: #f8fafc; }
9768
+ .dm-schedule-tag[data-tag-tone="alert"] { border-color: #fde68a; color: #92400e; background: #fffbeb; }
9769
+ .dm-schedule-tag[data-tag-tone="ok"] { border-color: #bbf7d0; color: #166534; background: #f0fdf4; }
9770
+ .dm-schedule-card-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
@@ -1,9 +1,8 @@
1
1
  import { Suspense } from "react";
2
- import workspaceConfig from "../growthub.config.json";
3
2
  import { readAdapterConfig } from "@/lib/adapters/env";
4
3
  import { describeIntegrationAdapter, listGovernedWorkspaceIntegrations } from "@/lib/adapters/integrations";
5
4
  import { groupIntegrationsByLane } from "@/lib/domain/integrations";
6
- import { describePersistenceMode, readWorkspaceSourceRecords } from "@/lib/workspace-config";
5
+ import { describePersistenceMode, readWorkspaceConfig, readWorkspaceSourceRecords } from "@/lib/workspace-config";
7
6
  import WorkspaceBuilder from "./workspace-builder.jsx";
8
7
 
9
8
  async function Home() {
@@ -11,6 +10,7 @@ async function Home() {
11
10
  const integrationAdapter = describeIntegrationAdapter();
12
11
  const integrations = await listGovernedWorkspaceIntegrations();
13
12
  const persistence = describePersistenceMode();
13
+ const workspaceConfig = await readWorkspaceConfig();
14
14
  let initialSourceRecords = {};
15
15
  try {
16
16
  initialSourceRecords = (await readWorkspaceSourceRecords()) || {};
@@ -0,0 +1,197 @@
1
+ "use client";
2
+
3
+ import { useEffect, useState } from "react";
4
+ import { useRouter } from "next/navigation";
5
+ import { WorkspaceAddOnsMarketplace } from "../../components/WorkspaceAddOnsMarketplace.jsx";
6
+
7
+ function AddOnsSettingsClient({ initialWorkspaceConfig, envSignals }) {
8
+ const router = useRouter();
9
+ const [workspaceConfig, setWorkspaceConfig] = useState(initialWorkspaceConfig || {});
10
+ const [activeAction, setActiveAction] = useState("");
11
+ const [errorMessage, setErrorMessage] = useState("");
12
+ const [pendingProviderId, setPendingProviderId] = useState("");
13
+ const [setupMessage, setSetupMessage] = useState("");
14
+ const [providerSetupWindow, setProviderSetupWindow] = useState(null);
15
+ const normalizedEnvSignals = {
16
+ configuredEnvRefs: envSignals?.configuredEnvRefs || [],
17
+ persistenceAdapters: envSignals?.persistenceAdapters || [],
18
+ providerProductReadiness: envSignals?.providerProductReadiness || {},
19
+ };
20
+
21
+ async function connectProvider(setup = {}) {
22
+ const providerId = setup.providerId;
23
+ if (!providerId) return;
24
+ if (!setup.openedExternally) setActiveAction("connect");
25
+ setErrorMessage("");
26
+ setPendingProviderId(providerId);
27
+ setSetupMessage("Provider account setup is open. Return here after the account page is ready; the workspace will sync automatically.");
28
+ try {
29
+ const response = await fetch(`/api/workspace/add-ons/providers/${encodeURIComponent(providerId)}/connect`, {
30
+ method: "POST",
31
+ headers: { "content-type": "application/json" },
32
+ body: JSON.stringify(setup),
33
+ });
34
+ const payload = await response.json();
35
+ if (!response.ok) {
36
+ setErrorMessage(payload?.error || "Provider setup state could not be recorded.");
37
+ return;
38
+ }
39
+ if (payload.workspaceConfig) {
40
+ setWorkspaceConfig(payload.workspaceConfig);
41
+ }
42
+ if (payload.accountState === "setup-opened") {
43
+ setPendingProviderId(providerId);
44
+ setSetupMessage("Provider account setup is open. Return here after the account page is ready; the workspace will sync automatically.");
45
+ } else {
46
+ setPendingProviderId("");
47
+ setSetupMessage("");
48
+ }
49
+ if (!setup.openedExternally && payload.connectUrl) {
50
+ const setupWindow = window.open(payload.connectUrl, `${providerId}-provider-setup`, "popup,width=1160,height=820");
51
+ setProviderSetupWindow(setupWindow || null);
52
+ }
53
+ } catch (error) {
54
+ console.warn(error);
55
+ setErrorMessage(error?.message || "Provider setup failed.");
56
+ } finally {
57
+ if (!setup.openedExternally) setActiveAction("");
58
+ }
59
+ }
60
+
61
+ async function syncProvider(setup = {}, options = {}) {
62
+ const providerId = setup.providerId;
63
+ if (!providerId) return;
64
+ setActiveAction("sync-provider");
65
+ setErrorMessage("");
66
+ try {
67
+ const response = await fetch(`/api/workspace/add-ons/providers/${encodeURIComponent(providerId)}/sync`, {
68
+ method: "POST",
69
+ headers: { "content-type": "application/json" },
70
+ body: JSON.stringify(setup),
71
+ });
72
+ const payload = await response.json();
73
+ if (!response.ok) {
74
+ if (!options.silent) {
75
+ setErrorMessage(payload?.error || payload?.sync?.summary || "Provider sync failed.");
76
+ }
77
+ return;
78
+ }
79
+ setWorkspaceConfig(payload.workspaceConfig || workspaceConfig);
80
+ setPendingProviderId("");
81
+ setSetupMessage("");
82
+ setProviderSetupWindow(null);
83
+ } catch (error) {
84
+ console.warn(error);
85
+ if (!options.silent) {
86
+ setErrorMessage(error?.message || "Provider sync failed.");
87
+ }
88
+ } finally {
89
+ setActiveAction("");
90
+ }
91
+ }
92
+
93
+ async function saveProviderCredentials(setup = {}) {
94
+ const providerId = setup.providerId;
95
+ if (!providerId) return;
96
+ setActiveAction("save-provider");
97
+ setErrorMessage("");
98
+ try {
99
+ const response = await fetch(`/api/workspace/add-ons/providers/${encodeURIComponent(providerId)}/credentials`, {
100
+ method: "POST",
101
+ headers: { "content-type": "application/json" },
102
+ body: JSON.stringify({ credentials: setup.credentials || {} }),
103
+ });
104
+ const payload = await response.json();
105
+ if (!response.ok) {
106
+ setErrorMessage(payload?.error || "Provider account could not be verified.");
107
+ return;
108
+ }
109
+ setWorkspaceConfig(payload.workspaceConfig || workspaceConfig);
110
+ setPendingProviderId("");
111
+ setSetupMessage("");
112
+ setProviderSetupWindow(null);
113
+ } catch (error) {
114
+ console.warn(error);
115
+ setErrorMessage(error?.message || "Provider account setup failed.");
116
+ } finally {
117
+ setActiveAction("");
118
+ }
119
+ }
120
+
121
+ async function syncProduct({ providerId, productId, region, plan, selectedResourceId, selectedResourceLabel, selectedResourceSource }) {
122
+ if (!providerId || !productId) return;
123
+ setActiveAction("sync-product");
124
+ setErrorMessage("");
125
+ try {
126
+ const response = await fetch(`/api/workspace/add-ons/providers/${encodeURIComponent(providerId)}/products/sync`, {
127
+ method: "POST",
128
+ headers: { "content-type": "application/json" },
129
+ body: JSON.stringify({ productId, region, plan, selectedResourceId, selectedResourceLabel, selectedResourceSource }),
130
+ });
131
+ const payload = await response.json();
132
+ if (!response.ok) {
133
+ const missing = Array.isArray(payload?.missingEnv) && payload.missingEnv.length
134
+ ? ` Missing env: ${payload.missingEnv.join(", ")}.`
135
+ : "";
136
+ setErrorMessage(`${payload?.error || payload?.sync?.summary || "Product sync failed."}${missing}`);
137
+ return;
138
+ }
139
+ setWorkspaceConfig(payload.workspaceConfig || workspaceConfig);
140
+ } catch (error) {
141
+ console.warn(error);
142
+ setErrorMessage(error?.message || "Product sync failed.");
143
+ } finally {
144
+ setActiveAction("");
145
+ }
146
+ }
147
+
148
+ useEffect(() => {
149
+ if (!pendingProviderId) return undefined;
150
+ let didSync = false;
151
+ const trySync = () => {
152
+ if (didSync || document.visibilityState === "hidden") return;
153
+ didSync = true;
154
+ syncProvider({ providerId: pendingProviderId });
155
+ };
156
+ const onFocus = () => trySync();
157
+ const onVisibilityChange = () => {
158
+ if (document.visibilityState === "visible") trySync();
159
+ };
160
+ const pollWindow = window.setInterval(() => {
161
+ if (providerSetupWindow?.closed) {
162
+ window.clearInterval(pollWindow);
163
+ trySync();
164
+ }
165
+ }, 1000);
166
+ window.addEventListener("focus", onFocus);
167
+ document.addEventListener("visibilitychange", onVisibilityChange);
168
+ return () => {
169
+ window.clearInterval(pollWindow);
170
+ window.removeEventListener("focus", onFocus);
171
+ document.removeEventListener("visibilitychange", onVisibilityChange);
172
+ };
173
+ }, [pendingProviderId, providerSetupWindow]);
174
+
175
+ return (
176
+ <>
177
+ <WorkspaceAddOnsMarketplace
178
+ shell="page"
179
+ workspaceConfig={workspaceConfig}
180
+ envSignals={normalizedEnvSignals}
181
+ installing={Boolean(activeAction)}
182
+ activeAction={activeAction}
183
+ errorMessage={errorMessage}
184
+ setupMessage={setupMessage}
185
+ onConnectProvider={connectProvider}
186
+ onSyncProvider={syncProvider}
187
+ onSaveProviderCredentials={saveProviderCredentials}
188
+ onSyncProduct={syncProduct}
189
+ onCustomSetup={() => router.push("/settings/apis-webhooks")}
190
+ />
191
+ </>
192
+ );
193
+ }
194
+
195
+ export {
196
+ AddOnsSettingsClient
197
+ };
@@ -0,0 +1,23 @@
1
+ import { SettingsShell } from "../settings-shell.jsx";
2
+ import { readWorkspaceConfig } from "@/lib/workspace-config";
3
+ import { computeConfiguredEnvRefs, listPersistenceAdapterReadiness } from "@/lib/env-status";
4
+ import { listAllProviderProductReadiness } from "@/lib/workspace-add-ons";
5
+ import { AddOnsSettingsClient } from "./add-ons-client.jsx";
6
+
7
+ async function AddOnsSettingsPage() {
8
+ const workspaceConfig = await readWorkspaceConfig();
9
+ const envSignals = {
10
+ configuredEnvRefs: computeConfiguredEnvRefs(workspaceConfig, process.env),
11
+ persistenceAdapters: listPersistenceAdapterReadiness(process.env),
12
+ // Key MUST match what add-ons-client.jsx normalizes (`providerProductReadiness`).
13
+ // Provider-keyed so every marketplace provider's per-product readiness renders.
14
+ providerProductReadiness: listAllProviderProductReadiness(process.env),
15
+ };
16
+ return <SettingsShell active="/settings/add-ons" eyebrow="Settings" title="Marketplace">
17
+ <AddOnsSettingsClient initialWorkspaceConfig={workspaceConfig} envSignals={envSignals} />
18
+ </SettingsShell>;
19
+ }
20
+
21
+ export {
22
+ AddOnsSettingsPage as default
23
+ };
@@ -4,6 +4,7 @@ import { X } from "lucide-react";
4
4
  const SETTINGS_TABS = [
5
5
  { href: "/settings/general", label: "General" },
6
6
  { href: "/settings/apis-webhooks", label: "APIs & Webhooks" },
7
+ { href: "/settings/add-ons", label: "Marketplace" },
7
8
  { href: "/settings/apps", label: "Apps" },
8
9
  { href: "/settings/ownership", label: "Ownership" }
9
10
  ];