mirror of
https://github.com/nimbusdotstorage/Nimbus
synced 2026-04-22 17:45:03 +02:00
POLAR N STuFF
This commit is contained in:
64
.github/PULL_REQUEST_TEMPLATE.md
vendored
64
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,54 +1,10 @@
|
||||
# Pull Request
|
||||
|
||||
## Description
|
||||
|
||||
<!-- A clear and concise description of what this PR does and why it's needed. -->
|
||||
|
||||
## Type of Change
|
||||
|
||||
<!-- Check one of the following with [x] -->
|
||||
|
||||
- [ ] 🚀 Feature (non-breaking change that adds functionality)
|
||||
- [ ] 🐛 Bug fix (non-breaking change that fixes an issue)
|
||||
- [ ] ♻️ Refactor (code change that neither fixes a bug nor adds a feature)
|
||||
- [ ] 📚 Documentation update
|
||||
- [ ] 🧪 Test update
|
||||
- [ ] 🔧 Chore (updates to build process, CI, dependencies, etc.)
|
||||
- [ ] 🔥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||
|
||||
## Changes
|
||||
|
||||
<!-- List the main changes in your PR. Be specific and use bullet points. -->
|
||||
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
## Description (what did you change?)
|
||||
|
||||
## Screenshots/Videos
|
||||
|
||||
<!-- If applicable, add screenshots or screen recordings to help explain your changes. -->
|
||||
|
||||
## Testing
|
||||
|
||||
<!-- Describe how you tested your changes. Include test cases if applicable. -->
|
||||
|
||||
- [ ] I have tested these changes locally
|
||||
- [ ] I have added/updated tests for these changes
|
||||
- [ ] I have tested in the following browsers:
|
||||
- [ ] Chrome
|
||||
- [ ] Firefox
|
||||
- [ ] Safari
|
||||
- [ ] Edge
|
||||
|
||||
### Test Cases
|
||||
|
||||
<!-- Add any specific test cases you've added or updated -->
|
||||
|
||||
1. [Test Case 1]
|
||||
- [ ] Test passed
|
||||
2. [Test Case 2]
|
||||
- [ ] Test passed
|
||||
## Testing (did you break anything?)
|
||||
|
||||
## Checklist
|
||||
|
||||
@@ -61,22 +17,14 @@
|
||||
- [ ] New and existing unit tests pass locally with my changes
|
||||
- [ ] Any dependent changes have been merged and published in downstream modules
|
||||
|
||||
## Additional Context
|
||||
|
||||
<!-- Add any other context about the PR here. This could include decisions you made, alternatives considered, etc. -->
|
||||
## Anything else you want us to know?
|
||||
|
||||
## Related Issues
|
||||
|
||||
<!-- If this PR closes any issues, use the keyword 'closes' followed by the issue number -->
|
||||
Link the issue on the Github ui
|
||||
|
||||
Closes # Fixes #
|
||||
|
||||
## Deployment Notes
|
||||
|
||||
<!-- Any special configurations or considerations for deployment? -->
|
||||
## Deployment Notes (new env vars, special url configs, etc.)
|
||||
|
||||
## Reviewers
|
||||
|
||||
<!-- Tag any specific reviewers if needed -->
|
||||
|
||||
@reviewer1 @reviewer2
|
||||
Request reviewers in the GitHub ui
|
||||
|
||||
45
.github/workflows/pr-merge-check.yml
vendored
45
.github/workflows/pr-merge-check.yml
vendored
@@ -1,45 +0,0 @@
|
||||
name: Ready to Merge
|
||||
on:
|
||||
pull_request:
|
||||
types: [ready_for_review]
|
||||
|
||||
jobs:
|
||||
pr-merge-check:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.pull_request.mergeable_state == 'clean' && github.event.pull_request.draft == false
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Fetch all branches
|
||||
run: git fetch --all
|
||||
|
||||
- name: Wait for CI checks to succeed
|
||||
uses: fountainhead/action-wait-for-check@master
|
||||
id: wait-for-ci-checks
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# IMPORTANT: If the check you're referencing is provided by another GitHub Actions workflow,
|
||||
# make sure that you reference the name of a Job within that workflow, and not the name the Workflow itself.
|
||||
checkName: ci
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
||||
- name: Fail if CI checks did not succeed
|
||||
if: steps.wait-for-ci-checks.outputs.conclusion != 'success'
|
||||
run: exit 1
|
||||
|
||||
- name: Check for Changesets
|
||||
run: bun changeset status --since origin/main
|
||||
|
||||
- name: Set up environment variables
|
||||
id: set-env
|
||||
run: |
|
||||
DEPLOYMENT_NAME="pr-${{ github.event.pull_request.number }}"
|
||||
echo "$DEPLOYMENT_NAME" > deployment_name.txt
|
||||
|
||||
- name: Upload deployment info
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: deployment-info
|
||||
path: deployment_name.txt
|
||||
13
TODO.md
13
TODO.md
@@ -1,2 +1,11 @@
|
||||
- Remove next/navigation from the codebase. Figure out how tanstack router does it.
|
||||
-
|
||||
# TODO
|
||||
|
||||
- [x] Remove next/navigation from the codebase. Figure out how tanstack router does it.
|
||||
- [x] Payments
|
||||
- [ ] Enforce connections even more by preventing muti account access when user doesnt ahve a subscription
|
||||
- [ ] Add s3 and Nimbus storage
|
||||
- [ ] Add Box, dropbox, etc
|
||||
- [ ] Add functionality for the pro subscription callback so that a component tpops up congratulating them on joining the pro tier.
|
||||
- [ ] An API
|
||||
- [ ] A desktop app
|
||||
- [ ] A mobile app
|
||||
|
||||
@@ -20,6 +20,8 @@ import tagsRoutes from "./tags";
|
||||
import authRoutes from "./auth";
|
||||
import { Hono } from "hono";
|
||||
|
||||
// TODO: this sucks. make it simpler. Just pass the ids as either a path or query params
|
||||
|
||||
const driveRouter = new Hono<HonoContext>()
|
||||
.use("*", async (c, next) => {
|
||||
const user = c.var.user;
|
||||
|
||||
@@ -30,10 +30,11 @@
|
||||
"@radix-ui/react-select": "^2.2.5",
|
||||
"@radix-ui/react-separator": "^1.1.7",
|
||||
"@radix-ui/react-slot": "^1.2.3",
|
||||
"@radix-ui/react-tabs": "^1.1.12",
|
||||
"@radix-ui/react-tabs": "^1.1.13",
|
||||
"@radix-ui/react-tooltip": "^1.2.7",
|
||||
"@t3-oss/env-core": "^0.13.8",
|
||||
"@tailwindcss/postcss": "^4.1.14",
|
||||
"@tanstack/devtools-vite": "^0.3.11",
|
||||
"@tanstack/react-query": "^5.83.0",
|
||||
"@tanstack/react-query-devtools": "^5.84.1",
|
||||
"@tanstack/react-router": "^1.133.25",
|
||||
|
||||
@@ -1,32 +1,64 @@
|
||||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog";
|
||||
import { AuthProviderButtons } from "@/components/auth/shared/auth-provider-buttons";
|
||||
import { CheckCircle2, Sparkles, Zap } from "lucide-react";
|
||||
import { authClient } from "@nimbus/auth/auth-client";
|
||||
import { useLocation } from "@tanstack/react-router";
|
||||
import { useIsMounted } from "@/hooks/useIsMounted";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
type SigninAccountDialogProps = {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
};
|
||||
import PlusGrid from "../cool/plus-box";
|
||||
import { toast } from "sonner";
|
||||
|
||||
type ViewMode = "select" | "s3-form";
|
||||
|
||||
type SigninAccountDialogProps = {
|
||||
open: boolean;
|
||||
onOpenChange?: (open: boolean) => void;
|
||||
};
|
||||
|
||||
async function upgradePlan() {
|
||||
const response = await authClient.checkout({
|
||||
slug: "pro",
|
||||
});
|
||||
if (response.error) {
|
||||
toast.error(response.error.message);
|
||||
}
|
||||
}
|
||||
|
||||
export function SigninAccountDialog({ open, onOpenChange }: SigninAccountDialogProps) {
|
||||
const isMounted = useIsMounted();
|
||||
|
||||
// Build callback URL safely after mount
|
||||
const pathname = useLocation({
|
||||
select: location => location.pathname,
|
||||
});
|
||||
|
||||
const [callbackURL, setCallbackURL] = useState<string>("");
|
||||
const [viewMode, setViewMode] = useState<ViewMode>("select");
|
||||
|
||||
const { data: subscriptions } = useQuery({
|
||||
queryKey: ["subscriptions"],
|
||||
queryFn: async () => {
|
||||
const response = await authClient.customer.subscriptions.list({
|
||||
query: {
|
||||
page: 1,
|
||||
limit: 10,
|
||||
active: true,
|
||||
},
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (isMounted) {
|
||||
const callbackURL = `${window.location.origin}${pathname}`;
|
||||
setCallbackURL(callbackURL);
|
||||
const url = `${window.location.origin}${pathname}`;
|
||||
setCallbackURL(url);
|
||||
}
|
||||
}, [isMounted, pathname]);
|
||||
|
||||
// Reset view mode when dialog closes
|
||||
// Reset the internal view when dialog closes
|
||||
useEffect(() => {
|
||||
if (!open) {
|
||||
setViewMode("select");
|
||||
@@ -35,20 +67,70 @@ export function SigninAccountDialog({ open, onOpenChange }: SigninAccountDialogP
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent
|
||||
className="sm:max-w-[500px]"
|
||||
showBackButton={viewMode === "s3-form"}
|
||||
onBack={() => setViewMode("select")}
|
||||
>
|
||||
{viewMode === "select" && (
|
||||
<DialogHeader>
|
||||
<DialogTitle>Sign in with an account</DialogTitle>
|
||||
<DialogDescription>Connect a social account to sign in with it later.</DialogDescription>
|
||||
</DialogHeader>
|
||||
<DialogContent showBackButton={viewMode === "s3-form"} onBack={() => setViewMode("select")}>
|
||||
{subscriptions && subscriptions.result.items.length > 0 ? (
|
||||
<>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Sign in with an account</DialogTitle>
|
||||
<DialogDescription>Connect a storage provider to access your data</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="flex flex-col gap-4 py-4">
|
||||
<AuthProviderButtons action="signin" callbackURL={callbackURL} />
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<DialogHeader className="space-y-2 text-center">
|
||||
<DialogTitle className="text-2xl font-bold tracking-tight">
|
||||
Go{" "}
|
||||
<span className="from-primary to-primary/60 animate-gradient bg-gradient-to-r bg-clip-text text-transparent">
|
||||
Pro
|
||||
</span>
|
||||
<Zap className="mb-1 ml-2 inline-block h-6 w-6 text-yellow-400" />
|
||||
</DialogTitle>
|
||||
<DialogDescription className="text-base">Be the most productive you</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="relative flex flex-col items-center justify-center overflow-hidden py-6">
|
||||
{/* Subtle animated background shimmer */}
|
||||
<div className="from-muted/40 to-background absolute inset-0 animate-pulse rounded-lg bg-gradient-to-br via-transparent opacity-60 blur-2xl" />
|
||||
|
||||
{/* Image placeholder */}
|
||||
<div className="relative flex aspect-[15/5] w-full items-center justify-center overflow-hidden rounded-lg border backdrop-blur-sm">
|
||||
<PlusGrid />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center gap-3">
|
||||
<CheckCircle2 className="h-5 w-5 text-green-400" />
|
||||
<span className="text-sm font-medium">1 TB of our secure file storage</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<CheckCircle2 className="h-5 w-5 text-green-400" />
|
||||
<span className="text-sm font-medium">Connect as many storage providers as you want</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<CheckCircle2 className="h-5 w-5 text-green-400" />
|
||||
<span className="text-sm font-medium">AI-powered search. Never lose a file again.</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 flex flex-col gap-4">
|
||||
<Button
|
||||
size="lg"
|
||||
className="group relative w-full overflow-hidden transition-transform hover:scale-99 active:scale-97"
|
||||
onClick={upgradePlan}
|
||||
>
|
||||
<Sparkles className="h-4 w-4" />
|
||||
|
||||
<span className="relative z-10">Upgrade to Pro</span>
|
||||
{/* Soft hover highlight effect */}
|
||||
<div className="from-primary/30 to-primary/10 absolute inset-0 bg-gradient-to-r opacity-0 transition-opacity duration-300 group-hover:opacity-100" />
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<div className="flex flex-col gap-4 py-4">
|
||||
<AuthProviderButtons action="signin" callbackURL={callbackURL} />
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
|
||||
52
apps/web/src/components/cool/plus-box.tsx
Normal file
52
apps/web/src/components/cool/plus-box.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import { Plus } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
|
||||
// I saw this on twitter and wanted to recreate it. Ill probably remove it with something cooler and less toy-like later.
|
||||
|
||||
const PlusGrid = () => {
|
||||
const cols = 15;
|
||||
const rows = 5;
|
||||
const total = cols * rows;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="grid h-full w-full"
|
||||
style={{
|
||||
gridTemplateColumns: `repeat(${cols}, 1fr)`,
|
||||
gridTemplateRows: `repeat(${rows}, 1fr)`,
|
||||
gap: "4px",
|
||||
}}
|
||||
>
|
||||
{Array.from({ length: total }).map((_, i) => (
|
||||
<HoverPlus key={i} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const HoverPlus = () => {
|
||||
const [isHovered, setHovered] = useState(false);
|
||||
|
||||
const handleEnter = () => setHovered(true);
|
||||
const handleLeave = () => setTimeout(() => setHovered(false), 500);
|
||||
|
||||
return (
|
||||
<div
|
||||
onMouseEnter={handleEnter}
|
||||
onMouseLeave={handleLeave}
|
||||
className={`flex transform items-center justify-center transition-transform duration-300 ease-out ${
|
||||
isHovered ? "scale-105 rotate-45 text-orange-400" : "scale-100 rotate-0 text-gray-500"
|
||||
}`}
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
aspectRatio: "1 / 1", // ensures perfect squares, avoids vertical overflow
|
||||
}}
|
||||
>
|
||||
{/* icon scales automatically with container */}
|
||||
<Plus className="h-[70%] w-[70%]" strokeWidth={3} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PlusGrid;
|
||||
@@ -220,7 +220,7 @@ export function FileActions({ file, fileType }: { file: File; fileType: "file" |
|
||||
{file.mimeType?.startsWith("application/vnd.google-apps.") ? (
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger className="cursor-pointer">
|
||||
<Download className="mr-2 h-4 w-4" />
|
||||
<Download className="mr-2 h-4 w-4 text-neutral-500 dark:text-neutral-400" />
|
||||
Download As...
|
||||
</DropdownMenuSubTrigger>
|
||||
<DropdownMenuPortal>
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
FileText,
|
||||
Folder,
|
||||
ImageIcon,
|
||||
Loader2,
|
||||
Music,
|
||||
Presentation,
|
||||
Video,
|
||||
@@ -26,7 +25,6 @@ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@
|
||||
import { DownloadProvider } from "@/components/providers/download-provider";
|
||||
import { useNavigate, useSearch } from "@tanstack/react-router";
|
||||
import { useDraggable, useDroppable } from "@dnd-kit/react";
|
||||
import { UploadButton } from "@/components/upload-button";
|
||||
import { pointerIntersection } from "@dnd-kit/collision";
|
||||
import DragNDropUploader from "./drag-n-drop-uploader";
|
||||
import { useMemo, useState, type JSX } from "react";
|
||||
@@ -293,13 +291,13 @@ export function FileTable({ files, isLoading, refetch, error }: FileTableProps)
|
||||
{/* h-0 is required to make the table scrollable */}
|
||||
<div className="scrollbar-thumb-rounded-full scrollbar-track-rounded-full scrollbar scrollbar-thumb-accent/70 scrollbar-track-transparent scrollbar-hover:scrollbar-thumb-accent scrollbar-w-2 scrollbar-h-2 h-0 min-h-full w-full overflow-auto overflow-y-scroll pb-5">
|
||||
<Table>
|
||||
<TableHeader className="hover:bg-transparent">
|
||||
<TableHeader className="select-none hover:bg-transparent">
|
||||
{table.getHeaderGroups().map(headerGroup => (
|
||||
<TableRow key={headerGroup.id} className="h-6 hover:bg-transparent">
|
||||
<TableRow key={headerGroup.id} className="h-6 select-none hover:bg-transparent">
|
||||
{headerGroup.headers.map(header => (
|
||||
<TableHead
|
||||
key={header.id}
|
||||
className="whitespace-nowrap"
|
||||
className="whitespace-nowrap select-none"
|
||||
style={{
|
||||
width:
|
||||
header.id === "tags" || header.id === "size" || header.id === "modifiedTime"
|
||||
@@ -313,48 +311,11 @@ export function FileTable({ files, isLoading, refetch, error }: FileTableProps)
|
||||
</TableRow>
|
||||
))}
|
||||
</TableHeader>
|
||||
{error ? (
|
||||
<TableBody>
|
||||
<TableRow className="hover:bg-transparent">
|
||||
<TableCell colSpan={columns.length} className="h-[600px]">
|
||||
<div className="flex h-full flex-col items-center justify-center gap-3">
|
||||
<h3>An error occured when getting your files. Please try again</h3>
|
||||
<Button variant="outline" onClick={refetch}>
|
||||
Try again
|
||||
</Button>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : isLoading ? (
|
||||
<TableBody>
|
||||
<TableRow className="hover:bg-transparent">
|
||||
<TableCell colSpan={columns.length} className="h-[600px]">
|
||||
<div className="flex h-full flex-col items-center justify-center gap-2">
|
||||
<Loader2 className="h-6 w-6 animate-spin" />
|
||||
<p>Loading files</p>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : table.getRowModel().rows.length === 0 ? (
|
||||
<TableBody>
|
||||
<TableRow className="hover:bg-transparent">
|
||||
<TableCell colSpan={columns.length} className="h-[600px]">
|
||||
<div className="flex h-full flex-col items-center justify-center gap-2">
|
||||
<p>No files found. Lets add one!</p>
|
||||
<UploadButton name="Add File" />
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
) : (
|
||||
<TableBody className="border-spacing-2">
|
||||
{table.getRowModel().rows.map(row => (
|
||||
<DroppableTableRow key={row.id} row={row} handleRowDoubleClick={handleRowDoubleClick} />
|
||||
))}
|
||||
</TableBody>
|
||||
)}
|
||||
<TableBody className="select-none">
|
||||
{table.getRowModel().rows.map(row => (
|
||||
<DroppableTableRow key={row.id} row={row} handleRowDoubleClick={handleRowDoubleClick} />
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</DragNDropUploader>
|
||||
|
||||
@@ -8,9 +8,9 @@ import {
|
||||
import { BoxIcon, DropboxIcon, GoogleDriveIcon, LogoIcon, OneDriveIcon, S3Icon } from "@/components/icons";
|
||||
import { useUserInfoProvider } from "@/components/providers/user-info-provider";
|
||||
import { useAccountProvider } from "@/components/providers/account-provider";
|
||||
import { useAuth } from "@/components/providers/auth-provider";
|
||||
import type { LimitedAccessAccount } from "@nimbus/shared";
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
import { useNavigate } from "@tanstack/react-router";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { ChevronsUpDown, Plus } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
@@ -37,9 +37,9 @@ export function providerToIcon(providerId: string) {
|
||||
export function SourceSelector() {
|
||||
const { accounts, isLoading } = useUserInfoProvider();
|
||||
const { providerId, accountId, setDriveProviderById } = useAccountProvider();
|
||||
const { openSignIn } = useAuth();
|
||||
const [selectedAccountNickname, setSelectedAccountNickname] = useState<string | null>(null);
|
||||
const [selectedAccountNickname, setSelectedAccountNickname] = useState(null);
|
||||
const [selectedIcon, setSelectedIcon] = useState(<LogoIcon className="h-5 w-5" />);
|
||||
const navigate = useNavigate({ from: "/dashboard/$providerSlug/$accountId" });
|
||||
|
||||
useEffect(() => {
|
||||
if (providerId && accountId) {
|
||||
@@ -114,7 +114,15 @@ export function SourceSelector() {
|
||||
</div>
|
||||
</ScrollArea>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onClick={openSignIn} className="flex cursor-pointer items-center gap-2 font-medium">
|
||||
<DropdownMenuItem
|
||||
onClick={() =>
|
||||
navigate({
|
||||
replace: true,
|
||||
search: prev => ({ ...prev, connectAccount: true }),
|
||||
})
|
||||
}
|
||||
className="flex cursor-pointer items-center gap-2 font-medium"
|
||||
>
|
||||
<Plus className="h-4 w-4" />
|
||||
<span>Add source</span>
|
||||
</DropdownMenuItem>
|
||||
|
||||
@@ -9,7 +9,7 @@ import TagMenu from "@/components/dashboard/sidebar/tag-menu";
|
||||
|
||||
export function AppSidebar({ ...props }: ComponentProps<typeof Sidebar>) {
|
||||
return (
|
||||
<Sidebar {...props} className="px-0 py-1 dark:bg-neutral-800">
|
||||
<Sidebar {...props} className="px-0 py-2 dark:bg-neutral-800">
|
||||
<SidebarHeader className="gap-4 p-2 pt-0 dark:bg-neutral-800">
|
||||
<UserAccount />
|
||||
{/* <SearchBar /> */}
|
||||
|
||||
@@ -88,7 +88,7 @@ export default function TagMenu() {
|
||||
<SidebarGroupContent>
|
||||
<SidebarMenu>
|
||||
{error ? (
|
||||
<div className="text-muted-foreground px-3 py-2 text-xs">Your tags seems empty.</div>
|
||||
<div className="text-muted-foreground px-3 py-2 text-xs">Your tags seem empty.</div>
|
||||
) : isLoading ? (
|
||||
<>
|
||||
<Skeleton className="mb-2 h-6 w-full bg-neutral-200 dark:bg-neutral-700" />
|
||||
|
||||
@@ -11,11 +11,20 @@ import { ChevronsUpDown, LogOut, Sparkles } from "lucide-react";
|
||||
import { authClient } from "@nimbus/auth/auth-client";
|
||||
import Profile from "@/components/user-profile";
|
||||
import { useSignOut } from "@/hooks/useAuth";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { toast } from "sonner";
|
||||
|
||||
async function upgradePlan() {
|
||||
const response = await authClient.checkout({
|
||||
slug: "pro",
|
||||
});
|
||||
if (response.error) {
|
||||
toast.error(response.error.message);
|
||||
}
|
||||
}
|
||||
|
||||
export default function UserAccount() {
|
||||
const { data: session, isPending } = authClient.useSession();
|
||||
const { signOut, isLoading } = useSignOut();
|
||||
const { mutate: signOut, isPending: isPendingSignOut } = useSignOut();
|
||||
|
||||
const userName = session?.user?.name;
|
||||
const userEmail = session?.user?.email;
|
||||
@@ -57,27 +66,26 @@ export default function UserAccount() {
|
||||
|
||||
<DropdownMenuItem
|
||||
// Redirect to Polar page
|
||||
className={cn(
|
||||
"flex cursor-pointer items-center gap-2 px-2 py-1.5 text-sm",
|
||||
"text-amber-600 dark:text-amber-400"
|
||||
)}
|
||||
className={"flex cursor-pointer items-center gap-2 px-2 py-1.5 text-sm"}
|
||||
onClick={upgradePlan}
|
||||
>
|
||||
<Sparkles className="h-4 w-4" />
|
||||
<Sparkles className="h-4 w-4 text-orange-500 dark:text-yellow-400" />
|
||||
Upgrade to Pro
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuSeparator />
|
||||
|
||||
<DropdownMenuItem
|
||||
onClick={() => signOut()}
|
||||
className={cn(
|
||||
"flex cursor-pointer items-center gap-2 px-2 py-1.5 text-sm",
|
||||
"text-red-400 dark:text-red-500"
|
||||
)}
|
||||
disabled={isLoading}
|
||||
onClick={() =>
|
||||
signOut({
|
||||
redirectTo: "/signin",
|
||||
})
|
||||
}
|
||||
className={"flex cursor-pointer items-center gap-2 px-2 py-1.5 text-sm"}
|
||||
disabled={isPendingSignOut}
|
||||
>
|
||||
<LogOut className="h-4 w-4" />
|
||||
<span>{isLoading ? "Signing out..." : "Sign Out"}</span>
|
||||
<LogOut className="h-4 w-4 text-red-400 dark:text-red-500" />
|
||||
<span>{isPendingSignOut ? "Signing out..." : "Sign Out"}</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import { SigninAccountDialog } from "@/components/auth/signin-account-dialog";
|
||||
import { AuthProvider, useAuth } from "@/components/providers/auth-provider";
|
||||
import { setAuthContext } from "@/utils/client";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
// This component wraps the auth provider with the sign-in dialog
|
||||
function AuthWrapper({ children }: { children: ReactNode }) {
|
||||
const { showSignIn, openSignIn, closeSignIn } = useAuth();
|
||||
|
||||
// Set the auth context so it can be accessed outside of React components
|
||||
setAuthContext({ openSignIn });
|
||||
|
||||
return (
|
||||
<>
|
||||
{children}
|
||||
<SigninAccountDialog open={showSignIn} onOpenChange={open => (open ? openSignIn() : closeSignIn())} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function AppProviders({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<AuthProvider>
|
||||
<AuthWrapper>{children}</AuthWrapper>
|
||||
</AuthProvider>
|
||||
);
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
import { createContext, useContext, useState, useCallback } from "react";
|
||||
|
||||
type AuthContextType = {
|
||||
showSignIn: boolean;
|
||||
openSignIn: () => void;
|
||||
closeSignIn: () => void;
|
||||
};
|
||||
|
||||
const AuthContext = createContext<AuthContextType | undefined>(undefined);
|
||||
|
||||
export function AuthProvider({ children }: { children: React.ReactNode }) {
|
||||
const [showSignIn, setShowSignIn] = useState(false);
|
||||
|
||||
const openSignIn = useCallback(() => setShowSignIn(true), []);
|
||||
const closeSignIn = useCallback(() => setShowSignIn(false), []);
|
||||
|
||||
return (
|
||||
<AuthContext.Provider
|
||||
value={{
|
||||
showSignIn,
|
||||
openSignIn,
|
||||
closeSignIn,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export const useAuth = () => {
|
||||
const context = useContext(AuthContext);
|
||||
if (!context) {
|
||||
throw new Error("useAuth must be used within an AuthProvider");
|
||||
}
|
||||
return context;
|
||||
};
|
||||
@@ -2,7 +2,6 @@ import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle }
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
|
||||
import { AlertCircle, Check, Edit, Loader2, Plus, X } from "lucide-react";
|
||||
import { nicknameSchema, type DriveProvider } from "@nimbus/shared";
|
||||
import { useAuth } from "@/components/providers/auth-provider";
|
||||
import type { LimitedAccessAccount } from "@nimbus/shared";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
@@ -93,21 +92,20 @@ const NicknameInput = ({
|
||||
{isSuccess ? (
|
||||
<Check className="h-4 w-4 text-green-500" />
|
||||
) : (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-6 w-6 p-0 hover:bg-transparent"
|
||||
onClick={onCancel}
|
||||
aria-label="Cancel editing"
|
||||
>
|
||||
<X className="text-muted-foreground hover:text-destructive h-4 w-4" />
|
||||
</Button>
|
||||
<div className="flex items-center gap-1">
|
||||
<span className="text-muted-foreground text-xs">{remainingChars}</span>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-6 w-6 p-0 hover:bg-transparent"
|
||||
onClick={onCancel}
|
||||
aria-label="Cancel editing"
|
||||
>
|
||||
<X className="text-muted-foreground hover:text-destructive h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{/* Character counter - positioned absolutely relative to input */}
|
||||
<div className="text-muted-foreground absolute -bottom-5 left-0 text-xs">
|
||||
{remainingChars} characters remaining
|
||||
</div>
|
||||
</div>
|
||||
{/* Error message with proper spacing */}
|
||||
{error && (
|
||||
@@ -128,7 +126,6 @@ export function ConnectedAccountsSection({
|
||||
onSetDefault,
|
||||
onUpdateAccount,
|
||||
}: ConnectedAccountsSectionProps) {
|
||||
const { openSignIn } = useAuth();
|
||||
const [editing, setEditing] = useState<EditingState | null>(null);
|
||||
const [validationError, setValidationError] = useState<string | null>(null);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
@@ -306,7 +303,12 @@ export function ConnectedAccountsSection({
|
||||
</Table>
|
||||
</CardContent>
|
||||
<CardFooter className="flex justify-between">
|
||||
<Button variant="outline" onClick={openSignIn}>
|
||||
<Button
|
||||
variant="outline"
|
||||
// onClick={
|
||||
// Implement opening the signing dialog
|
||||
// }
|
||||
>
|
||||
<Plus className="mr-2 h-4 w-4" />
|
||||
Add Account
|
||||
</Button>
|
||||
|
||||
97
apps/web/src/components/subscription/subscription-info.tsx
Normal file
97
apps/web/src/components/subscription/subscription-info.tsx
Normal file
@@ -0,0 +1,97 @@
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { CreditCard, Zap, CheckCircle2 } from "lucide-react";
|
||||
import { authClient } from "@nimbus/auth/auth-client";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { toast } from "sonner";
|
||||
|
||||
async function upgradePlan() {
|
||||
const response = await authClient.checkout({ slug: "pro" });
|
||||
if (response.error) {
|
||||
toast.error(response.error.message);
|
||||
}
|
||||
}
|
||||
|
||||
export function SubscriptionInfo() {
|
||||
const { data: subscriptions } = useQuery({
|
||||
queryKey: ["subscriptions"],
|
||||
queryFn: async () => {
|
||||
const response = await authClient.customer.subscriptions.list({
|
||||
query: { page: 1, limit: 10, active: true },
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
});
|
||||
|
||||
const planId = subscriptions?.result.items[0]?.id;
|
||||
const isPro = Boolean(planId);
|
||||
|
||||
return (
|
||||
<Card className="border-muted/30 max-w-full border shadow-sm">
|
||||
<CardHeader>
|
||||
<div className="flex items-start justify-between">
|
||||
<div>
|
||||
<CardTitle className="text-lg font-semibold">Subscription</CardTitle>
|
||||
<CardDescription>Manage your subscription and billing</CardDescription>
|
||||
</div>
|
||||
<Badge variant={isPro ? "default" : "secondary"} className="ml-auto capitalize">
|
||||
{isPro ? "Pro" : "Free"}
|
||||
</Badge>
|
||||
</div>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className="space-y-6">
|
||||
{/* Plan Summary */}
|
||||
<div className="space-y-2">
|
||||
<h3 className="text-base font-medium">{isPro ? "Pro Plan" : "Free Plan"}</h3>
|
||||
<p className="text-muted-foreground text-sm">
|
||||
{isPro
|
||||
? "You’re enjoying premium access with all features enabled."
|
||||
: "Upgrade to unlock advanced features and full control."}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Features List */}
|
||||
{!isPro && (
|
||||
<ul className="space-y-2 pl-1">
|
||||
{["1 TB of secure encrypted storage", "AI-powered file search", "Unlimited provider connections"].map(
|
||||
feature => (
|
||||
<li key={feature} className="text-muted-foreground flex items-start gap-2 text-sm">
|
||||
<CheckCircle2 className="mt-0.5 h-4 w-4 text-green-500" />
|
||||
{feature}
|
||||
</li>
|
||||
)
|
||||
)}
|
||||
</ul>
|
||||
)}
|
||||
|
||||
{/* Action Button */}
|
||||
<div className="flex w-full justify-center pt-2">
|
||||
{isPro ? (
|
||||
<Button variant="outline" className="w-3/4 transition-transform hover:scale-99 active:scale-97">
|
||||
<CreditCard className="mr-2 h-4 w-4" />
|
||||
Manage Subscription
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
onClick={upgradePlan}
|
||||
className="h-12 w-3/4 text-lg shadow-[0_0_15px_rgba(59,130,246,0.6)] transition-transform duration-300 hover:scale-99 hover:shadow-[0_0_25px_rgba(59,130,246,0.8)] active:scale-97"
|
||||
variant={"outline"}
|
||||
>
|
||||
<Zap className="mr-2 h-4 w-4 text-yellow-300" />
|
||||
Upgrade to Pro – $25/month
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Footer Text */}
|
||||
<p className="text-muted-foreground text-center text-xs">
|
||||
{isPro
|
||||
? "Manage billing and invoices in the Polar customer portal."
|
||||
: "Secure payment powered by Polar. Cancel anytime."}
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
77
apps/web/src/components/subscription/upgrade-dialog.tsx
Normal file
77
apps/web/src/components/subscription/upgrade-dialog.tsx
Normal file
@@ -0,0 +1,77 @@
|
||||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { CheckCircle2, XCircle } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
export function UpgradeDialog() {
|
||||
return (
|
||||
<Dialog>
|
||||
<DialogContent className="max-w-2xl">
|
||||
<DialogHeader>
|
||||
{/* DialogTitle is required for accessibility */}
|
||||
<DialogTitle className="text-2xl font-bold">Upgrade to Pro</DialogTitle>
|
||||
|
||||
<DialogDescription className="text-gray-600 dark:text-gray-400">
|
||||
You’ve hit the free plan limit. Unlock full power with Nimbus Pro.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="space-y-6">
|
||||
{/* Current Status */}
|
||||
<Card className="border-amber-200 bg-amber-50 dark:border-amber-900 dark:bg-amber-950/20">
|
||||
<CardContent className="pt-5">
|
||||
<div className="flex items-center gap-2 text-amber-800 dark:text-amber-200">
|
||||
<XCircle className="h-5 w-5 shrink-0" />
|
||||
<p className="font-medium">Connection limit reached — time to scale up!</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Pro Plan */}
|
||||
<div>
|
||||
<div className="flex items-baseline justify-between pb-3">
|
||||
<div>
|
||||
<h3 className="text-xl font-semibold">Nimbus Pro</h3>
|
||||
<p className="text-muted-foreground text-sm">Designed for professionals who outgrow free.</p>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<div className="flex items-baseline gap-1">
|
||||
<span className="text-3xl font-bold">$25</span>
|
||||
<span className="text-muted-foreground text-sm">/mo</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Card>
|
||||
<CardContent className="pt-5">
|
||||
<ul className="space-y-3">
|
||||
{[
|
||||
"Unlimited connections",
|
||||
"1 TB secure storage",
|
||||
"AI-powered search & insights",
|
||||
"Priority support",
|
||||
].map(feature => (
|
||||
<li key={feature} className="flex items-start gap-3">
|
||||
<CheckCircle2 className="mt-0.5 h-5 w-5 shrink-0 text-green-600 dark:text-green-400" />
|
||||
<span className="text-sm">{feature}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* CTA */}
|
||||
<div className="flex gap-3 pt-2">
|
||||
<Button variant="ghost" className="flex-1">
|
||||
Not Now
|
||||
</Button>
|
||||
<Button className="flex-1 bg-indigo-600 text-white hover:bg-indigo-700">Upgrade Now — $25/mo</Button>
|
||||
</div>
|
||||
|
||||
<p className="text-muted-foreground text-center text-xs">Secure checkout powered by Polar · Cancel anytime</p>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
@@ -46,13 +46,15 @@ const Profile = ({ className, url, name, size }: ProfileProps) => {
|
||||
|
||||
// Don't render anything on the server to avoid hydration mismatch
|
||||
if (!isMounted) {
|
||||
return <div className={cn(iconvVariants({ size }), "animate-pulse bg-gray-200 dark:bg-gray-700", className)} />;
|
||||
return (
|
||||
<div className={cn(iconvVariants({ size }), "animate-pulse bg-neutral-200 dark:bg-neutral-700", className)} />
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Avatar className={cn(iconvVariants({ size }), className)}>
|
||||
{url && <AvatarImage src={url} alt={name} />}
|
||||
<AvatarFallback className="rounded-md bg-gray-100 font-semibold text-gray-500 dark:bg-gray-800 dark:text-gray-400">
|
||||
<AvatarFallback className="rounded-md bg-neutral-100 font-semibold text-neutral-500 dark:bg-neutral-800 dark:text-neutral-400">
|
||||
{isMounted ? initials : "..."}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { type ClassValue, clsx } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import env from "@nimbus/env/client";
|
||||
|
||||
/**
|
||||
* Merges class names using clsx and tailwind-merge
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { ReactQueryProvider } from "@/components/providers/query-provider";
|
||||
import { TanStackRouterDevtools } from "@tanstack/react-router-devtools";
|
||||
import { ThemeProvider } from "@/components/providers/theme-provider";
|
||||
import { AppProviders } from "@/components/providers/app-providers";
|
||||
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
|
||||
import { createRootRoute, Outlet } from "@tanstack/react-router";
|
||||
import { geistSans, geistMono, manrope } from "@/utils/fonts";
|
||||
import { TanStackDevtools } from "@tanstack/react-devtools";
|
||||
import { Toaster } from "sonner";
|
||||
import { Suspense } from "react";
|
||||
|
||||
@@ -35,18 +33,16 @@ export const Route = createRootRoute({
|
||||
function RootComponent() {
|
||||
return (
|
||||
<ReactQueryProvider>
|
||||
<AppProviders>
|
||||
<ThemeProvider attribute="class" defaultTheme="system" enableSystem disableTransitionOnChange>
|
||||
<div
|
||||
className={`bg-background text-foreground relative min-h-screen ${geistSans.variable} ${geistMono.variable} ${manrope.variable}`}
|
||||
>
|
||||
<Suspense>
|
||||
<Outlet />
|
||||
</Suspense>
|
||||
<Toaster position="bottom-right" richColors theme="system" />
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
</AppProviders>
|
||||
<ThemeProvider attribute="class" defaultTheme="system" enableSystem disableTransitionOnChange>
|
||||
<div
|
||||
className={`bg-background text-foreground relative min-h-screen ${geistSans.variable} ${geistMono.variable} ${manrope.variable}`}
|
||||
>
|
||||
<Suspense>
|
||||
<Outlet />
|
||||
</Suspense>
|
||||
<Toaster position="bottom-right" richColors theme="system" />
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
<TanStackRouterDevtools />
|
||||
<ReactQueryDevtools />
|
||||
</ReactQueryProvider>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { SigninAccountDialog } from "@/components/auth/signin-account-dialog";
|
||||
import { AccountProvider } from "@/components/providers/account-provider";
|
||||
import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar";
|
||||
import { createFileRoute, useNavigate } from "@tanstack/react-router";
|
||||
import DndKitProvider from "@/components/providers/dnd-kit-provider";
|
||||
import { FileTable } from "@/components/dashboard/file-browser";
|
||||
import { AppSidebar } from "@/components/dashboard/sidebar";
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
import { useGetFiles } from "@/hooks/useFileOperations";
|
||||
import { Header } from "@/components/dashboard/header";
|
||||
import { Suspense } from "react";
|
||||
@@ -12,6 +13,7 @@ type DashboardSearch = {
|
||||
folderId?: string;
|
||||
type?: string;
|
||||
id?: string;
|
||||
connectAccount?: boolean;
|
||||
};
|
||||
|
||||
export const Route = createFileRoute("/_protected/dashboard/$providerSlug/$accountId")({
|
||||
@@ -21,14 +23,31 @@ export const Route = createFileRoute("/_protected/dashboard/$providerSlug/$accou
|
||||
folderId: (search.folderId as string) || undefined,
|
||||
type: (search.type as string) || undefined,
|
||||
id: (search.id as string) || undefined,
|
||||
connectAccount: (search.connectAccount as boolean) || undefined,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
function DrivePage() {
|
||||
const { folderId } = Route.useSearch();
|
||||
const { folderId, connectAccount } = Route.useSearch();
|
||||
const navigate = useNavigate({ from: "/dashboard/$providerSlug/$accountId" });
|
||||
const currentFolderId = folderId ?? "root";
|
||||
|
||||
const handleSigninOpenChange = (open: boolean) => {
|
||||
navigate({
|
||||
replace: true,
|
||||
search: prev => {
|
||||
const next = { ...prev };
|
||||
if (open) {
|
||||
next.connectAccount = true;
|
||||
} else {
|
||||
delete next.connectAccount;
|
||||
}
|
||||
return next;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const { data, isLoading, refetch, error } = useGetFiles({
|
||||
parentId: currentFolderId,
|
||||
pageSize: 30,
|
||||
@@ -47,6 +66,7 @@ function DrivePage() {
|
||||
<Header />
|
||||
<FileTable files={data || []} isLoading={isLoading} refetch={refetch} error={error} />
|
||||
</DndKitProvider>
|
||||
<SigninAccountDialog open={!!connectAccount} onOpenChange={handleSigninOpenChange} />
|
||||
</SidebarInset>
|
||||
</SidebarProvider>
|
||||
</Suspense>
|
||||
|
||||
@@ -8,8 +8,8 @@ export const Route = createFileRoute("/_protected/dashboard/")({
|
||||
|
||||
function DashboardPage() {
|
||||
const { error } = useUserInfoProvider();
|
||||
const title = "Loading your dashboard...";
|
||||
const description = "Please wait while we fetch your provider and account information.";
|
||||
const title = "Loading your dashboard";
|
||||
const description = "Searching the cloud for your files...";
|
||||
const errorTitle = "Error loading your dashboard";
|
||||
const errorDescription = "Please try again later.";
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ import { useUnlinkAccount } from "@/hooks/useUnlinkAccount";
|
||||
import { protectedClient } from "@/utils/client";
|
||||
|
||||
import { ConnectedAccountsSection } from "@/components/settings/connected-accounts-section";
|
||||
import { SubscriptionInfo } from "@/components/subscription/subscription-info";
|
||||
import { UpgradeDialog } from "@/components/subscription/upgrade-dialog";
|
||||
// import { SecuritySection } from "@/components/settings/security-section";
|
||||
import { ProfileSection } from "@/components/settings/profile-section";
|
||||
import { SettingsHeader } from "@/components/settings/header";
|
||||
@@ -158,7 +160,7 @@ function SettingsPage() {
|
||||
return (
|
||||
<div className="flex flex-1 flex-col">
|
||||
<SettingsHeader />
|
||||
<div className="container mx-auto flex-1 space-y-6 p-6">
|
||||
<div className="container mx-auto w-200 flex-1 space-y-6 p-6">
|
||||
<ProfileSection
|
||||
name={name}
|
||||
email={email}
|
||||
@@ -170,6 +172,8 @@ function SettingsPage() {
|
||||
isSaving={isSaving}
|
||||
/>
|
||||
|
||||
<SubscriptionInfo />
|
||||
|
||||
<ConnectedAccountsSection
|
||||
accounts={accounts}
|
||||
defaultAccountId={defaultAccountId}
|
||||
@@ -181,6 +185,8 @@ function SettingsPage() {
|
||||
|
||||
{/*<SecuritySection />*/}
|
||||
</div>
|
||||
|
||||
<UpgradeDialog />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { SigninFormSkeleton } from "@/components/auth/skeletons/signin-form";
|
||||
import { createFileRoute, redirect } from "@tanstack/react-router";
|
||||
import { SignInForm } from "@/components/auth/signin-form";
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
import { authClient } from "@nimbus/auth/auth-client";
|
||||
import { Suspense } from "react";
|
||||
|
||||
export const Route = createFileRoute("/_public/signin")({
|
||||
@@ -10,6 +11,13 @@ export const Route = createFileRoute("/_public/signin")({
|
||||
redirectTo: (search.redirectTo as string) || undefined,
|
||||
};
|
||||
},
|
||||
beforeLoad: async () => {
|
||||
const session = await authClient.getSession();
|
||||
console.log(session.data);
|
||||
if (session.data?.session) {
|
||||
return redirect({ to: "/dashboard" });
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
function SigninPage() {
|
||||
|
||||
163
bun.lock
163
bun.lock
@@ -3,11 +3,6 @@
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "nimbus",
|
||||
"dependencies": {
|
||||
"@tanstack/devtools-vite": "^0.3.6",
|
||||
"@tanstack/react-devtools": "^0.7.6",
|
||||
"stripe": "^19.0.0",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@changesets/cli": "^2.29.5",
|
||||
"glob": "^11.0.3",
|
||||
@@ -75,10 +70,12 @@
|
||||
"@radix-ui/react-select": "^2.2.5",
|
||||
"@radix-ui/react-separator": "^1.1.7",
|
||||
"@radix-ui/react-slot": "^1.2.3",
|
||||
"@radix-ui/react-tabs": "^1.1.12",
|
||||
"@radix-ui/react-tabs": "^1.1.13",
|
||||
"@radix-ui/react-tooltip": "^1.2.7",
|
||||
"@t3-oss/env-core": "^0.13.8",
|
||||
"@tailwindcss/postcss": "^4.1.14",
|
||||
"@tanstack/devtools-vite": "^0.3.11",
|
||||
"@tanstack/react-devtools": "^0.8.0",
|
||||
"@tanstack/react-query": "^5.83.0",
|
||||
"@tanstack/react-query-devtools": "^5.84.1",
|
||||
"@tanstack/react-router": "^1.133.25",
|
||||
@@ -119,11 +116,11 @@
|
||||
"name": "@nimbus/auth",
|
||||
"version": "0.0.4",
|
||||
"dependencies": {
|
||||
"@better-auth/stripe": "^1.3.24",
|
||||
"@nimbus/cache": "workspace:*",
|
||||
"@nimbus/db": "workspace:*",
|
||||
"@nimbus/env": "workspace:*",
|
||||
"better-auth": "^1.3.4",
|
||||
"@polar-sh/better-auth": "^1.2.0",
|
||||
"@polar-sh/sdk": "^0.40.2",
|
||||
"better-auth": "^1.3.33",
|
||||
"drizzle-orm": "^0.44.4",
|
||||
"resend": "^4.7.0",
|
||||
},
|
||||
@@ -312,11 +309,13 @@
|
||||
|
||||
"@babel/traverse": ["@babel/traverse@7.28.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", "@babel/types": "^7.28.4", "debug": "^4.3.1" } }, "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ=="],
|
||||
|
||||
"@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="],
|
||||
"@babel/types": ["@babel/types@7.28.2", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ=="],
|
||||
|
||||
"@better-auth/stripe": ["@better-auth/stripe@1.3.24", "", { "dependencies": { "zod": "^4.1.5" }, "peerDependencies": { "better-auth": "1.3.24", "stripe": "^18" } }, "sha512-7Ib0w4FRbUSgWTVljLU/H7NKZzu8l1iJ0CdZgY24qKahpNy0yoTV/tQbaUv1eQ/bw4+X46g8EpsNZsxgdwDZJQ=="],
|
||||
"@better-auth/core": ["@better-auth/core@1.3.33", "", { "dependencies": { "zod": "^4.1.5" }, "peerDependencies": { "@better-auth/utils": "0.3.0", "@better-fetch/fetch": "1.1.18", "better-call": "1.0.19", "jose": "^6.1.0", "kysely": "^0.28.5", "nanostores": "^1.0.1" } }, "sha512-QDJZwGbozYVwPIR+2Odrp+vhdSF+C4Eneh1vcoILbnQT6OdVT8egpMsa/ubisHgk7VY+P5idAE45sgdAvoG6Nw=="],
|
||||
|
||||
"@better-auth/utils": ["@better-auth/utils@0.2.6", "", { "dependencies": { "uncrypto": "^0.1.3" } }, "sha512-3y/vaL5Ox33dBwgJ6ub3OPkVqr6B5xL2kgxNHG8eHZuryLyG/4JSPGqjbdRSgjuy9kALUZYDFl+ORIAxlWMSuA=="],
|
||||
"@better-auth/telemetry": ["@better-auth/telemetry@1.3.33", "", { "dependencies": { "@better-auth/core": "1.3.33", "@better-auth/utils": "0.3.0", "@better-fetch/fetch": "1.1.18" } }, "sha512-ayeMCH4Eo3/4La3qnoVtC5cen/I3jahUHPZmdZJWCr42oVU2045n+9HVJ62uD8Ag6+AjNxAK52uo8c0WLvhvow=="],
|
||||
|
||||
"@better-auth/utils": ["@better-auth/utils@0.3.0", "", {}, "sha512-W+Adw6ZA6mgvnSnhOki270rwJ42t4XzSK6YWGF//BbVXL6SwCLWfyzBc1lN2m/4RM28KubdBKQ4X5VMoLRNPQw=="],
|
||||
|
||||
"@better-fetch/fetch": ["@better-fetch/fetch@1.1.18", "", {}, "sha512-rEFOE1MYIsBmoMJtQbl32PGHHXuG2hDxvEd7rUHE0vCBoFQVSDqaVs9hkZEtHCxRoY+CljXKFCOuJ8uxqw1LcA=="],
|
||||
|
||||
@@ -356,6 +355,8 @@
|
||||
|
||||
"@cypress/request": ["@cypress/request@3.0.9", "", { "dependencies": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", "caseless": "~0.12.0", "combined-stream": "~1.0.6", "extend": "~3.0.2", "forever-agent": "~0.6.1", "form-data": "~4.0.4", "http-signature": "~1.4.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", "json-stringify-safe": "~5.0.1", "mime-types": "~2.1.19", "performance-now": "^2.1.0", "qs": "6.14.0", "safe-buffer": "^5.1.2", "tough-cookie": "^5.0.0", "tunnel-agent": "^0.6.0", "uuid": "^8.3.2" } }, "sha512-I3l7FdGRXluAS44/0NguwWlO83J18p0vlr2FYHrJkWdNYhgVoiYo61IXPqaOsL+vNxU1ZqMACzItGK3/KKDsdw=="],
|
||||
|
||||
"@date-fns/tz": ["@date-fns/tz@1.4.1", "", {}, "sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA=="],
|
||||
|
||||
"@dnd-kit/abstract": ["@dnd-kit/abstract@0.1.21", "", { "dependencies": { "@dnd-kit/geometry": "^0.1.21", "@dnd-kit/state": "^0.1.21", "tslib": "^2.6.2" } }, "sha512-6sJut6/D21xPIK8EFMu+JJeF+fBCOmQKN1BRpeUYFi5m9P1CJpTYbBwfI107h7PHObI6a5bsckiKkRpF2orHpw=="],
|
||||
|
||||
"@dnd-kit/collision": ["@dnd-kit/collision@0.1.21", "", { "dependencies": { "@dnd-kit/abstract": "^0.1.21", "@dnd-kit/geometry": "^0.1.21", "tslib": "^2.6.2" } }, "sha512-9AJ4NbuwGDexxMCZXZyKdNQhbAe93p6C6IezQaDaWmdCqZHMHmC3+ul7pGefBQfOooSarGwIf8Bn182o9SMa1A=="],
|
||||
@@ -524,9 +525,9 @@
|
||||
|
||||
"@nimbus/web": ["@nimbus/web@workspace:apps/web"],
|
||||
|
||||
"@noble/ciphers": ["@noble/ciphers@0.6.0", "", {}, "sha512-mIbq/R9QXk5/cTfESb1OKtyFnk7oc1Om/8onA1158K9/OZUQFDEVy55jVTato+xmp3XX6F6Qh0zz0Nc1AxAlRQ=="],
|
||||
"@noble/ciphers": ["@noble/ciphers@2.0.1", "", {}, "sha512-xHK3XHPUW8DTAobU+G0XT+/w+JLM7/8k1UFdB5xg/zTFPnFCobhftzw8wl4Lw2aq/Rvir5pxfZV5fEazmeCJ2g=="],
|
||||
|
||||
"@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="],
|
||||
"@noble/hashes": ["@noble/hashes@2.0.1", "", {}, "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw=="],
|
||||
|
||||
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
|
||||
|
||||
@@ -612,12 +613,24 @@
|
||||
|
||||
"@peculiar/asn1-x509": ["@peculiar/asn1-x509@2.4.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.4.0", "asn1js": "^3.0.6", "pvtsutils": "^1.3.6", "tslib": "^2.8.1" } }, "sha512-F7mIZY2Eao2TaoVqigGMLv+NDdpwuBKU1fucHPONfzaBS4JXXCNCmfO0Z3dsy7JzKGqtDcYC1mr9JjaZQZNiuw=="],
|
||||
|
||||
"@polar-sh/better-auth": ["@polar-sh/better-auth@1.2.0", "", { "dependencies": { "@polar-sh/checkout": "^0.1.13" }, "peerDependencies": { "@polar-sh/sdk": "^0.40.2", "better-auth": "^1.3.9", "zod": "^3.24.2 || ^4" } }, "sha512-Pmy5HY1UPFvMsrFhKsHcmtzZzkrkNKQwlmqcvv9N66/rB/EUbWyLsE/wYcNtaR6AMHgNogDSXTSNngECAHuLiw=="],
|
||||
|
||||
"@polar-sh/checkout": ["@polar-sh/checkout@0.1.14", "", { "dependencies": { "@polar-sh/sdk": "^0.39.1", "@polar-sh/ui": "^0.1.2", "event-source-plus": "^0.1.12", "eventemitter3": "^5.0.1", "markdown-to-jsx": "^7.7.17", "react-hook-form": "^7.65.0" }, "peerDependencies": { "@stripe/react-stripe-js": "^3.6.0 || ^4.0.2", "@stripe/stripe-js": "^7.1.0", "react": "^18 || ^19" } }, "sha512-O5ylbVSCTXq7S+DSaC2c0m4ihb7b9ONFYpkX1WnvxEa1gnmy/DOJcqk6pjkuwb598a2frb0/WjZY+oXGoh2xhQ=="],
|
||||
|
||||
"@polar-sh/sdk": ["@polar-sh/sdk@0.40.2", "", { "dependencies": { "standardwebhooks": "^1.0.0", "zod": "^3.25.76" } }, "sha512-c6KLRAuJ4DhqBEBt2TCoGe0azXY41EuQDA3dI6FRUdhS3WzXFUJSUNiOji40qLzm4k/ey+OgKKuoZ1s7foZdnA=="],
|
||||
|
||||
"@polar-sh/ui": ["@polar-sh/ui@0.1.2", "", { "dependencies": { "@radix-ui/react-accordion": "^1.2.12", "@radix-ui/react-alert-dialog": "^1.1.15", "@radix-ui/react-checkbox": "^1.3.3", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-dropdown-menu": "^2.1.16", "@radix-ui/react-label": "^2.1.7", "@radix-ui/react-popover": "^1.1.15", "@radix-ui/react-radio-group": "^1.3.8", "@radix-ui/react-select": "^2.2.6", "@radix-ui/react-separator": "^1.1.7", "@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-switch": "^1.2.6", "@radix-ui/react-tabs": "^1.1.13", "@radix-ui/react-toast": "^1.2.15", "@radix-ui/react-toggle": "^1.1.10", "@radix-ui/react-toggle-group": "^1.1.11", "@radix-ui/react-tooltip": "^1.2.8", "@tanstack/react-table": "^8.21.3", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", "countries-list": "^3.2.0", "date-fns": "^4.1.0", "input-otp": "^1.4.2", "lucide-react": "^0.547.0", "react-day-picker": "^9.11.1", "react-hook-form": "^7.65.0", "react-timeago": "^8.3.0", "recharts": "^3.3.0", "tailwind-merge": "^3.3.1" }, "peerDependencies": { "react": "^18 || ^19", "react-dom": "^18 || ^19" } }, "sha512-YTmMB2lr+PplMTDZnTs0Crgu0KNBKyQcSX4N0FYXSlo1Q6e9IKs4hwzEcqNUv3eHS4BxGO1SvxxNjuSK+il49Q=="],
|
||||
|
||||
"@preact/signals-core": ["@preact/signals-core@1.12.1", "", {}, "sha512-BwbTXpj+9QutoZLQvbttRg5x3l5468qaV2kufh+51yha1c53ep5dY4kTuZR35+3pAZxpfQerGJiQqg34ZNZ6uA=="],
|
||||
|
||||
"@radix-ui/number": ["@radix-ui/number@1.1.1", "", {}, "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g=="],
|
||||
|
||||
"@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="],
|
||||
|
||||
"@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collapsible": "1.1.12", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA=="],
|
||||
|
||||
"@radix-ui/react-alert-dialog": ["@radix-ui/react-alert-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw=="],
|
||||
|
||||
"@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.7", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w=="],
|
||||
|
||||
"@radix-ui/react-avatar": ["@radix-ui/react-avatar@1.1.10", "", { "dependencies": { "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-is-hydrated": "0.1.0", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog=="],
|
||||
@@ -650,6 +663,8 @@
|
||||
|
||||
"@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg=="],
|
||||
|
||||
"@radix-ui/react-popover": ["@radix-ui/react-popover@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA=="],
|
||||
|
||||
"@radix-ui/react-popper": ["@radix-ui/react-popper@1.2.8", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-rect": "1.1.1", "@radix-ui/react-use-size": "1.1.1", "@radix-ui/rect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw=="],
|
||||
|
||||
"@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.9", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ=="],
|
||||
@@ -660,6 +675,8 @@
|
||||
|
||||
"@radix-ui/react-progress": ["@radix-ui/react-progress@1.1.7", "", { "dependencies": { "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg=="],
|
||||
|
||||
"@radix-ui/react-radio-group": ["@radix-ui/react-radio-group@1.3.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ=="],
|
||||
|
||||
"@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA=="],
|
||||
|
||||
"@radix-ui/react-scroll-area": ["@radix-ui/react-scroll-area@1.2.10", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A=="],
|
||||
@@ -670,8 +687,16 @@
|
||||
|
||||
"@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
|
||||
|
||||
"@radix-ui/react-switch": ["@radix-ui/react-switch@1.2.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ=="],
|
||||
|
||||
"@radix-ui/react-tabs": ["@radix-ui/react-tabs@1.1.13", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A=="],
|
||||
|
||||
"@radix-ui/react-toast": ["@radix-ui/react-toast@1.2.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g=="],
|
||||
|
||||
"@radix-ui/react-toggle": ["@radix-ui/react-toggle@1.1.10", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ=="],
|
||||
|
||||
"@radix-ui/react-toggle-group": ["@radix-ui/react-toggle-group@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-toggle": "1.1.10", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q=="],
|
||||
|
||||
"@radix-ui/react-tooltip": ["@radix-ui/react-tooltip@1.2.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg=="],
|
||||
|
||||
"@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg=="],
|
||||
@@ -852,14 +877,24 @@
|
||||
|
||||
"@solid-primitives/keyboard": ["@solid-primitives/keyboard@1.3.3", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "@solid-primitives/rootless": "^1.5.2", "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-9dQHTTgLBqyAI7aavtO+HnpTVJgWQA1ghBSrmLtMu1SMxLPDuLfuNr+Tk5udb4AL4Ojg7h9JrKOGEEDqsJXWJA=="],
|
||||
|
||||
"@solid-primitives/resize-observer": ["@solid-primitives/resize-observer@2.1.3", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "@solid-primitives/rootless": "^1.5.2", "@solid-primitives/static-store": "^0.1.2", "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-zBLje5E06TgOg93S7rGPldmhDnouNGhvfZVKOp+oG2XU8snA+GoCSSCz1M+jpNAg5Ek2EakU5UVQqL152WmdXQ=="],
|
||||
|
||||
"@solid-primitives/rootless": ["@solid-primitives/rootless@1.5.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-9HULb0QAzL2r47CCad0M+NKFtQ+LrGGNHZfteX/ThdGvKIg2o2GYhBooZubTCd/RTu2l2+Nw4s+dEfiDGvdrrQ=="],
|
||||
|
||||
"@solid-primitives/static-store": ["@solid-primitives/static-store@0.1.2", "", { "dependencies": { "@solid-primitives/utils": "^6.3.2" }, "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-ReK+5O38lJ7fT+L6mUFvUr6igFwHBESZF+2Ug842s7fvlVeBdIVEdTCErygff6w7uR6+jrr7J8jQo+cYrEq4Iw=="],
|
||||
|
||||
"@solid-primitives/utils": ["@solid-primitives/utils@6.3.2", "", { "peerDependencies": { "solid-js": "^1.6.12" } }, "sha512-hZ/M/qr25QOCcwDPOHtGjxTD8w2mNyVAYvcfgwzBHq2RwNqHNdDNsMZYap20+ruRwW4A3Cdkczyoz0TSxLCAPQ=="],
|
||||
|
||||
"@stablelib/base64": ["@stablelib/base64@1.0.1", "", {}, "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ=="],
|
||||
|
||||
"@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="],
|
||||
|
||||
"@standard-schema/utils": ["@standard-schema/utils@0.3.0", "", {}, "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g=="],
|
||||
|
||||
"@stripe/react-stripe-js": ["@stripe/react-stripe-js@4.0.2", "", { "dependencies": { "prop-types": "^15.7.2" }, "peerDependencies": { "@stripe/stripe-js": ">=1.44.1 <8.0.0", "react": ">=16.8.0 <20.0.0", "react-dom": ">=16.8.0 <20.0.0" } }, "sha512-l2wau+8/LOlHl+Sz8wQ1oDuLJvyw51nQCsu6/ljT6smqzTszcMHifjAJoXlnMfcou3+jK/kQyVe04u/ufyTXgg=="],
|
||||
|
||||
"@stripe/stripe-js": ["@stripe/stripe-js@7.9.0", "", {}, "sha512-ggs5k+/0FUJcIgNY08aZTqpBTtbExkJMYMLSMwyucrhtWexVOEY1KJmhBsxf+E/Q15f5rbwBpj+t0t2AW2oCsQ=="],
|
||||
|
||||
"@t3-oss/env-core": ["@t3-oss/env-core@0.13.8", "", { "peerDependencies": { "arktype": "^2.1.0", "typescript": ">=5.0.0", "valibot": "^1.0.0-beta.7 || ^1.0.0", "zod": "^3.24.0 || ^4.0.0-beta.0" }, "optionalPeers": ["arktype", "typescript", "valibot", "zod"] }, "sha512-L1inmpzLQyYu4+Q1DyrXsGJYCXbtXjC4cICw1uAKv0ppYPQv656lhZPU91Qd1VS6SO/bou1/q5ufVzBGbNsUpw=="],
|
||||
|
||||
"@tailwindcss/node": ["@tailwindcss/node@4.1.14", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "enhanced-resolve": "^5.18.3", "jiti": "^2.6.0", "lightningcss": "1.30.1", "magic-string": "^0.30.19", "source-map-js": "^1.2.1", "tailwindcss": "4.1.14" } }, "sha512-hpz+8vFk3Ic2xssIA3e01R6jkmsAhvkQdXlEbRTk6S10xDAtiQiM3FyvZVGsucefq764euO/b8WUW9ysLdThHw=="],
|
||||
@@ -892,17 +927,17 @@
|
||||
|
||||
"@tailwindcss/postcss": ["@tailwindcss/postcss@4.1.14", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "@tailwindcss/node": "4.1.14", "@tailwindcss/oxide": "4.1.14", "postcss": "^8.4.41", "tailwindcss": "4.1.14" } }, "sha512-BdMjIxy7HUNThK87C7BC8I1rE8BVUsfNQSI5siQ4JK3iIa3w0XyVvVL9SXLWO//CtYTcp1v7zci0fYwJOjB+Zg=="],
|
||||
|
||||
"@tanstack/devtools": ["@tanstack/devtools@0.6.20", "", { "dependencies": { "@solid-primitives/keyboard": "^1.3.3", "@tanstack/devtools-event-bus": "0.3.2", "@tanstack/devtools-ui": "0.4.2", "clsx": "^2.1.1", "goober": "^2.1.16", "solid-js": "^1.9.9" } }, "sha512-7Sw6bWvwKsHDNLg+8v7xOXhE5tzwx6/KgLWSSP55pJ86wpSXYdIm89vvXm4ED1lgKfEU5l3f4Y6QVagU4rgRiQ=="],
|
||||
"@tanstack/devtools": ["@tanstack/devtools@0.8.0", "", { "dependencies": { "@solid-primitives/event-listener": "^2.4.3", "@solid-primitives/keyboard": "^1.3.3", "@solid-primitives/resize-observer": "^2.1.3", "@tanstack/devtools-client": "0.0.4", "@tanstack/devtools-event-bus": "0.3.3", "@tanstack/devtools-ui": "0.4.4", "clsx": "^2.1.1", "goober": "^2.1.16", "solid-js": "^1.9.9" } }, "sha512-j6tBkMpAyTkiGH4ELiHzFSpV0f9fCYtAMEqTEiXEOVVfB57C36KR8LyIHtdeGzK6eQ5sKEdgLbHG9EU31L3Jng=="],
|
||||
|
||||
"@tanstack/devtools-client": ["@tanstack/devtools-client@0.0.2", "", { "dependencies": { "@tanstack/devtools-event-client": "^0.3.3" } }, "sha512-j4XPrLjaZ8GaUe9Lt0QOyfrv0Q2jy/9Og5nLQM5/cFcOLxuBp5mXR/fFrA9/9oVCIld/CxetMEac8CwayXVTHQ=="],
|
||||
"@tanstack/devtools-client": ["@tanstack/devtools-client@0.0.4", "", { "dependencies": { "@tanstack/devtools-event-client": "^0.3.4" } }, "sha512-LefnH9KE9uRDEWifc3QDcooskA8ikfs41bybDTgpYQpyTUspZnaEdUdya9Hry0KYxZ8nos0S3nNbsP79KHqr6Q=="],
|
||||
|
||||
"@tanstack/devtools-event-bus": ["@tanstack/devtools-event-bus@0.3.2", "", { "dependencies": { "ws": "^8.18.3" } }, "sha512-yJT2As/drc+Epu0nsqCsJaKaLcaNGufiNxSlp/+/oeTD0jsBxF9/PJBfh66XVpYXkKr97b8689mSu7QMef0Rrw=="],
|
||||
"@tanstack/devtools-event-bus": ["@tanstack/devtools-event-bus@0.3.3", "", { "dependencies": { "ws": "^8.18.3" } }, "sha512-lWl88uLAz7ZhwNdLH6A3tBOSEuBCrvnY9Fzr5JPdzJRFdM5ZFdyNWz1Bf5l/F3GU57VodrN0KCFi9OA26H5Kpg=="],
|
||||
|
||||
"@tanstack/devtools-event-client": ["@tanstack/devtools-event-client@0.3.3", "", {}, "sha512-RfV+OPV/M3CGryYqTue684u10jUt55PEqeBOnOtCe6tAmHI9Iqyc8nHeDhWPEV9715gShuauFVaMc9RiUVNdwg=="],
|
||||
"@tanstack/devtools-event-client": ["@tanstack/devtools-event-client@0.3.4", "", {}, "sha512-eq+PpuutUyubXu+ycC1GIiVwBs86NF/8yYJJAKSpPcJLWl6R/761F1H4F/9ziX6zKezltFUH1ah3Cz8Ah+KJrw=="],
|
||||
|
||||
"@tanstack/devtools-ui": ["@tanstack/devtools-ui@0.4.2", "", { "dependencies": { "clsx": "^2.1.1", "goober": "^2.1.16", "solid-js": "^1.9.9" } }, "sha512-xvALRLeD+TYjaLx9f9OrRBBZITAYPIk7RH8LRiESUQHw7lZO/sBU1ggrcSePh7TwKWXl9zLmtUi+7xVIS+j/dQ=="],
|
||||
"@tanstack/devtools-ui": ["@tanstack/devtools-ui@0.4.4", "", { "dependencies": { "clsx": "^2.1.1", "goober": "^2.1.16", "solid-js": "^1.9.9" } }, "sha512-5xHXFyX3nom0UaNfiOM92o6ziaHjGo3mcSGe2HD5Xs8dWRZNpdZ0Smd0B9ddEhy0oB+gXyMzZgUJb9DmrZV0Mg=="],
|
||||
|
||||
"@tanstack/devtools-vite": ["@tanstack/devtools-vite@0.3.6", "", { "dependencies": { "@babel/core": "^7.28.4", "@babel/generator": "^7.28.3", "@babel/parser": "^7.28.4", "@babel/traverse": "^7.28.4", "@babel/types": "^7.28.4", "@tanstack/devtools-client": "0.0.2", "@tanstack/devtools-event-bus": "0.3.2", "chalk": "^5.6.2", "launch-editor": "^2.11.1" }, "peerDependencies": { "vite": "^6.0.0 || ^7.0.0" } }, "sha512-OYzyRVxHvrEMJLYIicD5HekQTrQeEqVGpEEHnQuAXmZydRh4qXebUBV+XYDaz+AA6woRuAzvYXALCwBq0kNMfw=="],
|
||||
"@tanstack/devtools-vite": ["@tanstack/devtools-vite@0.3.11", "", { "dependencies": { "@babel/core": "^7.28.4", "@babel/generator": "^7.28.3", "@babel/parser": "^7.28.4", "@babel/traverse": "^7.28.4", "@babel/types": "^7.28.4", "@tanstack/devtools-client": "0.0.4", "@tanstack/devtools-event-bus": "0.3.3", "chalk": "^5.6.2", "launch-editor": "^2.11.1", "picomatch": "^4.0.3" }, "peerDependencies": { "vite": "^6.0.0 || ^7.0.0" } }, "sha512-t5jaWJNgkXOQTxuNrwkz71cN86zPZnLJY2Rz0IaMDgjb0ib1EKHeRgdqHMR/2YL96yhCHHDCHroBQXsw5Da4dg=="],
|
||||
|
||||
"@tanstack/history": ["@tanstack/history@1.133.19", "", {}, "sha512-Y866qBVVprdQkmO0/W1AFBI8tiQy398vFeIwP+VrRWCOzs3VecxSVzAvaOM4iHfkJz81fFAZMhLLjDVoPikD+w=="],
|
||||
|
||||
@@ -910,7 +945,7 @@
|
||||
|
||||
"@tanstack/query-devtools": ["@tanstack/query-devtools@5.84.0", "", {}, "sha512-fbF3n+z1rqhvd9EoGp5knHkv3p5B2Zml1yNRjh7sNXklngYI5RVIWUrUjZ1RIcEoscarUb0+bOvIs5x9dwzOXQ=="],
|
||||
|
||||
"@tanstack/react-devtools": ["@tanstack/react-devtools@0.7.6", "", { "dependencies": { "@tanstack/devtools": "0.6.20" }, "peerDependencies": { "@types/react": ">=16.8", "@types/react-dom": ">=16.8", "react": ">=16.8", "react-dom": ">=16.8" } }, "sha512-fP0jY7yed0HVIEhs+rjn8wZqABD/6TUiq6SV8jlyYP8NBK2Jfq3ce+IRw5w+N7KBzEokveLQFktxoLNpt3ZOkA=="],
|
||||
"@tanstack/react-devtools": ["@tanstack/react-devtools@0.8.0", "", { "dependencies": { "@tanstack/devtools": "0.8.0" }, "peerDependencies": { "@types/react": ">=16.8", "@types/react-dom": ">=16.8", "react": ">=16.8", "react-dom": ">=16.8" } }, "sha512-0TsFICBPr68us3iWHFXCIBSEilTo8j1OdIJLW48LNQNjC/Puno82uqX4qFuaZWfZv6K37QnS6UeRxzWJItMFSA=="],
|
||||
|
||||
"@tanstack/react-query": ["@tanstack/react-query@5.85.5", "", { "dependencies": { "@tanstack/query-core": "5.85.5" }, "peerDependencies": { "react": "^18 || ^19" } }, "sha512-/X4EFNcnPiSs8wM2v+b6DqS5mmGeuJQvxBglmDxl6ZQb5V26ouD2SJYAcC3VjbNwqhY2zjxVD15rDA5nGbMn3A=="],
|
||||
|
||||
@@ -1048,9 +1083,9 @@
|
||||
|
||||
"bcrypt-pbkdf": ["bcrypt-pbkdf@1.0.2", "", { "dependencies": { "tweetnacl": "^0.14.3" } }, "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w=="],
|
||||
|
||||
"better-auth": ["better-auth@1.3.7", "", { "dependencies": { "@better-auth/utils": "0.2.6", "@better-fetch/fetch": "^1.1.18", "@noble/ciphers": "^0.6.0", "@noble/hashes": "^1.8.0", "@simplewebauthn/browser": "^13.1.2", "@simplewebauthn/server": "^13.1.2", "better-call": "^1.0.13", "defu": "^6.1.4", "jose": "^5.10.0", "kysely": "^0.28.5", "nanostores": "^0.11.4" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0", "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["react", "react-dom"] }, "sha512-/1fEyx2SGgJQM5ujozDCh9eJksnVkNU/J7Fk/tG5Y390l8nKbrPvqiFlCjlMM+scR+UABJbQzA6An7HT50LHyQ=="],
|
||||
"better-auth": ["better-auth@1.3.33", "", { "dependencies": { "@better-auth/core": "1.3.33", "@better-auth/telemetry": "1.3.33", "@better-auth/utils": "0.3.0", "@better-fetch/fetch": "1.1.18", "@noble/ciphers": "^2.0.0", "@noble/hashes": "^2.0.0", "@simplewebauthn/browser": "^13.1.2", "@simplewebauthn/server": "^13.1.2", "better-call": "1.0.19", "defu": "^6.1.4", "jose": "^6.1.0", "kysely": "^0.28.5", "nanostores": "^1.0.1", "zod": "^4.1.5" } }, "sha512-4jKI/rbpOh/Qu4puM6sMFvqzmp2sXiZdqqcIYI7fvdb27jBjVylRG7b4nhSHUbl4zXAgsb/FSMi2Jx2sy/5EbA=="],
|
||||
|
||||
"better-call": ["better-call@1.0.16", "", { "dependencies": { "@better-fetch/fetch": "^1.1.4", "rou3": "^0.5.1", "set-cookie-parser": "^2.7.1", "uncrypto": "^0.1.3" } }, "sha512-42dgJ1rOtc0anOoxjXPOWuel/Z/4aeO7EJ2SiXNwvlkySSgjXhNjAjTMWa8DL1nt6EXS3jl3VKC3mPsU/lUgVA=="],
|
||||
"better-call": ["better-call@1.0.19", "", { "dependencies": { "@better-auth/utils": "^0.3.0", "@better-fetch/fetch": "^1.1.4", "rou3": "^0.5.1", "set-cookie-parser": "^2.7.1", "uncrypto": "^0.1.3" } }, "sha512-sI3GcA1SCVa3H+CDHl8W8qzhlrckwXOTKhqq3OOPXjgn5aTOMIqGY34zLY/pHA6tRRMjTUC3lz5Mi7EbDA24Kw=="],
|
||||
|
||||
"better-path-resolve": ["better-path-resolve@1.0.0", "", { "dependencies": { "is-windows": "^1.0.0" } }, "sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g=="],
|
||||
|
||||
@@ -1106,6 +1141,8 @@
|
||||
|
||||
"cluster-key-slot": ["cluster-key-slot@1.1.2", "", {}, "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA=="],
|
||||
|
||||
"cmdk": ["cmdk@1.1.1", "", { "dependencies": { "@radix-ui/react-compose-refs": "^1.1.1", "@radix-ui/react-dialog": "^1.1.6", "@radix-ui/react-id": "^1.1.0", "@radix-ui/react-primitive": "^2.0.2" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "react-dom": "^18 || ^19 || ^19.0.0-rc" } }, "sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg=="],
|
||||
|
||||
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
|
||||
|
||||
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
|
||||
@@ -1124,6 +1161,8 @@
|
||||
|
||||
"core-util-is": ["core-util-is@1.0.2", "", {}, "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="],
|
||||
|
||||
"countries-list": ["countries-list@3.2.0", "", {}, "sha512-HYHAo2fwEsG3TmbsNdVmIQPHizRlqeYMTtLEAl0IANG/3jRYX7p3NR6VapDqKP0n60TmsRy1dyRjVN5JbywDbA=="],
|
||||
|
||||
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
||||
|
||||
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
||||
@@ -1156,6 +1195,8 @@
|
||||
|
||||
"date-fns": ["date-fns@4.1.0", "", {}, "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg=="],
|
||||
|
||||
"date-fns-jalali": ["date-fns-jalali@4.1.0-0", "", {}, "sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg=="],
|
||||
|
||||
"debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
|
||||
|
||||
"decimal.js-light": ["decimal.js-light@2.5.1", "", {}, "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="],
|
||||
@@ -1172,6 +1213,8 @@
|
||||
|
||||
"denque": ["denque@2.1.0", "", {}, "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw=="],
|
||||
|
||||
"destr": ["destr@2.0.5", "", {}, "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA=="],
|
||||
|
||||
"detect-indent": ["detect-indent@6.1.0", "", {}, "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA=="],
|
||||
|
||||
"detect-libc": ["detect-libc@2.0.4", "", {}, "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA=="],
|
||||
@@ -1256,6 +1299,8 @@
|
||||
|
||||
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
|
||||
|
||||
"event-source-plus": ["event-source-plus@0.1.12", "", { "dependencies": { "ofetch": "^1.4.1" } }, "sha512-98wOULBKdZV9BnI2OY0wCb4VCoQmyRyESDtKPYR4l9D8hEXbfLdk0ue6va1zlYW1wqhcJHm2w9kJtUtsl9ZB9A=="],
|
||||
|
||||
"eventemitter3": ["eventemitter3@5.0.1", "", {}, "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA=="],
|
||||
|
||||
"events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="],
|
||||
@@ -1274,6 +1319,8 @@
|
||||
|
||||
"fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="],
|
||||
|
||||
"fast-sha256": ["fast-sha256@1.3.0", "", {}, "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ=="],
|
||||
|
||||
"fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
|
||||
|
||||
"fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="],
|
||||
@@ -1400,6 +1447,8 @@
|
||||
|
||||
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
|
||||
|
||||
"input-otp": ["input-otp@1.4.2", "", { "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-l3jWwYNvrEa6NTCt7BECfCm48GvwuZzkoeG3gBL2w4CHeOXW3eKFmf9UNYkNfYc3mxMrthMnxjIE07MT0zLBQA=="],
|
||||
|
||||
"internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="],
|
||||
|
||||
"iovalkey": ["iovalkey@0.3.3", "", { "dependencies": { "@iovalkey/commands": "^0.1.0", "cluster-key-slot": "^1.1.0", "debug": "^4.3.4", "denque": "^2.1.0", "lodash.defaults": "^4.2.0", "lodash.isarguments": "^3.1.0", "redis-errors": "^1.2.0", "redis-parser": "^3.0.0", "standard-as-callback": "^2.1.0" } }, "sha512-4rTJX6Q5wTYEvxboXi8DsEiUo+OvqJGtLYOSGm37KpdRXsG5XJjbVtYKGJpPSWP+QT7rWscA4vsrdmzbEbenpw=="],
|
||||
@@ -1434,7 +1483,7 @@
|
||||
|
||||
"jiti": ["jiti@2.5.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w=="],
|
||||
|
||||
"jose": ["jose@5.10.0", "", {}, "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg=="],
|
||||
"jose": ["jose@6.1.0", "", {}, "sha512-TTQJyoEoKcC1lscpVDCSsVgYzUDg/0Bt3WE//WiTPK6uOCQC2KZS4MpugbMWt/zyjkopgZoXhZuCi00gLudfUA=="],
|
||||
|
||||
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
|
||||
|
||||
@@ -1474,7 +1523,7 @@
|
||||
|
||||
"kysely": ["kysely@0.28.5", "", {}, "sha512-rlB0I/c6FBDWPcQoDtkxi9zIvpmnV5xoIalfCMSMCa7nuA6VGA3F54TW9mEgX4DVf10sXAWCF5fDbamI/5ZpKA=="],
|
||||
|
||||
"launch-editor": ["launch-editor@2.11.1", "", { "dependencies": { "picocolors": "^1.1.1", "shell-quote": "^1.8.3" } }, "sha512-SEET7oNfgSaB6Ym0jufAdCeo3meJVeCaaDyzRygy0xsp2BFKCprcfHljTq4QkzTLUxEKkFK6OK4811YM2oSrRg=="],
|
||||
"launch-editor": ["launch-editor@2.12.0", "", { "dependencies": { "picocolors": "^1.1.1", "shell-quote": "^1.8.3" } }, "sha512-giOHXoOtifjdHqUamwKq6c49GzBdLjvxrd2D+Q4V6uOHopJv7p9VJxikDsQ/CBXZbEITgUqSVHXLTG3VhPP1Dg=="],
|
||||
|
||||
"leac": ["leac@0.6.0", "", {}, "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg=="],
|
||||
|
||||
@@ -1542,6 +1591,8 @@
|
||||
|
||||
"magic-string": ["magic-string@0.30.19", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw=="],
|
||||
|
||||
"markdown-to-jsx": ["markdown-to-jsx@7.7.17", "", { "peerDependencies": { "react": ">= 0.14.0" }, "optionalPeers": ["react"] }, "sha512-7mG/1feQ0TX5I7YyMZVDgCC/y2I3CiEhIRQIhyov9nGBP5eoVrOXXHuL5ZP8GRfxVZKRiXWJgwXkb9It+nQZfQ=="],
|
||||
|
||||
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
|
||||
|
||||
"merge-options": ["merge-options@3.0.4", "", { "dependencies": { "is-plain-obj": "^2.1.0" } }, "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ=="],
|
||||
@@ -1578,7 +1629,7 @@
|
||||
|
||||
"nanoid": ["nanoid@5.1.5", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw=="],
|
||||
|
||||
"nanostores": ["nanostores@0.11.4", "", {}, "sha512-k1oiVNN4hDK8NcNERSZLQiMfRzEGtfnvZvdBvey3SQbgn8Dcrk0h1I6vpxApjb10PFUflZrgJ2WEZyJQ+5v7YQ=="],
|
||||
"nanostores": ["nanostores@1.0.1", "", {}, "sha512-kNZ9xnoJYKg/AfxjrVL4SS0fKX++4awQReGqWnwTRHxeHGZ1FJFVgTqr/eMrNQdp0Tz7M7tG/TDaX8QfHDwVCw=="],
|
||||
|
||||
"napi-postinstall": ["napi-postinstall@0.3.3", "", { "bin": { "napi-postinstall": "lib/cli.js" } }, "sha512-uTp172LLXSxuSYHv/kou+f6KW3SMppU9ivthaVTXian9sOt3XM/zHYHpRZiLgQoxeWfYUnslNWQHF1+G71xcow=="],
|
||||
|
||||
@@ -1592,6 +1643,8 @@
|
||||
|
||||
"node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="],
|
||||
|
||||
"node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="],
|
||||
|
||||
"node-releases": ["node-releases@2.0.23", "", {}, "sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg=="],
|
||||
|
||||
"normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
|
||||
@@ -1602,6 +1655,8 @@
|
||||
|
||||
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
|
||||
|
||||
"ofetch": ["ofetch@1.5.0", "", { "dependencies": { "destr": "^2.0.5", "node-fetch-native": "^1.6.7", "ufo": "^1.6.1" } }, "sha512-A7llJ7eZyziA5xq9//3ZurA8OhFqtS99K5/V1sLBJ5j137CM/OAjlbA/TEJXBuOWwOfLqih+oH5U3ran4za1FQ=="],
|
||||
|
||||
"onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="],
|
||||
|
||||
"optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
|
||||
@@ -1718,11 +1773,13 @@
|
||||
|
||||
"react": ["react@19.1.1", "", {}, "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ=="],
|
||||
|
||||
"react-day-picker": ["react-day-picker@9.11.1", "", { "dependencies": { "@date-fns/tz": "^1.4.1", "date-fns": "^4.1.0", "date-fns-jalali": "^4.1.0-0" }, "peerDependencies": { "react": ">=16.8.0" } }, "sha512-l3ub6o8NlchqIjPKrRFUCkTUEq6KwemQlfv3XZzzwpUeGwmDJ+0u0Upmt38hJyd7D/vn2dQoOoLV/qAp0o3uUw=="],
|
||||
|
||||
"react-dom": ["react-dom@19.1.1", "", { "dependencies": { "scheduler": "^0.26.0" }, "peerDependencies": { "react": "^19.1.1" } }, "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw=="],
|
||||
|
||||
"react-dropzone": ["react-dropzone@14.3.8", "", { "dependencies": { "attr-accept": "^2.2.4", "file-selector": "^2.1.0", "prop-types": "^15.8.1" }, "peerDependencies": { "react": ">= 16.8 || 18.0.0" } }, "sha512-sBgODnq+lcA4P296DY4wacOZz3JFpD99fp+hb//iBO2HHnyeZU3FwWyXJ6salNpqQdsZrgMrotuko/BdJMV8Ug=="],
|
||||
|
||||
"react-hook-form": ["react-hook-form@7.62.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17 || ^18 || ^19" } }, "sha512-7KWFejc98xqG/F4bAxpL41NB3o1nnvQO1RWZT3TqRZYL8RryQETGfEdVnJN2fy1crCiBLLjkRBVK05j24FxJGA=="],
|
||||
"react-hook-form": ["react-hook-form@7.65.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17 || ^18 || ^19" } }, "sha512-xtOzDz063WcXvGWaHgLNrNzlsdFgtUWcb32E6WFaGTd7kPZG3EeDusjdZfUsPwKCKVXy1ZlntifaHZ4l8pAsmw=="],
|
||||
|
||||
"react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="],
|
||||
|
||||
@@ -1738,6 +1795,8 @@
|
||||
|
||||
"react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="],
|
||||
|
||||
"react-timeago": ["react-timeago@8.3.0", "", { "peerDependencies": { "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-BeR0hj/5qqTc2+zxzBSQZMky6MmqwOtKseU3CSmcjKR5uXerej2QY34v2d+cdz11PoeVfAdWLX+qjM/UdZkUUg=="],
|
||||
|
||||
"read-yaml-file": ["read-yaml-file@1.1.0", "", { "dependencies": { "graceful-fs": "^4.1.5", "js-yaml": "^3.6.1", "pify": "^4.0.1", "strip-bom": "^3.0.0" } }, "sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA=="],
|
||||
|
||||
"readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="],
|
||||
@@ -1746,7 +1805,7 @@
|
||||
|
||||
"recast": ["recast@0.23.11", "", { "dependencies": { "ast-types": "^0.16.1", "esprima": "~4.0.0", "source-map": "~0.6.1", "tiny-invariant": "^1.3.3", "tslib": "^2.0.1" } }, "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA=="],
|
||||
|
||||
"recharts": ["recharts@3.1.2", "", { "dependencies": { "@reduxjs/toolkit": "1.x.x || 2.x.x", "clsx": "^2.1.1", "decimal.js-light": "^2.5.1", "es-toolkit": "^1.39.3", "eventemitter3": "^5.0.1", "immer": "^10.1.1", "react-redux": "8.x.x || 9.x.x", "reselect": "5.1.1", "tiny-invariant": "^1.3.3", "use-sync-external-store": "^1.2.2", "victory-vendor": "^37.0.2" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-vhNbYwaxNbk/IATK0Ki29k3qvTkGqwvCgyQAQ9MavvvBwjvKnMTswdbklJpcOAoMPN/qxF3Lyqob0zO+ZXkZ4g=="],
|
||||
"recharts": ["recharts@3.3.0", "", { "dependencies": { "@reduxjs/toolkit": "1.x.x || 2.x.x", "clsx": "^2.1.1", "decimal.js-light": "^2.5.1", "es-toolkit": "^1.39.3", "eventemitter3": "^5.0.1", "immer": "^10.1.1", "react-redux": "8.x.x || 9.x.x", "reselect": "5.1.1", "tiny-invariant": "^1.3.3", "use-sync-external-store": "^1.2.2", "victory-vendor": "^37.0.2" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Vi0qmTB0iz1+/Cz9o5B7irVyUjX2ynvEgImbgMt/3sKRREcUM07QiYjS1QpAVrkmVlXqy5gykq4nGWMz9AS4Rg=="],
|
||||
|
||||
"redis-errors": ["redis-errors@1.2.0", "", {}, "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w=="],
|
||||
|
||||
@@ -1840,6 +1899,8 @@
|
||||
|
||||
"standard-as-callback": ["standard-as-callback@2.1.0", "", {}, "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A=="],
|
||||
|
||||
"standardwebhooks": ["standardwebhooks@1.0.0", "", { "dependencies": { "@stablelib/base64": "^1.0.0", "fast-sha256": "^1.3.0" } }, "sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg=="],
|
||||
|
||||
"stream-browserify": ["stream-browserify@3.0.0", "", { "dependencies": { "inherits": "~2.0.4", "readable-stream": "^3.5.0" } }, "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA=="],
|
||||
|
||||
"string-argv": ["string-argv@0.3.2", "", {}, "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q=="],
|
||||
@@ -1858,8 +1919,6 @@
|
||||
|
||||
"strip-json-comments": ["strip-json-comments@5.0.2", "", {}, "sha512-4X2FR3UwhNUE9G49aIsJW5hRRR3GXGTBTZRMfv568O60ojM8HcWjV/VxAxCDW3SUND33O6ZY66ZuRcdkj73q2g=="],
|
||||
|
||||
"stripe": ["stripe@19.0.0", "", { "dependencies": { "qs": "^6.11.0" }, "peerDependencies": { "@types/node": ">=16" }, "optionalPeers": ["@types/node"] }, "sha512-4HG17r7mui4Awic75DVSFVmH4EIXqNvoo3T2cYrVhcwovQz3gzQIPUiqzLzGcgxdUd9CB8zCntKzm0o63tUBgw=="],
|
||||
|
||||
"strnum": ["strnum@2.1.1", "", {}, "sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw=="],
|
||||
|
||||
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
|
||||
@@ -1920,6 +1979,8 @@
|
||||
|
||||
"typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],
|
||||
|
||||
"ufo": ["ufo@1.6.1", "", {}, "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA=="],
|
||||
|
||||
"uncrypto": ["uncrypto@0.1.3", "", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="],
|
||||
|
||||
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
|
||||
@@ -1992,14 +2053,36 @@
|
||||
|
||||
"@aws-crypto/util/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="],
|
||||
|
||||
"@babel/core/@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="],
|
||||
|
||||
"@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||
|
||||
"@babel/generator/@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="],
|
||||
|
||||
"@babel/helper-annotate-as-pure/@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="],
|
||||
|
||||
"@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
|
||||
|
||||
"@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||
|
||||
"@babel/helper-create-class-features-plugin/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||
|
||||
"@babel/helper-member-expression-to-functions/@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="],
|
||||
|
||||
"@babel/helper-module-imports/@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="],
|
||||
|
||||
"@babel/helper-optimise-call-expression/@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="],
|
||||
|
||||
"@babel/helper-skip-transparent-expression-wrappers/@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="],
|
||||
|
||||
"@babel/helpers/@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="],
|
||||
|
||||
"@babel/parser/@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="],
|
||||
|
||||
"@babel/template/@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="],
|
||||
|
||||
"@babel/traverse/@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="],
|
||||
|
||||
"@changesets/apply-release-plan/prettier": ["prettier@2.8.8", "", { "bin": { "prettier": "bin-prettier.js" } }, "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q=="],
|
||||
|
||||
"@changesets/parse/js-yaml": ["js-yaml@3.14.1", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g=="],
|
||||
@@ -2034,6 +2117,12 @@
|
||||
|
||||
"@manypkg/get-packages/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="],
|
||||
|
||||
"@polar-sh/checkout/@polar-sh/sdk": ["@polar-sh/sdk@0.39.1", "", { "dependencies": { "standardwebhooks": "^1.0.0", "zod": "^3.25.76" } }, "sha512-PSWnp2EX+guVxtLyUwk2hCgsV/FTOXf+nI33xXwAGHyakACEmJOIeHMxlja++t4YVHf+5GZouT9iYE1yxnmIjQ=="],
|
||||
|
||||
"@polar-sh/sdk/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
|
||||
|
||||
"@polar-sh/ui/lucide-react": ["lucide-react@0.547.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-YLChGBWKq8ynr1UWP8WWRPhHhyuBAXfSBnHSgfoj51L//9TU3d0zvxpigf5C1IJ4vnEoTzthl5awPK55PiZhdA=="],
|
||||
|
||||
"@tailwindcss/node/jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.5.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg=="],
|
||||
@@ -2048,6 +2137,8 @@
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"@tanstack/devtools-vite/@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="],
|
||||
|
||||
"@tanstack/devtools-vite/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
|
||||
|
||||
"@tanstack/react-router/@tanstack/router-core": ["@tanstack/router-core@1.133.25", "", { "dependencies": { "@tanstack/history": "1.133.19", "@tanstack/store": "^0.7.0", "cookie-es": "^2.0.0", "seroval": "^1.3.2", "seroval-plugins": "^1.3.2", "tiny-invariant": "^1.3.3", "tiny-warning": "^1.0.3" } }, "sha512-u3lBGKsGbt0i66qTBaqMCGPnE9yZrxeMi2Al3ZRaikOmSnTeuxXExbX+QAW4cI6GtFigdI3Ec8KW5M29Uft7Hg=="],
|
||||
@@ -2060,15 +2151,17 @@
|
||||
|
||||
"@tanstack/router-generator/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
|
||||
|
||||
"@tanstack/router-plugin/@babel/types": ["@babel/types@7.28.2", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ=="],
|
||||
|
||||
"@tanstack/router-plugin/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
|
||||
|
||||
"@tanstack/router-utils/tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
|
||||
|
||||
"@types/babel__core/@babel/parser": ["@babel/parser@7.28.3", "", { "dependencies": { "@babel/types": "^7.28.2" }, "bin": "./bin/babel-parser.js" }, "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA=="],
|
||||
|
||||
"@types/babel__core/@babel/types": ["@babel/types@7.28.2", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ=="],
|
||||
"@types/babel__generator/@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="],
|
||||
|
||||
"@types/babel__template/@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="],
|
||||
|
||||
"@types/babel__traverse/@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="],
|
||||
|
||||
"@types/node-fetch/@types/node": ["@types/node@24.3.0", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow=="],
|
||||
|
||||
@@ -2076,6 +2169,8 @@
|
||||
|
||||
"anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||
|
||||
"babel-dead-code-elimination/@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="],
|
||||
|
||||
"box-node-sdk/@types/node": ["@types/node@18.19.123", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-K7DIaHnh0mzVxreCR9qwgNxp3MH9dltPNIEddW9MYUlcKAzm+3grKNSTe2vCJHI1FaLpvpL5JGJrz1UZDKYvDg=="],
|
||||
|
||||
"chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||
@@ -2200,6 +2295,8 @@
|
||||
|
||||
"@manypkg/find-root/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="],
|
||||
|
||||
"@polar-sh/checkout/@polar-sh/sdk/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
|
||||
|
||||
"@tanstack/react-router-devtools/vite/tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
|
||||
|
||||
"@tanstack/router-devtools-core/vite/tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
|
||||
|
||||
@@ -42,10 +42,5 @@
|
||||
"workspaces": [
|
||||
"apps/*",
|
||||
"packages/*"
|
||||
],
|
||||
"dependencies": {
|
||||
"@tanstack/devtools-vite": "^0.3.6",
|
||||
"@tanstack/react-devtools": "^0.7.6",
|
||||
"stripe": "^19.0.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
"./auth": "./src/auth.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@better-auth/stripe": "^1.3.24",
|
||||
"@nimbus/cache": "workspace:*",
|
||||
"@nimbus/db": "workspace:*",
|
||||
"@nimbus/env": "workspace:*",
|
||||
"better-auth": "^1.3.4",
|
||||
"@polar-sh/better-auth": "^1.2.0",
|
||||
"@polar-sh/sdk": "^0.40.2",
|
||||
"better-auth": "^1.3.33",
|
||||
"drizzle-orm": "^0.44.4",
|
||||
"resend": "^4.7.0"
|
||||
}
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
import { genericOAuthClient } from "better-auth/client/plugins";
|
||||
import { stripeClient } from "@better-auth/stripe/client";
|
||||
import { createAuthClient } from "better-auth/react";
|
||||
import { polarClient } from "@polar-sh/better-auth";
|
||||
import env from "@nimbus/env/client";
|
||||
|
||||
export const authClient = createAuthClient({
|
||||
baseURL: env.VITE_BACKEND_URL,
|
||||
callbackUrl: `${env.VITE_FRONTEND_URL}/dashboard`,
|
||||
plugins: [
|
||||
genericOAuthClient(),
|
||||
stripeClient({
|
||||
subscription: true, //if you want to enable subscription management
|
||||
}),
|
||||
],
|
||||
plugins: [genericOAuthClient(), polarClient()],
|
||||
});
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
import schema, { user as userTable, account as accountTable } from "@nimbus/db/schema";
|
||||
import { type Account, type AuthContext, betterAuth } from "better-auth";
|
||||
import { polar, checkout, portal } from "@polar-sh/better-auth";
|
||||
import { drizzleAdapter } from "better-auth/adapters/drizzle";
|
||||
// import { cacheClient, type CacheClient } from "@nimbus/cache";
|
||||
import { stripe } from "@better-auth/stripe";
|
||||
// import { genericOAuth } from "better-auth/plugins";
|
||||
import { sendMail } from "./utils/send-mail";
|
||||
import { env } from "@nimbus/env/server";
|
||||
import { db, type DB } from "@nimbus/db";
|
||||
import { Polar } from "@polar-sh/sdk";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { Resend } from "resend";
|
||||
import Stripe from "stripe";
|
||||
|
||||
const stripeClient = new Stripe(env.STRIPE_SECRET_KEY!, {
|
||||
apiVersion: "2025-08-27.basil",
|
||||
const polarClient = new Polar({
|
||||
accessToken: env.POLAR_ACCESS_TOKEN,
|
||||
server: "sandbox",
|
||||
});
|
||||
|
||||
// TODO: add rate limiting
|
||||
@@ -115,10 +116,22 @@ export const auth = betterAuth({
|
||||
},
|
||||
|
||||
plugins: [
|
||||
stripe({
|
||||
stripeClient,
|
||||
stripeWebhookSecret: env.STRIPE_WEBHOOK_SECRET,
|
||||
polar({
|
||||
client: polarClient,
|
||||
createCustomerOnSignUp: true,
|
||||
use: [
|
||||
checkout({
|
||||
products: [
|
||||
{
|
||||
productId: env.POLAR_PRO_PRODUCT_ID,
|
||||
slug: "pro",
|
||||
},
|
||||
],
|
||||
successUrl: "http://localhost:3000/dashboard?success=true&checkout_id={CHECKOUT_ID}",
|
||||
authenticatedUsersOnly: true,
|
||||
}),
|
||||
portal(),
|
||||
],
|
||||
}),
|
||||
// genericOAuth({
|
||||
// config: [
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { boolean, foreignKey, index, integer, pgTable, text, timestamp } from "drizzle-orm/pg-core";
|
||||
import { boolean, foreignKey, index, pgTable, text, timestamp } from "drizzle-orm/pg-core";
|
||||
|
||||
const defaultTimestamp = (name: string) =>
|
||||
timestamp(name)
|
||||
@@ -17,7 +17,6 @@ export const user = pgTable("user", {
|
||||
// references account.accountId and account.providerId. Is set via better-auth database hook after account creation
|
||||
defaultAccountId: text("default_account_id"),
|
||||
defaultProviderId: text("default_provider_id"),
|
||||
stripeCustomerId: text("stripe_customer_id"),
|
||||
createdAt: defaultTimestamp("created_at"),
|
||||
updatedAt: defaultTimestamp("updated_at"),
|
||||
});
|
||||
@@ -70,43 +69,6 @@ export const account = pgTable(
|
||||
]
|
||||
);
|
||||
|
||||
// Subscription schema
|
||||
export const subscription = pgTable(
|
||||
"subscription",
|
||||
{
|
||||
id: text("id").primaryKey(),
|
||||
plan: text("plan").notNull(),
|
||||
|
||||
// Typically user ID, but could support teams/orgs later
|
||||
referenceId: text("reference_id").notNull(),
|
||||
|
||||
stripeCustomerId: text("stripe_customer_id"),
|
||||
stripeSubscriptionId: text("stripe_subscription_id"),
|
||||
|
||||
status: text("status").notNull(),
|
||||
|
||||
periodStart: timestamp("period_start"),
|
||||
periodEnd: timestamp("period_end"),
|
||||
cancelAtPeriodEnd: boolean("cancel_at_period_end").$defaultFn(() => false),
|
||||
|
||||
seats: integer("seats"),
|
||||
|
||||
trialStart: timestamp("trial_start"),
|
||||
trialEnd: timestamp("trial_end"),
|
||||
|
||||
createdAt: defaultTimestamp("created_at"),
|
||||
updatedAt: defaultTimestamp("updated_at"),
|
||||
},
|
||||
table => [
|
||||
index("subscription_reference_id_idx").using("btree", table.referenceId.asc().nullsLast().op("text_ops")),
|
||||
foreignKey({
|
||||
columns: [table.referenceId],
|
||||
foreignColumns: [user.id],
|
||||
name: "subscription_reference_id_user_id_fk",
|
||||
}).onDelete("cascade"),
|
||||
]
|
||||
);
|
||||
|
||||
export const verification = pgTable("verification", {
|
||||
id: text("id").primaryKey(),
|
||||
identifier: text("identifier").notNull(),
|
||||
|
||||
7
packages/env/server.ts
vendored
7
packages/env/server.ts
vendored
@@ -67,11 +67,10 @@ export const env = createEnv({
|
||||
VALKEY_USERNAME: z.string(),
|
||||
VALKEY_PASSWORD: z.string(),
|
||||
|
||||
// Stripe
|
||||
STRIPE_SECRET_KEY: z.string(),
|
||||
STRIPE_WEBHOOK_SECRET: z.string(),
|
||||
|
||||
ENCRYPTION_KEY: z.string(),
|
||||
POLAR_ACCESS_TOKEN: z.string(),
|
||||
POLAR_SUCCESS_URL: z.url(),
|
||||
POLAR_PRO_PRODUCT_ID: z.string(),
|
||||
},
|
||||
|
||||
runtimeEnv: process.env,
|
||||
|
||||
Reference in New Issue
Block a user