@wopr-network/platform-ui-core 1.27.7 → 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.
Files changed (353) hide show
  1. package/next.config.ts +1 -2
  2. package/package.json +17 -17
  3. package/src/__tests__/account-switcher.test.tsx +21 -20
  4. package/src/__tests__/activity-page.test.tsx +2 -6
  5. package/src/__tests__/add-payment-method-dialog.test.tsx +9 -32
  6. package/src/__tests__/admin-api.test.ts +1 -6
  7. package/src/__tests__/admin-gpu-api.test.ts +1 -3
  8. package/src/__tests__/admin-marketplace-api.test.ts +1 -4
  9. package/src/__tests__/admin-middleware.test.ts +76 -83
  10. package/src/__tests__/affiliate-dashboard.test.tsx +3 -3
  11. package/src/__tests__/api-401-redirect.test.ts +46 -9
  12. package/src/__tests__/api-client.test.ts +3 -5
  13. package/src/__tests__/api-config.test.ts +22 -42
  14. package/src/__tests__/api-fleet-resources.test.ts +1 -2
  15. package/src/__tests__/api-fleet-trpc.test.ts +2 -8
  16. package/src/__tests__/api-null-guards.test.ts +3 -1
  17. package/src/__tests__/audit-log-table-pagination.test.tsx +2 -6
  18. package/src/__tests__/auth-password-reset.test.tsx +7 -21
  19. package/src/__tests__/auth-redirect.test.tsx +8 -2
  20. package/src/__tests__/auth.test.tsx +25 -23
  21. package/src/__tests__/auto-topup-card.test.tsx +4 -12
  22. package/src/__tests__/backups-tab.test.tsx +3 -4
  23. package/src/__tests__/billing-layout-nav-hidden.test.tsx +5 -37
  24. package/src/__tests__/billing-payment-org-invoices.test.tsx +2 -18
  25. package/src/__tests__/billing.test.tsx +8 -39
  26. package/src/__tests__/bot-settings/resources-tab.test.tsx +1 -3
  27. package/src/__tests__/bot-settings/storage-tab.test.tsx +1 -3
  28. package/src/__tests__/bot-settings/vps-upgrade-card.test.tsx +1 -3
  29. package/src/__tests__/bot-settings-restart.test.tsx +1 -3
  30. package/src/__tests__/bot-settings.test.tsx +2 -6
  31. package/src/__tests__/brand.test.ts +6 -26
  32. package/src/__tests__/buy-credits-panel.test.tsx +1 -3
  33. package/src/__tests__/buy-crypto-credits-panel.test.tsx +101 -119
  34. package/src/__tests__/capability-conflicts.test.ts +2 -8
  35. package/src/__tests__/capability-resolver.test.tsx +2 -12
  36. package/src/__tests__/channel-wizard.test.tsx +4 -17
  37. package/src/__tests__/chat/chat-panel.test.tsx +1 -4
  38. package/src/__tests__/chat-store.test.ts +5 -15
  39. package/src/__tests__/command-center.test.tsx +10 -12
  40. package/src/__tests__/compliance-retention-edit.test.tsx +3 -6
  41. package/src/__tests__/confirmation-tracker.test.tsx +3 -18
  42. package/src/__tests__/coupon-input.test.tsx +1 -3
  43. package/src/__tests__/create-instance.test.tsx +1 -3
  44. package/src/__tests__/credit-balance.test.tsx +4 -12
  45. package/src/__tests__/credits.test.tsx +32 -85
  46. package/src/__tests__/email-verification-banner.test.tsx +2 -6
  47. package/src/__tests__/error-boundaries.test.tsx +0 -1
  48. package/src/__tests__/fetch-pricing.test.ts +2 -1
  49. package/src/__tests__/field-oauth.test.tsx +2 -6
  50. package/src/__tests__/fixtures/mock-manifests-data.js +1 -3
  51. package/src/__tests__/fixtures/mock-manifests.ts +2 -4
  52. package/src/__tests__/fleet-health-timestamp.test.tsx +1 -8
  53. package/src/__tests__/fleet-health-update.test.tsx +1 -8
  54. package/src/__tests__/gpu-dashboard.test.tsx +2 -6
  55. package/src/__tests__/instance-detail.test.tsx +3 -9
  56. package/src/__tests__/instance-list.test.tsx +1 -5
  57. package/src/__tests__/layout-snapshots.test.tsx +64 -11
  58. package/src/__tests__/marketplace-admin.test.tsx +2 -6
  59. package/src/__tests__/marketplace.test.tsx +11 -35
  60. package/src/__tests__/merge-api-rates.test.ts +1 -6
  61. package/src/__tests__/middleware.test.ts +32 -219
  62. package/src/__tests__/next-config-headers.test.ts +1 -3
  63. package/src/__tests__/notifications.test.tsx +4 -11
  64. package/src/__tests__/oauth-buttons.test.tsx +36 -59
  65. package/src/__tests__/oauth-error-mapping.test.tsx +2 -6
  66. package/src/__tests__/observability.test.tsx +23 -36
  67. package/src/__tests__/onboarding-page.test.tsx +4 -6
  68. package/src/__tests__/org-billing-api.test.tsx +1 -6
  69. package/src/__tests__/plugin-install-flow.test.tsx +28 -58
  70. package/src/__tests__/plugin-registry.test.tsx +3 -11
  71. package/src/__tests__/plugin-tool-sync.test.ts +1 -3
  72. package/src/__tests__/plugins-catalog-error.test.tsx +2 -6
  73. package/src/__tests__/plugins-toggle-race.test.tsx +3 -5
  74. package/src/__tests__/portfolio-chart.test.tsx +2 -6
  75. package/src/__tests__/promotion-form.test.tsx +2 -6
  76. package/src/__tests__/promotions-list.test.tsx +1 -3
  77. package/src/__tests__/provider-key-api.test.ts +2 -1
  78. package/src/__tests__/resend-verification-button.test.tsx +8 -24
  79. package/src/__tests__/secrets-audit-pagination.test.tsx +1 -3
  80. package/src/__tests__/settings.test.tsx +11 -21
  81. package/src/__tests__/setup-checklist.test.tsx +3 -9
  82. package/src/__tests__/setup.ts +25 -6
  83. package/src/__tests__/snapshot-api.test.ts +2 -1
  84. package/src/__tests__/step-superpowers.test.tsx +1 -3
  85. package/src/__tests__/tenant-context.test.tsx +1 -6
  86. package/src/__tests__/tenant-keys-api.test.ts +3 -4
  87. package/src/__tests__/tenant-table-pagination.test.tsx +2 -6
  88. package/src/__tests__/terminal-log-cleanup.test.tsx +0 -1
  89. package/src/__tests__/transaction-history.test.tsx +190 -238
  90. package/src/__tests__/trpc-types.test.ts +2 -6
  91. package/src/__tests__/use-chat.test.ts +1 -3
  92. package/src/__tests__/use-plugin-setup-chat-stale-closure.test.ts +1 -4
  93. package/src/__tests__/use-sidecar-bridge.test.tsx +105 -0
  94. package/src/__tests__/use-webmcp.test.ts +1 -3
  95. package/src/__tests__/validate-elevenlabs-key.test.ts +2 -1
  96. package/src/__tests__/verify-page.test.tsx +4 -13
  97. package/src/__tests__/verify-redirect.test.tsx +2 -6
  98. package/src/app/(auth)/error.tsx +1 -7
  99. package/src/app/(auth)/forgot-password/page.tsx +4 -18
  100. package/src/app/(auth)/login/page.tsx +5 -22
  101. package/src/app/(auth)/reset-password/page.tsx +2 -12
  102. package/src/app/(auth)/signup/page.tsx +10 -44
  103. package/src/app/(auth)/verify/page.tsx +47 -0
  104. package/src/app/(dashboard)/billing/credits/page.tsx +14 -67
  105. package/src/app/(dashboard)/billing/error.tsx +2 -10
  106. package/src/app/(dashboard)/billing/layout.tsx +12 -62
  107. package/src/app/(dashboard)/billing/payment/page.tsx +17 -68
  108. package/src/app/(dashboard)/billing/plans/page.tsx +3 -9
  109. package/src/app/(dashboard)/billing/usage/hosted/page.tsx +8 -25
  110. package/src/app/(dashboard)/billing/usage/page.tsx +63 -103
  111. package/src/app/(dashboard)/changesets/[id]/changeset-detail-client.tsx +9 -27
  112. package/src/app/(dashboard)/changesets/[id]/error.tsx +2 -6
  113. package/src/app/(dashboard)/changesets/error.tsx +1 -7
  114. package/src/app/(dashboard)/chat/page.tsx +2 -6
  115. package/src/app/(dashboard)/dashboard/network/page.tsx +5 -19
  116. package/src/app/(dashboard)/error.tsx +1 -7
  117. package/src/app/(dashboard)/layout.tsx +15 -36
  118. package/src/app/(dashboard)/marketplace/[plugin]/page.tsx +14 -51
  119. package/src/app/(dashboard)/marketplace/error.tsx +1 -7
  120. package/src/app/(dashboard)/marketplace/page.tsx +6 -27
  121. package/src/app/(dashboard)/not-found.tsx +2 -5
  122. package/src/app/(dashboard)/onboarding/page.tsx +5 -22
  123. package/src/app/(dashboard)/settings/account/page.tsx +1 -6
  124. package/src/app/(dashboard)/settings/activity/page.tsx +8 -34
  125. package/src/app/(dashboard)/settings/api-keys/page.tsx +15 -60
  126. package/src/app/(dashboard)/settings/brain/page.tsx +9 -31
  127. package/src/app/(dashboard)/settings/error.tsx +2 -10
  128. package/src/app/(dashboard)/settings/notifications/page.tsx +2 -6
  129. package/src/app/(dashboard)/settings/org/page.tsx +13 -56
  130. package/src/app/(dashboard)/settings/page.tsx +1 -0
  131. package/src/app/(dashboard)/settings/profile/page.tsx +126 -73
  132. package/src/app/(dashboard)/settings/providers/page.tsx +21 -78
  133. package/src/app/(dashboard)/settings/secrets/page.tsx +13 -58
  134. package/src/app/(dashboard)/settings/security/page.tsx +31 -111
  135. package/src/app/admin/email-templates/email-templates-client.tsx +15 -58
  136. package/src/app/admin/error.tsx +1 -7
  137. package/src/app/admin/fleet-updates/error.tsx +1 -7
  138. package/src/app/admin/fleet-updates/fleet-updates-client.tsx +10 -50
  139. package/src/app/admin/layout.tsx +4 -0
  140. package/src/app/admin/payment-methods/page.tsx +9 -38
  141. package/src/app/admin/products/error.tsx +2 -7
  142. package/src/app/admin/products/page.tsx +1 -4
  143. package/src/app/admin/promotions/[id]/page.tsx +9 -38
  144. package/src/app/admin/promotions/page.tsx +9 -36
  145. package/src/app/admin/rate-overrides/page.tsx +9 -45
  146. package/src/app/auth/callback/[provider]/page.tsx +1 -8
  147. package/src/app/auth/verify/page.tsx +9 -36
  148. package/src/app/channels/error.tsx +2 -10
  149. package/src/app/channels/layout.tsx +9 -0
  150. package/src/app/channels/page.tsx +8 -20
  151. package/src/app/channels/setup/[plugin]/page.tsx +3 -5
  152. package/src/app/error.tsx +1 -7
  153. package/src/app/fleet/error.tsx +1 -7
  154. package/src/app/fleet/layout.tsx +5 -0
  155. package/src/app/fleet/settings/page.tsx +1 -3
  156. package/src/app/global-error.tsx +2 -10
  157. package/src/app/globals.css +1 -4
  158. package/src/app/instances/[id]/instance-detail-client.tsx +51 -125
  159. package/src/app/instances/error.tsx +2 -10
  160. package/src/app/instances/instance-list-client.tsx +20 -69
  161. package/src/app/instances/layout.tsx +9 -0
  162. package/src/app/instances/new/create-instance-client.tsx +10 -31
  163. package/src/app/layout.tsx +2 -10
  164. package/src/app/not-found.tsx +1 -3
  165. package/src/app/page.tsx +1 -2
  166. package/src/app/plugins/error.tsx +2 -10
  167. package/src/app/plugins/layout.tsx +5 -0
  168. package/src/app/plugins/page.tsx +16 -48
  169. package/src/app/pricing/error.tsx +1 -7
  170. package/src/app/privacy/page.tsx +93 -150
  171. package/src/app/status/error.tsx +1 -7
  172. package/src/app/terms/page.tsx +89 -144
  173. package/src/components/account-switcher.tsx +25 -52
  174. package/src/components/admin/accounting-dashboard.tsx +1 -3
  175. package/src/components/admin/admin-guard.tsx +1 -3
  176. package/src/components/admin/admin-nav.tsx +1 -3
  177. package/src/components/admin/affiliate-dashboard.tsx +25 -94
  178. package/src/components/admin/audit-log-table.tsx +13 -49
  179. package/src/components/admin/billing-health-dashboard.tsx +7 -25
  180. package/src/components/admin/bulk-actions-bar.test.tsx +1 -7
  181. package/src/components/admin/bulk-actions-bar.tsx +1 -3
  182. package/src/components/admin/bulk-export-dialog.test.tsx +1 -7
  183. package/src/components/admin/bulk-export-dialog.tsx +6 -32
  184. package/src/components/admin/bulk-grant-dialog.test.tsx +2 -6
  185. package/src/components/admin/bulk-grant-dialog.tsx +4 -15
  186. package/src/components/admin/bulk-preview-dialog.tsx +3 -12
  187. package/src/components/admin/bulk-reactivate-dialog.tsx +1 -7
  188. package/src/components/admin/bulk-select-all-banner.tsx +1 -6
  189. package/src/components/admin/bulk-suspend-dialog.tsx +5 -12
  190. package/src/components/admin/bulk-undo-toast.tsx +1 -2
  191. package/src/components/admin/compliance-dashboard.tsx +31 -101
  192. package/src/components/admin/gpu-dashboard.tsx +21 -70
  193. package/src/components/admin/grant-credits-dialog.tsx +4 -17
  194. package/src/components/admin/incident-dashboard.tsx +10 -25
  195. package/src/components/admin/inference-dashboard.tsx +14 -54
  196. package/src/components/admin/marketplace-admin.tsx +18 -60
  197. package/src/components/admin/migrations-dashboard.tsx +9 -42
  198. package/src/components/admin/onboarding-dashboard.tsx +14 -64
  199. package/src/components/admin/pool-config-dashboard.tsx +4 -10
  200. package/src/components/admin/products/fleet-form.tsx +2 -11
  201. package/src/components/admin/products/nav-editor.tsx +3 -10
  202. package/src/components/admin/promotions/promotion-form.tsx +9 -42
  203. package/src/components/admin/roles-dashboard.tsx +7 -34
  204. package/src/components/admin/suspend-dialog.tsx +4 -11
  205. package/src/components/admin/tenant-notes-panel.tsx +1 -3
  206. package/src/components/admin/tenant-row-actions.tsx +4 -20
  207. package/src/components/admin/tenant-table.tsx +12 -49
  208. package/src/components/auth/auth-redirect.tsx +11 -3
  209. package/src/components/auth/email-verification-result-banner.tsx +1 -3
  210. package/src/components/auth/resend-verification-button.tsx +2 -10
  211. package/src/components/auth/wopr-wordmark.tsx +1 -3
  212. package/src/components/billing/add-payment-method-dialog.tsx +1 -2
  213. package/src/components/billing/affiliate-dashboard.tsx +4 -16
  214. package/src/components/billing/amount-selector.tsx +1 -3
  215. package/src/components/billing/auto-topup-card.tsx +2 -11
  216. package/src/components/billing/buy-credits-panel.tsx +14 -17
  217. package/src/components/billing/byok-callout.tsx +6 -8
  218. package/src/components/billing/confirmation-tracker.tsx +4 -14
  219. package/src/components/billing/credit-balance-badge.tsx +22 -0
  220. package/src/components/billing/credit-balance.tsx +3 -9
  221. package/src/components/billing/crypto-checkout.tsx +5 -24
  222. package/src/components/billing/degraded-state-banner.tsx +1 -3
  223. package/src/components/billing/deposit-view.tsx +301 -41
  224. package/src/components/billing/dividend-banner.tsx +1 -3
  225. package/src/components/billing/dividend-eligibility.tsx +3 -12
  226. package/src/components/billing/dividend-pool-stats.tsx +6 -20
  227. package/src/components/billing/first-dividend-dialog.tsx +2 -2
  228. package/src/components/billing/org-billing-page.tsx +8 -31
  229. package/src/components/billing/payment-method-picker.tsx +2 -10
  230. package/src/components/billing/suspension-banner.tsx +2 -7
  231. package/src/components/billing/transaction-history.tsx +10 -58
  232. package/src/components/billing/unified-checkout.tsx +547 -0
  233. package/src/components/bot-settings/backups-tab.tsx +9 -33
  234. package/src/components/bot-settings/bot-settings-client.tsx +32 -134
  235. package/src/components/bot-settings/resources-tab.tsx +2 -9
  236. package/src/components/bot-settings/storage-tab.tsx +19 -48
  237. package/src/components/bot-settings/vps-info-panel.tsx +3 -11
  238. package/src/components/bot-settings/vps-upgrade-card.tsx +3 -4
  239. package/src/components/brand-hydrator.tsx +13 -0
  240. package/src/components/channel-wizard/field-interactive.tsx +1 -3
  241. package/src/components/channel-wizard/field-qr.tsx +10 -39
  242. package/src/components/channel-wizard/step-renderer.tsx +5 -28
  243. package/src/components/channel-wizard/wizard.tsx +6 -31
  244. package/src/components/chat/chat-message.tsx +1 -4
  245. package/src/components/chat/chat-panel.tsx +4 -18
  246. package/src/components/chat/chat-widget.tsx +3 -14
  247. package/src/components/dashboard/command-center.tsx +15 -61
  248. package/src/components/fleet/update-settings-card.tsx +7 -23
  249. package/src/components/instance-update-banner.tsx +130 -0
  250. package/src/components/instances/friends-tab.test.tsx +2 -9
  251. package/src/components/instances/friends-tab.tsx +18 -74
  252. package/src/components/instances/update-available-badge.tsx +2 -11
  253. package/src/components/landing/hero.tsx +3 -9
  254. package/src/components/landing/landing-page.tsx +1 -3
  255. package/src/components/landing/portfolio-chart.tsx +4 -9
  256. package/src/components/landing/story-sections.tsx +1 -3
  257. package/src/components/landing/terminal-sequence.tsx +4 -17
  258. package/src/components/marketplace/empty-state.tsx +2 -6
  259. package/src/components/marketplace/first-visit-hero.tsx +1 -3
  260. package/src/components/marketplace/install-wizard.tsx +20 -77
  261. package/src/components/marketplace/marketplace-tabs.tsx +1 -4
  262. package/src/components/marketplace/plugin-card.tsx +2 -9
  263. package/src/components/marketplace/superpower-content.tsx +1 -3
  264. package/src/components/marketplace/terminal-search.tsx +2 -8
  265. package/src/components/oauth-buttons.tsx +29 -14
  266. package/src/components/observability/fleet-health.tsx +5 -18
  267. package/src/components/observability/health-overview.tsx +7 -20
  268. package/src/components/observability/logs-viewer.tsx +8 -32
  269. package/src/components/observability/metrics-dashboard.tsx +2 -15
  270. package/src/components/onboarding/fallback-setup.tsx +6 -25
  271. package/src/components/onboarding/setup-checklist.tsx +18 -51
  272. package/src/components/onboarding/step-superpowers.tsx +1 -4
  273. package/src/components/plugin-setup/setup-chat-panel.tsx +6 -22
  274. package/src/components/pricing/dividend-calculator.tsx +6 -12
  275. package/src/components/pricing/dividend-stats.tsx +5 -17
  276. package/src/components/pricing/pricing-page.tsx +17 -36
  277. package/src/components/settings/create-org-wizard.tsx +2 -5
  278. package/src/components/sidebar.tsx +7 -42
  279. package/src/components/sidecar-frame.tsx +78 -0
  280. package/src/components/status/status-page.tsx +6 -28
  281. package/src/components/ui/alert-dialog.tsx +8 -25
  282. package/src/components/ui/badge.tsx +2 -8
  283. package/src/components/ui/banner.tsx +1 -6
  284. package/src/components/ui/card.tsx +5 -24
  285. package/src/components/ui/checkbox.tsx +1 -5
  286. package/src/components/ui/collapsible.tsx +3 -8
  287. package/src/components/ui/dialog.tsx +4 -10
  288. package/src/components/ui/dropdown-menu.tsx +9 -18
  289. package/src/components/ui/form.tsx +2 -16
  290. package/src/components/ui/popover.tsx +3 -23
  291. package/src/components/ui/progress.tsx +1 -5
  292. package/src/components/ui/radio-group.tsx +3 -15
  293. package/src/components/ui/select.tsx +4 -17
  294. package/src/components/ui/sheet.tsx +5 -19
  295. package/src/components/ui/skeleton.tsx +1 -7
  296. package/src/components/ui/table.tsx +5 -22
  297. package/src/components/ui/tabs.tsx +3 -13
  298. package/src/components/ui/tooltip.tsx +1 -1
  299. package/src/components/unified-sidebar.tsx +493 -0
  300. package/src/hooks/__tests__/use-fleet-sse.test.ts +1 -4
  301. package/src/hooks/__tests__/use-save-queue.test.ts +2 -8
  302. package/src/hooks/use-credit-balance.ts +27 -0
  303. package/src/hooks/use-my-org-role.ts +1 -3
  304. package/src/hooks/use-plugin-registry.ts +8 -14
  305. package/src/hooks/use-plugin-setup-chat.ts +2 -5
  306. package/src/hooks/use-sidecar-bridge.tsx +148 -0
  307. package/src/hooks/use-webmcp.ts +1 -4
  308. package/src/lib/__tests__/admin-api.test.ts +1 -3
  309. package/src/lib/__tests__/api-bot-crud.test.ts +8 -18
  310. package/src/lib/__tests__/api-fetch.test.ts +4 -16
  311. package/src/lib/__tests__/org-billing-api.test.ts +1 -3
  312. package/src/lib/__tests__/pricing-data.test.ts +0 -8
  313. package/src/lib/__tests__/settings-api.test.ts +1 -3
  314. package/src/lib/admin-affiliate-api.ts +2 -7
  315. package/src/lib/admin-api.ts +6 -26
  316. package/src/lib/admin-incident-api.ts +11 -19
  317. package/src/lib/admin-marketplace-api.ts +1 -5
  318. package/src/lib/api-config.test.ts +5 -50
  319. package/src/lib/api.ts +143 -122
  320. package/src/lib/auth-client.ts +1 -2
  321. package/src/lib/bot-settings-data.ts +11 -36
  322. package/src/lib/brand-config.ts +56 -115
  323. package/src/lib/brand.ts +2 -15
  324. package/src/lib/chat/use-chat.ts +2 -7
  325. package/src/lib/cost-comparison-data.test.ts +1 -3
  326. package/src/lib/cost-comparison-data.ts +1 -4
  327. package/src/lib/errors.ts +1 -4
  328. package/src/lib/fetch-utils.test.ts +26 -9
  329. package/src/lib/fetch-utils.ts +40 -11
  330. package/src/lib/logger.ts +2 -0
  331. package/src/lib/marketplace-data.ts +3 -11
  332. package/src/lib/oauth-errors.ts +2 -4
  333. package/src/lib/onboarding-data.ts +3 -11
  334. package/src/lib/org-api.ts +2 -10
  335. package/src/lib/org-billing-api.ts +5 -19
  336. package/src/lib/plugin/tool-definitions.ts +1 -2
  337. package/src/lib/require-auth.ts +57 -0
  338. package/src/lib/settings-api.ts +1 -4
  339. package/src/lib/sidecar-routes.ts +43 -0
  340. package/src/lib/trpc-server.ts +49 -0
  341. package/src/lib/trpc-types.ts +4 -6
  342. package/src/lib/trpc.tsx +12 -4
  343. package/src/lib/validate-redirect-url.ts +1 -4
  344. package/src/lib/webmcp/marketplace-onboarding-tools.ts +6 -16
  345. package/src/lib/webmcp/register.ts +1 -4
  346. package/src/lib/webmcp/tools.ts +2 -9
  347. package/src/proxy.ts +35 -212
  348. package/src/types/missing-deps.d.ts +2 -8
  349. package/tsconfig.json +1 -8
  350. package/biome.json +0 -52
  351. package/src/__tests__/__snapshots__/layout-snapshots.test.tsx.snap +0 -741
  352. package/src/__tests__/billing-byok-callout.test.tsx +0 -76
  353. package/src/lib/__tests__/__snapshots__/pricing-data.test.ts.snap +0 -112
