@wopr-network/platform-ui-core 1.27.8 → 1.27.9
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/next.config.ts +1 -2
- package/package.json +17 -17
- package/src/__tests__/account-switcher.test.tsx +21 -20
- package/src/__tests__/activity-page.test.tsx +2 -6
- package/src/__tests__/add-payment-method-dialog.test.tsx +9 -32
- package/src/__tests__/admin-api.test.ts +1 -6
- package/src/__tests__/admin-gpu-api.test.ts +1 -3
- package/src/__tests__/admin-marketplace-api.test.ts +1 -4
- package/src/__tests__/admin-middleware.test.ts +76 -83
- package/src/__tests__/affiliate-dashboard.test.tsx +3 -3
- package/src/__tests__/api-401-redirect.test.ts +46 -9
- package/src/__tests__/api-client.test.ts +3 -5
- package/src/__tests__/api-config.test.ts +22 -42
- package/src/__tests__/api-fleet-resources.test.ts +1 -2
- package/src/__tests__/api-fleet-trpc.test.ts +2 -8
- package/src/__tests__/api-null-guards.test.ts +3 -1
- package/src/__tests__/audit-log-table-pagination.test.tsx +2 -6
- package/src/__tests__/auth-password-reset.test.tsx +7 -21
- package/src/__tests__/auth-redirect.test.tsx +8 -2
- package/src/__tests__/auth.test.tsx +25 -23
- package/src/__tests__/auto-topup-card.test.tsx +4 -12
- package/src/__tests__/backups-tab.test.tsx +3 -4
- package/src/__tests__/billing-layout-nav-hidden.test.tsx +5 -37
- package/src/__tests__/billing-payment-org-invoices.test.tsx +2 -18
- package/src/__tests__/billing.test.tsx +8 -39
- package/src/__tests__/bot-settings/resources-tab.test.tsx +1 -3
- package/src/__tests__/bot-settings/storage-tab.test.tsx +1 -3
- package/src/__tests__/bot-settings/vps-upgrade-card.test.tsx +1 -3
- package/src/__tests__/bot-settings-restart.test.tsx +1 -3
- package/src/__tests__/bot-settings.test.tsx +2 -6
- package/src/__tests__/brand.test.ts +6 -26
- package/src/__tests__/buy-credits-panel.test.tsx +1 -3
- package/src/__tests__/buy-crypto-credits-panel.test.tsx +101 -119
- package/src/__tests__/capability-conflicts.test.ts +2 -8
- package/src/__tests__/capability-resolver.test.tsx +2 -12
- package/src/__tests__/channel-wizard.test.tsx +4 -17
- package/src/__tests__/chat/chat-panel.test.tsx +1 -4
- package/src/__tests__/chat-store.test.ts +5 -15
- package/src/__tests__/command-center.test.tsx +10 -12
- package/src/__tests__/compliance-retention-edit.test.tsx +3 -6
- package/src/__tests__/confirmation-tracker.test.tsx +3 -18
- package/src/__tests__/coupon-input.test.tsx +1 -3
- package/src/__tests__/create-instance.test.tsx +1 -3
- package/src/__tests__/credit-balance.test.tsx +4 -12
- package/src/__tests__/credits.test.tsx +32 -85
- package/src/__tests__/email-verification-banner.test.tsx +2 -6
- package/src/__tests__/error-boundaries.test.tsx +0 -1
- package/src/__tests__/fetch-pricing.test.ts +2 -1
- package/src/__tests__/field-oauth.test.tsx +2 -6
- package/src/__tests__/fixtures/mock-manifests-data.js +1 -3
- package/src/__tests__/fixtures/mock-manifests.ts +2 -4
- package/src/__tests__/fleet-health-timestamp.test.tsx +1 -8
- package/src/__tests__/fleet-health-update.test.tsx +1 -8
- package/src/__tests__/gpu-dashboard.test.tsx +2 -6
- package/src/__tests__/instance-detail.test.tsx +3 -9
- package/src/__tests__/instance-list.test.tsx +1 -5
- package/src/__tests__/layout-snapshots.test.tsx +64 -11
- package/src/__tests__/marketplace-admin.test.tsx +2 -6
- package/src/__tests__/marketplace.test.tsx +11 -35
- package/src/__tests__/merge-api-rates.test.ts +1 -6
- package/src/__tests__/middleware.test.ts +32 -219
- package/src/__tests__/next-config-headers.test.ts +1 -3
- package/src/__tests__/notifications.test.tsx +4 -11
- package/src/__tests__/oauth-buttons.test.tsx +36 -59
- package/src/__tests__/oauth-error-mapping.test.tsx +2 -6
- package/src/__tests__/observability.test.tsx +23 -36
- package/src/__tests__/onboarding-page.test.tsx +4 -6
- package/src/__tests__/org-billing-api.test.tsx +1 -6
- package/src/__tests__/plugin-install-flow.test.tsx +28 -58
- package/src/__tests__/plugin-registry.test.tsx +3 -11
- package/src/__tests__/plugin-tool-sync.test.ts +1 -3
- package/src/__tests__/plugins-catalog-error.test.tsx +2 -6
- package/src/__tests__/plugins-toggle-race.test.tsx +3 -5
- package/src/__tests__/portfolio-chart.test.tsx +2 -6
- package/src/__tests__/promotion-form.test.tsx +2 -6
- package/src/__tests__/promotions-list.test.tsx +1 -3
- package/src/__tests__/provider-key-api.test.ts +2 -1
- package/src/__tests__/resend-verification-button.test.tsx +8 -24
- package/src/__tests__/secrets-audit-pagination.test.tsx +1 -3
- package/src/__tests__/settings.test.tsx +11 -21
- package/src/__tests__/setup-checklist.test.tsx +3 -9
- package/src/__tests__/setup.ts +25 -6
- package/src/__tests__/snapshot-api.test.ts +2 -1
- package/src/__tests__/step-superpowers.test.tsx +1 -3
- package/src/__tests__/tenant-context.test.tsx +1 -6
- package/src/__tests__/tenant-keys-api.test.ts +3 -4
- package/src/__tests__/tenant-table-pagination.test.tsx +2 -6
- package/src/__tests__/terminal-log-cleanup.test.tsx +0 -1
- package/src/__tests__/transaction-history.test.tsx +190 -238
- package/src/__tests__/trpc-types.test.ts +2 -6
- package/src/__tests__/use-chat.test.ts +1 -3
- package/src/__tests__/use-plugin-setup-chat-stale-closure.test.ts +1 -4
- package/src/__tests__/use-sidecar-bridge.test.tsx +105 -0
- package/src/__tests__/use-webmcp.test.ts +1 -3
- package/src/__tests__/validate-elevenlabs-key.test.ts +2 -1
- package/src/__tests__/verify-page.test.tsx +4 -13
- package/src/__tests__/verify-redirect.test.tsx +2 -6
- package/src/app/(auth)/error.tsx +1 -7
- package/src/app/(auth)/forgot-password/page.tsx +4 -18
- package/src/app/(auth)/login/page.tsx +5 -22
- package/src/app/(auth)/reset-password/page.tsx +2 -12
- package/src/app/(auth)/signup/page.tsx +10 -44
- package/src/app/(auth)/verify/page.tsx +47 -0
- package/src/app/(dashboard)/billing/credits/page.tsx +14 -67
- package/src/app/(dashboard)/billing/error.tsx +2 -10
- package/src/app/(dashboard)/billing/layout.tsx +12 -62
- package/src/app/(dashboard)/billing/payment/page.tsx +17 -68
- package/src/app/(dashboard)/billing/plans/page.tsx +3 -9
- package/src/app/(dashboard)/billing/usage/hosted/page.tsx +8 -25
- package/src/app/(dashboard)/billing/usage/page.tsx +63 -103
- package/src/app/(dashboard)/changesets/[id]/changeset-detail-client.tsx +9 -27
- package/src/app/(dashboard)/changesets/[id]/error.tsx +2 -6
- package/src/app/(dashboard)/changesets/error.tsx +1 -7
- package/src/app/(dashboard)/chat/page.tsx +2 -6
- package/src/app/(dashboard)/dashboard/network/page.tsx +5 -19
- package/src/app/(dashboard)/error.tsx +1 -7
- package/src/app/(dashboard)/layout.tsx +15 -36
- package/src/app/(dashboard)/marketplace/[plugin]/page.tsx +14 -51
- package/src/app/(dashboard)/marketplace/error.tsx +1 -7
- package/src/app/(dashboard)/marketplace/page.tsx +6 -27
- package/src/app/(dashboard)/not-found.tsx +2 -5
- package/src/app/(dashboard)/onboarding/page.tsx +5 -22
- package/src/app/(dashboard)/settings/account/page.tsx +1 -6
- package/src/app/(dashboard)/settings/activity/page.tsx +8 -34
- package/src/app/(dashboard)/settings/api-keys/page.tsx +15 -60
- package/src/app/(dashboard)/settings/brain/page.tsx +9 -31
- package/src/app/(dashboard)/settings/error.tsx +2 -10
- package/src/app/(dashboard)/settings/notifications/page.tsx +2 -6
- package/src/app/(dashboard)/settings/org/page.tsx +13 -56
- package/src/app/(dashboard)/settings/page.tsx +1 -0
- package/src/app/(dashboard)/settings/profile/page.tsx +126 -73
- package/src/app/(dashboard)/settings/providers/page.tsx +21 -78
- package/src/app/(dashboard)/settings/secrets/page.tsx +13 -58
- package/src/app/(dashboard)/settings/security/page.tsx +31 -111
- package/src/app/admin/email-templates/email-templates-client.tsx +15 -58
- package/src/app/admin/error.tsx +1 -7
- package/src/app/admin/fleet-updates/error.tsx +1 -7
- package/src/app/admin/fleet-updates/fleet-updates-client.tsx +10 -50
- package/src/app/admin/layout.tsx +4 -0
- package/src/app/admin/payment-methods/page.tsx +9 -38
- package/src/app/admin/products/error.tsx +2 -7
- package/src/app/admin/products/page.tsx +1 -4
- package/src/app/admin/promotions/[id]/page.tsx +9 -38
- package/src/app/admin/promotions/page.tsx +9 -36
- package/src/app/admin/rate-overrides/page.tsx +9 -45
- package/src/app/auth/callback/[provider]/page.tsx +1 -8
- package/src/app/auth/verify/page.tsx +9 -36
- package/src/app/channels/error.tsx +2 -10
- package/src/app/channels/layout.tsx +9 -0
- package/src/app/channels/page.tsx +8 -20
- package/src/app/channels/setup/[plugin]/page.tsx +3 -5
- package/src/app/error.tsx +1 -7
- package/src/app/fleet/error.tsx +1 -7
- package/src/app/fleet/layout.tsx +5 -0
- package/src/app/fleet/settings/page.tsx +1 -3
- package/src/app/global-error.tsx +2 -10
- package/src/app/globals.css +1 -4
- package/src/app/instances/[id]/instance-detail-client.tsx +51 -125
- package/src/app/instances/error.tsx +2 -10
- package/src/app/instances/instance-list-client.tsx +20 -69
- package/src/app/instances/layout.tsx +9 -0
- package/src/app/instances/new/create-instance-client.tsx +10 -31
- package/src/app/layout.tsx +2 -10
- package/src/app/not-found.tsx +1 -3
- package/src/app/page.tsx +1 -2
- package/src/app/plugins/error.tsx +2 -10
- package/src/app/plugins/layout.tsx +5 -0
- package/src/app/plugins/page.tsx +16 -48
- package/src/app/pricing/error.tsx +1 -7
- package/src/app/privacy/page.tsx +93 -150
- package/src/app/status/error.tsx +1 -7
- package/src/app/terms/page.tsx +89 -144
- package/src/components/account-switcher.tsx +25 -52
- package/src/components/admin/accounting-dashboard.tsx +1 -3
- package/src/components/admin/admin-guard.tsx +1 -3
- package/src/components/admin/admin-nav.tsx +1 -3
- package/src/components/admin/affiliate-dashboard.tsx +25 -94
- package/src/components/admin/audit-log-table.tsx +13 -49
- package/src/components/admin/billing-health-dashboard.tsx +7 -25
- package/src/components/admin/bulk-actions-bar.test.tsx +1 -7
- package/src/components/admin/bulk-actions-bar.tsx +1 -3
- package/src/components/admin/bulk-export-dialog.test.tsx +1 -7
- package/src/components/admin/bulk-export-dialog.tsx +6 -32
- package/src/components/admin/bulk-grant-dialog.test.tsx +2 -6
- package/src/components/admin/bulk-grant-dialog.tsx +4 -15
- package/src/components/admin/bulk-preview-dialog.tsx +3 -12
- package/src/components/admin/bulk-reactivate-dialog.tsx +1 -7
- package/src/components/admin/bulk-select-all-banner.tsx +1 -6
- package/src/components/admin/bulk-suspend-dialog.tsx +5 -12
- package/src/components/admin/bulk-undo-toast.tsx +1 -2
- package/src/components/admin/compliance-dashboard.tsx +31 -101
- package/src/components/admin/gpu-dashboard.tsx +21 -70
- package/src/components/admin/grant-credits-dialog.tsx +4 -17
- package/src/components/admin/incident-dashboard.tsx +10 -25
- package/src/components/admin/inference-dashboard.tsx +14 -54
- package/src/components/admin/marketplace-admin.tsx +18 -60
- package/src/components/admin/migrations-dashboard.tsx +9 -42
- package/src/components/admin/onboarding-dashboard.tsx +14 -64
- package/src/components/admin/pool-config-dashboard.tsx +4 -10
- package/src/components/admin/products/fleet-form.tsx +2 -11
- package/src/components/admin/products/nav-editor.tsx +3 -10
- package/src/components/admin/promotions/promotion-form.tsx +9 -42
- package/src/components/admin/roles-dashboard.tsx +7 -34
- package/src/components/admin/suspend-dialog.tsx +4 -11
- package/src/components/admin/tenant-notes-panel.tsx +1 -3
- package/src/components/admin/tenant-row-actions.tsx +4 -20
- package/src/components/admin/tenant-table.tsx +12 -49
- package/src/components/auth/auth-redirect.tsx +11 -3
- package/src/components/auth/email-verification-result-banner.tsx +1 -3
- package/src/components/auth/resend-verification-button.tsx +2 -10
- package/src/components/auth/wopr-wordmark.tsx +1 -3
- package/src/components/billing/add-payment-method-dialog.tsx +1 -2
- package/src/components/billing/affiliate-dashboard.tsx +4 -16
- package/src/components/billing/amount-selector.tsx +1 -3
- package/src/components/billing/auto-topup-card.tsx +2 -11
- package/src/components/billing/buy-credits-panel.tsx +4 -14
- package/src/components/billing/byok-callout.tsx +6 -8
- package/src/components/billing/confirmation-tracker.tsx +4 -14
- package/src/components/billing/credit-balance-badge.tsx +22 -0
- package/src/components/billing/credit-balance.tsx +3 -9
- package/src/components/billing/crypto-checkout.tsx +5 -24
- package/src/components/billing/degraded-state-banner.tsx +1 -3
- package/src/components/billing/deposit-view.tsx +301 -41
- package/src/components/billing/dividend-banner.tsx +1 -3
- package/src/components/billing/dividend-eligibility.tsx +3 -12
- package/src/components/billing/dividend-pool-stats.tsx +6 -20
- package/src/components/billing/first-dividend-dialog.tsx +2 -2
- package/src/components/billing/org-billing-page.tsx +8 -31
- package/src/components/billing/payment-method-picker.tsx +2 -10
- package/src/components/billing/suspension-banner.tsx +2 -7
- package/src/components/billing/transaction-history.tsx +10 -58
- package/src/components/billing/unified-checkout.tsx +547 -0
- package/src/components/bot-settings/backups-tab.tsx +9 -33
- package/src/components/bot-settings/bot-settings-client.tsx +32 -134
- package/src/components/bot-settings/resources-tab.tsx +2 -9
- package/src/components/bot-settings/storage-tab.tsx +19 -48
- package/src/components/bot-settings/vps-info-panel.tsx +3 -11
- package/src/components/bot-settings/vps-upgrade-card.tsx +3 -4
- package/src/components/brand-hydrator.tsx +13 -0
- package/src/components/channel-wizard/field-interactive.tsx +1 -3
- package/src/components/channel-wizard/field-qr.tsx +10 -39
- package/src/components/channel-wizard/step-renderer.tsx +5 -28
- package/src/components/channel-wizard/wizard.tsx +6 -31
- package/src/components/chat/chat-message.tsx +1 -4
- package/src/components/chat/chat-panel.tsx +4 -18
- package/src/components/chat/chat-widget.tsx +3 -14
- package/src/components/dashboard/command-center.tsx +15 -61
- package/src/components/fleet/update-settings-card.tsx +7 -23
- package/src/components/instance-update-banner.tsx +130 -0
- package/src/components/instances/friends-tab.test.tsx +2 -9
- package/src/components/instances/friends-tab.tsx +18 -74
- package/src/components/instances/update-available-badge.tsx +2 -11
- package/src/components/landing/hero.tsx +3 -9
- package/src/components/landing/landing-page.tsx +1 -3
- package/src/components/landing/portfolio-chart.tsx +4 -9
- package/src/components/landing/story-sections.tsx +1 -3
- package/src/components/landing/terminal-sequence.tsx +4 -17
- package/src/components/marketplace/empty-state.tsx +2 -6
- package/src/components/marketplace/first-visit-hero.tsx +1 -3
- package/src/components/marketplace/install-wizard.tsx +20 -77
- package/src/components/marketplace/marketplace-tabs.tsx +1 -4
- package/src/components/marketplace/plugin-card.tsx +2 -9
- package/src/components/marketplace/superpower-content.tsx +1 -3
- package/src/components/marketplace/terminal-search.tsx +2 -8
- package/src/components/oauth-buttons.tsx +29 -14
- package/src/components/observability/fleet-health.tsx +5 -18
- package/src/components/observability/health-overview.tsx +7 -20
- package/src/components/observability/logs-viewer.tsx +8 -32
- package/src/components/observability/metrics-dashboard.tsx +2 -15
- package/src/components/onboarding/fallback-setup.tsx +6 -25
- package/src/components/onboarding/setup-checklist.tsx +18 -51
- package/src/components/onboarding/step-superpowers.tsx +1 -4
- package/src/components/plugin-setup/setup-chat-panel.tsx +6 -22
- package/src/components/pricing/dividend-calculator.tsx +6 -12
- package/src/components/pricing/dividend-stats.tsx +5 -17
- package/src/components/pricing/pricing-page.tsx +17 -36
- package/src/components/settings/create-org-wizard.tsx +2 -5
- package/src/components/sidebar.tsx +7 -42
- package/src/components/sidecar-frame.tsx +78 -0
- package/src/components/status/status-page.tsx +6 -28
- package/src/components/ui/alert-dialog.tsx +8 -25
- package/src/components/ui/badge.tsx +2 -8
- package/src/components/ui/banner.tsx +1 -6
- package/src/components/ui/card.tsx +5 -24
- package/src/components/ui/checkbox.tsx +1 -5
- package/src/components/ui/collapsible.tsx +3 -8
- package/src/components/ui/dialog.tsx +4 -10
- package/src/components/ui/dropdown-menu.tsx +9 -18
- package/src/components/ui/form.tsx +2 -16
- package/src/components/ui/popover.tsx +3 -23
- package/src/components/ui/progress.tsx +1 -5
- package/src/components/ui/radio-group.tsx +3 -15
- package/src/components/ui/select.tsx +4 -17
- package/src/components/ui/sheet.tsx +5 -19
- package/src/components/ui/skeleton.tsx +1 -7
- package/src/components/ui/table.tsx +5 -22
- package/src/components/ui/tabs.tsx +3 -13
- package/src/components/ui/tooltip.tsx +1 -1
- package/src/components/unified-sidebar.tsx +493 -0
- package/src/hooks/__tests__/use-fleet-sse.test.ts +1 -4
- package/src/hooks/__tests__/use-save-queue.test.ts +2 -8
- package/src/hooks/use-credit-balance.ts +27 -0
- package/src/hooks/use-my-org-role.ts +1 -3
- package/src/hooks/use-plugin-registry.ts +8 -14
- package/src/hooks/use-plugin-setup-chat.ts +2 -5
- package/src/hooks/use-sidecar-bridge.tsx +148 -0
- package/src/hooks/use-webmcp.ts +1 -4
- package/src/lib/__tests__/admin-api.test.ts +1 -3
- package/src/lib/__tests__/api-bot-crud.test.ts +8 -18
- package/src/lib/__tests__/api-fetch.test.ts +4 -16
- package/src/lib/__tests__/org-billing-api.test.ts +1 -3
- package/src/lib/__tests__/pricing-data.test.ts +0 -8
- package/src/lib/__tests__/settings-api.test.ts +1 -3
- package/src/lib/admin-affiliate-api.ts +2 -7
- package/src/lib/admin-api.ts +6 -26
- package/src/lib/admin-incident-api.ts +11 -19
- package/src/lib/admin-marketplace-api.ts +1 -5
- package/src/lib/api-config.test.ts +5 -50
- package/src/lib/api.ts +143 -122
- package/src/lib/auth-client.ts +1 -2
- package/src/lib/bot-settings-data.ts +11 -36
- package/src/lib/brand-config.ts +56 -115
- package/src/lib/brand.ts +2 -15
- package/src/lib/chat/use-chat.ts +2 -7
- package/src/lib/cost-comparison-data.test.ts +1 -3
- package/src/lib/cost-comparison-data.ts +1 -4
- package/src/lib/errors.ts +1 -4
- package/src/lib/fetch-utils.test.ts +26 -9
- package/src/lib/fetch-utils.ts +40 -11
- package/src/lib/logger.ts +2 -0
- package/src/lib/marketplace-data.ts +3 -11
- package/src/lib/oauth-errors.ts +2 -4
- package/src/lib/onboarding-data.ts +3 -11
- package/src/lib/org-api.ts +2 -10
- package/src/lib/org-billing-api.ts +5 -19
- package/src/lib/plugin/tool-definitions.ts +1 -2
- package/src/lib/require-auth.ts +57 -0
- package/src/lib/settings-api.ts +1 -4
- package/src/lib/sidecar-routes.ts +43 -0
- package/src/lib/trpc-server.ts +49 -0
- package/src/lib/trpc-types.ts +4 -6
- package/src/lib/trpc.tsx +12 -4
- package/src/lib/validate-redirect-url.ts +1 -4
- package/src/lib/webmcp/marketplace-onboarding-tools.ts +6 -16
- package/src/lib/webmcp/register.ts +1 -4
- package/src/lib/webmcp/tools.ts +2 -9
- package/src/proxy.ts +35 -212
- package/src/types/missing-deps.d.ts +2 -8
- package/tsconfig.json +1 -8
- package/biome.json +0 -52
- package/src/__tests__/__snapshots__/layout-snapshots.test.tsx.snap +0 -741
- package/src/__tests__/billing-byok-callout.test.tsx +0 -76
- package/src/lib/__tests__/__snapshots__/pricing-data.test.ts.snap +0 -112
package/src/lib/brand-config.ts
CHANGED
|
@@ -99,111 +99,43 @@ export interface BrandConfig {
|
|
|
99
99
|
|
|
100
100
|
/** Feature bullet points shown on the billing plans page. */
|
|
101
101
|
planFeatures: string[];
|
|
102
|
+
|
|
103
|
+
/** Instance detail tabs to hide for this brand (e.g. ["plugins", "channels", "friends"]). */
|
|
104
|
+
hiddenInstanceTabs: string[];
|
|
102
105
|
}
|
|
103
106
|
|
|
104
107
|
/**
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*/
|
|
110
|
-
/**
|
|
111
|
-
* Parse NEXT_PUBLIC_BRAND_NAV_ITEMS env var.
|
|
112
|
-
* Format: JSON array of {label, href} objects.
|
|
113
|
-
* Example: '[{"label":"Home","href":"/"},{"label":"Settings","href":"/settings"}]'
|
|
114
|
-
* Returns null if unset or invalid (falls back to defaults).
|
|
108
|
+
* Static defaults used before initBrandConfig() fetches from the core API.
|
|
109
|
+
* These are intentionally minimal — the real config comes from the DB.
|
|
110
|
+
* No process.env references. Brand shells call setBrandConfig() or
|
|
111
|
+
* initBrandConfig() to populate from the core API.
|
|
115
112
|
*/
|
|
116
|
-
function
|
|
117
|
-
if (!raw) return null;
|
|
118
|
-
try {
|
|
119
|
-
const parsed = JSON.parse(raw);
|
|
120
|
-
if (
|
|
121
|
-
Array.isArray(parsed) &&
|
|
122
|
-
parsed.every(
|
|
123
|
-
(item: unknown) =>
|
|
124
|
-
typeof item === "object" &&
|
|
125
|
-
item !== null &&
|
|
126
|
-
typeof (item as { label?: unknown }).label === "string" &&
|
|
127
|
-
typeof (item as { href?: unknown }).href === "string",
|
|
128
|
-
)
|
|
129
|
-
) {
|
|
130
|
-
return parsed as Array<{ label: string; href: string }>;
|
|
131
|
-
}
|
|
132
|
-
} catch {
|
|
133
|
-
// Invalid JSON — fall back to defaults
|
|
134
|
-
}
|
|
135
|
-
return null;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/** Parse a JSON string array env var. Returns null if unset/invalid. */
|
|
139
|
-
function parseStringArray(raw: string | undefined): string[] | null {
|
|
140
|
-
if (!raw) return null;
|
|
141
|
-
try {
|
|
142
|
-
const parsed = JSON.parse(raw);
|
|
143
|
-
if (Array.isArray(parsed) && parsed.every((s: unknown) => typeof s === "string")) {
|
|
144
|
-
return parsed as string[];
|
|
145
|
-
}
|
|
146
|
-
} catch {
|
|
147
|
-
// Invalid JSON — fall back to defaults
|
|
148
|
-
}
|
|
149
|
-
return null;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function envDefaults(): BrandConfig {
|
|
153
|
-
// Direct process.env.X access is required — Next.js Turbopack only inlines
|
|
154
|
-
// NEXT_PUBLIC_* vars when accessed as literal dot-property references.
|
|
155
|
-
// Dynamic access like process.env[key] is NOT inlined at build time.
|
|
156
|
-
const productName = process.env.NEXT_PUBLIC_BRAND_PRODUCT_NAME || "Platform";
|
|
157
|
-
const brandName = process.env.NEXT_PUBLIC_BRAND_NAME || "Platform";
|
|
158
|
-
const storagePrefix = process.env.NEXT_PUBLIC_BRAND_STORAGE_PREFIX || "platform";
|
|
159
|
-
const eventPrefix = process.env.NEXT_PUBLIC_BRAND_EVENT_PREFIX || storagePrefix;
|
|
113
|
+
function staticDefaults(): BrandConfig {
|
|
160
114
|
return {
|
|
161
|
-
productName,
|
|
162
|
-
brandName,
|
|
163
|
-
domain:
|
|
164
|
-
appDomain:
|
|
165
|
-
tagline:
|
|
166
|
-
emails: {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
dividendsEnabled: process.env.NEXT_PUBLIC_BRAND_DIVIDENDS_ENABLED === "true",
|
|
182
|
-
planFeatures: parseStringArray(process.env.NEXT_PUBLIC_BRAND_PLAN_FEATURES) ?? [
|
|
183
|
-
"Signup credit included",
|
|
184
|
-
"All channels",
|
|
185
|
-
"All plugins",
|
|
186
|
-
"Hosted AI — no API keys needed",
|
|
187
|
-
],
|
|
188
|
-
navItems: parseNavItems(process.env.NEXT_PUBLIC_BRAND_NAV_ITEMS) ?? [
|
|
189
|
-
{ label: "Dashboard", href: "/dashboard" },
|
|
190
|
-
{ label: "Chat", href: "/chat" },
|
|
191
|
-
{ label: "Marketplace", href: "/marketplace" },
|
|
192
|
-
{ label: "Channels", href: "/channels" },
|
|
193
|
-
{ label: "Plugins", href: "/plugins" },
|
|
194
|
-
{ label: "Instances", href: "/instances" },
|
|
195
|
-
{ label: "Changesets", href: "/changesets" },
|
|
196
|
-
{ label: "Network", href: "/dashboard/network" },
|
|
197
|
-
{ label: "Fleet Health", href: "/fleet/health" },
|
|
198
|
-
{ label: "Credits", href: "/billing/credits" },
|
|
199
|
-
{ label: "Billing", href: "/billing/plans" },
|
|
200
|
-
{ label: "Settings", href: "/settings/profile" },
|
|
201
|
-
{ label: "Admin", href: "/admin/tenants" },
|
|
202
|
-
],
|
|
115
|
+
productName: "Platform",
|
|
116
|
+
brandName: "Platform",
|
|
117
|
+
domain: "localhost",
|
|
118
|
+
appDomain: "localhost:3000",
|
|
119
|
+
tagline: "",
|
|
120
|
+
emails: { privacy: "", legal: "", support: "" },
|
|
121
|
+
defaultImage: "",
|
|
122
|
+
storagePrefix: "platform",
|
|
123
|
+
eventPrefix: "platform",
|
|
124
|
+
envVarPrefix: "PLATFORM",
|
|
125
|
+
toolPrefix: "platform",
|
|
126
|
+
tenantCookieName: "platform_tenant_id",
|
|
127
|
+
companyLegalName: "",
|
|
128
|
+
price: "",
|
|
129
|
+
homePath: "/",
|
|
130
|
+
chatEnabled: true,
|
|
131
|
+
dividendsEnabled: false,
|
|
132
|
+
planFeatures: [],
|
|
133
|
+
hiddenInstanceTabs: [],
|
|
134
|
+
navItems: [],
|
|
203
135
|
};
|
|
204
136
|
}
|
|
205
137
|
|
|
206
|
-
let _config: BrandConfig =
|
|
138
|
+
let _config: BrandConfig = staticDefaults();
|
|
207
139
|
|
|
208
140
|
/**
|
|
209
141
|
* Set the brand configuration. Call once at app startup
|
|
@@ -214,7 +146,7 @@ let _config: BrandConfig = envDefaults();
|
|
|
214
146
|
* from the new prefix unless explicitly provided.
|
|
215
147
|
*/
|
|
216
148
|
export function setBrandConfig(config: Partial<BrandConfig>): void {
|
|
217
|
-
const base = { ...
|
|
149
|
+
const base = { ...staticDefaults(), ...config };
|
|
218
150
|
// Re-derive prefix-dependent fields when storagePrefix is overridden
|
|
219
151
|
// but the dependent fields were not explicitly provided.
|
|
220
152
|
if (config.storagePrefix) {
|
|
@@ -276,31 +208,40 @@ export function envKey(suffix: string): string {
|
|
|
276
208
|
}
|
|
277
209
|
|
|
278
210
|
/**
|
|
279
|
-
* Fetch brand config from
|
|
280
|
-
* Call once in root layout server component.
|
|
281
|
-
* Falls back to env var defaults if
|
|
211
|
+
* Fetch brand config from core server and apply it.
|
|
212
|
+
* Call once in root layout server component with the product slug.
|
|
213
|
+
* Falls back to env var defaults if core is unavailable.
|
|
214
|
+
*
|
|
215
|
+
* Uses INTERNAL_API_URL (server-side, private network) with service token auth.
|
|
216
|
+
* The slug determines which product config is returned from the product table.
|
|
282
217
|
*
|
|
283
|
-
* @param
|
|
218
|
+
* @param slug - Product slug (e.g. "paperclip", "wopr", "nemoclaw", "holyship")
|
|
284
219
|
*/
|
|
285
|
-
export async function initBrandConfig(
|
|
220
|
+
export async function initBrandConfig(slug?: string): Promise<void> {
|
|
221
|
+
const productSlug = slug ?? process.env.PRODUCT_SLUG ?? process.env.NEXT_PUBLIC_PRODUCT_SLUG;
|
|
222
|
+
if (!productSlug) return; // No slug — env var defaults remain active
|
|
223
|
+
|
|
224
|
+
const coreUrl = process.env.INTERNAL_API_URL ?? process.env.NEXT_PUBLIC_API_URL ?? "http://localhost:3001";
|
|
225
|
+
const serviceToken = process.env.CORE_SERVICE_TOKEN ?? "";
|
|
226
|
+
|
|
286
227
|
try {
|
|
287
|
-
const
|
|
288
|
-
|
|
228
|
+
const headers: Record<string, string> = {
|
|
229
|
+
"X-Product": productSlug,
|
|
230
|
+
};
|
|
231
|
+
if (serviceToken) {
|
|
232
|
+
headers.Authorization = `Bearer ${serviceToken}`;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const res = await fetch(`${coreUrl}/api/products/${encodeURIComponent(productSlug)}`, {
|
|
236
|
+
headers,
|
|
289
237
|
next: { revalidate: 60 },
|
|
290
238
|
});
|
|
291
239
|
if (!res.ok) return;
|
|
292
|
-
const
|
|
293
|
-
let json: unknown;
|
|
294
|
-
try {
|
|
295
|
-
json = JSON.parse(text);
|
|
296
|
-
} catch {
|
|
297
|
-
return; // Non-JSON response (proxy error, HTML page, etc.)
|
|
298
|
-
}
|
|
299
|
-
const data = (json as { result?: { data?: unknown } })?.result?.data;
|
|
240
|
+
const data = (await res.json()) as Partial<BrandConfig>;
|
|
300
241
|
if (data) {
|
|
301
|
-
setBrandConfig(data
|
|
242
|
+
setBrandConfig(data);
|
|
302
243
|
}
|
|
303
244
|
} catch {
|
|
304
|
-
//
|
|
245
|
+
// Core unavailable — env var defaults remain active
|
|
305
246
|
}
|
|
306
247
|
}
|
package/src/lib/brand.ts
CHANGED
|
@@ -105,14 +105,7 @@ export const product = {
|
|
|
105
105
|
],
|
|
106
106
|
|
|
107
107
|
/** What it is NOT. Never use these. */
|
|
108
|
-
isNot: [
|
|
109
|
-
"A chatbot",
|
|
110
|
-
"An AI assistant",
|
|
111
|
-
"An automation tool",
|
|
112
|
-
"A platform",
|
|
113
|
-
"A SaaS product",
|
|
114
|
-
"An agent framework",
|
|
115
|
-
],
|
|
108
|
+
isNot: ["A chatbot", "An AI assistant", "An automation tool", "A platform", "A SaaS product", "An agent framework"],
|
|
116
109
|
|
|
117
110
|
/** What it does. Always outcomes, never features. */
|
|
118
111
|
does: [
|
|
@@ -527,13 +520,7 @@ export const animation = {
|
|
|
527
520
|
*/
|
|
528
521
|
marketing: {
|
|
529
522
|
allowed: ["typing-effect", "cursor-blink", "fade-in-on-scroll"],
|
|
530
|
-
banned: [
|
|
531
|
-
"parallax",
|
|
532
|
-
"floating-elements",
|
|
533
|
-
"scroll-jacking",
|
|
534
|
-
"hover-bounce",
|
|
535
|
-
"auto-playing-video",
|
|
536
|
-
],
|
|
523
|
+
banned: ["parallax", "floating-elements", "scroll-jacking", "hover-bounce", "auto-playing-video"],
|
|
537
524
|
philosophy: "Let the words land. One animation per viewport. The restraint IS the brand.",
|
|
538
525
|
},
|
|
539
526
|
|
package/src/lib/chat/use-chat.ts
CHANGED
|
@@ -83,14 +83,9 @@ export function useChat(): UseChatReturn {
|
|
|
83
83
|
setMessages((prev) => {
|
|
84
84
|
const existing = prev.find((m) => m.id === msgId);
|
|
85
85
|
if (existing) {
|
|
86
|
-
return prev.map((m) =>
|
|
87
|
-
m.id === msgId ? { ...m, content: m.content + data.delta } : m,
|
|
88
|
-
);
|
|
86
|
+
return prev.map((m) => (m.id === msgId ? { ...m, content: m.content + data.delta } : m));
|
|
89
87
|
}
|
|
90
|
-
return [
|
|
91
|
-
...prev,
|
|
92
|
-
{ id: msgId, role: "bot" as const, content: data.delta, timestamp: Date.now() },
|
|
93
|
-
];
|
|
88
|
+
return [...prev, { id: msgId, role: "bot" as const, content: data.delta, timestamp: Date.now() }];
|
|
94
89
|
});
|
|
95
90
|
} else if (data.type === "tool_call") {
|
|
96
91
|
window.dispatchEvent(
|
|
@@ -41,9 +41,7 @@ describe("buildCostComparison", () => {
|
|
|
41
41
|
});
|
|
42
42
|
|
|
43
43
|
it("accepts superpowers in the second argument", () => {
|
|
44
|
-
const superItem = DIY_COSTS.find((c) =>
|
|
45
|
-
["image-gen", "video-gen", "voice"].includes(c.capabilityId),
|
|
46
|
-
);
|
|
44
|
+
const superItem = DIY_COSTS.find((c) => ["image-gen", "video-gen", "voice"].includes(c.capabilityId));
|
|
47
45
|
if (!superItem) return;
|
|
48
46
|
|
|
49
47
|
const result = buildCostComparison([], [superItem.capabilityId]);
|
|
@@ -25,10 +25,7 @@ export const DIY_COSTS: DiyCostItem[] = [
|
|
|
25
25
|
.map((s) => ({ capabilityId: s.id, ...s.diyCostData })),
|
|
26
26
|
];
|
|
27
27
|
|
|
28
|
-
export function buildCostComparison(
|
|
29
|
-
selectedChannels: string[],
|
|
30
|
-
selectedSuperpowers: string[],
|
|
31
|
-
): CostComparisonSummary {
|
|
28
|
+
export function buildCostComparison(selectedChannels: string[], selectedSuperpowers: string[]): CostComparisonSummary {
|
|
32
29
|
const selectedIds = new Set([...selectedChannels, ...selectedSuperpowers]);
|
|
33
30
|
const items = DIY_COSTS.filter((c) => selectedIds.has(c.capabilityId));
|
|
34
31
|
|
package/src/lib/errors.ts
CHANGED
|
@@ -42,10 +42,7 @@ export class NetworkError extends AppError {
|
|
|
42
42
|
* Extract a user-friendly message from any thrown value.
|
|
43
43
|
* Use in catch blocks: `setError(toUserMessage(err))`
|
|
44
44
|
*/
|
|
45
|
-
export function toUserMessage(
|
|
46
|
-
err: unknown,
|
|
47
|
-
fallback = "Something went wrong. Please try again.",
|
|
48
|
-
): string {
|
|
45
|
+
export function toUserMessage(err: unknown, fallback = "Something went wrong. Please try again."): string {
|
|
49
46
|
if (err instanceof Error) return err.message;
|
|
50
47
|
if (typeof err === "string") return err;
|
|
51
48
|
return fallback;
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
2
|
import { handleUnauthorized, UnauthorizedError } from "./fetch-utils";
|
|
3
3
|
|
|
4
|
+
function flushPromises() {
|
|
5
|
+
return new Promise<void>((resolve) => {
|
|
6
|
+
setTimeout(resolve, 0);
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
|
|
4
10
|
describe("UnauthorizedError", () => {
|
|
5
11
|
it("has default message", () => {
|
|
6
12
|
const err = new UnauthorizedError();
|
|
@@ -21,32 +27,43 @@ describe("UnauthorizedError", () => {
|
|
|
21
27
|
describe("handleUnauthorized", () => {
|
|
22
28
|
afterEach(() => {
|
|
23
29
|
vi.restoreAllMocks();
|
|
30
|
+
vi.unstubAllGlobals();
|
|
24
31
|
});
|
|
25
32
|
|
|
26
33
|
it("always throws UnauthorizedError", () => {
|
|
27
34
|
expect(() => handleUnauthorized()).toThrow(UnauthorizedError);
|
|
28
35
|
});
|
|
29
36
|
|
|
30
|
-
it("sets window.location.href to login URL with callbackUrl", () => {
|
|
37
|
+
it("sets window.location.href to login URL with callbackUrl after async session check", async () => {
|
|
38
|
+
const mockLocation = {
|
|
39
|
+
pathname: "/dashboard",
|
|
40
|
+
search: "?tab=fleet",
|
|
41
|
+
href: "",
|
|
42
|
+
};
|
|
31
43
|
Object.defineProperty(window, "location", {
|
|
32
|
-
value:
|
|
33
|
-
pathname: "/dashboard",
|
|
34
|
-
search: "?tab=fleet",
|
|
35
|
-
href: "",
|
|
36
|
-
},
|
|
44
|
+
value: mockLocation,
|
|
37
45
|
writable: true,
|
|
38
46
|
configurable: true,
|
|
39
47
|
});
|
|
40
48
|
|
|
49
|
+
// Mock fetch to return expired session
|
|
50
|
+
vi.stubGlobal(
|
|
51
|
+
"fetch",
|
|
52
|
+
vi.fn().mockResolvedValue({
|
|
53
|
+
json: () => Promise.resolve({ session: null }),
|
|
54
|
+
}),
|
|
55
|
+
);
|
|
56
|
+
|
|
41
57
|
try {
|
|
42
58
|
handleUnauthorized();
|
|
43
59
|
} catch {
|
|
44
60
|
// expected
|
|
45
61
|
}
|
|
46
62
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
63
|
+
// The redirect happens asynchronously after session check
|
|
64
|
+
await flushPromises();
|
|
65
|
+
|
|
66
|
+
expect(mockLocation.href).toBe("/login?reason=expired&callbackUrl=%2Fdashboard%3Ftab%3Dfleet");
|
|
50
67
|
|
|
51
68
|
Object.defineProperty(window, "location", {
|
|
52
69
|
value: { pathname: "/", search: "", href: "" },
|
package/src/lib/fetch-utils.ts
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* Thrown after triggering a redirect to /login, so call sites can
|
|
4
4
|
* identify auth failures if they catch before the redirect completes.
|
|
5
5
|
*/
|
|
6
|
+
import { API_BASE_URL } from "./api-config";
|
|
7
|
+
|
|
6
8
|
export class UnauthorizedError extends Error {
|
|
7
9
|
constructor(message = "Session expired") {
|
|
8
10
|
super(message);
|
|
@@ -10,21 +12,48 @@ export class UnauthorizedError extends Error {
|
|
|
10
12
|
}
|
|
11
13
|
}
|
|
12
14
|
|
|
15
|
+
/** Track whether we're already checking the session to avoid loops */
|
|
16
|
+
let sessionCheckInFlight = false;
|
|
17
|
+
|
|
13
18
|
/**
|
|
14
|
-
* Handle a 401 response
|
|
15
|
-
*
|
|
16
|
-
*
|
|
19
|
+
* Handle a 401 response intelligently.
|
|
20
|
+
*
|
|
21
|
+
* Instead of blindly assuming "session expired" on every 401:
|
|
22
|
+
* 1. Check if the session is actually valid by hitting the auth endpoint.
|
|
23
|
+
* Uses API_BASE_URL (api.<domain>/api) — hitting the shell-relative
|
|
24
|
+
* `/api/auth/get-session` returns HTML (no shell route) → JSON parse
|
|
25
|
+
* fails → the catch arm would redirect every single 401, even when
|
|
26
|
+
* the session is fine. That broke any page that called an endpoint
|
|
27
|
+
* returning 401 for non-session reasons (e.g., billing/dividend/stats
|
|
28
|
+
* which requires a service token).
|
|
29
|
+
* 2. If session IS valid — the 401 was from a permission/routing issue, not expiry.
|
|
30
|
+
* Log a warning and throw (let the caller handle it) but DON'T redirect.
|
|
31
|
+
* 3. If session is truly expired — redirect to /login.
|
|
17
32
|
*
|
|
18
|
-
* Guards against redirect loops: if already on /login,
|
|
19
|
-
* again — just throws so the login page can handle the error state.
|
|
33
|
+
* Guards against redirect loops: if already on /login or already checking, just throws.
|
|
20
34
|
*/
|
|
21
35
|
export function handleUnauthorized(): never {
|
|
22
|
-
if (typeof window !== "undefined") {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
36
|
+
if (typeof window !== "undefined" && !window.location.pathname.startsWith("/login") && !sessionCheckInFlight) {
|
|
37
|
+
sessionCheckInFlight = true;
|
|
38
|
+
fetch(`${API_BASE_URL}/auth/get-session`, { credentials: "include" })
|
|
39
|
+
.then((res) => res.json())
|
|
40
|
+
.then((data) => {
|
|
41
|
+
sessionCheckInFlight = false;
|
|
42
|
+
if (data?.session) {
|
|
43
|
+
// Session IS valid — 401 was a permission/routing issue, not expiry.
|
|
44
|
+
// Do NOT redirect. Caller's UnauthorizedError throw stands.
|
|
45
|
+
} else {
|
|
46
|
+
const callbackUrl = window.location.pathname + window.location.search;
|
|
47
|
+
const loginUrl = `/login?reason=expired&callbackUrl=${encodeURIComponent(callbackUrl)}`;
|
|
48
|
+
window.location.href = loginUrl;
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
.catch((_err) => {
|
|
52
|
+
sessionCheckInFlight = false;
|
|
53
|
+
const callbackUrl = window.location.pathname + window.location.search;
|
|
54
|
+
const loginUrl = `/login?reason=expired&callbackUrl=${encodeURIComponent(callbackUrl)}`;
|
|
55
|
+
window.location.href = loginUrl;
|
|
56
|
+
});
|
|
28
57
|
}
|
|
29
58
|
throw new UnauthorizedError();
|
|
30
59
|
}
|
package/src/lib/logger.ts
CHANGED
|
@@ -19,9 +19,11 @@ export interface Logger {
|
|
|
19
19
|
export function logger(namespace: string): Logger {
|
|
20
20
|
return {
|
|
21
21
|
warn(message: string, ...args: unknown[]) {
|
|
22
|
+
// biome-ignore lint/suspicious/noConsole: logger is the approved console wrapper
|
|
22
23
|
console.warn(`[${namespace}] ${message}`, ...args);
|
|
23
24
|
},
|
|
24
25
|
error(message: string, ...args: unknown[]) {
|
|
26
|
+
// biome-ignore lint/suspicious/noConsole: logger is the approved console wrapper
|
|
25
27
|
console.error(`[${namespace}] ${message}`, ...args);
|
|
26
28
|
},
|
|
27
29
|
};
|
|
@@ -86,9 +86,7 @@ const pluginManifestSchema = z.object({
|
|
|
86
86
|
configSchema: z.array(configSchemaFieldSchema).default([]),
|
|
87
87
|
setup: z.array(setupStepSchema).default([]),
|
|
88
88
|
installCount: z.number().default(0),
|
|
89
|
-
changelog: z
|
|
90
|
-
.array(z.object({ version: z.string(), date: z.string(), notes: z.string() }))
|
|
91
|
-
.default([]),
|
|
89
|
+
changelog: z.array(z.object({ version: z.string(), date: z.string(), notes: z.string() })).default([]),
|
|
92
90
|
connectionTest: z.object({ label: z.string(), endpoint: z.string() }).optional(),
|
|
93
91
|
superpowerHeadline: z.string().optional(),
|
|
94
92
|
superpowerTagline: z.string().optional(),
|
|
@@ -273,9 +271,7 @@ export async function installPlugin(
|
|
|
273
271
|
}
|
|
274
272
|
|
|
275
273
|
/** Fetch installed plugins for a bot, with enabled state. */
|
|
276
|
-
export async function listInstalledPlugins(
|
|
277
|
-
botId: string,
|
|
278
|
-
): Promise<{ pluginId: string; enabled: boolean }[]> {
|
|
274
|
+
export async function listInstalledPlugins(botId: string): Promise<{ pluginId: string; enabled: boolean }[]> {
|
|
279
275
|
const data = await fleetFetch<{
|
|
280
276
|
botId: string;
|
|
281
277
|
plugins: { pluginId: string; enabled: boolean }[];
|
|
@@ -284,11 +280,7 @@ export async function listInstalledPlugins(
|
|
|
284
280
|
}
|
|
285
281
|
|
|
286
282
|
/** Toggle a plugin's enabled state on a bot. */
|
|
287
|
-
export async function togglePluginEnabled(
|
|
288
|
-
botId: string,
|
|
289
|
-
pluginId: string,
|
|
290
|
-
enabled: boolean,
|
|
291
|
-
): Promise<void> {
|
|
283
|
+
export async function togglePluginEnabled(botId: string, pluginId: string, enabled: boolean): Promise<void> {
|
|
292
284
|
await fleetFetch(`/bots/${botId}/plugins/${pluginId}`, {
|
|
293
285
|
method: "PATCH",
|
|
294
286
|
body: JSON.stringify({ enabled }),
|
package/src/lib/oauth-errors.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
const OAUTH_ERROR_MESSAGES: Record<string, string> = {
|
|
2
2
|
access_denied: "Access was denied. Please try again.",
|
|
3
|
-
account_already_linked:
|
|
4
|
-
"An account with this email already exists. Sign in to link your account.",
|
|
3
|
+
account_already_linked: "An account with this email already exists. Sign in to link your account.",
|
|
5
4
|
server_error: "The authentication server encountered an error. Please try again later.",
|
|
6
|
-
temporarily_unavailable:
|
|
7
|
-
"The authentication service is temporarily unavailable. Please try again later.",
|
|
5
|
+
temporarily_unavailable: "The authentication service is temporarily unavailable. Please try again later.",
|
|
8
6
|
invalid_request: "The authentication request was invalid. Please try again.",
|
|
9
7
|
unauthorized_client: "This application is not authorized. Please contact support.",
|
|
10
8
|
unsupported_response_type: "Authentication configuration error. Please contact support.",
|
|
@@ -256,10 +256,7 @@ export interface Preset {
|
|
|
256
256
|
// marketplace configSchema fields. Kept separate intentionally — they serve
|
|
257
257
|
// the onboarding BYOK flow, not the marketplace install wizard.
|
|
258
258
|
// diyCostData is co-located here so adding a new channel only requires one entry.
|
|
259
|
-
const CHANNEL_OVERLAY: Record<
|
|
260
|
-
string,
|
|
261
|
-
{ configFields: OnboardingConfigField[]; diyCostData?: DiyCostData }
|
|
262
|
-
> = {
|
|
259
|
+
const CHANNEL_OVERLAY: Record<string, { configFields: OnboardingConfigField[]; diyCostData?: DiyCostData }> = {
|
|
263
260
|
discord: {
|
|
264
261
|
configFields: [
|
|
265
262
|
{
|
|
@@ -822,9 +819,7 @@ export async function getOptionalPlugins(): Promise<PluginCategory[]> {
|
|
|
822
819
|
const knownCats = new Set<string>(optionalCategories);
|
|
823
820
|
const extraCats = new Set(
|
|
824
821
|
plugins
|
|
825
|
-
.filter(
|
|
826
|
-
(m) => !knownCats.has(m.category) && m.category !== "channel" && m.category !== "provider",
|
|
827
|
-
)
|
|
822
|
+
.filter((m) => !knownCats.has(m.category) && m.category !== "channel" && m.category !== "provider")
|
|
828
823
|
.map((m) => m.category),
|
|
829
824
|
);
|
|
830
825
|
for (const catId of extraCats) {
|
|
@@ -1225,10 +1220,7 @@ export function getAiKeySuperpowers(selectedIds: string[]): Superpower[] {
|
|
|
1225
1220
|
}
|
|
1226
1221
|
|
|
1227
1222
|
/** Capability descriptions shown after key validation */
|
|
1228
|
-
export const AI_CAPABILITY_DESCRIPTIONS: Record<
|
|
1229
|
-
string,
|
|
1230
|
-
{ label: string; openai: string; openrouter: string }
|
|
1231
|
-
> = {
|
|
1223
|
+
export const AI_CAPABILITY_DESCRIPTIONS: Record<string, { label: string; openai: string; openrouter: string }> = {
|
|
1232
1224
|
memory: {
|
|
1233
1225
|
label: "Memory",
|
|
1234
1226
|
openai: "Embeddings for long-term recall",
|
package/src/lib/org-api.ts
CHANGED
|
@@ -25,11 +25,7 @@ export async function updateOrganization(
|
|
|
25
25
|
return trpcVanilla.org.updateOrganization.mutate({ orgId, ...data });
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
export async function inviteMember(
|
|
29
|
-
orgId: string,
|
|
30
|
-
email: string,
|
|
31
|
-
role: "admin" | "member",
|
|
32
|
-
): Promise<OrgInvite> {
|
|
28
|
+
export async function inviteMember(orgId: string, email: string, role: "admin" | "member"): Promise<OrgInvite> {
|
|
33
29
|
const row = await trpcVanilla.org.inviteMember.mutate({ orgId, email, role });
|
|
34
30
|
const typed = row as OrgInviteRow;
|
|
35
31
|
return {
|
|
@@ -46,11 +42,7 @@ export async function revokeInvite(orgId: string, inviteId: string): Promise<voi
|
|
|
46
42
|
await trpcVanilla.org.revokeInvite.mutate({ orgId, inviteId });
|
|
47
43
|
}
|
|
48
44
|
|
|
49
|
-
export async function changeRole(
|
|
50
|
-
orgId: string,
|
|
51
|
-
userId: string,
|
|
52
|
-
role: "admin" | "member",
|
|
53
|
-
): Promise<void> {
|
|
45
|
+
export async function changeRole(orgId: string, userId: string, role: "admin" | "member"): Promise<void> {
|
|
54
46
|
await trpcVanilla.org.changeRole.mutate({ orgId, userId, role });
|
|
55
47
|
}
|
|
56
48
|
|
|
@@ -22,11 +22,8 @@ export interface OrgMemberUsageRow {
|
|
|
22
22
|
export async function getOrgCreditBalance(_orgId: string): Promise<OrgCreditBalance> {
|
|
23
23
|
const res = await trpcVanilla.billing.creditsBalance.query({});
|
|
24
24
|
return {
|
|
25
|
-
balance:
|
|
26
|
-
|
|
27
|
-
dailyBurn:
|
|
28
|
-
(res?.daily_burn_credits ?? (res as { daily_burn_cents?: number })?.daily_burn_cents ?? 0) /
|
|
29
|
-
100,
|
|
25
|
+
balance: (res?.balance_credits ?? (res as { balance_cents?: number })?.balance_cents ?? 0) / 100,
|
|
26
|
+
dailyBurn: (res?.daily_burn_credits ?? (res as { daily_burn_cents?: number })?.daily_burn_cents ?? 0) / 100,
|
|
30
27
|
runway: (res as { runway_days?: number | null })?.runway_days ?? null,
|
|
31
28
|
};
|
|
32
29
|
}
|
|
@@ -66,26 +63,15 @@ export async function getOrgBillingInfo(_orgId: string) {
|
|
|
66
63
|
}
|
|
67
64
|
}
|
|
68
65
|
|
|
69
|
-
export async function createOrgTopupCheckout(
|
|
70
|
-
orgId: string,
|
|
71
|
-
priceId: string,
|
|
72
|
-
successUrl: string,
|
|
73
|
-
cancelUrl: string,
|
|
74
|
-
) {
|
|
66
|
+
export async function createOrgTopupCheckout(orgId: string, priceId: string, successUrl: string, cancelUrl: string) {
|
|
75
67
|
return trpcVanilla.org.orgTopupCheckout.mutate({ orgId, priceId, successUrl, cancelUrl });
|
|
76
68
|
}
|
|
77
69
|
|
|
78
|
-
export async function removeOrgPaymentMethod(
|
|
79
|
-
orgId: string,
|
|
80
|
-
paymentMethodId: string,
|
|
81
|
-
): Promise<{ removed: boolean }> {
|
|
70
|
+
export async function removeOrgPaymentMethod(orgId: string, paymentMethodId: string): Promise<{ removed: boolean }> {
|
|
82
71
|
return trpcVanilla.org.orgRemovePaymentMethod.mutate({ orgId, paymentMethodId });
|
|
83
72
|
}
|
|
84
73
|
|
|
85
|
-
export async function setOrgDefaultPaymentMethod(
|
|
86
|
-
orgId: string,
|
|
87
|
-
paymentMethodId: string,
|
|
88
|
-
): Promise<void> {
|
|
74
|
+
export async function setOrgDefaultPaymentMethod(orgId: string, paymentMethodId: string): Promise<void> {
|
|
89
75
|
await trpcVanilla.org.orgSetDefaultPaymentMethod.mutate({ orgId, paymentMethodId });
|
|
90
76
|
}
|
|
91
77
|
|
|
@@ -232,8 +232,7 @@ export function getPlatformUIToolDefinitions(): ToolDefinition[] {
|
|
|
232
232
|
// Plugin setup tools
|
|
233
233
|
{
|
|
234
234
|
name: "setup.begin",
|
|
235
|
-
description:
|
|
236
|
-
"Begin conversational setup for a plugin. Bot receives plugin ID and config schema.",
|
|
235
|
+
description: "Begin conversational setup for a plugin. Bot receives plugin ID and config schema.",
|
|
237
236
|
inputSchema: {
|
|
238
237
|
type: "object",
|
|
239
238
|
properties: {
|