@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
@@ -38,13 +38,7 @@ async function deriveXpubFromMnemonic(mnemonic: string, coinType: number): Promi
38
38
  return xpub;
39
39
  }
40
40
 
41
- function MnemonicDeriveSection({
42
- chain,
43
- onXpubDerived,
44
- }: {
45
- chain: string;
46
- onXpubDerived: (xpub: string) => void;
47
- }) {
41
+ function MnemonicDeriveSection({ chain, onXpubDerived }: { chain: string; onXpubDerived: (xpub: string) => void }) {
48
42
  const [mnemonic, setMnemonic] = useState("");
49
43
  const [deriving, setDeriving] = useState(false);
50
44
  const [error, setError] = useState<string | null>(null);
@@ -72,9 +66,7 @@ function MnemonicDeriveSection({
72
66
  if (derived) {
73
67
  return (
74
68
  <div className="col-span-2 rounded-md border border-green-500/30 bg-green-500/5 p-3">
75
- <p className="text-xs text-green-500">
76
- xpub derived and set. Mnemonic was cleared from memory.
77
- </p>
69
+ <p className="text-xs text-green-500">xpub derived and set. Mnemonic was cleared from memory.</p>
78
70
  </div>
79
71
  );
80
72
  }
@@ -98,13 +90,7 @@ function MnemonicDeriveSection({
98
90
  spellCheck={false}
99
91
  />
100
92
  {error && <p className="text-xs text-destructive">{error}</p>}
101
- <Button
102
- type="button"
103
- variant="outline"
104
- size="sm"
105
- onClick={handleDerive}
106
- disabled={deriving || !mnemonic.trim()}
107
- >
93
+ <Button type="button" variant="outline" size="sm" onClick={handleDerive} disabled={deriving || !mnemonic.trim()}>
108
94
  {deriving ? "Deriving..." : "Derive xpub"}
109
95
  </Button>
110
96
  </div>
@@ -248,9 +234,7 @@ function AddMethodForm({ onSaved }: { onSaved: () => void }) {
248
234
  />
249
235
  </label>
250
236
  <label className="col-span-2 space-y-1">
251
- <span className="text-xs text-muted-foreground">
252
- Oracle Address (Chainlink feed — empty for stablecoins)
253
- </span>
237
+ <span className="text-xs text-muted-foreground">Oracle Address (Chainlink feed — empty for stablecoins)</span>
254
238
  <input
255
239
  className="w-full rounded-md border bg-background px-3 py-1.5 text-sm font-mono"
256
240
  placeholder="0x..."
@@ -260,10 +244,7 @@ function AddMethodForm({ onSaved }: { onSaved: () => void }) {
260
244
  </label>
261
245
 
262
246
  {/* --- xpub: paste directly or derive from mnemonic --- */}
263
- <MnemonicDeriveSection
264
- chain={form.chain}
265
- onXpubDerived={(xpub) => setForm((f) => ({ ...f, xpub }))}
266
- />
247
+ <MnemonicDeriveSection chain={form.chain} onXpubDerived={(xpub) => setForm((f) => ({ ...f, xpub }))} />
267
248
  <label className="col-span-2 space-y-1">
268
249
  <span className="text-xs text-muted-foreground">
269
250
  xpub (auto-filled from mnemonic above, or paste directly)
@@ -372,29 +353,19 @@ export default function AdminPaymentMethodsPage() {
372
353
  <td className="py-2 pr-4 font-mono text-xs">
373
354
  {m.contractAddress ? `${m.contractAddress.slice(0, 10)}...` : "—"}
374
355
  </td>
375
- <td className="py-2 pr-4 font-mono text-xs">
376
- {m.xpub ? `${m.xpub.slice(0, 12)}...` : "—"}
377
- </td>
378
- <td className="py-2 pr-4 font-mono text-xs">
379
- {m.rpcUrl ? `${m.rpcUrl.slice(0, 20)}...` : "—"}
380
- </td>
356
+ <td className="py-2 pr-4 font-mono text-xs">{m.xpub ? `${m.xpub.slice(0, 12)}...` : "—"}</td>
357
+ <td className="py-2 pr-4 font-mono text-xs">{m.rpcUrl ? `${m.rpcUrl.slice(0, 20)}...` : "—"}</td>
381
358
  <td className="py-2 pr-4">
382
359
  <span
383
360
  className={
384
- m.enabled
385
- ? "text-xs font-medium text-green-500"
386
- : "text-xs font-medium text-red-500"
361
+ m.enabled ? "text-xs font-medium text-green-500" : "text-xs font-medium text-red-500"
387
362
  }
388
363
  >
389
364
  {m.enabled ? "Enabled" : "Disabled"}
390
365
  </span>
391
366
  </td>
392
367
  <td className="py-2">
393
- <Button
394
- variant="ghost"
395
- size="sm"
396
- onClick={() => handleToggle(m.id, !m.enabled)}
397
- >
368
+ <Button variant="ghost" size="sm" onClick={() => handleToggle(m.id, !m.enabled)}>
398
369
  {m.enabled ? "Disable" : "Enable"}
399
370
  </Button>
400
371
  </td>
@@ -3,14 +3,9 @@
3
3
  import { useEffect } from "react";
4
4
  import { Button } from "@/components/ui/button";
5
5
 
6
- export default function ProductsError({
7
- error,
8
- reset,
9
- }: {
10
- error: Error & { digest?: string };
11
- reset: () => void;
12
- }) {
6
+ export default function ProductsError({ error, reset }: { error: Error & { digest?: string }; reset: () => void }) {
13
7
  useEffect(() => {
8
+ // biome-ignore lint/suspicious/noConsole: error boundary diagnostic logging
14
9
  console.error("Admin products page error:", error);
15
10
  }, [error]);
16
11
 
@@ -215,10 +215,7 @@ export default function AdminProductsPage() {
215
215
  </TabsContent>
216
216
 
217
217
  <TabsContent value="features">
218
- <FeaturesForm
219
- initial={config.features ?? DEFAULT_FEATURES}
220
- onSave={mutateProductConfig}
221
- />
218
+ <FeaturesForm initial={config.features ?? DEFAULT_FEATURES} onSave={mutateProductConfig} />
222
219
  </TabsContent>
223
220
 
224
221
  <TabsContent value="fleet">
@@ -7,24 +7,11 @@ import { useCallback, useEffect, useState } from "react";
7
7
  import { Badge } from "@/components/ui/badge";
8
8
  import { Button } from "@/components/ui/button";
9
9
  import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
10
- import {
11
- Dialog,
12
- DialogContent,
13
- DialogHeader,
14
- DialogTitle,
15
- DialogTrigger,
16
- } from "@/components/ui/dialog";
10
+ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
17
11
  import { Input } from "@/components/ui/input";
18
12
  import { Progress } from "@/components/ui/progress";
19
13
  import { Skeleton } from "@/components/ui/skeleton";
20
- import {
21
- Table,
22
- TableBody,
23
- TableCell,
24
- TableHead,
25
- TableHeader,
26
- TableRow,
27
- } from "@/components/ui/table";
14
+ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
28
15
  import type { Promotion, Redemption } from "@/lib/promotions-types";
29
16
  import { trpcVanilla } from "@/lib/trpc";
30
17
  import { cn } from "@/lib/utils";
@@ -142,9 +129,7 @@ export default function PromotionDetailPage() {
142
129
  }
143
130
 
144
131
  const budgetUsedPercent =
145
- promo.budgetCap && promo.budgetCap > 0
146
- ? Math.min(100, (promo.totalCreditsGranted / promo.budgetCap) * 100)
147
- : null;
132
+ promo.budgetCap && promo.budgetCap > 0 ? Math.min(100, (promo.totalCreditsGranted / promo.budgetCap) * 100) : null;
148
133
 
149
134
  return (
150
135
  <div className="p-6 space-y-6">
@@ -171,18 +156,14 @@ export default function PromotionDetailPage() {
171
156
  <div className="text-2xl font-bold tabular-nums">
172
157
  {promo.totalUses}
173
158
  {promo.totalUseLimit !== null && (
174
- <span className="text-sm text-muted-foreground font-normal">
175
- /{promo.totalUseLimit}
176
- </span>
159
+ <span className="text-sm text-muted-foreground font-normal">/{promo.totalUseLimit}</span>
177
160
  )}
178
161
  </div>
179
162
  </CardContent>
180
163
  </Card>
181
164
  <Card>
182
165
  <CardHeader className="pb-2">
183
- <CardTitle className="text-xs text-muted-foreground font-normal">
184
- Credits Granted
185
- </CardTitle>
166
+ <CardTitle className="text-xs text-muted-foreground font-normal">Credits Granted</CardTitle>
186
167
  </CardHeader>
187
168
  <CardContent>
188
169
  <div className="text-2xl font-bold tabular-nums text-terminal">
@@ -192,9 +173,7 @@ export default function PromotionDetailPage() {
192
173
  </Card>
193
174
  <Card>
194
175
  <CardHeader className="pb-2">
195
- <CardTitle className="text-xs text-muted-foreground font-normal">
196
- Budget Remaining
197
- </CardTitle>
176
+ <CardTitle className="text-xs text-muted-foreground font-normal">Budget Remaining</CardTitle>
198
177
  </CardHeader>
199
178
  <CardContent>
200
179
  {promo.budgetCap !== null ? (
@@ -211,9 +190,7 @@ export default function PromotionDetailPage() {
211
190
  </Card>
212
191
  <Card>
213
192
  <CardHeader className="pb-2">
214
- <CardTitle className="text-xs text-muted-foreground font-normal">
215
- Time Remaining
216
- </CardTitle>
193
+ <CardTitle className="text-xs text-muted-foreground font-normal">Time Remaining</CardTitle>
217
194
  </CardHeader>
218
195
  <CardContent>
219
196
  <div className="text-2xl font-bold">{timeRemaining(promo.endsAt)}</div>
@@ -252,11 +229,7 @@ export default function PromotionDetailPage() {
252
229
  />
253
230
  </div>
254
231
  {genResult && <p className="text-sm text-muted-foreground">{genResult}</p>}
255
- <Button
256
- onClick={handleGenerate}
257
- disabled={generating || genCount < 1}
258
- className="w-full"
259
- >
232
+ <Button onClick={handleGenerate} disabled={generating || genCount < 1} className="w-full">
260
233
  {generating ? "Generating..." : `Generate ${genCount} codes`}
261
234
  </Button>
262
235
  </div>
@@ -286,9 +259,7 @@ export default function PromotionDetailPage() {
286
259
  <TableBody>
287
260
  {redemptions.map((r) => (
288
261
  <TableRow key={r.id}>
289
- <TableCell className="font-mono text-xs">
290
- {r.tenantId.slice(0, 12)}...
291
- </TableCell>
262
+ <TableCell className="font-mono text-xs">{r.tenantId.slice(0, 12)}...</TableCell>
292
263
  <TableCell className="text-right tabular-nums text-terminal">
293
264
  {formatCreditCount(r.creditsGranted)}
294
265
  </TableCell>
@@ -11,22 +11,9 @@ import {
11
11
  DropdownMenuItem,
12
12
  DropdownMenuTrigger,
13
13
  } from "@/components/ui/dropdown-menu";
14
- import {
15
- Select,
16
- SelectContent,
17
- SelectItem,
18
- SelectTrigger,
19
- SelectValue,
20
- } from "@/components/ui/select";
14
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
21
15
  import { Skeleton } from "@/components/ui/skeleton";
22
- import {
23
- Table,
24
- TableBody,
25
- TableCell,
26
- TableHead,
27
- TableHeader,
28
- TableRow,
29
- } from "@/components/ui/table";
16
+ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
30
17
  import { toUserMessage } from "@/lib/errors";
31
18
  import type { Promotion, PromotionStatus, PromotionType } from "@/lib/promotions-types";
32
19
  import { trpcVanilla } from "@/lib/trpc";
@@ -53,8 +40,7 @@ const TYPE_LABELS: Record<PromotionType, string> = {
53
40
  };
54
41
 
55
42
  function formatWindow(startsAt: string | null, endsAt: string | null): string {
56
- const fmt = (d: string) =>
57
- new Date(d).toLocaleDateString("en-US", { month: "short", day: "numeric" });
43
+ const fmt = (d: string) => new Date(d).toLocaleDateString("en-US", { month: "short", day: "numeric" });
58
44
  if (!startsAt) return "Immediate";
59
45
  if (!endsAt) return `${fmt(startsAt)} — no end`;
60
46
  return `${fmt(startsAt)} — ${fmt(endsAt)}`;
@@ -168,9 +154,7 @@ export default function PromotionsListPage() {
168
154
  ))}
169
155
  </div>
170
156
  ) : promotions.length === 0 ? (
171
- <div className="flex h-40 items-center justify-center text-sm text-muted-foreground">
172
- No promotions found.
173
- </div>
157
+ <div className="flex h-40 items-center justify-center text-sm text-muted-foreground">No promotions found.</div>
174
158
  ) : (
175
159
  <Table>
176
160
  <TableHeader>
@@ -193,22 +177,16 @@ export default function PromotionsListPage() {
193
177
  {p.name}
194
178
  </Link>
195
179
  </TableCell>
196
- <TableCell className="text-sm text-muted-foreground">
197
- {TYPE_LABELS[p.type]}
198
- </TableCell>
180
+ <TableCell className="text-sm text-muted-foreground">{TYPE_LABELS[p.type]}</TableCell>
199
181
  <TableCell>
200
182
  <Badge variant="secondary" className={cn("text-xs", STATUS_COLORS[p.status])}>
201
183
  {p.status}
202
184
  </Badge>
203
185
  </TableCell>
204
- <TableCell className="text-sm text-muted-foreground">
205
- {formatWindow(p.startsAt, p.endsAt)}
206
- </TableCell>
186
+ <TableCell className="text-sm text-muted-foreground">{formatWindow(p.startsAt, p.endsAt)}</TableCell>
207
187
  <TableCell className="text-right tabular-nums">
208
188
  {p.totalUses}
209
- {p.totalUseLimit !== null && (
210
- <span className="text-muted-foreground">/{p.totalUseLimit}</span>
211
- )}
189
+ {p.totalUseLimit !== null && <span className="text-muted-foreground">/{p.totalUseLimit}</span>}
212
190
  </TableCell>
213
191
  <TableCell className="text-right tabular-nums text-terminal">
214
192
  {formatCreditCount(p.totalCreditsGranted)}
@@ -230,9 +208,7 @@ export default function PromotionsListPage() {
230
208
  View Detail
231
209
  </Link>
232
210
  </DropdownMenuItem>
233
- {(p.status === "draft" ||
234
- p.status === "scheduled" ||
235
- p.status === "paused") && (
211
+ {(p.status === "draft" || p.status === "scheduled" || p.status === "paused") && (
236
212
  <DropdownMenuItem onClick={() => handleAction(p.id, "activate")}>
237
213
  <Play className="h-4 w-4 mr-2" />
238
214
  Activate
@@ -245,10 +221,7 @@ export default function PromotionsListPage() {
245
221
  </DropdownMenuItem>
246
222
  )}
247
223
  {p.status !== "cancelled" && p.status !== "expired" && (
248
- <DropdownMenuItem
249
- onClick={() => handleAction(p.id, "cancel")}
250
- className="text-destructive"
251
- >
224
+ <DropdownMenuItem onClick={() => handleAction(p.id, "cancel")} className="text-destructive">
252
225
  <XCircle className="h-4 w-4 mr-2" />
253
226
  Cancel
254
227
  </DropdownMenuItem>
@@ -6,23 +6,10 @@ import { Badge } from "@/components/ui/badge";
6
6
  import { Button } from "@/components/ui/button";
7
7
  import { Input } from "@/components/ui/input";
8
8
  import { Label } from "@/components/ui/label";
9
- import {
10
- Select,
11
- SelectContent,
12
- SelectItem,
13
- SelectTrigger,
14
- SelectValue,
15
- } from "@/components/ui/select";
9
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
16
10
  import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "@/components/ui/sheet";
17
11
  import { Skeleton } from "@/components/ui/skeleton";
18
- import {
19
- Table,
20
- TableBody,
21
- TableCell,
22
- TableHead,
23
- TableHeader,
24
- TableRow,
25
- } from "@/components/ui/table";
12
+ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
26
13
  import { Textarea } from "@/components/ui/textarea";
27
14
  import { toUserMessage } from "@/lib/errors";
28
15
  import type { AdapterRateOverride, RateOverrideStatus } from "@/lib/promotions-types";
@@ -33,14 +20,7 @@ import { cn } from "@/lib/utils";
33
20
  // Constants
34
21
  // ---------------------------------------------------------------------------
35
22
 
36
- const ADAPTER_IDS = [
37
- "nano-banana",
38
- "elevenlabs",
39
- "deepgram",
40
- "openrouter",
41
- "replicate",
42
- "gemini",
43
- ] as const;
23
+ const ADAPTER_IDS = ["nano-banana", "elevenlabs", "deepgram", "openrouter", "replicate", "gemini"] as const;
44
24
 
45
25
  const STATUS_COLORS: Record<RateOverrideStatus, string> = {
46
26
  active: "bg-terminal/15 text-terminal border border-terminal/20",
@@ -50,8 +30,7 @@ const STATUS_COLORS: Record<RateOverrideStatus, string> = {
50
30
  };
51
31
 
52
32
  function formatWindow(startsAt: string, endsAt: string | null): string {
53
- const fmt = (d: string) =>
54
- new Date(d).toLocaleDateString("en-US", { month: "short", day: "numeric" });
33
+ const fmt = (d: string) => new Date(d).toLocaleDateString("en-US", { month: "short", day: "numeric" });
55
34
  if (!endsAt) return `${fmt(startsAt)} — no end`;
56
35
  return `${fmt(startsAt)} — ${fmt(endsAt)}`;
57
36
  }
@@ -181,9 +160,7 @@ export default function RateOverridesPage() {
181
160
  value={formDiscount}
182
161
  onChange={(e) => setFormDiscount(Number(e.target.value))}
183
162
  />
184
- <p className="text-xs text-muted-foreground mt-1">
185
- 100% = free for users — platform absorbs full cost
186
- </p>
163
+ <p className="text-xs text-muted-foreground mt-1">100% = free for users — platform absorbs full cost</p>
187
164
  </div>
188
165
  <div>
189
166
  <Label htmlFor="ro-starts">Starts At</Label>
@@ -205,19 +182,10 @@ export default function RateOverridesPage() {
205
182
  </div>
206
183
  <div>
207
184
  <Label htmlFor="ro-notes">Notes</Label>
208
- <Textarea
209
- id="ro-notes"
210
- value={formNotes}
211
- onChange={(e) => setFormNotes(e.target.value)}
212
- rows={2}
213
- />
185
+ <Textarea id="ro-notes" value={formNotes} onChange={(e) => setFormNotes(e.target.value)} rows={2} />
214
186
  </div>
215
187
  {formError && <p className="text-sm text-destructive">{formError}</p>}
216
- <Button
217
- onClick={handleCreate}
218
- disabled={creating || !formName || !formStartsAt}
219
- className="w-full"
220
- >
188
+ <Button onClick={handleCreate} disabled={creating || !formName || !formStartsAt} className="w-full">
221
189
  {creating ? "Creating..." : "Create Override"}
222
190
  </Button>
223
191
  </div>
@@ -257,17 +225,13 @@ export default function RateOverridesPage() {
257
225
  <TableCell className="font-mono text-xs">{o.adapterId}</TableCell>
258
226
  <TableCell className="font-medium">{o.name}</TableCell>
259
227
  <TableCell className="text-right tabular-nums">{o.discountPercent}%</TableCell>
260
- <TableCell className="text-sm text-muted-foreground">
261
- {formatWindow(o.startsAt, o.endsAt)}
262
- </TableCell>
228
+ <TableCell className="text-sm text-muted-foreground">{formatWindow(o.startsAt, o.endsAt)}</TableCell>
263
229
  <TableCell>
264
230
  <Badge variant="secondary" className={cn("text-xs", STATUS_COLORS[o.status])}>
265
231
  {o.status}
266
232
  </Badge>
267
233
  </TableCell>
268
- <TableCell className="text-sm text-muted-foreground">
269
- {o.createdBy ?? "—"}
270
- </TableCell>
234
+ <TableCell className="text-sm text-muted-foreground">{o.createdBy ?? "—"}</TableCell>
271
235
  <TableCell>
272
236
  {o.status !== "cancelled" && o.status !== "expired" && (
273
237
  <Button
@@ -5,14 +5,7 @@ import Link from "next/link";
5
5
  import { useParams, useRouter, useSearchParams } from "next/navigation";
6
6
  import { Suspense, useEffect, useState } from "react";
7
7
  import { AuthShell } from "@/components/auth/auth-shell";
8
- import {
9
- Card,
10
- CardContent,
11
- CardDescription,
12
- CardFooter,
13
- CardHeader,
14
- CardTitle,
15
- } from "@/components/ui/card";
8
+ import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
16
9
  import { getOAuthErrorMessage } from "@/lib/oauth-errors";
17
10
  import { sanitizeRedirectUrl } from "@/lib/utils";
18
11
 
@@ -8,14 +8,7 @@ import { Suspense, useEffect, useState } from "react";
8
8
  import { AuthShell } from "@/components/auth/auth-shell";
9
9
  import { ResendVerificationButton } from "@/components/auth/resend-verification-button";
10
10
  import { Button } from "@/components/ui/button";
11
- import {
12
- Card,
13
- CardContent,
14
- CardDescription,
15
- CardFooter,
16
- CardHeader,
17
- CardTitle,
18
- } from "@/components/ui/card";
11
+ import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
19
12
 
20
13
  function SuccessContent() {
21
14
  const router = useRouter();
@@ -50,14 +43,11 @@ function SuccessContent() {
50
43
  <CardTitle className="text-sm font-medium uppercase tracking-widest text-terminal text-center">
51
44
  Email verified
52
45
  </CardTitle>
53
- <CardDescription className="text-center">
54
- Your email has been verified successfully.
55
- </CardDescription>
46
+ <CardDescription className="text-center">Your email has been verified successfully.</CardDescription>
56
47
  </CardHeader>
57
48
  <CardContent className="flex flex-col gap-3">
58
49
  <p className="text-sm text-center text-muted-foreground">
59
- Your <span className="text-terminal font-medium">$5 signup credit</span> has been applied
60
- to your account.
50
+ Your <span className="text-terminal font-medium">$5 signup credit</span> has been applied to your account.
61
51
  </p>
62
52
  <p className="text-sm text-center text-muted-foreground">
63
53
  Redirecting in <span className="text-terminal font-medium tabular-nums">{countdown}</span>
@@ -65,10 +55,7 @@ function SuccessContent() {
65
55
  </p>
66
56
  </CardContent>
67
57
  <CardFooter className="justify-center">
68
- <Link
69
- href="/onboarding"
70
- className="text-sm text-terminal-dim underline underline-offset-4 hover:text-terminal"
71
- >
58
+ <Link href="/onboarding" className="text-sm text-terminal-dim underline underline-offset-4 hover:text-terminal">
72
59
  Continue to setup
73
60
  </Link>
74
61
  </CardFooter>
@@ -141,9 +128,7 @@ function ErrorContent({
141
128
  </div>
142
129
  );
143
130
  title = "Verification failed";
144
- description = status
145
- ? "Something went wrong verifying your email."
146
- : "No verification status provided.";
131
+ description = status ? "Something went wrong verifying your email." : "No verification status provided.";
147
132
  footer = null;
148
133
  break;
149
134
  }
@@ -151,17 +136,11 @@ function ErrorContent({
151
136
  const titleColor = reason === "already-verified" ? "text-terminal" : "text-destructive";
152
137
  const footerLink =
153
138
  reason === "already-verified" ? (
154
- <Link
155
- href="/login"
156
- className="text-sm text-terminal-dim underline underline-offset-4 hover:text-terminal"
157
- >
139
+ <Link href="/login" className="text-sm text-terminal-dim underline underline-offset-4 hover:text-terminal">
158
140
  Sign in
159
141
  </Link>
160
142
  ) : (
161
- <Link
162
- href="/login"
163
- className="text-sm text-terminal-dim underline underline-offset-4 hover:text-terminal"
164
- >
143
+ <Link href="/login" className="text-sm text-terminal-dim underline underline-offset-4 hover:text-terminal">
165
144
  Back to sign in
166
145
  </Link>
167
146
  );
@@ -176,9 +155,7 @@ function ErrorContent({
176
155
  >
177
156
  {icon}
178
157
  </motion.div>
179
- <CardTitle
180
- className={`text-sm font-medium uppercase tracking-widest ${titleColor} text-center`}
181
- >
158
+ <CardTitle className={`text-sm font-medium uppercase tracking-widest ${titleColor} text-center`}>
182
159
  {title}
183
160
  </CardTitle>
184
161
  <CardDescription className="text-center">{description}</CardDescription>
@@ -204,11 +181,7 @@ function VerifyContent() {
204
181
  </div>
205
182
  <div className="relative z-10 w-full max-w-sm">
206
183
  <AuthShell>
207
- {isSuccess ? (
208
- <SuccessContent />
209
- ) : (
210
- <ErrorContent status={status} reason={reason} email={emailParam} />
211
- )}
184
+ {isSuccess ? <SuccessContent /> : <ErrorContent status={status} reason={reason} email={emailParam} />}
212
185
  </AuthShell>
213
186
  </div>
214
187
  </div>
@@ -8,13 +8,7 @@ import { logger } from "@/lib/logger";
8
8
 
9
9
  const log = logger("error-boundary:channels");
10
10
 
11
- export default function ChannelsError({
12
- error,
13
- reset,
14
- }: {
15
- error: Error & { digest?: string };
16
- reset: () => void;
17
- }) {
11
+ export default function ChannelsError({ error, reset }: { error: Error & { digest?: string }; reset: () => void }) {
18
12
  const [showDetails, setShowDetails] = useState(false);
19
13
  const isDev = process.env.NODE_ENV === "development";
20
14
 
@@ -32,9 +26,7 @@ export default function ChannelsError({
32
26
  </div>
33
27
  </CardHeader>
34
28
  <CardContent className="space-y-4">
35
- <p className="text-muted-foreground">
36
- Something went wrong loading channels. This may be a temporary issue.
37
- </p>
29
+ <p className="text-muted-foreground">Something went wrong loading channels. This may be a temporary issue.</p>
38
30
  {isDev && (
39
31
  <Button
40
32
  type="button"
@@ -0,0 +1,9 @@
1
+ "use client";
2
+
3
+ import { useRequireAuth } from "@/lib/require-auth";
4
+
5
+ export default function ChannelsLayout({ children }: { children: React.ReactNode }) {
6
+ const { isPending, isAuthed } = useRequireAuth();
7
+ if (isPending || !isAuthed) return null;
8
+ return <>{children}</>;
9
+ }
@@ -66,16 +66,14 @@ export default function ChannelsPage() {
66
66
  <div className="mb-8">
67
67
  <h1 className="text-2xl font-bold tracking-widest uppercase">COMMS CHANNELS</h1>
68
68
  <p className="mt-1 text-sm text-muted-foreground">
69
- Connect messaging platforms to your {getBrandConfig().productName}. Each channel is driven
70
- by a plugin manifest.
69
+ Connect messaging platforms to your {getBrandConfig().productName}. Each channel is driven by a plugin
70
+ manifest.
71
71
  </p>
72
72
  </div>
73
73
 
74
74
  {loading && (
75
75
  <section className="mb-10">
76
- <h2 className="mb-4 text-sm font-semibold uppercase tracking-wider text-terminal">
77
- LINKED
78
- </h2>
76
+ <h2 className="mb-4 text-sm font-semibold uppercase tracking-wider text-terminal">LINKED</h2>
79
77
  <p className="mb-4 font-mono text-sm text-terminal/60">
80
78
  &gt; QUERYING CHANNEL STATUS...
81
79
  <span className="animate-[pulse-dot_1s_step-end_infinite]">_</span>
@@ -122,9 +120,7 @@ export default function ChannelsPage() {
122
120
  {!loading && !error && (
123
121
  <>
124
122
  <section className="mb-10">
125
- <h2 className="mb-4 text-sm font-semibold uppercase tracking-wider text-terminal">
126
- LINKED
127
- </h2>
123
+ <h2 className="mb-4 text-sm font-semibold uppercase tracking-wider text-terminal">LINKED</h2>
128
124
  {instances.some((inst) => inst.channels.length > 0) ? (
129
125
  <motion.div
130
126
  variants={staggerContainer}
@@ -168,9 +164,7 @@ export default function ChannelsPage() {
168
164
  </CardHeader>
169
165
  <CardContent>
170
166
  <Button variant="ghost" size="sm" asChild>
171
- <Link href={`/instances/${inst.id}?tab=channels`}>
172
- View Details
173
- </Link>
167
+ <Link href={`/instances/${inst.id}?tab=channels`}>View Details</Link>
174
168
  </Button>
175
169
  </CardContent>
176
170
  </Card>
@@ -182,17 +176,13 @@ export default function ChannelsPage() {
182
176
  </motion.div>
183
177
  ) : (
184
178
  <div className="flex h-40 items-center justify-center rounded-sm border border-dashed border-terminal/20">
185
- <p className="font-mono text-sm text-terminal/60">
186
- &gt; NO CHANNELS LINKED. YOUR BOT IS ISOLATED.
187
- </p>
179
+ <p className="font-mono text-sm text-terminal/60">&gt; NO CHANNELS LINKED. YOUR BOT IS ISOLATED.</p>
188
180
  </div>
189
181
  )}
190
182
  </section>
191
183
 
192
184
  <section>
193
- <h2 className="mb-4 text-sm font-semibold uppercase tracking-wider text-muted-foreground">
194
- AVAILABLE
195
- </h2>
185
+ <h2 className="mb-4 text-sm font-semibold uppercase tracking-wider text-muted-foreground">AVAILABLE</h2>
196
186
  <motion.div
197
187
  variants={staggerContainer}
198
188
  initial="hidden"
@@ -235,9 +225,7 @@ export default function ChannelsPage() {
235
225
  <CardContent className="mt-auto">
236
226
  {singleBotId ? (
237
227
  <Button variant="terminal" className="w-full" asChild>
238
- <Link href={`/channels/setup/${manifest.id}?botId=${singleBotId}`}>
239
- Connect
240
- </Link>
228
+ <Link href={`/channels/setup/${manifest.id}?botId=${singleBotId}`}>Connect</Link>
241
229
  </Button>
242
230
  ) : instances.length > 1 ? (
243
231
  <Button variant="terminal" className="w-full" asChild>