@@ -237,14 +237,9 @@ export function BotSettingsClient({ botId }: { botId: string }) {
237
237
  <Button variant="ghost" size="sm" asChild>
238
238
  <Link href="/dashboard">&larr; Back to Fleet</Link>
239
239
  </Button>
240
- <div
241
- className={`transition-all duration-500 ${statusChanged ? "ring-2 ring-terminal/30 rounded-full" : ""}`}
242
- >
240
+ <div className={`transition-all duration-500 ${statusChanged ? "ring-2 ring-terminal/30 rounded-full" : ""}`}>
243
241
  {actionPending && pendingAction === "restart" ? (
244
- <Badge
245
- variant="outline"
246
- className="gap-1.5 bg-yellow-500/15 text-yellow-500 border-yellow-500/25"
247
- >
242
+ <Badge variant="outline" className="gap-1.5 bg-yellow-500/15 text-yellow-500 border-yellow-500/25">
248
243
  <Loader2 className="size-3 animate-spin" />
249
244
  Restarting
250
245
  </Badge>
@@ -255,12 +250,7 @@ export function BotSettingsClient({ botId }: { botId: string }) {
255
250
  <h1 className="text-2xl font-bold tracking-tight">{settings.identity.name}</h1>
256
251
  <div className="flex gap-2 ml-auto">
257
252
  {(settings.status === "stopped" || settings.status === "archived") && (
258
- <Button
259
- size="sm"
260
- variant="terminal"
261
- disabled={actionPending}
262
- onClick={() => handleAction("start")}
263
- >
253
+ <Button size="sm" variant="terminal" disabled={actionPending} onClick={() => handleAction("start")}>
264
254
  {actionPending && pendingAction === "start" ? (
265
255
  <Loader2 className="size-4 animate-spin" />
266
256
  ) : (
@@ -285,12 +275,7 @@ export function BotSettingsClient({ botId }: { botId: string }) {
285
275
  )}
286
276
  Stop
287
277
  </Button>
288
- <Button
289
- size="sm"
290
- variant="outline"
291
- disabled={actionPending}
292
- onClick={() => handleAction("restart")}
293
- >
278
+ <Button size="sm" variant="outline" disabled={actionPending} onClick={() => handleAction("restart")}>
294
279
  <RotateCw
295
280
  className={`size-3.5 ${actionPending && pendingAction === "restart" ? "animate-spin" : ""}`}
296
281
  />
@@ -523,11 +508,7 @@ function BrainTab({
523
508
  [botId, settings, onUpdate],
524
509
  );
525
510
 
526
- const {
527
- enqueue: enqueueModelSave,
528
- saving: savingModel,
529
- error: modelSaveError,
530
- } = useSaveQueue(saveModelFn);
511
+ const { enqueue: enqueueModelSave, saving: savingModel, error: modelSaveError } = useSaveQueue(saveModelFn);
531
512
 
532
513
  useEffect(() => {
533
514
  if (modelSaveError) setBrainError(modelSaveError);
@@ -650,15 +631,7 @@ function BrainTab({
650
631
 
651
632
  // --- Tab 3: Channels ---
652
633
 
653
- function ChannelsTab({
654
- settings,
655
- botId,
656
- onUpdate,
657
- }: {
658
- settings: BotSettings;
659
- botId: string;
660
- onUpdate: () => void;
661
- }) {
634
+ function ChannelsTab({ settings, botId, onUpdate }: { settings: BotSettings; botId: string; onUpdate: () => void }) {
662
635
  const router = useRouter();
663
636
  const [disconnecting, setDisconnecting] = useState<string | null>(null);
664
637
  const [channelError, setChannelError] = useState<string | null>(null);
@@ -683,9 +656,7 @@ function ChannelsTab({
683
656
  <div className="max-w-2xl space-y-6">
684
657
  <div>
685
658
  <h2 className="text-xl font-bold">Channels</h2>
686
- <p className="text-sm text-muted-foreground">
687
- Connected channels and available integrations.
688
- </p>
659
+ <p className="text-sm text-muted-foreground">Connected channels and available integrations.</p>
689
660
  </div>
690
661
 
691
662
  <div className="space-y-3">
@@ -719,9 +690,7 @@ function ChannelsTab({
719
690
  <Card>
720
691
  <CardHeader>
721
692
  <CardTitle>Add More Channels</CardTitle>
722
- <CardDescription>
723
- Your {productName()} works everywhere you do. All channels are free.
724
- </CardDescription>
693
+ <CardDescription>Your {productName()} works everywhere you do. All channels are free.</CardDescription>
725
694
  </CardHeader>
726
695
  <CardContent>
727
696
  <div className="flex flex-wrap gap-3">
@@ -865,17 +834,11 @@ function ConfigureChannelDialog({
865
834
  {Object.entries(config).map(([key, value]) => (
866
835
  <div key={key} className="space-y-2">
867
836
  <Label htmlFor={`channel-cfg-${key}`}>{key}</Label>
868
- <Input
869
- id={`channel-cfg-${key}`}
870
- value={value}
871
- onChange={(e) => updateField(key, e.target.value)}
872
- />
837
+ <Input id={`channel-cfg-${key}`} value={value} onChange={(e) => updateField(key, e.target.value)} />
873
838
  </div>
874
839
  ))}
875
840
  {Object.keys(config).length === 0 && !error && (
876
- <p className="text-sm text-muted-foreground">
877
- No configurable settings for this channel.
878
- </p>
841
+ <p className="text-sm text-muted-foreground">No configurable settings for this channel.</p>
879
842
  )}
880
843
  </div>
881
844
  )}
@@ -895,15 +858,7 @@ function ConfigureChannelDialog({
895
858
 
896
859
  // --- Tab 4: Superpowers ---
897
860
 
898
- function SuperpowersTab({
899
- settings,
900
- botId,
901
- onUpdate,
902
- }: {
903
- settings: BotSettings;
904
- botId: string;
905
- onUpdate: () => void;
906
- }) {
861
+ function SuperpowersTab({ settings, botId, onUpdate }: { settings: BotSettings; botId: string; onUpdate: () => void }) {
907
862
  const [activating, setActivating] = useState<string | null>(null);
908
863
  const [activateError, setActivateError] = useState<string | null>(null);
909
864
  const [configuringSuperpower, setConfiguringSuperpower] = useState<ActiveSuperpower | null>(null);
@@ -925,22 +880,14 @@ function SuperpowersTab({
925
880
  <div className="space-y-6">
926
881
  <div>
927
882
  <h2 className="text-xl font-bold">Superpowers</h2>
928
- <p className="text-sm text-muted-foreground">
929
- Capabilities that make your bot extraordinary.
930
- </p>
883
+ <p className="text-sm text-muted-foreground">Capabilities that make your bot extraordinary.</p>
931
884
  </div>
932
885
 
933
886
  {/* Active superpowers */}
934
887
  <div className="space-y-3">
935
- <h3 className="text-sm font-semibold text-muted-foreground uppercase tracking-wider">
936
- Active
937
- </h3>
888
+ <h3 className="text-sm font-semibold text-muted-foreground uppercase tracking-wider">Active</h3>
938
889
  {(settings.activeSuperpowers ?? []).map((sp) => (
939
- <ActiveSuperpowerCard
940
- key={sp.id}
941
- superpower={sp}
942
- onConfigure={() => setConfiguringSuperpower(sp)}
943
- />
890
+ <ActiveSuperpowerCard key={sp.id} superpower={sp} onConfigure={() => setConfiguringSuperpower(sp)} />
944
891
  ))}
945
892
  </div>
946
893
 
@@ -1042,17 +989,11 @@ function ConfigureSuperpowerDialog({
1042
989
  {Object.entries(config).map(([key, value]) => (
1043
990
  <div key={key} className="space-y-2">
1044
991
  <Label htmlFor={`sp-cfg-${key}`}>{key}</Label>
1045
- <Input
1046
- id={`sp-cfg-${key}`}
1047
- value={value}
1048
- onChange={(e) => updateField(key, e.target.value)}
1049
- />
992
+ <Input id={`sp-cfg-${key}`} value={value} onChange={(e) => updateField(key, e.target.value)} />
1050
993
  </div>
1051
994
  ))}
1052
995
  {Object.keys(config).length === 0 && !error && (
1053
- <p className="text-sm text-muted-foreground">
1054
- No configurable settings for this superpower.
1055
- </p>
996
+ <p className="text-sm text-muted-foreground">No configurable settings for this superpower.</p>
1056
997
  )}
1057
998
  </div>
1058
999
  )}
@@ -1070,13 +1011,7 @@ function ConfigureSuperpowerDialog({
1070
1011
  );
1071
1012
  }
1072
1013
 
1073
- function ActiveSuperpowerCard({
1074
- superpower,
1075
- onConfigure,
1076
- }: {
1077
- superpower: ActiveSuperpower;
1078
- onConfigure: () => void;
1079
- }) {
1014
+ function ActiveSuperpowerCard({ superpower, onConfigure }: { superpower: ActiveSuperpower; onConfigure: () => void }) {
1080
1015
  return (
1081
1016
  <Card>
1082
1017
  <CardContent className="flex items-center justify-between p-4">
@@ -1086,8 +1021,7 @@ function ActiveSuperpowerCard({
1086
1021
  <Badge variant="outline">{superpower.mode === "hosted" ? "Hosted" : "BYOK"}</Badge>
1087
1022
  </div>
1088
1023
  <p className="text-sm text-muted-foreground">
1089
- {superpower.usageCount} {superpower.usageLabel} &middot;{" "}
1090
- <CreditDetailed value={superpower.spend} /> spent
1024
+ {superpower.usageCount} {superpower.usageLabel} &middot; <CreditDetailed value={superpower.spend} /> spent
1091
1025
  </p>
1092
1026
  <p className="text-xs text-muted-foreground">
1093
1027
  Provider: {superpower.provider} &middot; {superpower.model}
@@ -1132,15 +1066,7 @@ function AvailableSuperpowerCard({
1132
1066
 
1133
1067
  // --- Tab 5: Plugins ---
1134
1068
 
1135
- function PluginsTab({
1136
- settings,
1137
- botId,
1138
- onUpdate,
1139
- }: {
1140
- settings: BotSettings;
1141
- botId: string;
1142
- onUpdate: () => void;
1143
- }) {
1069
+ function PluginsTab({ settings, botId, onUpdate }: { settings: BotSettings; botId: string; onUpdate: () => void }) {
1144
1070
  const [togglingPlugin, setTogglingPlugin] = useState<string | null>(null);
1145
1071
  const [installingPlugin, setInstallingPlugin] = useState<string | null>(null);
1146
1072
  const [pluginError, setPluginError] = useState<string | null>(null);
@@ -1197,9 +1123,7 @@ function PluginsTab({
1197
1123
 
1198
1124
  {/* Installed */}
1199
1125
  <div className="space-y-3">
1200
- <h3 className="text-sm font-semibold text-muted-foreground uppercase tracking-wider">
1201
- Installed
1202
- </h3>
1126
+ <h3 className="text-sm font-semibold text-muted-foreground uppercase tracking-wider">Installed</h3>
1203
1127
  {(settings.installedPlugins ?? []).map((plugin) => (
1204
1128
  <InstalledPluginCard
1205
1129
  key={plugin.id}
@@ -1216,9 +1140,7 @@ function PluginsTab({
1216
1140
 
1217
1141
  {/* Discover */}
1218
1142
  <div className="space-y-3">
1219
- <h3 className="text-sm font-semibold text-muted-foreground uppercase tracking-wider">
1220
- Discover Plugins
1221
- </h3>
1143
+ <h3 className="text-sm font-semibold text-muted-foreground uppercase tracking-wider">Discover Plugins</h3>
1222
1144
  <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
1223
1145
  {(settings.discoverPlugins ?? []).map((plugin) => (
1224
1146
  <DiscoverPluginCard
@@ -1247,8 +1169,7 @@ function PluginsTab({
1247
1169
  <DialogHeader>
1248
1170
  <DialogTitle>Uninstall {confirmUninstall.name}?</DialogTitle>
1249
1171
  <DialogDescription>
1250
- This will remove the plugin and its configuration from your bot. This action cannot
1251
- be undone.
1172
+ This will remove the plugin and its configuration from your bot. This action cannot be undone.
1252
1173
  </DialogDescription>
1253
1174
  </DialogHeader>
1254
1175
  <DialogFooter>
@@ -1348,17 +1269,11 @@ function ConfigurePluginDialog({
1348
1269
  {Object.entries(config).map(([key, value]) => (
1349
1270
  <div key={key} className="space-y-2">
1350
1271
  <Label htmlFor={`plugin-cfg-${key}`}>{key}</Label>
1351
- <Input
1352
- id={`plugin-cfg-${key}`}
1353
- value={value}
1354
- onChange={(e) => updateField(key, e.target.value)}
1355
- />
1272
+ <Input id={`plugin-cfg-${key}`} value={value} onChange={(e) => updateField(key, e.target.value)} />
1356
1273
  </div>
1357
1274
  ))}
1358
1275
  {Object.keys(config).length === 0 && !error && (
1359
- <p className="text-sm text-muted-foreground">
1360
- No configurable settings for this plugin.
1361
- </p>
1276
+ <p className="text-sm text-muted-foreground">No configurable settings for this plugin.</p>
1362
1277
  )}
1363
1278
  </div>
1364
1279
  )}
@@ -1395,10 +1310,7 @@ function InstalledPluginCard({
1395
1310
  <div className="space-y-1">
1396
1311
  <div className="flex items-center gap-2">
1397
1312
  <span className="font-medium">{plugin.name}</span>
1398
- <Badge
1399
- variant="outline"
1400
- className={PLUGIN_STATUS_STYLES[plugin.status] ?? DEFAULT_STATUS_STYLE}
1401
- >
1313
+ <Badge variant="outline" className={PLUGIN_STATUS_STYLES[plugin.status] ?? DEFAULT_STATUS_STYLE}>
1402
1314
  {plugin.status === "active" ? "Active" : "Disabled"}
1403
1315
  </Badge>
1404
1316
  </div>
@@ -1483,8 +1395,8 @@ function UsageTab({ settings }: { settings: BotSettings }) {
1483
1395
  <Card>
1484
1396
  <CardContent className="space-y-4 p-4">
1485
1397
  <div className="text-sm text-muted-foreground">
1486
- This week: {formatCreditStandard(usage.totalSpend)} of{" "}
1487
- {formatCreditStandard(usage.creditBalance)} remaining credits
1398
+ This week: {formatCreditStandard(usage.totalSpend)} of {formatCreditStandard(usage.creditBalance)} remaining
1399
+ credits
1488
1400
  </div>
1489
1401
  <Progress value={spendPercent} className="h-2" />
1490
1402
  </CardContent>
@@ -1528,10 +1440,7 @@ function UsageTab({ settings }: { settings: BotSettings }) {
1528
1440
  className="flex flex-1 flex-col items-center gap-1"
1529
1441
  title={`${point.date}: ${formatCreditDetailed(point.spend)}`}
1530
1442
  >
1531
- <div
1532
- className="w-full rounded-t bg-primary/60"
1533
- style={{ height: `${height}%` }}
1534
- />
1443
+ <div className="w-full rounded-t bg-primary/60" style={{ height: `${height}%` }} />
1535
1444
  <span className="text-[10px] text-muted-foreground">{point.date.slice(-2)}</span>
1536
1445
  </div>
1537
1446
  );
@@ -1565,15 +1474,7 @@ function UsageTab({ settings }: { settings: BotSettings }) {
1565
1474
 
1566
1475
  // --- Tab 7: Danger Zone ---
1567
1476
 
1568
- function DangerZoneTab({
1569
- settings,
1570
- botId,
1571
- onUpdate,
1572
- }: {
1573
- settings: BotSettings;
1574
- botId: string;
1575
- onUpdate: () => void;
1576
- }) {
1477
+ function DangerZoneTab({ settings, botId, onUpdate }: { settings: BotSettings; botId: string; onUpdate: () => void }) {
1577
1478
  const router = useRouter();
1578
1479
  const [confirmAction, setConfirmAction] = useState<"stop" | "archive" | "delete" | null>(null);
1579
1480
  const [confirmText, setConfirmText] = useState("");
@@ -1633,9 +1534,7 @@ function DangerZoneTab({
1633
1534
  <div className="max-w-2xl space-y-6">
1634
1535
  <div>
1635
1536
  <h2 className="text-xl font-bold text-destructive">Danger Zone</h2>
1636
- <p className="text-sm text-muted-foreground">
1637
- Irreversible and destructive actions. Proceed with caution.
1638
- </p>
1537
+ <p className="text-sm text-muted-foreground">Irreversible and destructive actions. Proceed with caution.</p>
1639
1538
  </div>
1640
1539
 
1641
1540
  <div className="space-y-4">
@@ -1669,9 +1568,8 @@ function DangerZoneTab({
1669
1568
  "This will remove your bot from the fleet. Config and memories are kept for 30 days. You can restore it within that window."}
1670
1569
  {confirmAction === "delete" && (
1671
1570
  <>
1672
- This action is permanent and cannot be undone. All data, memories, and
1673
- configuration will be destroyed. Type{" "}
1674
- <strong className="text-foreground">{botName}</strong> to confirm.
1571
+ This action is permanent and cannot be undone. All data, memories, and configuration will be
1572
+ destroyed. Type <strong className="text-foreground">{botName}</strong> to confirm.
1675
1573
  </>
1676
1574
  )}
1677
1575
  </DialogDescription>
@@ -64,7 +64,6 @@ export function ResourcesTab({ botId }: { botId: string }) {
64
64
  const [applying, setApplying] = useState(false);
65
65
  const [error, setError] = useState<string | null>(null);
66
66
 
67
- // biome-ignore lint/suspicious/noEmptyBlockStatements: initial no-op placeholder replaced in useEffect
68
67
  const retryRef = useRef<() => void>(() => {});
69
68
 
70
69
  useEffect(() => {
@@ -153,9 +152,7 @@ export function ResourcesTab({ botId }: { botId: string }) {
153
152
  <span>{tier.cpu}</span>
154
153
  </div>
155
154
  <div className="text-sm font-medium">
156
- {tier.dailyCost === 0
157
- ? "Included"
158
- : `+${tier.dailyCost} credits/day (${tier.monthlyCost})`}
155
+ {tier.dailyCost === 0 ? "Included" : `+${tier.dailyCost} credits/day (${tier.monthlyCost})`}
159
156
  </div>
160
157
  {!isCurrent && (
161
158
  <Button
@@ -163,11 +160,7 @@ export function ResourcesTab({ botId }: { botId: string }) {
163
160
  variant={tier.key === "standard" ? "outline" : "default"}
164
161
  onClick={() => setConfirmTier(tier)}
165
162
  >
166
- {currentTier === null
167
- ? "Select"
168
- : tierIndex < currentTierIndex
169
- ? "Downgrade"
170
- : "Upgrade"}
163
+ {currentTier === null ? "Select" : tierIndex < currentTierIndex ? "Downgrade" : "Upgrade"}
171
164
  </Button>
172
165
  )}
173
166
  </CardContent>
@@ -13,12 +13,7 @@ import {
13
13
  DialogTitle,
14
14
  } from "@/components/ui/dialog";
15
15
  import { Progress } from "@/components/ui/progress";
16
- import {
17
- getStorageTier,
18
- getStorageUsage,
19
- type StorageUsage,
20
- setStorageTier,
21
- } from "@/lib/bot-settings-data";
16
+ import { getStorageTier, getStorageUsage, type StorageUsage, setStorageTier } from "@/lib/bot-settings-data";
22
17
 
23
18
  const STORAGE_TIERS = [
24
19
  {
@@ -73,10 +68,7 @@ export function StorageTab({ botId }: { botId: string }) {
73
68
  async function load() {
74
69
  setLoading(true);
75
70
  try {
76
- const [tierResult, usageResult] = await Promise.all([
77
- getStorageTier(botId),
78
- getStorageUsage(botId),
79
- ]);
71
+ const [tierResult, usageResult] = await Promise.all([getStorageTier(botId), getStorageUsage(botId)]);
80
72
  if (!cancelled) {
81
73
  setCurrentTier(tierResult.tier as TierKey);
82
74
  setUsage(usageResult);
@@ -109,11 +101,7 @@ export function StorageTab({ botId }: { botId: string }) {
109
101
  }
110
102
 
111
103
  if (loading) {
112
- return (
113
- <div className="flex h-40 items-center justify-center text-muted-foreground">
114
- Loading storage info...
115
- </div>
116
- );
104
+ return <div className="flex h-40 items-center justify-center text-muted-foreground">Loading storage info...</div>;
117
105
  }
118
106
 
119
107
  const tierInfo = STORAGE_TIERS.find((t) => t.key === currentTier) ?? STORAGE_TIERS[0];
@@ -125,16 +113,13 @@ export function StorageTab({ botId }: { botId: string }) {
125
113
  const pendingTierInfo = pendingTier ? STORAGE_TIERS.find((t) => t.key === pendingTier) : null;
126
114
  const isDowngrade =
127
115
  pendingTier !== null &&
128
- STORAGE_TIERS.findIndex((t) => t.key === pendingTier) <
129
- STORAGE_TIERS.findIndex((t) => t.key === currentTier);
116
+ STORAGE_TIERS.findIndex((t) => t.key === pendingTier) < STORAGE_TIERS.findIndex((t) => t.key === currentTier);
130
117
 
131
118
  return (
132
119
  <div className="max-w-2xl space-y-6">
133
120
  <div>
134
121
  <h2 className="text-xl font-bold">Storage</h2>
135
- <p className="text-sm text-muted-foreground">
136
- Persistent storage for bot memories, files, and data.
137
- </p>
122
+ <p className="text-sm text-muted-foreground">Persistent storage for bot memories, files, and data.</p>
138
123
  </div>
139
124
 
140
125
  {/* Usage bar */}
@@ -142,23 +127,15 @@ export function StorageTab({ botId }: { botId: string }) {
142
127
  <CardContent className="space-y-3 p-4">
143
128
  <div className="flex items-center justify-between text-sm">
144
129
  <span className="font-medium">
145
- {usage ? formatBytes(usedBytes) : "Usage unavailable"} of {tierInfo.storageLimitGb} GB
146
- used
130
+ {usage ? formatBytes(usedBytes) : "Usage unavailable"} of {tierInfo.storageLimitGb} GB used
147
131
  </span>
148
132
  {usage && (
149
- <span className={usageHigh ? "text-amber-500" : "text-muted-foreground"}>
150
- {usagePercent.toFixed(0)}%
151
- </span>
133
+ <span className={usageHigh ? "text-amber-500" : "text-muted-foreground"}>{usagePercent.toFixed(0)}%</span>
152
134
  )}
153
135
  </div>
154
- <Progress
155
- value={usage ? usagePercent : 0}
156
- className={`h-2 ${usageHigh ? "[&>div]:bg-amber-500" : ""}`}
157
- />
136
+ <Progress value={usage ? usagePercent : 0} className={`h-2 ${usageHigh ? "[&>div]:bg-amber-500" : ""}`} />
158
137
  {!usage && (
159
- <p className="text-xs text-muted-foreground">
160
- Disk usage is only available while the bot is running.
161
- </p>
138
+ <p className="text-xs text-muted-foreground">Disk usage is only available while the bot is running.</p>
162
139
  )}
163
140
  </CardContent>
164
141
  </Card>
@@ -168,9 +145,7 @@ export function StorageTab({ botId }: { botId: string }) {
168
145
 
169
146
  {/* Tier cards */}
170
147
  <div className="space-y-3">
171
- <h3 className="text-sm font-semibold uppercase tracking-wider text-muted-foreground">
172
- Storage Tiers
173
- </h3>
148
+ <h3 className="text-sm font-semibold uppercase tracking-wider text-muted-foreground">Storage Tiers</h3>
174
149
  <div className="grid gap-3 sm:grid-cols-2">
175
150
  {STORAGE_TIERS.map((tier) => {
176
151
  const isActive = tier.key === currentTier;
@@ -178,9 +153,7 @@ export function StorageTab({ botId }: { botId: string }) {
178
153
  <Card
179
154
  key={tier.key}
180
155
  className={`cursor-pointer transition-colors ${
181
- isActive
182
- ? "border-primary bg-primary/5"
183
- : "hover:border-primary/50 hover:bg-accent/30"
156
+ isActive ? "border-primary bg-primary/5" : "hover:border-primary/50 hover:bg-accent/30"
184
157
  }`}
185
158
  onClick={() => {
186
159
  if (!isActive) setPendingTier(tier.key);
@@ -203,8 +176,8 @@ export function StorageTab({ botId }: { botId: string }) {
203
176
  })}
204
177
  </div>
205
178
  <p className="text-xs text-muted-foreground">
206
- Storage costs are billed daily from your credit balance. Downgrades take effect
207
- immediately but do not delete existing data.
179
+ Storage costs are billed daily from your credit balance. Downgrades take effect immediately but do not delete
180
+ existing data.
208
181
  </p>
209
182
  </div>
210
183
 
@@ -218,17 +191,15 @@ export function StorageTab({ botId }: { botId: string }) {
218
191
  <DialogDescription>
219
192
  {isDowngrade ? (
220
193
  <>
221
- Downgrading to <strong>{pendingTierInfo?.label}</strong> (
222
- {pendingTierInfo?.storageLimitGb} GB) takes effect immediately. Existing data is
223
- not deleted, but the bot will be unable to write new data once it exceeds the new
224
- limit.
194
+ Downgrading to <strong>{pendingTierInfo?.label}</strong> ({pendingTierInfo?.storageLimitGb} GB) takes
195
+ effect immediately. Existing data is not deleted, but the bot will be unable to write new data once it
196
+ exceeds the new limit.
225
197
  </>
226
198
  ) : (
227
199
  <>
228
- Upgrading to <strong>{pendingTierInfo?.label}</strong> (
229
- {pendingTierInfo?.storageLimitGb} GB) adds{" "}
230
- <strong>{pendingTierInfo?.dailyCostCents}¢ per day</strong> to this bot's credit
231
- cost, billed from your balance.
200
+ Upgrading to <strong>{pendingTierInfo?.label}</strong> ({pendingTierInfo?.storageLimitGb} GB) adds{" "}
201
+ <strong>{pendingTierInfo?.dailyCostCents}¢ per day</strong> to this bot's credit cost, billed from
202
+ your balance.
232
203
  </>
233
204
  )}
234
205
  </DialogDescription>
@@ -36,9 +36,7 @@ export function VpsInfoPanel({ botId }: VpsPanelProps) {
36
36
  <Card className="border-destructive/30">
37
37
  <CardContent className="flex items-center gap-2 py-4">
38
38
  <Server className="size-5 text-destructive" />
39
- <p className="text-sm text-destructive">
40
- Failed to load VPS info. Please try again later.
41
- </p>
39
+ <p className="text-sm text-destructive">Failed to load VPS info. Please try again later.</p>
42
40
  </CardContent>
43
41
  </Card>
44
42
  );
@@ -111,20 +109,14 @@ export function VpsInfoPanel({ botId }: VpsPanelProps) {
111
109
  onClick={handleCopy}
112
110
  title="Copy SSH command"
113
111
  >
114
- {copied ? (
115
- <CheckCircle className="size-4 text-terminal" />
116
- ) : (
117
- <Copy className="size-4" />
118
- )}
112
+ {copied ? <CheckCircle className="size-4 text-terminal" /> : <Copy className="size-4" />}
119
113
  </Button>
120
114
  </div>
121
115
  </div>
122
116
  )}
123
117
 
124
118
  {!vps.sshConnectionString && vps.status === "active" && (
125
- <p className="text-sm text-muted-foreground">
126
- SSH access is being provisioned. Check back shortly.
127
- </p>
119
+ <p className="text-sm text-muted-foreground">SSH access is being provisioned. Check back shortly.</p>
128
120
  )}
129
121
  </CardContent>
130
122
  </Card>
@@ -68,8 +68,7 @@ export function VpsUpgradeCard({ botId }: VpsUpgradeCardProps) {
68
68
  </Badge>
69
69
  </div>
70
70
  <CardDescription>
71
- Get a dedicated persistent container with fixed monthly pricing — no per-credit billing
72
- for compute.
71
+ Get a dedicated persistent container with fixed monthly pricing — no per-credit billing for compute.
73
72
  </CardDescription>
74
73
  </CardHeader>
75
74
  <CardContent className="flex flex-col gap-4">
@@ -97,8 +96,8 @@ export function VpsUpgradeCard({ botId }: VpsUpgradeCardProps) {
97
96
  {error && <p className="text-sm text-destructive">{error}</p>}
98
97
 
99
98
  <p className="text-xs text-muted-foreground">
100
- Your bot will experience brief downtime during the container upgrade. You will be
101
- redirected to Stripe Checkout to complete the subscription.
99
+ Your bot will experience brief downtime during the container upgrade. You will be redirected to Stripe
100
+ Checkout to complete the subscription.
102
101
  </p>
103
102
 
104
103
  <Button onClick={handleUpgrade} disabled={loading} className="w-full sm:w-auto">
@@ -0,0 +1,13 @@
1
+ "use client";
2
+
3
+ import { type BrandConfig, setBrandConfig } from "@/lib/brand-config";
4
+
5
+ /**
6
+ * Client component that hydrates the brand config from server-fetched data.
7
+ * Renders nothing — just calls setBrandConfig() during module evaluation
8
+ * so all client components see the DB-driven config.
9
+ */
10
+ export function BrandHydrator({ config }: { config: Partial<BrandConfig> }) {
11
+ setBrandConfig(config);
12
+ return null;
13
+ }
@@ -33,9 +33,7 @@ export function FieldInteractive({ field, value, onChange, error }: FieldInterac
33
33
  )}
34
34
  >
35
35
  <span className="flex-1">{option.label}</span>
36
- {value === option.value && (
37
- <span className="text-primary text-xs font-medium">Selected</span>
38
- )}
36
+ {value === option.value && <span className="text-primary text-xs font-medium">Selected</span>}
39
37
  </Button>
40
38
  ))}
41
39
  </div>