@wopr-network/platform-ui-core 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.paperclip +18 -0
- package/.env.wopr +18 -0
- package/README.md +36 -0
- package/biome.json +52 -0
- package/next.config.ts +45 -0
- package/package.json +84 -0
- package/postcss.config.mjs +7 -0
- package/public/file.svg +1 -0
- package/public/globe.svg +1 -0
- package/public/window.svg +1 -0
- package/src/__tests__/__snapshots__/layout-snapshots.test.tsx.snap +741 -0
- package/src/__tests__/account-page-redirect.test.tsx +73 -0
- package/src/__tests__/account-switcher.test.tsx +85 -0
- package/src/__tests__/activity-page.test.tsx +176 -0
- package/src/__tests__/add-payment-method-dialog.test.tsx +160 -0
- package/src/__tests__/admin-api.test.ts +244 -0
- package/src/__tests__/admin-gpu-api.test.ts +188 -0
- package/src/__tests__/admin-guard.test.tsx +79 -0
- package/src/__tests__/admin-marketplace-api.test.ts +179 -0
- package/src/__tests__/admin-middleware.test.ts +157 -0
- package/src/__tests__/admin-tenant-table.test.tsx +95 -0
- package/src/__tests__/affiliate-dashboard.test.tsx +178 -0
- package/src/__tests__/api-401-redirect.test.ts +78 -0
- package/src/__tests__/api-client.test.ts +316 -0
- package/src/__tests__/api-config.test.ts +89 -0
- package/src/__tests__/api-control-instance.test.ts +69 -0
- package/src/__tests__/api-fleet-resources.test.ts +52 -0
- package/src/__tests__/api-fleet-trpc.test.ts +252 -0
- package/src/__tests__/api-get-instance-config.test.ts +41 -0
- package/src/__tests__/api-null-guards.test.ts +244 -0
- package/src/__tests__/api-rename-instance.test.ts +60 -0
- package/src/__tests__/api-update-instance-config.test.ts +60 -0
- package/src/__tests__/audit-log-table-pagination.test.tsx +136 -0
- package/src/__tests__/auth-client.test.ts +87 -0
- package/src/__tests__/auth-password-reset.test.tsx +435 -0
- package/src/__tests__/auth-redirect.test.tsx +60 -0
- package/src/__tests__/auth.test.tsx +269 -0
- package/src/__tests__/auto-topup-card.test.tsx +257 -0
- package/src/__tests__/backups-tab.test.tsx +221 -0
- package/src/__tests__/billing-byok-callout.test.tsx +76 -0
- package/src/__tests__/billing-layout-nav-hidden.test.tsx +47 -0
- package/src/__tests__/billing-payment-org-invoices.test.tsx +123 -0
- package/src/__tests__/billing.test.tsx +509 -0
- package/src/__tests__/bot-settings/resources-tab.test.tsx +119 -0
- package/src/__tests__/bot-settings/storage-tab.test.tsx +80 -0
- package/src/__tests__/bot-settings/vps-info-panel.test.tsx +108 -0
- package/src/__tests__/bot-settings/vps-upgrade-card.test.tsx +52 -0
- package/src/__tests__/bot-settings-data-control.test.ts +49 -0
- package/src/__tests__/bot-settings-restart.test.tsx +149 -0
- package/src/__tests__/bot-settings.test.tsx +678 -0
- package/src/__tests__/brand.test.ts +335 -0
- package/src/__tests__/buy-credits-panel.test.tsx +249 -0
- package/src/__tests__/buy-crypto-credits-panel.test.tsx +178 -0
- package/src/__tests__/capability-conflicts.test.ts +88 -0
- package/src/__tests__/capability-resolver.test.tsx +173 -0
- package/src/__tests__/changeset-detail.test.tsx +156 -0
- package/src/__tests__/channel-setup-logger.test.ts +22 -0
- package/src/__tests__/channel-setup-toast.test.tsx +60 -0
- package/src/__tests__/channel-wizard.test.tsx +505 -0
- package/src/__tests__/chat/ambient-dot.test.tsx +35 -0
- package/src/__tests__/chat/chat-input.test.tsx +78 -0
- package/src/__tests__/chat/chat-message.test.tsx +45 -0
- package/src/__tests__/chat/chat-panel.test.tsx +111 -0
- package/src/__tests__/chat/chat-widget.test.tsx +82 -0
- package/src/__tests__/chat-store.test.ts +87 -0
- package/src/__tests__/command-center.test.tsx +246 -0
- package/src/__tests__/compliance-retention-edit.test.tsx +134 -0
- package/src/__tests__/coupon-input.test.tsx +119 -0
- package/src/__tests__/create-instance.test.tsx +96 -0
- package/src/__tests__/create-org-wizard.test.tsx +200 -0
- package/src/__tests__/credit-balance.test.tsx +103 -0
- package/src/__tests__/credits.test.tsx +376 -0
- package/src/__tests__/csrf-middleware.test.ts +198 -0
- package/src/__tests__/degraded-state-banner.test.tsx +130 -0
- package/src/__tests__/dividend-calculator.test.tsx +20 -0
- package/src/__tests__/dividend-stats.test.tsx +64 -0
- package/src/__tests__/dividend.test.tsx +169 -0
- package/src/__tests__/dockerfile.test.ts +110 -0
- package/src/__tests__/email-verification-banner.test.tsx +64 -0
- package/src/__tests__/env-example.test.ts +25 -0
- package/src/__tests__/error-boundaries.test.tsx +64 -0
- package/src/__tests__/fetch-pricing.test.ts +121 -0
- package/src/__tests__/field-oauth.test.tsx +302 -0
- package/src/__tests__/fixtures/mock-manifests-data.js +372 -0
- package/src/__tests__/fixtures/mock-manifests.ts +24 -0
- package/src/__tests__/fleet-health-timestamp.test.tsx +101 -0
- package/src/__tests__/fleet-health-update.test.tsx +83 -0
- package/src/__tests__/format-credit.test.ts +58 -0
- package/src/__tests__/gpu-dashboard.test.tsx +236 -0
- package/src/__tests__/hosted-usage-date-range.test.tsx +54 -0
- package/src/__tests__/instance-detail.test.tsx +571 -0
- package/src/__tests__/instance-list.test.tsx +230 -0
- package/src/__tests__/landing-hero.test.tsx +27 -0
- package/src/__tests__/landing-nav.test.tsx +24 -0
- package/src/__tests__/layout-snapshots.test.tsx +167 -0
- package/src/__tests__/logger.test.ts +54 -0
- package/src/__tests__/login-page-redirect.test.tsx +142 -0
- package/src/__tests__/manifest-validation.test.ts +126 -0
- package/src/__tests__/marketplace-admin.test.tsx +151 -0
- package/src/__tests__/marketplace.test.tsx +609 -0
- package/src/__tests__/merge-api-rates.test.ts +70 -0
- package/src/__tests__/middleware.test.ts +690 -0
- package/src/__tests__/network-page.test.tsx +100 -0
- package/src/__tests__/next-config-headers.test.ts +28 -0
- package/src/__tests__/not-found.test.tsx +26 -0
- package/src/__tests__/notifications.test.tsx +128 -0
- package/src/__tests__/oauth-buttons.test.tsx +101 -0
- package/src/__tests__/oauth-error-mapping.test.tsx +97 -0
- package/src/__tests__/observability.test.tsx +541 -0
- package/src/__tests__/onboarding-data.test.ts +363 -0
- package/src/__tests__/onboarding-page.test.tsx +113 -0
- package/src/__tests__/onboarding-store.test.ts +121 -0
- package/src/__tests__/org-billing-api.test.tsx +70 -0
- package/src/__tests__/org-billing-null-guards.test.ts +64 -0
- package/src/__tests__/org-billing-page.test.tsx +124 -0
- package/src/__tests__/plugin-definition.test.ts +43 -0
- package/src/__tests__/plugin-install-flow.test.tsx +535 -0
- package/src/__tests__/plugin-registry.test.tsx +475 -0
- package/src/__tests__/plugin-setup/setup-chat-panel.test.ts +142 -0
- package/src/__tests__/plugin-setup/use-plugin-setup-chat.test.ts +49 -0
- package/src/__tests__/plugin-tool-definitions.test.ts +51 -0
- package/src/__tests__/plugin-tool-sync.test.ts +59 -0
- package/src/__tests__/portfolio-chart.test.tsx +24 -0
- package/src/__tests__/pricing.test.tsx +107 -0
- package/src/__tests__/promotion-form.test.tsx +180 -0
- package/src/__tests__/promotions-list.test.tsx +194 -0
- package/src/__tests__/provider-key-api.test.ts +134 -0
- package/src/__tests__/resend-verification-button.test.tsx +104 -0
- package/src/__tests__/sanitize-redirect-url.test.ts +47 -0
- package/src/__tests__/secrets-audit-pagination.test.tsx +139 -0
- package/src/__tests__/settings.test.tsx +937 -0
- package/src/__tests__/setup-checklist.test.tsx +274 -0
- package/src/__tests__/setup.ts +82 -0
- package/src/__tests__/smoke.test.tsx +10 -0
- package/src/__tests__/snapshot-api.test.ts +104 -0
- package/src/__tests__/status-api.test.ts +46 -0
- package/src/__tests__/status-badge.test.tsx +33 -0
- package/src/__tests__/status-colors.test.ts +83 -0
- package/src/__tests__/status-page.test.tsx +86 -0
- package/src/__tests__/step-superpowers.test.tsx +218 -0
- package/src/__tests__/story-sections.test.tsx +24 -0
- package/src/__tests__/superpower-content-sanitize.test.tsx +87 -0
- package/src/__tests__/superpower-content.test.tsx +44 -0
- package/src/__tests__/suspension-banner.test.tsx +140 -0
- package/src/__tests__/tenant-context.test.tsx +146 -0
- package/src/__tests__/tenant-keys-api.test.ts +114 -0
- package/src/__tests__/tenant-table-pagination.test.tsx +124 -0
- package/src/__tests__/terminal-log-cleanup.test.tsx +51 -0
- package/src/__tests__/terminal-sequence.test.tsx +28 -0
- package/src/__tests__/transaction-history.test.tsx +325 -0
- package/src/__tests__/trpc-types.test.ts +102 -0
- package/src/__tests__/use-capability-meta.test.ts +161 -0
- package/src/__tests__/use-chat.test.ts +616 -0
- package/src/__tests__/use-has-org.test.ts +44 -0
- package/src/__tests__/use-image-status.test.ts +77 -0
- package/src/__tests__/use-pagination-params.test.ts +88 -0
- package/src/__tests__/use-plugin-setup-chat-stale-closure.test.ts +53 -0
- package/src/__tests__/use-webmcp.test.ts +119 -0
- package/src/__tests__/validate-elevenlabs-key.test.ts +95 -0
- package/src/__tests__/validate-redirect-url.test.ts +61 -0
- package/src/__tests__/verify-page.test.tsx +140 -0
- package/src/__tests__/verify-redirect.test.tsx +41 -0
- package/src/__tests__/verify-result-banner.test.tsx +66 -0
- package/src/__tests__/webmcp-feature-detect.test.ts +54 -0
- package/src/__tests__/webmcp-hook.test.tsx +72 -0
- package/src/__tests__/webmcp-marketplace-onboarding-tools.test.ts +185 -0
- package/src/__tests__/webmcp-register.test.ts +103 -0
- package/src/__tests__/webmcp-set-provider.test.ts +47 -0
- package/src/__tests__/webmcp-tools.test.ts +348 -0
- package/src/app/(auth)/error.tsx +72 -0
- package/src/app/(auth)/forgot-password/page.tsx +137 -0
- package/src/app/(auth)/layout.tsx +14 -0
- package/src/app/(auth)/loading.tsx +26 -0
- package/src/app/(auth)/login/page.tsx +188 -0
- package/src/app/(auth)/reset-password/page.tsx +169 -0
- package/src/app/(auth)/signup/page.tsx +309 -0
- package/src/app/(dashboard)/billing/credits/page.tsx +209 -0
- package/src/app/(dashboard)/billing/error.tsx +72 -0
- package/src/app/(dashboard)/billing/layout.tsx +73 -0
- package/src/app/(dashboard)/billing/loading.tsx +41 -0
- package/src/app/(dashboard)/billing/payment/page.tsx +639 -0
- package/src/app/(dashboard)/billing/plans/page.tsx +58 -0
- package/src/app/(dashboard)/billing/referrals/page.tsx +7 -0
- package/src/app/(dashboard)/billing/usage/hosted/page.tsx +348 -0
- package/src/app/(dashboard)/billing/usage/page.tsx +663 -0
- package/src/app/(dashboard)/changesets/[id]/changeset-detail-client.tsx +400 -0
- package/src/app/(dashboard)/changesets/[id]/error.tsx +57 -0
- package/src/app/(dashboard)/changesets/[id]/loading.tsx +23 -0
- package/src/app/(dashboard)/changesets/[id]/page.tsx +10 -0
- package/src/app/(dashboard)/changesets/error.tsx +72 -0
- package/src/app/(dashboard)/changesets/page.tsx +10 -0
- package/src/app/(dashboard)/chat/page.tsx +74 -0
- package/src/app/(dashboard)/dashboard/bots/[id]/settings/page.tsx +10 -0
- package/src/app/(dashboard)/dashboard/network/page.tsx +97 -0
- package/src/app/(dashboard)/dashboard/page.tsx +13 -0
- package/src/app/(dashboard)/error.tsx +72 -0
- package/src/app/(dashboard)/layout.tsx +113 -0
- package/src/app/(dashboard)/loading.tsx +27 -0
- package/src/app/(dashboard)/marketplace/[plugin]/page.tsx +548 -0
- package/src/app/(dashboard)/marketplace/error.tsx +72 -0
- package/src/app/(dashboard)/marketplace/loading.tsx +27 -0
- package/src/app/(dashboard)/marketplace/page.tsx +268 -0
- package/src/app/(dashboard)/not-found.tsx +46 -0
- package/src/app/(dashboard)/onboarding/page.tsx +267 -0
- package/src/app/(dashboard)/settings/account/page.tsx +132 -0
- package/src/app/(dashboard)/settings/activity/page.tsx +280 -0
- package/src/app/(dashboard)/settings/api-keys/page.tsx +530 -0
- package/src/app/(dashboard)/settings/brain/page.tsx +412 -0
- package/src/app/(dashboard)/settings/error.tsx +72 -0
- package/src/app/(dashboard)/settings/layout.tsx +114 -0
- package/src/app/(dashboard)/settings/loading.tsx +31 -0
- package/src/app/(dashboard)/settings/notifications/page.tsx +216 -0
- package/src/app/(dashboard)/settings/org/page.tsx +617 -0
- package/src/app/(dashboard)/settings/profile/page.tsx +510 -0
- package/src/app/(dashboard)/settings/providers/page.tsx +842 -0
- package/src/app/(dashboard)/settings/secrets/page.tsx +658 -0
- package/src/app/(dashboard)/settings/security/page.tsx +1133 -0
- package/src/app/admin/accounting/loading.tsx +32 -0
- package/src/app/admin/accounting/page.tsx +5 -0
- package/src/app/admin/affiliates/loading.tsx +32 -0
- package/src/app/admin/affiliates/page.tsx +5 -0
- package/src/app/admin/audit/loading.tsx +32 -0
- package/src/app/admin/audit/page.tsx +5 -0
- package/src/app/admin/billing-health/loading.tsx +17 -0
- package/src/app/admin/billing-health/page.tsx +10 -0
- package/src/app/admin/compliance/page.tsx +5 -0
- package/src/app/admin/error.tsx +72 -0
- package/src/app/admin/gpu/loading.tsx +38 -0
- package/src/app/admin/gpu/page.tsx +5 -0
- package/src/app/admin/incidents/page.tsx +10 -0
- package/src/app/admin/inference/loading.tsx +32 -0
- package/src/app/admin/inference/page.tsx +5 -0
- package/src/app/admin/layout.tsx +44 -0
- package/src/app/admin/loading.tsx +32 -0
- package/src/app/admin/marketplace/loading.tsx +32 -0
- package/src/app/admin/marketplace/page.tsx +5 -0
- package/src/app/admin/migrations/loading.tsx +22 -0
- package/src/app/admin/migrations/page.tsx +5 -0
- package/src/app/admin/onboarding/loading.tsx +18 -0
- package/src/app/admin/onboarding/page.tsx +5 -0
- package/src/app/admin/promotions/[id]/edit/loading.tsx +16 -0
- package/src/app/admin/promotions/[id]/edit/page.tsx +56 -0
- package/src/app/admin/promotions/[id]/loading.tsx +15 -0
- package/src/app/admin/promotions/[id]/page.tsx +311 -0
- package/src/app/admin/promotions/loading.tsx +21 -0
- package/src/app/admin/promotions/new/loading.tsx +16 -0
- package/src/app/admin/promotions/new/page.tsx +12 -0
- package/src/app/admin/promotions/page.tsx +266 -0
- package/src/app/admin/rate-overrides/loading.tsx +17 -0
- package/src/app/admin/rate-overrides/page.tsx +290 -0
- package/src/app/admin/roles/loading.tsx +27 -0
- package/src/app/admin/roles/page.tsx +5 -0
- package/src/app/admin/tenants/loading.tsx +32 -0
- package/src/app/admin/tenants/page.tsx +5 -0
- package/src/app/apple-icon.tsx +32 -0
- package/src/app/auth/callback/[provider]/page.tsx +104 -0
- package/src/app/auth/verify/page.tsx +224 -0
- package/src/app/channels/error.tsx +72 -0
- package/src/app/channels/loading.tsx +29 -0
- package/src/app/channels/page.tsx +262 -0
- package/src/app/channels/setup/[plugin]/page.tsx +136 -0
- package/src/app/error.tsx +72 -0
- package/src/app/favicon.ico +0 -0
- package/src/app/fleet/error.tsx +72 -0
- package/src/app/fleet/health/page.tsx +9 -0
- package/src/app/fleet/layout.tsx +14 -0
- package/src/app/fleet/loading.tsx +33 -0
- package/src/app/fleet/page.tsx +5 -0
- package/src/app/global-error.tsx +96 -0
- package/src/app/globals.css +251 -0
- package/src/app/icon.svg +4 -0
- package/src/app/instances/[id]/instance-detail-client.tsx +1298 -0
- package/src/app/instances/[id]/page.tsx +10 -0
- package/src/app/instances/error.tsx +72 -0
- package/src/app/instances/instance-list-client.tsx +540 -0
- package/src/app/instances/loading.tsx +33 -0
- package/src/app/instances/new/create-instance-client.tsx +377 -0
- package/src/app/instances/new/page.tsx +9 -0
- package/src/app/instances/page.tsx +9 -0
- package/src/app/layout.tsx +83 -0
- package/src/app/not-found.tsx +38 -0
- package/src/app/og/route.tsx +50 -0
- package/src/app/page.tsx +39 -0
- package/src/app/plugins/error.tsx +72 -0
- package/src/app/plugins/layout.tsx +14 -0
- package/src/app/plugins/loading.tsx +30 -0
- package/src/app/plugins/page.tsx +555 -0
- package/src/app/pricing/error.tsx +72 -0
- package/src/app/pricing/loading.tsx +25 -0
- package/src/app/pricing/page.tsx +20 -0
- package/src/app/privacy/page.tsx +406 -0
- package/src/app/robots.ts +9 -0
- package/src/app/sitemap.ts +11 -0
- package/src/app/status/error.tsx +72 -0
- package/src/app/status/loading.tsx +21 -0
- package/src/app/status/page.tsx +20 -0
- package/src/app/terms/page.tsx +414 -0
- package/src/components/account-switcher.tsx +82 -0
- package/src/components/admin/accounting-dashboard.tsx +190 -0
- package/src/components/admin/admin-guard.tsx +36 -0
- package/src/components/admin/admin-nav.tsx +71 -0
- package/src/components/admin/affiliate-dashboard.tsx +564 -0
- package/src/components/admin/audit-log-table.tsx +336 -0
- package/src/components/admin/billing-health-dashboard.test.tsx +40 -0
- package/src/components/admin/billing-health-dashboard.tsx +416 -0
- package/src/components/admin/bulk-actions-bar.test.tsx +92 -0
- package/src/components/admin/bulk-actions-bar.tsx +80 -0
- package/src/components/admin/bulk-export-dialog.test.tsx +75 -0
- package/src/components/admin/bulk-export-dialog.tsx +189 -0
- package/src/components/admin/bulk-grant-dialog.test.tsx +81 -0
- package/src/components/admin/bulk-grant-dialog.tsx +147 -0
- package/src/components/admin/bulk-preview-dialog.test.tsx +72 -0
- package/src/components/admin/bulk-preview-dialog.tsx +106 -0
- package/src/components/admin/bulk-reactivate-dialog.test.tsx +51 -0
- package/src/components/admin/bulk-reactivate-dialog.tsx +55 -0
- package/src/components/admin/bulk-select-all-banner.test.tsx +36 -0
- package/src/components/admin/bulk-select-all-banner.tsx +44 -0
- package/src/components/admin/bulk-suspend-dialog.test.tsx +77 -0
- package/src/components/admin/bulk-suspend-dialog.tsx +129 -0
- package/src/components/admin/bulk-undo-toast.test.tsx +66 -0
- package/src/components/admin/bulk-undo-toast.tsx +121 -0
- package/src/components/admin/compliance-dashboard.tsx +1341 -0
- package/src/components/admin/gpu-dashboard.tsx +552 -0
- package/src/components/admin/grant-credits-dialog.tsx +121 -0
- package/src/components/admin/incident-dashboard.test.tsx +44 -0
- package/src/components/admin/incident-dashboard.tsx +717 -0
- package/src/components/admin/inference-dashboard.tsx +415 -0
- package/src/components/admin/marketplace-admin.tsx +765 -0
- package/src/components/admin/migrations-dashboard.tsx +404 -0
- package/src/components/admin/onboarding-dashboard.tsx +422 -0
- package/src/components/admin/promotions/promotion-form.tsx +440 -0
- package/src/components/admin/roles-dashboard.tsx +278 -0
- package/src/components/admin/suspend-dialog.tsx +98 -0
- package/src/components/admin/tenant-notes-panel.tsx +134 -0
- package/src/components/admin/tenant-row-actions.tsx +78 -0
- package/src/components/admin/tenant-table.tsx +339 -0
- package/src/components/auth/auth-error.tsx +22 -0
- package/src/components/auth/auth-redirect.tsx +18 -0
- package/src/components/auth/auth-shell.tsx +25 -0
- package/src/components/auth/email-verification-banner.tsx +25 -0
- package/src/components/auth/email-verification-result-banner.tsx +70 -0
- package/src/components/auth/resend-verification-button.tsx +94 -0
- package/src/components/auth/wopr-wordmark.tsx +19 -0
- package/src/components/billing/add-payment-method-dialog.tsx +267 -0
- package/src/components/billing/affiliate-dashboard.tsx +300 -0
- package/src/components/billing/auto-topup-card.tsx +432 -0
- package/src/components/billing/buy-credits-panel.tsx +180 -0
- package/src/components/billing/buy-crypto-credits-panel.tsx +96 -0
- package/src/components/billing/byok-callout.tsx +87 -0
- package/src/components/billing/coupon-input.tsx +86 -0
- package/src/components/billing/credit-balance.tsx +79 -0
- package/src/components/billing/degraded-state-banner.tsx +95 -0
- package/src/components/billing/dividend-banner.tsx +97 -0
- package/src/components/billing/dividend-eligibility.tsx +86 -0
- package/src/components/billing/dividend-pool-stats.tsx +86 -0
- package/src/components/billing/first-dividend-dialog.tsx +109 -0
- package/src/components/billing/low-balance-banner.tsx +50 -0
- package/src/components/billing/org-billing-page.tsx +360 -0
- package/src/components/billing/suspension-banner.tsx +53 -0
- package/src/components/billing/transaction-history.tsx +239 -0
- package/src/components/bot-settings/__tests__/bot-settings-client.test.tsx +205 -0
- package/src/components/bot-settings/backups-tab.tsx +377 -0
- package/src/components/bot-settings/bot-settings-client.tsx +1712 -0
- package/src/components/bot-settings/resources-tab.tsx +203 -0
- package/src/components/bot-settings/storage-tab.tsx +248 -0
- package/src/components/bot-settings/vps-info-panel.tsx +132 -0
- package/src/components/bot-settings/vps-upgrade-card.tsx +110 -0
- package/src/components/capability/CapabilityResolver.tsx +113 -0
- package/src/components/channel-wizard/field-interactive.tsx +48 -0
- package/src/components/channel-wizard/field-oauth.tsx +181 -0
- package/src/components/channel-wizard/field-paste.tsx +47 -0
- package/src/components/channel-wizard/field-qr.tsx +302 -0
- package/src/components/channel-wizard/index.ts +6 -0
- package/src/components/channel-wizard/step-renderer.tsx +103 -0
- package/src/components/channel-wizard/wizard.tsx +200 -0
- package/src/components/chat/ambient-dot.tsx +32 -0
- package/src/components/chat/chat-input.tsx +56 -0
- package/src/components/chat/chat-message.tsx +36 -0
- package/src/components/chat/chat-panel.tsx +138 -0
- package/src/components/chat/chat-widget.tsx +41 -0
- package/src/components/chat/index.ts +5 -0
- package/src/components/dashboard/command-center.tsx +614 -0
- package/src/components/instances/friends-tab.test.tsx +265 -0
- package/src/components/instances/friends-tab.tsx +721 -0
- package/src/components/landing/hero.tsx +53 -0
- package/src/components/landing/landing-nav.tsx +21 -0
- package/src/components/landing/landing-page.tsx +71 -0
- package/src/components/landing/portfolio-chart.tsx +349 -0
- package/src/components/landing/story-sections.tsx +50 -0
- package/src/components/landing/terminal-lines.ts +99 -0
- package/src/components/landing/terminal-sequence.tsx +453 -0
- package/src/components/landing/typing-effect.tsx +43 -0
- package/src/components/marketplace/category-filter.tsx +61 -0
- package/src/components/marketplace/empty-state.tsx +61 -0
- package/src/components/marketplace/featured-heroes.tsx +84 -0
- package/src/components/marketplace/first-visit-hero.tsx +110 -0
- package/src/components/marketplace/index.ts +9 -0
- package/src/components/marketplace/install-wizard.tsx +782 -0
- package/src/components/marketplace/marketplace-tabs.tsx +54 -0
- package/src/components/marketplace/plugin-card.tsx +129 -0
- package/src/components/marketplace/superpower-card.tsx +104 -0
- package/src/components/marketplace/superpower-content.tsx +117 -0
- package/src/components/marketplace/terminal-search.tsx +67 -0
- package/src/components/oauth-buttons.tsx +75 -0
- package/src/components/observability/fleet-health.tsx +370 -0
- package/src/components/observability/health-overview.tsx +246 -0
- package/src/components/observability/logs-viewer.tsx +215 -0
- package/src/components/observability/metrics-dashboard.tsx +288 -0
- package/src/components/onboarding/fallback-setup.tsx +137 -0
- package/src/components/onboarding/index.ts +3 -0
- package/src/components/onboarding/setup-checklist.tsx +333 -0
- package/src/components/onboarding/step-superpowers.tsx +122 -0
- package/src/components/plugin-setup/index.ts +1 -0
- package/src/components/plugin-setup/setup-chat-panel.tsx +188 -0
- package/src/components/pricing/dividend-calculator.tsx +47 -0
- package/src/components/pricing/dividend-stats.tsx +117 -0
- package/src/components/pricing/pricing-page.tsx +229 -0
- package/src/components/settings/create-org-wizard.tsx +225 -0
- package/src/components/sidebar.tsx +202 -0
- package/src/components/status/status-page.tsx +209 -0
- package/src/components/status-badge.tsx +28 -0
- package/src/components/theme-provider.tsx +8 -0
- package/src/components/ui/alert-dialog.tsx +141 -0
- package/src/components/ui/badge.tsx +47 -0
- package/src/components/ui/banner.tsx +36 -0
- package/src/components/ui/button.tsx +64 -0
- package/src/components/ui/card.tsx +75 -0
- package/src/components/ui/checkbox.tsx +52 -0
- package/src/components/ui/collapsible.tsx +31 -0
- package/src/components/ui/credit-detailed.tsx +33 -0
- package/src/components/ui/dialog.tsx +143 -0
- package/src/components/ui/dropdown-menu.tsx +228 -0
- package/src/components/ui/form.tsx +151 -0
- package/src/components/ui/input.tsx +21 -0
- package/src/components/ui/label.tsx +21 -0
- package/src/components/ui/popover.tsx +74 -0
- package/src/components/ui/progress.tsx +28 -0
- package/src/components/ui/radio-group.tsx +45 -0
- package/src/components/ui/select.tsx +175 -0
- package/src/components/ui/separator.tsx +28 -0
- package/src/components/ui/sheet.tsx +125 -0
- package/src/components/ui/skeleton.tsx +15 -0
- package/src/components/ui/switch.tsx +35 -0
- package/src/components/ui/table.tsx +92 -0
- package/src/components/ui/tabs.tsx +81 -0
- package/src/components/ui/textarea.tsx +18 -0
- package/src/components/ui/tooltip.tsx +44 -0
- package/src/config/provider-docs.ts +17 -0
- package/src/hooks/__tests__/use-async.test.ts +127 -0
- package/src/hooks/__tests__/use-count-up.test.ts +129 -0
- package/src/hooks/__tests__/use-debounce.test.ts +105 -0
- package/src/hooks/__tests__/use-fleet-sse.test.ts +216 -0
- package/src/hooks/__tests__/use-local-storage.test.ts +74 -0
- package/src/hooks/__tests__/use-mobile.test.ts +86 -0
- package/src/hooks/__tests__/use-save-queue.test.ts +159 -0
- package/src/hooks/use-async.ts +54 -0
- package/src/hooks/use-capability-meta.ts +99 -0
- package/src/hooks/use-count-up.ts +23 -0
- package/src/hooks/use-debounce.ts +12 -0
- package/src/hooks/use-fleet-sse.ts +47 -0
- package/src/hooks/use-has-org.ts +18 -0
- package/src/hooks/use-image-status.ts +36 -0
- package/src/hooks/use-local-storage.ts +36 -0
- package/src/hooks/use-mobile.ts +17 -0
- package/src/hooks/use-page-context.ts +24 -0
- package/src/hooks/use-pagination-params.ts +30 -0
- package/src/hooks/use-plugin-registry.ts +247 -0
- package/src/hooks/use-plugin-setup-chat.ts +211 -0
- package/src/hooks/use-save-queue.ts +54 -0
- package/src/hooks/use-webmcp.ts +40 -0
- package/src/lib/__tests__/__snapshots__/pricing-data.test.ts.snap +112 -0
- package/src/lib/__tests__/admin-api.test.ts +487 -0
- package/src/lib/__tests__/api-bot-crud.test.ts +391 -0
- package/src/lib/__tests__/api-fetch.test.ts +196 -0
- package/src/lib/__tests__/bot-settings-data.test.ts +352 -0
- package/src/lib/__tests__/org-api.test.ts +281 -0
- package/src/lib/__tests__/org-billing-api.test.ts +242 -0
- package/src/lib/__tests__/pricing-data.test.ts +32 -0
- package/src/lib/__tests__/settings-api.test.ts +272 -0
- package/src/lib/admin-affiliate-api.ts +51 -0
- package/src/lib/admin-api.ts +325 -0
- package/src/lib/admin-compliance-api.ts +127 -0
- package/src/lib/admin-gpu-api.ts +82 -0
- package/src/lib/admin-incident-api.ts +121 -0
- package/src/lib/admin-inference-api.ts +47 -0
- package/src/lib/admin-marketplace-api.ts +97 -0
- package/src/lib/api-config.test.ts +111 -0
- package/src/lib/api-config.ts +65 -0
- package/src/lib/api-errors.test.ts +43 -0
- package/src/lib/api.ts +2011 -0
- package/src/lib/auth-client.ts +11 -0
- package/src/lib/bot-settings-data.ts +342 -0
- package/src/lib/brand-config.ts +145 -0
- package/src/lib/brand.ts +669 -0
- package/src/lib/changeset-api.ts +29 -0
- package/src/lib/changeset-types.ts +56 -0
- package/src/lib/channel-manifests.ts +50 -0
- package/src/lib/chat/chat-context.tsx +70 -0
- package/src/lib/chat/chat-store.ts +62 -0
- package/src/lib/chat/types.ts +35 -0
- package/src/lib/chat/use-chat.ts +255 -0
- package/src/lib/cost-comparison-data.test.ts +95 -0
- package/src/lib/cost-comparison-data.ts +54 -0
- package/src/lib/errors.test.ts +64 -0
- package/src/lib/errors.ts +52 -0
- package/src/lib/fetch-utils.test.ts +57 -0
- package/src/lib/fetch-utils.ts +25 -0
- package/src/lib/format-credit.test.ts +66 -0
- package/src/lib/format-credit.ts +24 -0
- package/src/lib/format.test.ts +62 -0
- package/src/lib/format.ts +17 -0
- package/src/lib/logger.ts +28 -0
- package/src/lib/marketplace-data.ts +346 -0
- package/src/lib/oauth-errors.ts +19 -0
- package/src/lib/onboarding-data.ts +1265 -0
- package/src/lib/onboarding-store.ts +233 -0
- package/src/lib/org-api.ts +74 -0
- package/src/lib/org-billing-api.ts +81 -0
- package/src/lib/page-prompts.test.ts +32 -0
- package/src/lib/page-prompts.ts +23 -0
- package/src/lib/plugin/index.ts +32 -0
- package/src/lib/plugin/tool-definitions.ts +306 -0
- package/src/lib/pricing-data.ts +115 -0
- package/src/lib/promotions-types.ts +58 -0
- package/src/lib/settings-api.ts +63 -0
- package/src/lib/status-colors.ts +38 -0
- package/src/lib/tenant-context.tsx +134 -0
- package/src/lib/trpc-types.ts +173 -0
- package/src/lib/trpc.tsx +86 -0
- package/src/lib/utils.test.ts +55 -0
- package/src/lib/utils.ts +18 -0
- package/src/lib/validate-redirect-url.ts +39 -0
- package/src/lib/webmcp/feature-detect.ts +13 -0
- package/src/lib/webmcp/marketplace-onboarding-tools.ts +202 -0
- package/src/lib/webmcp/register.ts +44 -0
- package/src/lib/webmcp/tools.ts +422 -0
- package/src/proxy.ts +258 -0
- package/src/types/missing-deps.d.ts +160 -0
- package/src/types/motion-dom.d.ts +162 -0
- package/src/types/vitest-matchers.d.ts +40 -0
- package/src/types/web-mcp.d.ts +22 -0
- package/tsconfig.json +34 -0
- package/vitest.config.ts +26 -0
package/src/proxy.ts
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { type NextRequest, NextResponse } from "next/server";
|
|
2
|
+
import { logger } from "@/lib/logger";
|
|
3
|
+
|
|
4
|
+
const log = logger("middleware");
|
|
5
|
+
|
|
6
|
+
const apiOrigin = process.env.NEXT_PUBLIC_API_URL
|
|
7
|
+
? new URL(process.env.NEXT_PUBLIC_API_URL).origin
|
|
8
|
+
: "";
|
|
9
|
+
|
|
10
|
+
const isSecureOrigin = process.env.NODE_ENV === "production";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Nonce-based style-src toggle.
|
|
14
|
+
*
|
|
15
|
+
* Enabled — style-src uses nonce-based policy instead of 'unsafe-inline'.
|
|
16
|
+
* Tailwind v4 compiles styles at build time (no runtime injection).
|
|
17
|
+
* framer-motion nonce support is provided via MotionConfig in the root layout.
|
|
18
|
+
*/
|
|
19
|
+
const NONCE_STYLES_ENABLED = true;
|
|
20
|
+
|
|
21
|
+
/** Build the CSP header value with a per-request nonce. */
|
|
22
|
+
function buildCsp(nonce: string): string {
|
|
23
|
+
return [
|
|
24
|
+
"default-src 'self'",
|
|
25
|
+
`script-src 'self' 'nonce-${nonce}' 'strict-dynamic' https://js.stripe.com`,
|
|
26
|
+
...(NONCE_STYLES_ENABLED
|
|
27
|
+
? [`style-src-elem 'self' 'nonce-${nonce}'`, "style-src-attr 'unsafe-inline'"]
|
|
28
|
+
: ["style-src 'self' 'unsafe-inline'"]),
|
|
29
|
+
"img-src 'self' data: blob:",
|
|
30
|
+
"font-src 'self'",
|
|
31
|
+
`connect-src 'self' https://api.stripe.com${apiOrigin ? ` ${apiOrigin}` : ""}`,
|
|
32
|
+
"frame-src https://js.stripe.com",
|
|
33
|
+
"frame-ancestors 'none'",
|
|
34
|
+
"base-uri 'self'",
|
|
35
|
+
"form-action 'self'",
|
|
36
|
+
"object-src 'none'",
|
|
37
|
+
...(isSecureOrigin ? ["upgrade-insecure-requests"] : []),
|
|
38
|
+
].join("; ");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const publicPaths = [
|
|
42
|
+
"/login",
|
|
43
|
+
"/signup",
|
|
44
|
+
"/forgot-password",
|
|
45
|
+
"/reset-password",
|
|
46
|
+
"/auth/callback",
|
|
47
|
+
"/auth/verify",
|
|
48
|
+
"/api/auth/",
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
/** Paths that are public only when matched exactly (not as a prefix). */
|
|
52
|
+
const publicExactPaths = new Set([
|
|
53
|
+
"/",
|
|
54
|
+
"/og",
|
|
55
|
+
"/terms",
|
|
56
|
+
"/privacy",
|
|
57
|
+
"/pricing",
|
|
58
|
+
"/status",
|
|
59
|
+
// Health endpoint must be publicly accessible for infra probes (uptime monitors,
|
|
60
|
+
// Kubernetes liveness/readiness, load balancers) that do not carry session cookies.
|
|
61
|
+
"/api/health",
|
|
62
|
+
// Better Auth root endpoint — sub-paths matched via publicPaths prefix list (/api/auth/).
|
|
63
|
+
"/api/auth",
|
|
64
|
+
]);
|
|
65
|
+
|
|
66
|
+
const MUTATION_METHODS = new Set(["POST", "PUT", "PATCH", "DELETE"]);
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Mutation paths under /api/auth that are exempt from CSRF origin validation.
|
|
70
|
+
* OAuth identity providers POST to callback URLs cross-origin — these cannot
|
|
71
|
+
* carry a matching Origin header, so we must allow them through.
|
|
72
|
+
* All other /api/auth mutations (sign-in, sign-up, sign-out, etc.) are
|
|
73
|
+
* validated like any other /api route.
|
|
74
|
+
*/
|
|
75
|
+
const CSRF_EXEMPT_AUTH_PATHS = [
|
|
76
|
+
"/api/auth/callback", // e.g. /api/auth/callback/google, /api/auth/callback/github
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
const PLATFORM_BASE_URL = process.env.NEXT_PUBLIC_API_URL ?? "http://localhost:3001";
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Validate that a state-changing request originates from this application.
|
|
83
|
+
* Checks the Origin header (preferred) with Referer as fallback.
|
|
84
|
+
* Returns true if the request is safe, false if it should be blocked.
|
|
85
|
+
*/
|
|
86
|
+
export function validateCsrfOrigin(request: NextRequest): boolean {
|
|
87
|
+
const origin = request.headers.get("origin");
|
|
88
|
+
const referer = request.headers.get("referer");
|
|
89
|
+
const host = request.headers.get("host");
|
|
90
|
+
|
|
91
|
+
if (!host) return false;
|
|
92
|
+
|
|
93
|
+
// Build the allowed origin using the request's actual protocol only,
|
|
94
|
+
// preventing protocol downgrade attacks (e.g. HTTP origin to HTTPS endpoint)
|
|
95
|
+
const protocol = request.nextUrl.protocol; // "https:" or "http:"
|
|
96
|
+
const allowedOrigin = `${protocol}//${host}`;
|
|
97
|
+
|
|
98
|
+
// Check Origin header first (most reliable)
|
|
99
|
+
if (origin) {
|
|
100
|
+
return origin === allowedOrigin;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Fall back to Referer header
|
|
104
|
+
if (referer) {
|
|
105
|
+
try {
|
|
106
|
+
const refererOrigin = new URL(referer).origin;
|
|
107
|
+
return refererOrigin === allowedOrigin;
|
|
108
|
+
} catch {
|
|
109
|
+
// Malformed referer URL — treat as non-matching origin
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// No Origin or Referer on a mutation request is suspicious — block it.
|
|
115
|
+
// Legitimate browser form submissions and fetch() calls include Origin.
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Fetch the authenticated user's role from Better Auth's get-session endpoint.
|
|
121
|
+
* Returns the role string (e.g. "platform_admin", "user") or null if the
|
|
122
|
+
* session is invalid or the request fails. Fails closed: any error → null.
|
|
123
|
+
*/
|
|
124
|
+
async function getSessionRole(request: NextRequest): Promise<string | null> {
|
|
125
|
+
const sessionCookie =
|
|
126
|
+
request.cookies.get("better-auth.session_token") ??
|
|
127
|
+
request.cookies.get("__Secure-better-auth.session_token");
|
|
128
|
+
|
|
129
|
+
if (!sessionCookie?.value.trim()) return null;
|
|
130
|
+
|
|
131
|
+
try {
|
|
132
|
+
const res = await fetch(`${PLATFORM_BASE_URL}/api/auth/get-session`, {
|
|
133
|
+
headers: {
|
|
134
|
+
cookie: `${sessionCookie.name}=${sessionCookie.value}`,
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
if (!res.ok) return null;
|
|
138
|
+
const data = await res.json();
|
|
139
|
+
return data?.user?.role ?? null;
|
|
140
|
+
} catch (e) {
|
|
141
|
+
log.warn("Failed to fetch user role for middleware routing", e);
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export default async function middleware(request: NextRequest) {
|
|
147
|
+
const { pathname } = request.nextUrl;
|
|
148
|
+
const host = request.headers.get("host") || "";
|
|
149
|
+
|
|
150
|
+
// Generate a per-request nonce for CSP
|
|
151
|
+
const nonce = crypto.randomUUID();
|
|
152
|
+
const cspHeaderValue = buildCsp(nonce);
|
|
153
|
+
|
|
154
|
+
/** Apply CSP and cache-busting headers to any response before returning it. */
|
|
155
|
+
function withCsp(response: NextResponse): NextResponse {
|
|
156
|
+
response.headers.set("Content-Security-Policy", cspHeaderValue);
|
|
157
|
+
// Nonce is passed to server components via request headers (not response headers).
|
|
158
|
+
// See nextWithNonce() below — it uses NextResponse.next({ request: { headers } }).
|
|
159
|
+
response.headers.set("Vary", "*");
|
|
160
|
+
return response;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Create a NextResponse.next() that forwards the CSP nonce to server components
|
|
165
|
+
* via request headers, without exposing it in the HTTP response.
|
|
166
|
+
*/
|
|
167
|
+
function nextWithNonce(): NextResponse {
|
|
168
|
+
const requestHeaders = new Headers(request.headers);
|
|
169
|
+
requestHeaders.set("x-nonce", nonce);
|
|
170
|
+
return NextResponse.next({ request: { headers: requestHeaders } });
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// CSRF protection: validate Origin/Referer on state-changing API requests.
|
|
174
|
+
if (pathname.startsWith("/api") && MUTATION_METHODS.has(request.method)) {
|
|
175
|
+
// OAuth callback endpoints receive cross-origin POSTs from identity providers (POST only)
|
|
176
|
+
const isCsrfExempt =
|
|
177
|
+
CSRF_EXEMPT_AUTH_PATHS.some((p) => pathname === p || pathname.startsWith(`${p}/`)) &&
|
|
178
|
+
request.method === "POST";
|
|
179
|
+
if (!isCsrfExempt && !validateCsrfOrigin(request)) {
|
|
180
|
+
return NextResponse.json({ error: "CSRF validation failed" }, { status: 403 });
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Redirect authenticated users from "/" to the app subdomain if on the marketing domain.
|
|
185
|
+
// On the app subdomain, redirect to /marketplace. On the base domain, redirect to app subdomain.
|
|
186
|
+
// NOTE: This check requires the Better Auth server to set the session cookie with
|
|
187
|
+
// domain=".<base-domain>" so it is visible on both the app and marketing subdomains.
|
|
188
|
+
// See: wopr-platform/src/auth/better-auth.ts advanced.cookies.session_token.attributes.domain
|
|
189
|
+
if (pathname === "/") {
|
|
190
|
+
const sessionToken =
|
|
191
|
+
request.cookies.get("better-auth.session_token") ??
|
|
192
|
+
request.cookies.get("__Secure-better-auth.session_token");
|
|
193
|
+
if (sessionToken?.value.trim()) {
|
|
194
|
+
const appDomain =
|
|
195
|
+
process.env.NEXT_PUBLIC_BRAND_APP_DOMAIN || process.env.NEXT_PUBLIC_APP_DOMAIN;
|
|
196
|
+
if (appDomain && !host.startsWith("app.")) {
|
|
197
|
+
// On marketing domain — redirect to the app subdomain
|
|
198
|
+
return withCsp(NextResponse.redirect(new URL(`https://${appDomain}/marketplace`)));
|
|
199
|
+
}
|
|
200
|
+
// On app subdomain (or no configured app domain) — redirect to /marketplace
|
|
201
|
+
return withCsp(NextResponse.redirect(new URL("/marketplace", request.url)));
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// --- Admin route authorization (server-side) ---
|
|
206
|
+
// Non-admins are redirected before any page JS loads.
|
|
207
|
+
// Unauthenticated users fall through to the session check below (→ /login).
|
|
208
|
+
if (pathname.startsWith("/admin")) {
|
|
209
|
+
const sessionCookie =
|
|
210
|
+
request.cookies.get("better-auth.session_token") ??
|
|
211
|
+
request.cookies.get("__Secure-better-auth.session_token");
|
|
212
|
+
if (sessionCookie?.value.trim()) {
|
|
213
|
+
const role = await getSessionRole(request);
|
|
214
|
+
if (role !== "platform_admin") {
|
|
215
|
+
return withCsp(NextResponse.redirect(new URL("/marketplace", request.url)));
|
|
216
|
+
}
|
|
217
|
+
// Admin confirmed — serve page with anti-cache headers so revocation
|
|
218
|
+
// is detected on the very next navigation (browser must revalidate).
|
|
219
|
+
const response = nextWithNonce();
|
|
220
|
+
response.headers.set("Cache-Control", "no-store, no-cache, must-revalidate");
|
|
221
|
+
response.headers.set("Pragma", "no-cache");
|
|
222
|
+
response.headers.set("Expires", "0");
|
|
223
|
+
return withCsp(response);
|
|
224
|
+
}
|
|
225
|
+
// No session cookie → fall through to the session check below which redirects to /login
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Allow public paths
|
|
229
|
+
if (publicExactPaths.has(pathname) || publicPaths.some((p) => pathname.startsWith(p))) {
|
|
230
|
+
return withCsp(nextWithNonce());
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Allow static files (but not API paths with dots, e.g. /api/config.json)
|
|
234
|
+
if (pathname.startsWith("/_next") || (pathname.includes(".") && !pathname.startsWith("/api"))) {
|
|
235
|
+
return withCsp(nextWithNonce());
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Check for session cookie (Better Auth uses "better-auth.session_token" by default).
|
|
239
|
+
// NOTE: Bearer token auth (Authorization: Bearer <token>) is intentionally not supported
|
|
240
|
+
// here. This is a browser-facing UI application; all API consumers are the Next.js
|
|
241
|
+
// front-end itself (cookie-based). Automation/SDK/CLI clients should use the platform
|
|
242
|
+
// API directly (wopr-platform), which issues and validates Bearer tokens independently.
|
|
243
|
+
const sessionToken =
|
|
244
|
+
request.cookies.get("better-auth.session_token") ??
|
|
245
|
+
request.cookies.get("__Secure-better-auth.session_token");
|
|
246
|
+
|
|
247
|
+
if (!sessionToken || !sessionToken.value.trim()) {
|
|
248
|
+
const loginUrl = new URL("/login", request.url);
|
|
249
|
+
loginUrl.searchParams.set("callbackUrl", pathname);
|
|
250
|
+
return withCsp(NextResponse.redirect(loginUrl));
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return withCsp(nextWithNonce());
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export const config = {
|
|
257
|
+
matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
|
|
258
|
+
};
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stub type declarations for packages whose type files cannot be resolved
|
|
3
|
+
* by moduleResolution:"bundler" due to missing `types` conditions in their
|
|
4
|
+
* package.json `exports` maps, or for Node.js built-in modules.
|
|
5
|
+
*
|
|
6
|
+
* Remove individual stubs when the upstream package fixes its exports map.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// NodeJS.Process augmentation – @types/node in this install omits env/Process.
|
|
11
|
+
// Ensures process.env is typed throughout the codebase.
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
declare namespace NodeJS {
|
|
14
|
+
interface Process {
|
|
15
|
+
env: ProcessEnv;
|
|
16
|
+
}
|
|
17
|
+
interface ProcessEnv {
|
|
18
|
+
readonly NODE_ENV?: "development" | "production" | "test";
|
|
19
|
+
[key: string]: string | undefined;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// node:path – @types/node path.d.ts is empty in this install.
|
|
25
|
+
// Explicitly declares the named exports used by this codebase.
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
declare module "node:path" {
|
|
28
|
+
export function resolve(...paths: string[]): string;
|
|
29
|
+
export function join(...paths: string[]): string;
|
|
30
|
+
export function dirname(path: string): string;
|
|
31
|
+
export function basename(path: string, ext?: string): string;
|
|
32
|
+
export function extname(path: string): string;
|
|
33
|
+
export function normalize(path: string): string;
|
|
34
|
+
export function isAbsolute(path: string): boolean;
|
|
35
|
+
export function relative(from: string, to: string): string;
|
|
36
|
+
export const sep: string;
|
|
37
|
+
export const delimiter: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// node:fs – @types/node fs.d.ts declarations for sync file reading used in tests.
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
declare module "node:fs" {
|
|
44
|
+
export function readFileSync(path: string, encoding: BufferEncoding): string;
|
|
45
|
+
export function readFileSync(
|
|
46
|
+
path: string,
|
|
47
|
+
options: { encoding: BufferEncoding; flag?: string },
|
|
48
|
+
): string;
|
|
49
|
+
export function readFileSync(path: string): Buffer;
|
|
50
|
+
export function existsSync(path: string): boolean;
|
|
51
|
+
export function writeFileSync(
|
|
52
|
+
path: string,
|
|
53
|
+
data: string | Buffer,
|
|
54
|
+
options?: { encoding?: BufferEncoding; flag?: string },
|
|
55
|
+
): void;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
// node:fs/promises – async file operations
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
declare module "node:fs/promises" {
|
|
62
|
+
export function readFile(path: string, encoding: BufferEncoding): Promise<string>;
|
|
63
|
+
export function writeFile(path: string, data: string | Buffer): Promise<void>;
|
|
64
|
+
export function access(path: string, mode?: number): Promise<void>;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
// node:url – URL utilities
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
declare module "node:url" {
|
|
71
|
+
export function fileURLToPath(url: string | URL): string;
|
|
72
|
+
export function pathToFileURL(path: string): URL;
|
|
73
|
+
export class URL {
|
|
74
|
+
constructor(input: string, base?: string | URL);
|
|
75
|
+
href: string;
|
|
76
|
+
origin: string;
|
|
77
|
+
protocol: string;
|
|
78
|
+
host: string;
|
|
79
|
+
hostname: string;
|
|
80
|
+
port: string;
|
|
81
|
+
pathname: string;
|
|
82
|
+
search: string;
|
|
83
|
+
hash: string;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// ---------------------------------------------------------------------------
|
|
88
|
+
// node:os – OS utilities
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
declare module "node:os" {
|
|
91
|
+
export function tmpdir(): string;
|
|
92
|
+
export function homedir(): string;
|
|
93
|
+
export function platform(): string;
|
|
94
|
+
export function arch(): string;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
// react-markdown – markdown renderer for React
|
|
99
|
+
// The package ships index.d.ts but does not expose it via its exports map,
|
|
100
|
+
// so moduleResolution:bundler cannot find it. Stub the default export here.
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
declare module "react-markdown" {
|
|
103
|
+
import type { ReactNode, ComponentType } from "react";
|
|
104
|
+
interface ReactMarkdownProps {
|
|
105
|
+
children?: string;
|
|
106
|
+
remarkPlugins?: unknown[];
|
|
107
|
+
rehypePlugins?: unknown[];
|
|
108
|
+
components?: Record<string, ComponentType<Record<string, unknown>>>;
|
|
109
|
+
}
|
|
110
|
+
export default function ReactMarkdown(props: ReactMarkdownProps): ReactNode;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ---------------------------------------------------------------------------
|
|
114
|
+
// remark-gfm – GitHub-Flavored Markdown plugin for remark/react-markdown
|
|
115
|
+
// Same exports-map issue as react-markdown above.
|
|
116
|
+
// ---------------------------------------------------------------------------
|
|
117
|
+
declare module "remark-gfm" {
|
|
118
|
+
const remarkGfm: (...args: unknown[]) => unknown;
|
|
119
|
+
export default remarkGfm;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// ---------------------------------------------------------------------------
|
|
123
|
+
// rehype-sanitize – HTML sanitization plugin for rehype/react-markdown
|
|
124
|
+
// Same exports-map issue as react-markdown above.
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
declare module "rehype-sanitize" {
|
|
127
|
+
interface SanitizeSchema {
|
|
128
|
+
tagNames?: string[];
|
|
129
|
+
attributes?: Record<string, string[]>;
|
|
130
|
+
protocols?: Record<string, string[]>;
|
|
131
|
+
[key: string]: unknown;
|
|
132
|
+
}
|
|
133
|
+
export const defaultSchema: SanitizeSchema;
|
|
134
|
+
const rehypeSanitize: (...args: unknown[]) => unknown;
|
|
135
|
+
export default rehypeSanitize;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ---------------------------------------------------------------------------
|
|
139
|
+
// node:child_process – child process utilities
|
|
140
|
+
// ---------------------------------------------------------------------------
|
|
141
|
+
declare module "node:child_process" {
|
|
142
|
+
export interface SpawnOptions {
|
|
143
|
+
cwd?: string;
|
|
144
|
+
env?: Record<string, string>;
|
|
145
|
+
stdio?: "pipe" | "inherit" | "ignore";
|
|
146
|
+
}
|
|
147
|
+
export interface ChildProcess {
|
|
148
|
+
pid?: number;
|
|
149
|
+
stdout: unknown;
|
|
150
|
+
stderr: unknown;
|
|
151
|
+
stdin: unknown;
|
|
152
|
+
on(event: string, listener: (...args: unknown[]) => void): this;
|
|
153
|
+
kill(signal?: string): boolean;
|
|
154
|
+
}
|
|
155
|
+
export function spawn(command: string, args?: string[], options?: SpawnOptions): ChildProcess;
|
|
156
|
+
export function execSync(
|
|
157
|
+
command: string,
|
|
158
|
+
options?: { encoding?: BufferEncoding; cwd?: string },
|
|
159
|
+
): string | Buffer;
|
|
160
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ambient type declarations for motion-dom 12.x, framer-motion 12.x shims,
|
|
3
|
+
* and process.env augmentation for Next.js/browser environments.
|
|
4
|
+
*
|
|
5
|
+
* motion-dom ships without bundled type declarations in some versions.
|
|
6
|
+
* This stub satisfies the imports that framer-motion's types expect.
|
|
7
|
+
* Remove this file once motion-dom ships with its own .d.ts files.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
declare module "motion-dom" {
|
|
11
|
+
/** A motion value that can animate between values. */
|
|
12
|
+
export class MotionValue<T = unknown> {
|
|
13
|
+
get(): T;
|
|
14
|
+
set(v: T): void;
|
|
15
|
+
on(event: string, cb: (v: T) => void): () => void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** CSS transform property names that motion supports independently. */
|
|
19
|
+
export interface TransformProperties {
|
|
20
|
+
x?: number | string;
|
|
21
|
+
y?: number | string;
|
|
22
|
+
z?: number | string;
|
|
23
|
+
rotate?: number | string;
|
|
24
|
+
rotateX?: number | string;
|
|
25
|
+
rotateY?: number | string;
|
|
26
|
+
rotateZ?: number | string;
|
|
27
|
+
scale?: number | string;
|
|
28
|
+
scaleX?: number | string;
|
|
29
|
+
scaleY?: number | string;
|
|
30
|
+
skew?: number | string;
|
|
31
|
+
skewX?: number | string;
|
|
32
|
+
skewY?: number | string;
|
|
33
|
+
originX?: number | string;
|
|
34
|
+
originY?: number | string;
|
|
35
|
+
originZ?: number | string;
|
|
36
|
+
perspective?: number | string;
|
|
37
|
+
translateX?: number | string;
|
|
38
|
+
translateY?: number | string;
|
|
39
|
+
translateZ?: number | string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** SVG path-specific animatable properties. */
|
|
43
|
+
export interface SVGPathProperties {
|
|
44
|
+
pathLength?: number;
|
|
45
|
+
pathOffset?: number;
|
|
46
|
+
pathSpacing?: number;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Target values for an animation — CSS properties plus transforms. */
|
|
50
|
+
export type TargetAndTransition = Record<string, unknown>;
|
|
51
|
+
|
|
52
|
+
/** A named set of animation states. */
|
|
53
|
+
export type VariantLabels = string | string[];
|
|
54
|
+
|
|
55
|
+
/** Transition configuration. */
|
|
56
|
+
export type Transition = Record<string, unknown>;
|
|
57
|
+
|
|
58
|
+
/** Bounding box used for drag constraints. */
|
|
59
|
+
export interface BoundingBox {
|
|
60
|
+
top: number;
|
|
61
|
+
right: number;
|
|
62
|
+
bottom: number;
|
|
63
|
+
left: number;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Information about a pan/drag gesture. */
|
|
67
|
+
export interface PanInfo {
|
|
68
|
+
point: { x: number; y: number };
|
|
69
|
+
delta: { x: number; y: number };
|
|
70
|
+
offset: { x: number; y: number };
|
|
71
|
+
velocity: { x: number; y: number };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** The core animation props exposed by every motion element. */
|
|
75
|
+
export interface MotionNodeOptions {
|
|
76
|
+
/** Initial visual state — can be a variant name, object, or false. */
|
|
77
|
+
initial?: boolean | TargetAndTransition | VariantLabels;
|
|
78
|
+
/** Animation target — can be a variant name, object, or controls. */
|
|
79
|
+
animate?: TargetAndTransition | VariantLabels;
|
|
80
|
+
/** State to animate to when removed from the React tree (requires AnimatePresence). */
|
|
81
|
+
exit?: TargetAndTransition | VariantLabels;
|
|
82
|
+
/** Named animation variants. */
|
|
83
|
+
// biome-ignore lint/suspicious/noExplicitAny: variant functions accept arbitrary custom args (e.g. stagger index)
|
|
84
|
+
variants?: Record<string, TargetAndTransition | ((arg: any) => TargetAndTransition)>;
|
|
85
|
+
/** Transition defaults for this element. */
|
|
86
|
+
transition?: Transition;
|
|
87
|
+
/** Animate when hovered. */
|
|
88
|
+
whileHover?: TargetAndTransition | VariantLabels;
|
|
89
|
+
/** Animate while focused. */
|
|
90
|
+
whileFocus?: TargetAndTransition | VariantLabels;
|
|
91
|
+
/** Animate while tapped / clicked. */
|
|
92
|
+
whileTap?: TargetAndTransition | VariantLabels;
|
|
93
|
+
/** Animate while dragging. */
|
|
94
|
+
whileDrag?: TargetAndTransition | VariantLabels;
|
|
95
|
+
/** Animate while element is in viewport. */
|
|
96
|
+
whileInView?: TargetAndTransition | VariantLabels;
|
|
97
|
+
/** Enable dragging. */
|
|
98
|
+
drag?: boolean | "x" | "y";
|
|
99
|
+
/** Drag constraints (ref or pixel values). */
|
|
100
|
+
dragConstraints?: false | Partial<BoundingBox> | { current: Element | null };
|
|
101
|
+
/** Drag elasticity (0 = rigid, 1 = full). */
|
|
102
|
+
dragElastic?: boolean | number | Partial<BoundingBox>;
|
|
103
|
+
/** Drag momentum. */
|
|
104
|
+
dragMomentum?: boolean;
|
|
105
|
+
/** Enable layout animations. */
|
|
106
|
+
layout?: boolean | "position" | "size" | "preserve-aspect";
|
|
107
|
+
/** Layout ID for shared-layout transitions. */
|
|
108
|
+
layoutId?: string;
|
|
109
|
+
/** Custom prop forwarding filter. */
|
|
110
|
+
custom?: unknown;
|
|
111
|
+
/** Called when animation starts. */
|
|
112
|
+
onAnimationStart?: (definition: string) => void;
|
|
113
|
+
/** Called when animation completes. */
|
|
114
|
+
onAnimationComplete?: (definition: string) => void;
|
|
115
|
+
/** Called when drag starts. */
|
|
116
|
+
onDragStart?: (event: MouseEvent | TouchEvent | PointerEvent, info: PanInfo) => void;
|
|
117
|
+
/** Called while dragging. */
|
|
118
|
+
onDrag?: (event: MouseEvent | TouchEvent | PointerEvent, info: PanInfo) => void;
|
|
119
|
+
/** Called when drag ends. */
|
|
120
|
+
onDragEnd?: (event: MouseEvent | TouchEvent | PointerEvent, info: PanInfo) => void;
|
|
121
|
+
/** Called when element enters viewport. */
|
|
122
|
+
onViewportEnter?: (entry: IntersectionObserverEntry | null) => void;
|
|
123
|
+
/** Called when element leaves viewport. */
|
|
124
|
+
onViewportLeave?: (entry: IntersectionObserverEntry | null) => void;
|
|
125
|
+
/** Inherited variant from parent. */
|
|
126
|
+
inherit?: boolean;
|
|
127
|
+
/** Viewport options for whileInView. */
|
|
128
|
+
viewport?: {
|
|
129
|
+
once?: boolean;
|
|
130
|
+
root?: React.RefObject<Element>;
|
|
131
|
+
margin?: string;
|
|
132
|
+
amount?: "some" | "all" | number;
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export type ElementOrSelector = Element | string | NodeListOf<Element> | Element[];
|
|
137
|
+
|
|
138
|
+
export type DOMKeyframesDefinition = Record<string, unknown>;
|
|
139
|
+
|
|
140
|
+
export type AnimationOptions = Record<string, unknown>;
|
|
141
|
+
|
|
142
|
+
export interface AnimationPlaybackControlsWithThen {
|
|
143
|
+
then(resolve: () => void, reject?: () => void): Promise<void>;
|
|
144
|
+
cancel(): void;
|
|
145
|
+
complete(): void;
|
|
146
|
+
pause(): void;
|
|
147
|
+
play(): void;
|
|
148
|
+
stop(): void;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export type AnimationPlaybackControls = AnimationPlaybackControlsWithThen;
|
|
152
|
+
|
|
153
|
+
export type AnimationScope<T = Element> = {
|
|
154
|
+
readonly current: T;
|
|
155
|
+
animations: AnimationPlaybackControls[];
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
export type ValueAnimationTransition = Record<string, unknown>;
|
|
159
|
+
|
|
160
|
+
export type NodeGroup = unknown;
|
|
161
|
+
export type IProjectionNode = unknown;
|
|
162
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type augmentation for @testing-library/jest-dom vitest matchers.
|
|
3
|
+
*
|
|
4
|
+
* The @testing-library/jest-dom package ships without types/vitest.d.ts
|
|
5
|
+
* in this npm install. This file augments @vitest/expect's Assertion
|
|
6
|
+
* interface with the jest-dom matchers.
|
|
7
|
+
*
|
|
8
|
+
* This is a module file (export {} below) so the declare module blocks
|
|
9
|
+
* act as augmentation rather than replacement.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// Make this a module file so declare module augments rather than replaces.
|
|
13
|
+
export {};
|
|
14
|
+
|
|
15
|
+
declare module "@vitest/expect" {
|
|
16
|
+
interface Assertion {
|
|
17
|
+
toBeInTheDocument(): void;
|
|
18
|
+
toBeVisible(): void;
|
|
19
|
+
toBeDisabled(): void;
|
|
20
|
+
toBeEnabled(): void;
|
|
21
|
+
toBeChecked(): void;
|
|
22
|
+
toBePartiallyChecked(): void;
|
|
23
|
+
toBeRequired(): void;
|
|
24
|
+
toBeValid(): void;
|
|
25
|
+
toBeInvalid(): void;
|
|
26
|
+
toBeEmptyDOMElement(): void;
|
|
27
|
+
toContainElement(element: Element | null): void;
|
|
28
|
+
toContainHTML(html: string): void;
|
|
29
|
+
toHaveAccessibleDescription(description?: string | RegExp): void;
|
|
30
|
+
toHaveAccessibleName(name?: string | RegExp): void;
|
|
31
|
+
toHaveAttribute(attr: string, value?: unknown): void;
|
|
32
|
+
toHaveClass(...classNames: string[]): void;
|
|
33
|
+
toHaveFocus(): void;
|
|
34
|
+
toHaveFormValues(values: Record<string, unknown>): void;
|
|
35
|
+
toHaveStyle(css: string | Record<string, unknown>): void;
|
|
36
|
+
toHaveTextContent(text: string | RegExp, options?: { normalizeWhitespace: boolean }): void;
|
|
37
|
+
toHaveValue(value?: string | string[] | number): void;
|
|
38
|
+
toHaveDisplayValue(value: string | RegExp | (string | RegExp)[]): void;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ambient type declarations for the WebMCP API (Chrome 146+ DevTrial).
|
|
3
|
+
* See: https://chromestatus.com/feature/xxxxx
|
|
4
|
+
*
|
|
5
|
+
* These types will be removed once WebMCP ships in stable Chrome
|
|
6
|
+
* and @types/web-mcp is published.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
interface ModelContextTool {
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
inputSchema: Record<string, unknown>;
|
|
13
|
+
handler: (params: Record<string, unknown>) => Promise<unknown>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface ModelContext {
|
|
17
|
+
registerTool(tool: ModelContextTool): void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface Navigator {
|
|
21
|
+
modelContext?: ModelContext;
|
|
22
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2017",
|
|
4
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
5
|
+
"allowJs": true,
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"noEmit": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"module": "esnext",
|
|
11
|
+
"moduleResolution": "bundler",
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"jsx": "react-jsx",
|
|
15
|
+
"incremental": true,
|
|
16
|
+
"plugins": [
|
|
17
|
+
{
|
|
18
|
+
"name": "next"
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"paths": {
|
|
22
|
+
"@/*": ["./src/*"]
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"include": [
|
|
26
|
+
"next-env.d.ts",
|
|
27
|
+
"**/*.ts",
|
|
28
|
+
"**/*.tsx",
|
|
29
|
+
".next/types/**/*.ts",
|
|
30
|
+
".next/dev/types/**/*.ts",
|
|
31
|
+
"**/*.mts"
|
|
32
|
+
],
|
|
33
|
+
"exclude": ["node_modules", "e2e", "playwright.config.ts"]
|
|
34
|
+
}
|