a homebrewed DnD campaign based in the Honkai: Star Rail universe
hsr honkaistarrail dnd

feat: implement password-based auth (#112)

There's still a lot of things that can be polished up, but they can be done in followup patches

authored by samanthanguyen.me and committed by

GitHub e8eef55f c4462f04

+2424 -470
+3
app/.env.example
··· 3 3 PUBLIC_SUPABASE_PUBLISHABLE_KEY= 4 4 DISCORD_CLIENT_ID= 5 5 DISCORD_CLIENT_SECRET= 6 + GOOGLE_CLIENT_ID= 7 + GOOGLE_CLIENT_SECRET= 8 + RESEND_KEY=
+16
app/components.json
··· 1 + { 2 + "$schema": "https://shadcn-svelte.com/schema.json", 3 + "tailwind": { 4 + "css": "src/app.css", 5 + "baseColor": "slate" 6 + }, 7 + "aliases": { 8 + "components": "$lib/components", 9 + "utils": "$lib/utils", 10 + "ui": "$lib/components/ui", 11 + "hooks": "$lib/hooks", 12 + "lib": "$lib" 13 + }, 14 + "typescript": true, 15 + "registry": "https://shadcn-svelte.com/registry" 16 + }
+10 -6
app/package.json
··· 24 24 }, 25 25 "dependencies": { 26 26 "@lucide/svelte": "catalog:svelte", 27 - "@starlight/color": "workspace:../packages/color", 28 - "@starlight/icons": "workspace:../packages/icons", 29 - "@starlight/storybook-utils": "workspace:../packages/storybook-utils", 30 - "@starlight/tokenizer": "workspace:../packages/tokenizer", 31 - "@starlight/types": "workspace:../packages/types", 27 + "@starlight/color": "link:../packages/color", 28 + "@starlight/icons": "link:../packages/icons", 29 + "@starlight/storybook-utils": "link:../packages/storybook-utils", 30 + "@starlight/tokenizer": "link:../packages/tokenizer", 31 + "@starlight/types": "link:../packages/types", 32 32 "@supabase/ssr": "catalog:app", 33 33 "@supabase/supabase-js": "catalog:app", 34 34 "bits-ui": "catalog:svelte", 35 35 "clsx": "catalog:tailwind", 36 36 "lorem-ipsum": "catalog:app", 37 37 "mode-watcher": "catalog:svelte", 38 + "sveltekit-superforms": "catalog:svelte", 38 39 "tailwind-merge": "catalog:tailwind", 39 - "tailwind-variants": "catalog:tailwind" 40 + "tailwind-variants": "catalog:tailwind", 41 + "tw-animate-css": "catalog:tailwind", 42 + "zod": "catalog:app" 40 43 }, 41 44 "devDependencies": { 42 45 "@sveltejs/adapter-cloudflare": "catalog:svelte", ··· 49 52 "lightningcss": "catalog:voidzero", 50 53 "mdsvex": "catalog:svelte", 51 54 "playwright": "catalog:voidzero", 55 + "resend": "catalog:app", 52 56 "supabase": "catalog:app", 53 57 "svelte": "catalog:svelte", 54 58 "svelte-check": "catalog:svelte",
+120
app/src/app.css
··· 1 1 @import 'tailwindcss'; 2 + @import 'tw-animate-css'; 2 3 @source './../../node_modules/@starlight/icons'; 4 + 5 + @custom-variant dark (&:is(.dark *)); 3 6 4 7 @theme { 5 8 --color-hsr-gold: #9f7755; ··· 79 82 @utility max-w-120ch { 80 83 max-width: 120ch; 81 84 } 85 + 86 + :root { 87 + --radius: 0.625rem; 88 + --background: oklch(1 0 0); 89 + --foreground: oklch(0.129 0.042 264.695); 90 + --card: oklch(1 0 0); 91 + --card-foreground: oklch(0.129 0.042 264.695); 92 + --popover: oklch(1 0 0); 93 + --popover-foreground: oklch(0.129 0.042 264.695); 94 + --primary: oklch(0.208 0.042 265.755); 95 + --primary-foreground: oklch(0.984 0.003 247.858); 96 + --secondary: oklch(0.968 0.007 247.896); 97 + --secondary-foreground: oklch(0.208 0.042 265.755); 98 + --muted: oklch(0.968 0.007 247.896); 99 + --muted-foreground: oklch(0.554 0.046 257.417); 100 + --accent: oklch(0.968 0.007 247.896); 101 + --accent-foreground: oklch(0.208 0.042 265.755); 102 + --destructive: oklch(0.577 0.245 27.325); 103 + --border: oklch(0.929 0.013 255.508); 104 + --input: oklch(0.929 0.013 255.508); 105 + --ring: oklch(0.704 0.04 256.788); 106 + --chart-1: oklch(0.646 0.222 41.116); 107 + --chart-2: oklch(0.6 0.118 184.704); 108 + --chart-3: oklch(0.398 0.07 227.392); 109 + --chart-4: oklch(0.828 0.189 84.429); 110 + --chart-5: oklch(0.769 0.188 70.08); 111 + --sidebar: oklch(0.984 0.003 247.858); 112 + --sidebar-foreground: oklch(0.129 0.042 264.695); 113 + --sidebar-primary: oklch(0.208 0.042 265.755); 114 + --sidebar-primary-foreground: oklch(0.984 0.003 247.858); 115 + --sidebar-accent: oklch(0.968 0.007 247.896); 116 + --sidebar-accent-foreground: oklch(0.208 0.042 265.755); 117 + --sidebar-border: oklch(0.929 0.013 255.508); 118 + --sidebar-ring: oklch(0.704 0.04 256.788); 119 + } 120 + 121 + .dark { 122 + --background: oklch(0.129 0.042 264.695); 123 + --foreground: oklch(0.984 0.003 247.858); 124 + --card: oklch(0.208 0.042 265.755); 125 + --card-foreground: oklch(0.984 0.003 247.858); 126 + --popover: oklch(0.208 0.042 265.755); 127 + --popover-foreground: oklch(0.984 0.003 247.858); 128 + --primary: oklch(0.929 0.013 255.508); 129 + --primary-foreground: oklch(0.208 0.042 265.755); 130 + --secondary: oklch(0.279 0.041 260.031); 131 + --secondary-foreground: oklch(0.984 0.003 247.858); 132 + --muted: oklch(0.279 0.041 260.031); 133 + --muted-foreground: oklch(0.704 0.04 256.788); 134 + --accent: oklch(0.279 0.041 260.031); 135 + --accent-foreground: oklch(0.984 0.003 247.858); 136 + --destructive: oklch(0.704 0.191 22.216); 137 + --border: oklch(1 0 0 / 10%); 138 + --input: oklch(1 0 0 / 15%); 139 + --ring: oklch(0.551 0.027 264.364); 140 + --chart-1: oklch(0.488 0.243 264.376); 141 + --chart-2: oklch(0.696 0.17 162.48); 142 + --chart-3: oklch(0.769 0.188 70.08); 143 + --chart-4: oklch(0.627 0.265 303.9); 144 + --chart-5: oklch(0.645 0.246 16.439); 145 + --sidebar: oklch(0.208 0.042 265.755); 146 + --sidebar-foreground: oklch(0.984 0.003 247.858); 147 + --sidebar-primary: oklch(0.488 0.243 264.376); 148 + --sidebar-primary-foreground: oklch(0.984 0.003 247.858); 149 + --sidebar-accent: oklch(0.279 0.041 260.031); 150 + --sidebar-accent-foreground: oklch(0.984 0.003 247.858); 151 + --sidebar-border: oklch(1 0 0 / 10%); 152 + --sidebar-ring: oklch(0.551 0.027 264.364); 153 + } 154 + 155 + @theme inline { 156 + --radius-sm: calc(var(--radius) - 4px); 157 + --radius-md: calc(var(--radius) - 2px); 158 + --radius-lg: var(--radius); 159 + --radius-xl: calc(var(--radius) + 4px); 160 + --color-background: var(--background); 161 + --color-foreground: var(--foreground); 162 + --color-card: var(--card); 163 + --color-card-foreground: var(--card-foreground); 164 + --color-popover: var(--popover); 165 + --color-popover-foreground: var(--popover-foreground); 166 + --color-primary: var(--primary); 167 + --color-primary-foreground: var(--primary-foreground); 168 + --color-secondary: var(--secondary); 169 + --color-secondary-foreground: var(--secondary-foreground); 170 + --color-muted: var(--muted); 171 + --color-muted-foreground: var(--muted-foreground); 172 + --color-accent: var(--accent); 173 + --color-accent-foreground: var(--accent-foreground); 174 + --color-destructive: var(--destructive); 175 + --color-border: var(--border); 176 + --color-input: var(--input); 177 + --color-ring: var(--ring); 178 + --color-chart-1: var(--chart-1); 179 + --color-chart-2: var(--chart-2); 180 + --color-chart-3: var(--chart-3); 181 + --color-chart-4: var(--chart-4); 182 + --color-chart-5: var(--chart-5); 183 + --color-sidebar: var(--sidebar); 184 + --color-sidebar-foreground: var(--sidebar-foreground); 185 + --color-sidebar-primary: var(--sidebar-primary); 186 + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); 187 + --color-sidebar-accent: var(--sidebar-accent); 188 + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); 189 + --color-sidebar-border: var(--sidebar-border); 190 + --color-sidebar-ring: var(--sidebar-ring); 191 + } 192 + 193 + @layer base { 194 + * { 195 + @apply border-border outline-ring/50; 196 + } 197 + 198 + body { 199 + @apply bg-background text-foreground; 200 + } 201 + }
+2 -1
app/src/app.d.ts
··· 1 1 // oxlint-disable typescript/consistent-type-definitions 2 2 import type { Session, SupabaseClient, User } from '@supabase/supabase-js' 3 3 import type { Database } from './database.types.ts' // import generated types 4 + import type { DbClient } from '$lib/utils' 4 5 5 6 declare global { 6 7 namespace App { 7 8 // interface Error {} 8 9 9 10 interface Locals { 10 - supabase: SupabaseClient<Database> 11 + supabase: DbClient 11 12 safeGetSession: () => Promise<{ 12 13 session: Session | null 13 14 user: User | null
+16 -66
app/src/database.types.ts
··· 8 8 } 9 9 public: { 10 10 Tables: { 11 - character: { 12 - Row: { 13 - age: number 14 - created_at: string 15 - credits: number 16 - height: number | null 17 - id: number 18 - level: number 19 - name: string 20 - species_id: number | null 21 - weight: number | null 22 - } 23 - Insert: { 24 - age: number 25 - created_at?: string 26 - credits?: number 27 - height?: number | null 28 - id?: number 29 - level: number 30 - name: string 31 - species_id?: number | null 32 - weight?: number | null 33 - } 34 - Update: { 35 - age?: number 36 - created_at?: string 37 - credits?: number 38 - height?: number | null 39 - id?: number 40 - level?: number 41 - name?: string 42 - species_id?: number | null 43 - weight?: number | null 44 - } 45 - Relationships: [ 46 - { 47 - foreignKeyName: 'character_species_id_fkey' 48 - columns: ['species_id'] 49 - isOneToOne: false 50 - referencedRelation: 'species' 51 - referencedColumns: ['id'] 52 - }, 53 - ] 54 - } 55 - species: { 11 + profiles: { 56 12 Row: { 57 - id: number 58 - name: string 59 - } 60 - Insert: { 61 - id?: number 62 - name: string 63 - } 64 - Update: { 65 - id?: number 66 - name?: string 67 - } 68 - Relationships: [] 69 - } 70 - users: { 71 - Row: { 72 - auth_id: string | null 73 - id: number 13 + created_at: string | null 14 + display_name: string | null 15 + email: string 16 + id: string 17 + updated_at: string | null 74 18 username: string 75 19 } 76 20 Insert: { 77 - auth_id?: string | null 78 - id?: number 21 + created_at?: string | null 22 + display_name?: string | null 23 + email: string 24 + id: string 25 + updated_at?: string | null 79 26 username: string 80 27 } 81 28 Update: { 82 - auth_id?: string | null 83 - id?: number 29 + created_at?: string | null 30 + display_name?: string | null 31 + email?: string 32 + id?: string 33 + updated_at?: string | null 84 34 username?: string 85 35 } 86 36 Relationships: []
+1 -2
app/src/hooks.server.ts
··· 1 - import { redirect } from '@sveltejs/kit' 2 - import type { Handle } from '@sveltejs/kit' 1 + import { redirect, type Handle } from '@sveltejs/kit' 3 2 import { sequence } from '@sveltejs/kit/hooks' 4 3 import { createServerClient } from '@supabase/ssr' 5 4 import { PUBLIC_SUPABASE_PUBLISHABLE_KEY, PUBLIC_SUPABASE_URL } from '$env/static/public'
+20 -16
app/src/lib/components/Button/Button.svelte
··· 1 1 <script lang="ts"> 2 - import type { SvelteHTMLElements } from 'svelte/elements' 3 - import { tv } from 'tailwind-variants' 2 + import type { WithElementRef } from 'bits-ui' 3 + import type { HTMLButtonAttributes } from 'svelte/elements' 4 + import { cn } from '$lib/types' 5 + import { buttonTv, type ButtonIntent, type ButtonIsIconOnly } from './styles' 4 6 5 - type ButtonRootElement = SvelteHTMLElements['button'] 6 - type ButtonProps = ButtonRootElement 7 - let { children, ...props }: ButtonProps = $props() 7 + type ButtonRootProps = WithElementRef<HTMLButtonAttributes> 8 + type ButtonProps = ButtonRootProps & { 9 + isIconOnly?: ButtonIsIconOnly, 10 + intent?: ButtonIntent, 11 + } 8 12 9 - const button = tv({ 10 - base: [ 11 - 'cursor-pointer', 12 - 'flex flex-row gap-2 items-center', 13 - 'py-2 px-4 border-2 border-zinc-700 rounded-full', 14 - 'transition-colors', 15 - 'hover:bg-hsr-gold hover:border-hsr-gold hover:text-hsr-dark', 16 - ], 17 - }) 13 + let { 14 + intent = 'primary', 15 + isIconOnly = false, 16 + children, 17 + class: className, 18 + ref = $bindable(null), 19 + ...other 20 + }: ButtonProps = $props() 18 21 </script> 19 22 20 23 <button 21 - {...props} 22 - class={button()} 24 + bind:this={ref} 25 + class={cn(buttonTv({ isIconOnly, intent }), className)} 26 + {...other} 23 27 > 24 28 {@render children?.()} 25 29 </button>
-18
app/src/lib/components/Button/FormButton.stories.svelte
··· 1 - <script module> 2 - import { typeAs } from '@starlight/storybook-utils' 3 - import { defineMeta } from '@storybook/addon-svelte-csf' 4 - import FormButton from './FormButton.svelte' 5 - 6 - const { Story } = defineMeta({ 7 - component: FormButton, 8 - tags: ['autodocs'], 9 - argTypes: { 10 - children: typeAs.text(), 11 - }, 12 - args: { 13 - children: 'Hello World', 14 - }, 15 - }) 16 - </script> 17 - 18 - <Story name="Playground">Hello World</Story>
-22
app/src/lib/components/Button/FormButton.svelte
··· 1 - <script lang="ts"> 2 - import type { SvelteHTMLElements } from 'svelte/elements' 3 - import { tv } from 'tailwind-variants' 4 - 5 - const formButton = tv({ 6 - base: [ 7 - 'cursor-pointer', 8 - 'flex flex-row py-2 px-4', 9 - 'bg-hsr-dark dark:bg-white rounded-md', 10 - 'text-white dark:text-hsr-dark text-center font-medium font-sans', 11 - ] 12 - }) 13 - 14 - type FormButtonType = 'submit' | 'reset' 15 - type FormButtonRootElement = SvelteHTMLElements['input'] 16 - type FormButtonProps = Exclude<FormButtonRootElement, 'type'> & { 17 - type?: FormButtonType 18 - } 19 - let { value, type = 'submit', ...other }: FormButtonProps = $props() 20 - </script> 21 - 22 - <input {...other} class={formButton()} {type} {value} />
+31
app/src/lib/components/Button/LinkButton.svelte
··· 1 + <script lang="ts"> 2 + import type { WithElementRef } from 'bits-ui' 3 + import type { HTMLAnchorAttributes } from 'svelte/elements' 4 + import { cn } from '$lib/types' 5 + import { buttonTv, type ButtonIntent, type ButtonIsIconOnly } from './styles' 6 + 7 + type LinkButtonRootProps = WithElementRef<HTMLAnchorAttributes> 8 + type LinkButtonProps = LinkButtonRootProps & { 9 + isIconOnly?: ButtonIsIconOnly, 10 + intent?: ButtonIntent, 11 + } 12 + 13 + let { 14 + intent = 'primary', 15 + isIconOnly = false, 16 + children, 17 + class: className, 18 + href, 19 + ref = $bindable(null), 20 + ...other 21 + }: LinkButtonProps = $props() 22 + </script> 23 + 24 + <a 25 + bind:this={ref} 26 + href={href} 27 + class={cn(buttonTv({ isIconOnly, intent }), className)} 28 + {...other} 29 + > 30 + {@render children?.()} 31 + </a>
+1 -1
app/src/lib/components/Button/index.ts
··· 1 1 export { default as Button } from './Button.svelte' 2 - export { default as FormButton } from './FormButton.svelte' 2 + export { default as LinkButton } from './LinkButton.svelte'
+45
app/src/lib/components/Button/styles.ts
··· 1 + import { tv, type VariantProps } from 'tailwind-variants' 2 + 3 + export type ButtonVariants = VariantProps<typeof buttonTv> 4 + export type ButtonIsIconOnly = ButtonVariants['isIconOnly'] 5 + export type ButtonIntent = ButtonVariants['intent'] 6 + 7 + export const buttonTv = tv({ 8 + base: [ 9 + 'cursor-pointer', 10 + 'flex flex-row gap-2 items-center justify-center', 11 + 'border rounded-lg', 12 + 'text-center', 13 + 'transition-colors', 14 + 'focus:outline-0 focus:ring-2 focus:ring-offset-2', 15 + 'touch-manipulation', 16 + ], 17 + variants: { 18 + isIconOnly: { 19 + false: 'py-2 px-4', 20 + true: 'p-2', 21 + }, 22 + intent: { 23 + primary: [ 24 + 'bg-stone-900 border-stone-800', 25 + 'dark:bg-white dark:border-zinc-200', 26 + 'text-white', 27 + 'dark:text-zinc-900', 28 + 'hover:border-hsr-gold/50', 29 + 'focus:border-hsr-gold', 30 + 'focus:ring-hsr-gold', 31 + 'focus:text-hsr-gold', 32 + ], 33 + secondary: [ 34 + 'bg-white border-zinc-200', 35 + 'dark:bg-stone-900 dark:border-stone-800', 36 + 'text-zinc-900', 37 + 'dark:text-white', 38 + 'hover:border-hsr-gold/50', 39 + 'focus:border-hsr-gold', 40 + 'focus:ring-hsr-gold', 41 + 'focus:text-hsr-gold', 42 + ], 43 + }, 44 + }, 45 + })
+46
app/src/lib/components/Callout/Callout.svelte
··· 1 + <script lang="ts"> 2 + import CheckIcon from '@lucide/svelte/icons/check' 3 + import type { WithChildren, WithElementRef } from 'bits-ui' 4 + import type { SvelteHTMLElements } from 'svelte/elements' 5 + import { tv } from 'tailwind-variants' 6 + 7 + type CalloutRootElement = SvelteHTMLElements['div'] 8 + type CalloutProps = WithElementRef<WithChildren<CalloutRootElement>> & { 9 + title: string, 10 + } 11 + let { 12 + title, 13 + 'data-slot': dataSlot = 'callout', 14 + children, 15 + ref = $bindable(null), 16 + ...other 17 + }: CalloutProps = $props() 18 + 19 + const callout = tv({ 20 + slots: { 21 + container: [ 22 + 'flex flex-row gap-2 items-start', 23 + 'p-3 rounded-md', 24 + 'bg-hsr-gold/10', 25 + 'border border-hsr-gold/50', 26 + ], 27 + icon: 'size-5 mt-1 stroke-hsr-gold', 28 + textContainer: 'text-base', 29 + titleText: 'font-medium text-hsr-gold', 30 + } 31 + }) 32 + const { container, icon, textContainer, titleText } = callout() 33 + </script> 34 + 35 + <div 36 + bind:this={ref} 37 + class={container()} 38 + data-slot={dataSlot} 39 + {...other} 40 + > 41 + <CheckIcon class={icon()} /> 42 + <div class={textContainer()}> 43 + <div class={titleText()}>{title}</div> 44 + <div>{@render children?.()}</div> 45 + </div> 46 + </div>
+1
app/src/lib/components/Callout/index.ts
··· 1 + export { default as Callout } from './Callout.svelte'
+30
app/src/lib/components/Label/Label.svelte
··· 1 + <script lang="ts"> 2 + import { Label as LabelPrimitive } from 'bits-ui' 3 + import { tv } from 'tailwind-variants' 4 + import { cn } from '$lib/utils' 5 + 6 + let { 7 + ref = $bindable(null), 8 + class: className, 9 + ...restProps 10 + }: LabelPrimitive.RootProps = $props() 11 + 12 + const labelTv = tv({ 13 + base: [ 14 + 'flex items-center gap-2', 15 + 'leading-none font-medium', 16 + 'cursor-text', 17 + 'group-data-[disabled=true]:pointer-events-none', 18 + 'group-data-[disabled=true]:opacity-50', 19 + 'peer-disabled:cursor-not-allowed', 20 + 'peer-disabled:opacity-50', 21 + ], 22 + }) 23 + </script> 24 + 25 + <LabelPrimitive.Root 26 + bind:ref 27 + data-slot="label" 28 + class={cn(labelTv(), className)} 29 + {...restProps} 30 + />
+7
app/src/lib/components/Label/index.ts
··· 1 + import Root from './Label.svelte' 2 + 3 + export { 4 + Root, 5 + // 6 + Root as Label, 7 + }
+32
app/src/lib/components/Link/Link.svelte
··· 1 + <script lang='ts'> 2 + import type { WithChildren, WithElementRef } from 'bits-ui' 3 + import type { SvelteHTMLElements } from 'svelte/elements' 4 + import { tv } from 'tailwind-variants' 5 + import { cn } from '$lib/utils' 6 + 7 + type LinkRootElement = Exclude<SvelteHTMLElements['a'], 'href'> 8 + type LinkProps = WithElementRef<WithChildren<LinkRootElement>> & { 9 + href: string, 10 + } 11 + let { 12 + href, 13 + class: className, 14 + children, 15 + 'data-slot': dataSlot = 'page-link', 16 + ref = $bindable(null), 17 + ...other 18 + }: LinkProps = $props() 19 + const link = tv({ 20 + base: 'text-hsr-gold underline', 21 + }) 22 + </script> 23 + 24 + <a 25 + {href} 26 + bind:this={ref} 27 + data-slot={dataSlot} 28 + class={cn(link(), className)} 29 + {...other} 30 + > 31 + {@render children?.()} 32 + </a>
+1
app/src/lib/components/Link/index.ts
··· 1 + export { default as Link } from './Link.svelte'
+1 -1
app/src/lib/components/Profile/Profile.svelte
··· 23 23 </script> 24 24 25 25 <div class={parent()}> 26 - <ProfilePicture src={pfpUrl} /> 26 + <ProfilePicture {username} src={pfpUrl} /> 27 27 <span class={usernameParent()}> 28 28 <span class={usernameSans()}>{username}</span> 29 29 <span class={usernameScript()}>{username}</span>
+33 -11
app/src/lib/components/Profile/ProfilePicture.svelte
··· 1 1 <script lang="ts"> 2 + import { Avatar, type WithoutChildrenOrChild } from 'bits-ui' 2 3 import { tv, type VariantProps } from 'tailwind-variants' 3 - import type { SvelteHTMLElements } from 'svelte/elements' 4 4 import { cn } from '$lib/types' 5 5 6 6 const pfp = tv({ 7 - base: 'cursor-pointer', 7 + base: [ 8 + 'cursor-pointer', 9 + 'flex items-center justify-center', 10 + 'bg-hsr-gold/10 text-hsr-gold', 11 + ], 8 12 variants: { 9 13 size: { 10 14 sm: 'size-8', ··· 18 22 }) 19 23 20 24 type Variants = VariantProps<typeof pfp> 25 + type ProfilePictureRootElement = WithoutChildrenOrChild<Avatar.RootProps> 26 + type ProfilePictureProps = ProfilePictureRootElement & Variants & { 27 + username: string, 28 + src: string, 29 + imageRef?: HTMLImageElement | null, 30 + fallbackRef?: HTMLElement | null, 31 + } 21 32 22 - type ProfilePictureRootElement = SvelteHTMLElements['img'] 23 - type ProfilePictureProps = ProfilePictureRootElement & Variants 24 33 let { 34 + username, 25 35 src, 26 36 size = 'sm', 27 37 shape = 'circle', 28 38 class: className, 39 + ref = $bindable(null), 40 + imageRef = $bindable(null), 41 + fallbackRef = $bindable(null), 29 42 ...props 30 - }: ProfilePictureProps = $props() 43 + }: ProfilePictureProps = $props(); 44 + const fallback = $derived(username.charAt(0).toUpperCase()) 31 45 </script> 32 46 33 - <img 34 - {...props} 35 - src={src} 36 - alt="Avatar" 37 - class={cn(pfp({size, shape}), className)} 38 - /> 47 + <Avatar.Root {...props} bind:ref> 48 + <Avatar.Image 49 + bind:ref={imageRef} 50 + class={cn(pfp({size, shape}), className)} 51 + alt={`Avatar of ${username}`} 52 + {src} 53 + /> 54 + <Avatar.Fallback 55 + bind:ref={fallbackRef} 56 + class={cn(pfp({size, shape}), className)} 57 + > 58 + {fallback} 59 + </Avatar.Fallback> 60 + </Avatar.Root>
+16
app/src/lib/components/Separator/PhraseSeparator.stories.svelte
··· 1 + <script module> 2 + import { baseArgTypes, typeAs } from '@starlight/storybook-utils' 3 + import { defineMeta } from '@storybook/addon-svelte-csf' 4 + import PhraseSeparator from './PhraseSeparator.svelte' 5 + 6 + const { Story } = defineMeta({ 7 + component: PhraseSeparator, 8 + tags: ['autodocs'], 9 + argTypes: baseArgTypes(), 10 + args: { 11 + children: typeAs.text(), 12 + }, 13 + }) 14 + </script> 15 + 16 + <Story name="Playground" args={{ children: 'Or' }} />
+27
app/src/lib/components/Separator/PhraseSeparator.svelte
··· 1 + <script lang="ts"> 2 + import { Separator, type WithChildren } from 'bits-ui' 3 + import { tv } from 'tailwind-variants' 4 + 5 + type PhraseSeparatorRootElement = Separator.RootProps 6 + type PhraseSeparatorProps = WithChildren<PhraseSeparatorRootElement> 7 + 8 + const separatorTv = tv({ 9 + slots: { 10 + root: 'flex flex-row gap-4 items-center w-auto', 11 + separator: 'content=[\'\'] h-px bg-zinc-400 dark:bg-zinc-800 w-full', 12 + center: 'font-medium uppercase min-w-fit text-zinc-400 dark:text-white', 13 + } 14 + }) 15 + const { root, separator, center } = separatorTv() 16 + 17 + let { 18 + children, 19 + ...other 20 + }: PhraseSeparatorProps = $props() 21 + </script> 22 + 23 + <Separator.Root {...other} class={root()}> 24 + <div class={separator()}></div> 25 + <div class={center()}>{@render children?.()}</div> 26 + <div class={separator()}></div> 27 + </Separator.Root>
+3 -2
app/src/lib/components/Separator/Separator.svelte
··· 1 1 <script lang="ts"> 2 2 import { Separator } from 'bits-ui' 3 - import type { SvelteHTMLElements } from 'svelte/elements' 4 3 import { tv } from 'tailwind-variants' 5 4 import { cn } from '$lib/types' 6 5 ··· 42 41 43 42 const { root, outer, circle, middle } = separator() 44 43 45 - type SeparatorRootElement = SvelteHTMLElements['div'] 44 + type SeparatorRootElement = Separator.RootProps 46 45 type SeparatorProps = SeparatorRootElement & { 47 46 isDecorative?: boolean, 48 47 isSemiDashed?: boolean, 49 48 } 50 49 51 50 let { 51 + ref = $bindable(null), 52 52 isDecorative = false, 53 53 isSemiDashed = false, 54 54 class: className, ··· 58 58 </script> 59 59 60 60 <Separator.Root 61 + bind:ref 61 62 decorative={isDecorative} 62 63 role={htmlRole} 63 64 orientation={htmlOrientation}
+1
app/src/lib/components/Separator/index.ts
··· 1 1 export { default as Separator } from './Separator.svelte' 2 + export { default as PhraseSeparator } from './PhraseSeparator.svelte'
+64
app/src/lib/form/Field/Field.svelte
··· 1 + <script lang="ts" module> 2 + import { tv, type VariantProps } from 'tailwind-variants' 3 + 4 + export const fieldVariants = tv({ 5 + base: 'group/field data-[invalid=true]:text-destructive flex w-full gap-1', 6 + variants: { 7 + orientation: { 8 + vertical: 'flex-col *:w-full [&>.sr-only]:w-auto', 9 + horizontal: [ 10 + 'flex-row items-center', 11 + '*:data-[slot=field-label]:flex-auto', 12 + 'has-[>[data-slot=field-content]]:items-start', 13 + 'has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px', 14 + ], 15 + responsive: [ 16 + 'flex-col @md/field-group:flex-row @md/field-group:items-center', 17 + '*:w-full', 18 + '@md/field-group:*:w-auto', 19 + '[&>.sr-only]:w-auto', 20 + '@md/field-group:*:data-[slot=field-label]:flex-auto', 21 + '@md/field-group:has-[>[data-slot=field-content]]:items-start', 22 + '@md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px', 23 + ], 24 + }, 25 + }, 26 + defaultVariants: { 27 + orientation: 'vertical', 28 + }, 29 + }); 30 + 31 + export type FieldVariants = VariantProps<typeof fieldVariants> 32 + export type FieldOrientation = FieldVariants['orientation'] 33 + </script> 34 + 35 + <script lang='ts'> 36 + import type { WithElementRef } from 'bits-ui' 37 + import type { SvelteHTMLElements } from 'svelte/elements' 38 + import { cn } from '$lib/utils' 39 + 40 + type FieldRootElement = SvelteHTMLElements['div'] 41 + type FieldProps = WithElementRef<FieldRootElement> & { 42 + orientation?: FieldOrientation, 43 + } 44 + 45 + let { 46 + ref = $bindable(null), 47 + class: className, 48 + orientation = 'vertical', 49 + children, 50 + 'data-slot': dataSlot = 'field', 51 + ...restProps 52 + }: FieldProps = $props() 53 + </script> 54 + 55 + <div 56 + bind:this={ref} 57 + role='group' 58 + data-slot={dataSlot} 59 + data-orientation={orientation} 60 + class={cn(fieldVariants({ orientation }), className)} 61 + {...restProps} 62 + > 63 + {@render children?.()} 64 + </div>
+34
app/src/lib/form/Field/FieldContent.svelte
··· 1 + <script lang="ts"> 2 + import type { WithElementRef } from 'bits-ui' 3 + import type { SvelteHTMLElements } from 'svelte/elements' 4 + import { tv } from 'tailwind-variants' 5 + import { cn } from '$lib/utils' 6 + 7 + type FieldContentRootElement = SvelteHTMLElements['div'] 8 + type FieldContentProps = WithElementRef<FieldContentRootElement> 9 + 10 + let { 11 + ref = $bindable(null), 12 + class: className, 13 + children, 14 + 'data-slot': dataSlot = 'field-content', 15 + ...restProps 16 + }: FieldContentProps = $props() 17 + 18 + const fieldContent = tv({ 19 + base: [ 20 + 'group/field-content', 21 + 'flex flex-1 flex-col gap-0.5', 22 + 'leading-snug', 23 + ] 24 + }) 25 + </script> 26 + 27 + <div 28 + bind:this={ref} 29 + data-slot={dataSlot} 30 + class={cn(fieldContent(), className)} 31 + {...restProps} 32 + > 33 + {@render children?.()} 34 + </div>
+38
app/src/lib/form/Field/FieldDescription.svelte
··· 1 + <script lang="ts"> 2 + import type { WithElementRef } from 'bits-ui' 3 + import type { SvelteHTMLElements } from 'svelte/elements' 4 + import { tv } from 'tailwind-variants' 5 + import { cn } from '$lib/utils' 6 + 7 + type FieldDescriptionRootElement = SvelteHTMLElements['p'] 8 + type FieldDescriptionProps = WithElementRef<FieldDescriptionRootElement> 9 + 10 + let { 11 + ref = $bindable(null), 12 + class: className, 13 + children, 14 + 'data-slot': dataSlot = 'field-description', 15 + ...restProps 16 + }: FieldDescriptionProps = $props() 17 + 18 + const fieldDescription = tv({ 19 + base: [ 20 + 'text-muted-foreground text-sm leading-normal font-normal', 21 + 'group-has-data-[orientation=horizontal]/field:text-balance', 22 + 'last:mt-0 nth-last-2:-mt-1', 23 + '[[data-variant=legend]+&]:-mt-1.5', 24 + '[&>a:hover]:text-primary', 25 + '[&>a]:underline', 26 + '[&>a]:underline-offset-4', 27 + ] 28 + }) 29 + </script> 30 + 31 + <p 32 + bind:this={ref} 33 + data-slot={dataSlot} 34 + class={cn(fieldDescription(), className)} 35 + {...restProps} 36 + > 37 + {@render children?.()} 38 + </p>
+63
app/src/lib/form/Field/FieldError.svelte
··· 1 + <script lang="ts"> 2 + import type { WithElementRef } from 'bits-ui' 3 + import type { Snippet } from 'svelte' 4 + import type { SvelteHTMLElements } from 'svelte/elements' 5 + import { cn } from '$lib/utils' 6 + 7 + type FieldErrorRootElement = SvelteHTMLElements['div'] 8 + type FieldErrorProps = WithElementRef<FieldErrorRootElement> & { 9 + children?: Snippet, 10 + errors?: { message?: string }[], 11 + } 12 + 13 + let { 14 + ref = $bindable(null), 15 + class: className, 16 + children, 17 + errors, 18 + 'data-slot': dataSlot = 'field-error', 19 + ...restProps 20 + }: FieldErrorProps = $props() 21 + 22 + const hasContent = $derived.by(() => { 23 + // has slotted error 24 + if (children) return true 25 + 26 + // no errors 27 + if (!errors) return false 28 + 29 + // has an error but no message 30 + if (errors.length === 1 && !errors[0]?.message) { 31 + return false 32 + } 33 + 34 + return true 35 + }) 36 + 37 + const isMultipleErrors = $derived(errors && errors.length > 1) 38 + const singleErrorMessage = $derived(errors && errors.length === 1 && errors[0]?.message) 39 + </script> 40 + 41 + {#if hasContent} 42 + <div 43 + bind:this={ref} 44 + role="alert" 45 + data-slot={dataSlot} 46 + class={cn("text-destructive text-sm font-normal", className)} 47 + {...restProps} 48 + > 49 + {#if children} 50 + {@render children()} 51 + {:else if singleErrorMessage} 52 + {singleErrorMessage} 53 + {:else if isMultipleErrors} 54 + <ul class="ms-4 flex list-disc flex-col gap-1"> 55 + {#each errors ?? [] as error, index (index)} 56 + {#if error?.message} 57 + <li>{error.message}</li> 58 + {/if} 59 + {/each} 60 + </ul> 61 + {/if} 62 + </div> 63 + {/if}
+35
app/src/lib/form/Field/FieldGroup.svelte
··· 1 + <script lang="ts"> 2 + import type { WithElementRef } from 'bits-ui' 3 + import type { SvelteHTMLElements } from 'svelte/elements' 4 + import { tv } from 'tailwind-variants' 5 + import { cn } from '$lib/utils' 6 + 7 + type FieldGroupRootElement = SvelteHTMLElements['div'] 8 + type FieldGroupProps = WithElementRef<FieldGroupRootElement> 9 + 10 + let { 11 + ref = $bindable(null), 12 + class: className, 13 + children, 14 + 'data-slot': dataSlot = 'field-group', 15 + ...restProps 16 + }: FieldGroupProps = $props() 17 + 18 + const fieldGroup = tv({ 19 + base: [ 20 + 'group/field-group @container/field-group', 21 + 'flex w-full flex-col gap-7', 22 + 'data-[slot=checkbox-group]:gap-3', 23 + '*:data-[slot=field-group]:gap-4', 24 + ] 25 + }) 26 + </script> 27 + 28 + <div 29 + bind:this={ref} 30 + data-slot={dataSlot} 31 + class={cn(fieldGroup(), className)} 32 + {...restProps} 33 + > 34 + {@render children?.()} 35 + </div>
+42
app/src/lib/form/Field/FieldLabel.svelte
··· 1 + <script lang="ts"> 2 + import type { ComponentProps } from 'svelte' 3 + import { tv } from 'tailwind-variants' 4 + import { Label } from '$ui/Label' 5 + import { cn } from '$lib/utils' 6 + 7 + type FieldLabelProps = ComponentProps<typeof Label> 8 + 9 + let { 10 + ref = $bindable(null), 11 + class: className, 12 + children, 13 + 'data-slot': dataSlot = 'field-label', 14 + ...restProps 15 + }: FieldLabelProps = $props() 16 + 17 + const fieldLabel = tv({ 18 + base: [ 19 + 'group/field-label peer/field-label', 20 + 'flex w-fit gap-2', 21 + 'leading-snug', 22 + 'group-data-[disabled=true]/field:opacity-50', 23 + 'has-[>[data-slot=field]]:w-full', 24 + 'has-[>[data-slot=field]]:flex-col', 25 + 'has-[>[data-slot=field]]:rounded-md', 26 + 'has-[>[data-slot=field]]:border', 27 + '*:data-[slot=field]:p-4', 28 + 'has-data-[state=checked]:bg-primary/5', 29 + 'has-data-[state=checked]:border-primary', 30 + 'dark:has-data-[state=checked]:bg-primary/10', 31 + ], 32 + }) 33 + </script> 34 + 35 + <Label 36 + bind:ref 37 + data-slot={dataSlot} 38 + class={cn(fieldLabel(), className )} 39 + {...restProps} 40 + > 41 + {@render children?.()} 42 + </Label>
+38
app/src/lib/form/Field/FieldLegend.svelte
··· 1 + <script lang="ts"> 2 + import type { WithElementRef } from 'bits-ui' 3 + import type { SvelteHTMLElements } from 'svelte/elements' 4 + import { tv } from 'tailwind-variants' 5 + import { cn } from '$lib/utils' 6 + 7 + type FieldLegendRootElement = SvelteHTMLElements['legend'] 8 + type FieldLegendProps = WithElementRef<FieldLegendRootElement> & { 9 + variant?: 'legend' | 'label', 10 + } 11 + 12 + let { 13 + ref = $bindable(null), 14 + class: className, 15 + variant = 'legend', 16 + children, 17 + 'data-slot': dataSlot = 'field-legend', 18 + ...restProps 19 + }: FieldLegendProps = $props() 20 + 21 + const fieldLegend = tv({ 22 + base: [ 23 + 'mb-3 font-medium', 24 + 'data-[variant=legend]:text-base', 25 + 'data-[variant=label]:text-sm', 26 + ] 27 + }) 28 + </script> 29 + 30 + <legend 31 + bind:this={ref} 32 + data-slot={dataSlot} 33 + data-variant={variant} 34 + class={cn(fieldLegend(), className)} 35 + {...restProps} 36 + > 37 + {@render children?.()} 38 + </legend>
+34
app/src/lib/form/Field/FieldSet.svelte
··· 1 + <script lang="ts"> 2 + import type { WithElementRef } from 'bits-ui' 3 + import type { SvelteHTMLElements } from 'svelte/elements' 4 + import { tv } from 'tailwind-variants' 5 + import { cn } from '$lib/utils' 6 + 7 + type FieldSetRootElement = SvelteHTMLElements['fieldset'] 8 + type FieldSetProps = WithElementRef<FieldSetRootElement> 9 + 10 + let { 11 + ref = $bindable(null), 12 + class: className, 13 + children, 14 + 'data-slot': dataSlot = 'field-set', 15 + ...restProps 16 + }: FieldSetProps = $props() 17 + 18 + const fieldSet = tv({ 19 + base: [ 20 + 'flex flex-col gap-6', 21 + 'has-[>[data-slot=checkbox-group]]:gap-3', 22 + 'has-[>[data-slot=radio-group]]:gap-3', 23 + ] 24 + }) 25 + </script> 26 + 27 + <fieldset 28 + bind:this={ref} 29 + data-slot={dataSlot} 30 + class={cn(fieldSet(), className)} 31 + {...restProps} 32 + > 33 + {@render children?.()} 34 + </fieldset>
+34
app/src/lib/form/Field/FieldTitle.svelte
··· 1 + <script lang="ts"> 2 + import type { WithElementRef } from 'bits-ui' 3 + import type { SvelteHTMLElements } from 'svelte/elements' 4 + import { tv } from 'tailwind-variants' 5 + import { cn } from '$lib/utils' 6 + 7 + type FieldTitleRootElement = SvelteHTMLElements['div'] 8 + type FieldTitleProps = WithElementRef<FieldTitleRootElement> 9 + 10 + let { 11 + ref = $bindable(null), 12 + class: className, 13 + children, 14 + 'data-slot': dataSlot = 'field-title', 15 + ...restProps 16 + }: FieldTitleProps = $props() 17 + 18 + const fieldTitle = tv({ 19 + base: [ 20 + 'flex items-center gap-2 w-fit', 21 + 'text-sm leading-snug font-medium', 22 + 'group-data-[disabled=true]/field:opacity-50', 23 + ] 24 + }) 25 + </script> 26 + 27 + <div 28 + bind:this={ref} 29 + data-slot={dataSlot} 30 + class={cn(fieldTitle(),className)} 31 + {...restProps} 32 + > 33 + {@render children?.()} 34 + </div>
+30
app/src/lib/form/Field/index.ts
··· 1 + import Field from './Field.svelte' 2 + import Set from './FieldSet.svelte' 3 + import Legend from './FieldLegend.svelte' 4 + import Group from './FieldGroup.svelte' 5 + import Content from './FieldContent.svelte' 6 + import Label from './FieldLabel.svelte' 7 + import Title from './FieldTitle.svelte' 8 + import Description from './FieldDescription.svelte' 9 + import Error from './FieldError.svelte' 10 + 11 + export { 12 + Field, 13 + Set, 14 + Legend, 15 + Group, 16 + Content, 17 + Label, 18 + Title, 19 + Description, 20 + Error, 21 + // 22 + Set as FieldSet, 23 + Legend as FieldLegend, 24 + Group as FieldGroup, 25 + Content as FieldContent, 26 + Label as FieldLabel, 27 + Title as FieldTitle, 28 + Description as FieldDescription, 29 + Error as FieldError, 30 + }
+34
app/src/lib/form/Form/FormHeader.svelte
··· 1 + <script lang="ts"> 2 + import type { Snippet } from 'svelte' 3 + import type { SvelteHTMLElements } from 'svelte/elements' 4 + import { tv } from 'tailwind-variants' 5 + import FormLogoIcon from './FormLogoIcon.svelte' 6 + 7 + type FormHeaderRootElement = SvelteHTMLElements['header'] 8 + type FormHeaderProps = FormHeaderRootElement & { 9 + titleText: Snippet, 10 + descText: Snippet, 11 + } 12 + let { 13 + titleText, 14 + descText, 15 + }: FormHeaderProps = $props() 16 + 17 + const formHeader = tv({ 18 + slots: { 19 + header: 'flex flex-col gap-4 items-start', 20 + hgroup: 'block leading-8', 21 + h2: 'text-lg font-medium', 22 + p: 'max-w-60ch text-zinc-500 dark:text-stone-700 text-sm italic', 23 + } 24 + }) 25 + const { header, hgroup, h2, p } = formHeader() 26 + </script> 27 + 28 + <header class={header()}> 29 + <FormLogoIcon /> 30 + <hgroup class={hgroup()}> 31 + <h2 class={h2()}>{@render titleText?.()}</h2> 32 + <p class={p()}>{@render descText()}</p> 33 + </hgroup> 34 + </header>
+24
app/src/lib/form/Form/FormLogoIcon.svelte
··· 1 + <script> 2 + import { SparklesIcon } from '@lucide/svelte' 3 + import { tv } from 'tailwind-variants' 4 + 5 + const logoIcon = tv({ 6 + slots: { 7 + root: [ 8 + 'self-start p-4', 9 + 'rounded-lg', 10 + 'bg-zinc-100 dark:bg-stone-900', 11 + ], 12 + icon: [ 13 + 'size-6', 14 + 'stroke-none', 15 + 'fill-zinc-500 dark:fill-white', 16 + ], 17 + } 18 + }) 19 + const { root, icon } = logoIcon() 20 + </script> 21 + 22 + <div class={root()}> 23 + <SparklesIcon class={icon()} /> 24 + </div>
+1
app/src/lib/form/Form/index.ts
··· 1 + export { default as FormHeader } from './FormHeader.svelte'
-34
app/src/lib/form/TextInput/ClearButton.svelte
··· 1 - 2 - <script lang="ts"> 3 - import XIcon from '@lucide/svelte/icons/x' 4 - import type { SvelteHTMLElements } from 'svelte/elements' 5 - import { tv } from 'tailwind-variants' 6 - 7 - type ClearButtonRootElement = SvelteHTMLElements['button'] 8 - type ClearButtonProps = ClearButtonRootElement 9 - let { ...other }: ClearButtonProps = $props() 10 - 11 - const clearButton = tv({ 12 - slots: { 13 - button: [ 14 - 'rounded-full p-1 cursor-pointer', 15 - 'transition-colors', 16 - 'bg-zinc-200 dark:bg-zinc-700', 17 - 'hover:bg-hsr-gold', 18 - ], 19 - icon: [ 20 - 'size-3 stroke-zinc-400 dark:stroke-hsr-dark', 21 - 'hover:stroke-white', 22 - ], 23 - } 24 - }) 25 - const { button, icon } = clearButton() 26 - </script> 27 - 28 - <button 29 - {...other} 30 - title="Clear text field" 31 - class={button()} 32 - > 33 - <XIcon class={icon()} /> 34 - </button>
-25
app/src/lib/form/TextInput/HelpText.svelte
··· 1 - <script lang="ts"> 2 - import type { WithChildren } from 'bits-ui' 3 - import type { SvelteHTMLElements } from 'svelte/elements' 4 - import { tv } from 'tailwind-variants' 5 - 6 - type HelpTextRootElement = SvelteHTMLElements['div'] 7 - type HelpTextProps = WithChildren<HelpTextRootElement> & { 8 - isValid: boolean, 9 - } 10 - let { children, isValid = true, ...other }: HelpTextProps = $props() 11 - 12 - const helpText = tv({ 13 - base: 'text-sm', 14 - variants: { 15 - isValid: { 16 - true: 'text-zinc-500', 17 - false: 'text-red-500', 18 - } 19 - } 20 - }) 21 - </script> 22 - 23 - <div {...other} class={helpText({isValid})}> 24 - {@render children?.()} 25 - </div>
+30 -47
app/src/lib/form/TextInput/TextAreaInput.svelte
··· 1 1 <script lang="ts"> 2 - import { Label } from 'bits-ui' 2 + import type { WithElementRef } from 'bits-ui' 3 3 import type { SvelteHTMLElements } from 'svelte/elements' 4 4 import { tv } from 'tailwind-variants' 5 - import HelpText from './HelpText.svelte' 6 - import CharacterCounter from './CharacterCounter.svelte' 7 5 8 6 type TextAreaInputRootElement = SvelteHTMLElements['textarea'] 9 - type TextAreaInputProps = Exclude<TextAreaInputRootElement, 'resize'> & { 10 - label: string, 7 + type TextAreaInputProps = WithElementRef<Exclude<TextAreaInputRootElement, 'resize'>> & { 11 8 name: string, 12 - help?: string, 13 9 resizable?: boolean, 10 + value?: string, 14 11 } 15 12 16 13 let { 17 14 label, 18 15 name, 19 16 placeholder, 20 - help, 17 + desc, 21 18 resizable = true, 22 19 maxlength, 20 + ref = $bindable(null), 21 + value = $bindable(''), 23 22 ...other 24 23 }: TextAreaInputProps = $props() 25 - let value = $state('') 26 24 27 - const multi = tv({ 28 - slots: { 29 - root: [ 30 - 'flex flex-col gap-0.75', 31 - 'w-full', 32 - ], 33 - textarea: [ 34 - 'appearance-none', 35 - 'p-2', 36 - 'bg-white dark:bg-hsr-dark', 37 - 'border border-zinc-300 dark:border-zinc-800', 38 - 'placeholder:text-zinc-700', 39 - 'transition-colors', 40 - 'hover:border-hsr-gold/50', 41 - 'focus:outline-1 focus:outline-hsr-gold', 42 - 'focus-within:border-hsr-gold', 43 - 'focus-within:hover:border-hsr-gold', 44 - 'focus-within:shadow-2xs', 45 - 'focus-within:drop-shadow-hsr-gold', 46 - ], 47 - }, 25 + const textArea = tv({ 26 + base: [ 27 + 'appearance-none', 28 + 'p-2', 29 + 'bg-white dark:bg-hsr-dark', 30 + 'border border-zinc-300 dark:border-zinc-800', 31 + 'placeholder:text-zinc-700', 32 + 'transition-colors', 33 + 'hover:border-hsr-gold/50', 34 + 'focus:outline-1 focus:outline-hsr-gold', 35 + 'focus-within:border-hsr-gold', 36 + 'focus-within:hover:border-hsr-gold', 37 + 'focus-within:shadow-2xs', 38 + 'focus-within:drop-shadow-hsr-gold', 39 + ], 48 40 variants: { 49 41 resizable: { 50 42 true: 'resize-y', ··· 52 44 } 53 45 } 54 46 }) 55 - const { root, textarea } = multi() 56 47 </script> 57 48 58 - <div class={root()}> 59 - <div class="flex flex-row justify-between"> 60 - <Label.Root class="font-medium" for={name}>{label}</Label.Root> 61 - {#if maxlength} 62 - <CharacterCounter current={value.length} max={maxlength} /> 63 - {/if} 64 - </div> 65 - <textarea 66 - {...other} 67 - {name} 68 - {placeholder} 69 - class={textarea()} 70 - ></textarea> 71 - {#if help} 72 - <HelpText isValid>{help}</HelpText> 73 - {/if} 74 - </div> 49 + <textarea 50 + bind:this={ref} 51 + bind:value={value} 52 + {name} 53 + {placeholder} 54 + class={textArea({ resizable })} 55 + {...other} 56 + > 57 + </textarea>
+19 -54
app/src/lib/form/TextInput/TextInput.svelte
··· 1 1 <script lang="ts"> 2 - import { Label } from 'bits-ui' 2 + import type { WithElementRef } from 'bits-ui' 3 3 import type { Snippet } from 'svelte' 4 4 import type { SvelteHTMLElements } from 'svelte/elements' 5 5 import { tv } from 'tailwind-variants' 6 - import HelpText from './HelpText.svelte' 7 - import CharacterCounter from './CharacterCounter.svelte' 8 - import ClearButton from './ClearButton.svelte' 9 - 10 - type TextFieldInputType = 11 - | 'text' 12 - | 'email' 13 - | 'url' 14 - | 'number' 15 6 16 7 type TextFieldRootElement = SvelteHTMLElements['input'] 17 - type TextFieldProps = TextFieldRootElement & { 18 - type?: TextFieldInputType, 19 - label: string, 8 + type TextFieldProps = WithElementRef<TextFieldRootElement> & { 20 9 name: string, 21 - clearable?: boolean, 22 - helpMessage?: string, 23 10 before?: Snippet, 24 11 after?: Snippet, 12 + value?: string, 25 13 } 26 14 27 15 let { 28 16 type = 'text', 29 - label, 30 17 name, 31 18 placeholder, 32 - clearable = true, 33 - helpMessage, 34 19 before, 35 20 after, 36 21 maxlength, 22 + ref = $bindable(null), 23 + value = $bindable(''), 37 24 ...other 38 25 }: TextFieldProps = $props() 39 26 40 - let value = $state('') 41 - let isEmpty = $derived(value === '') 42 - function clearField() { 43 - value = '' 44 - } 45 - 46 27 const field = tv({ 47 28 slots: { 48 - root: [ 49 - 'flex flex-col gap-0.75', 50 - 'max-w-40ch', 51 - ], 52 29 inputParent: [ 53 30 'flex flex-row items-center gap-1', 54 31 'p-2', ··· 72 49 ], 73 50 }, 74 51 }) 75 - const { root, inputParent, inputElement } = field() 52 + const { inputParent, inputElement } = field() 76 53 </script> 77 54 78 - <div class={root()}> 79 - <div class="flex flex-row justify-between"> 80 - <Label.Root class="font-medium" for={name}>{label}</Label.Root> 81 - {#if maxlength} 82 - <CharacterCounter current={value.length} max={maxlength} /> 83 - {/if} 84 - </div> 85 - <div class={inputParent()}> 86 - {@render before?.()} 87 - <input 88 - {...other} 89 - bind:value 90 - type={type} 91 - class={inputElement()} 92 - {placeholder} 93 - {name} 94 - /> 95 - {#if clearable && !isEmpty} 96 - <ClearButton onclick={() => clearField()} /> 97 - {/if} 98 - {@render after?.()} 99 - </div> 100 - {#if helpMessage} 101 - <HelpText isValid>{helpMessage}</HelpText> 102 - {/if} 55 + <div class={inputParent()}> 56 + {@render before?.()} 57 + <input 58 + bind:this={ref} 59 + bind:value={value} 60 + type={type} 61 + class={inputElement()} 62 + {name} 63 + id={name} 64 + {placeholder} 65 + {...other} 66 + /> 67 + {@render after?.()} 103 68 </div>
-2
app/src/lib/form/TextInput/index.ts
··· 1 1 export { default as CharacterCounter } from './CharacterCounter.svelte' 2 - export { default as ClearButton } from './ClearButton.svelte' 3 - export { default as HelpText } from './HelpText.svelte' 4 2 export { default as TextAreaInput } from './TextAreaInput.svelte' 5 3 export { default as TextInput } from './TextInput.svelte'
+11
app/src/lib/queries/core.ts
··· 1 + export type ResultOk<T> = { data: T; error: null } 2 + export type ResultError<E> = { data: null; error: E } 3 + export type ResultEnum<T, E> = ResultOk<T> | ResultError<E> 4 + 5 + export function resultOk<T>(data: T): ResultOk<T> { 6 + return { data: data, error: null } 7 + } 8 + 9 + export function resultError<E>(error: E): ResultError<E> { 10 + return { data: null, error: error } 11 + }
+22
app/src/lib/queries/isEmailAvailable.ts
··· 1 + import type { PostgrestError } from '@supabase/supabase-js' 2 + import { resultError, resultOk, type ResultError, type ResultOk } from './core' 3 + import type { DbClient } from '$lib/utils' 4 + 5 + export type EmailAvailableResult = ResultOk<{ isAvailable: boolean }> | ResultError<PostgrestError> 6 + 7 + /** 8 + * Checks if a user has already registered an email address 9 + * within the database. 10 + */ 11 + export async function isEmailAvailable( 12 + dbClient: DbClient, 13 + email: string, 14 + ): Promise<EmailAvailableResult> { 15 + const { data, error } = await dbClient 16 + .from('profiles') 17 + .select() 18 + .ilike('email', email) 19 + .maybeSingle() 20 + 21 + return error ? resultError(error) : resultOk({ isAvailable: data === null }) 22 + }
+90
app/src/lib/queries/isUsernameAvailable.ts
··· 1 + import type { PostgrestError } from '@supabase/supabase-js/dist/index.cjs' 2 + import type { ResultError, ResultOk } from './core' 3 + import { resultError, resultOk } from './core' 4 + import type { DbClient } from '$lib/utils' 5 + 6 + /** 7 + * - 'taken': another user has taken the username 8 + * - 'reserved': the username is a keyword reserved by the system 9 + */ 10 + export type UsernameAvailablityReason = 'taken' | 'reserved' 11 + export type UsernameAvailablityResult = 12 + | ResultOk< 13 + | { 14 + isAvailable: true 15 + } 16 + | { 17 + isAvailable: false 18 + reason: UsernameAvailablityReason 19 + } 20 + > 21 + | ResultError<PostgrestError> 22 + 23 + const reservedUsernames = new Set([ 24 + // administrative-like access 25 + 'sysadmin', 26 + 'admin', 27 + 'administrator', 28 + 'root', 29 + 'sysroot', 30 + 'system', 31 + 'www', 32 + // users + user routes 33 + 'user', 34 + 'username', 35 + 'password', 36 + 'change-password', 37 + 'reset-password', 38 + 'email', 39 + 'settings', 40 + 'prefs', 41 + 'preferences', 42 + // tools and services 43 + 'resend', 44 + 'supabase', 45 + 'cloudflare', 46 + // actions 47 + 'edit', 48 + 'delete', 49 + 'new', 50 + 'create', 51 + 'protect', 52 + // js types 53 + 'void', 54 + 'undefined', 55 + 'null', 56 + ]) 57 + 58 + export function isUsernameReserved(username: string): boolean { 59 + return !reservedUsernames.has(username) 60 + } 61 + 62 + /** 63 + * Checks if a username is available by checking: 64 + * - it's not already been taken by another user 65 + * - it's not reserved by the system 66 + */ 67 + export async function isUsernameAvailable( 68 + dbClient: DbClient, 69 + username: string, 70 + ): Promise<UsernameAvailablityResult> { 71 + // username is resolved to lowercase to case-insensitively 72 + // compare against any elements in the reserved set 73 + if (isUsernameReserved(username.toLowerCase())) { 74 + return resultOk({ isAvailable: false, reason: 'reserved' }) 75 + } 76 + 77 + const { data, error } = await dbClient 78 + .from('profiles') 79 + .select() 80 + .ilike('username', username) 81 + .maybeSingle() 82 + 83 + if (error) { 84 + return resultError(error) 85 + } 86 + 87 + return typeof data?.username === 'string' 88 + ? resultOk({ isAvailable: false, reason: 'taken' }) 89 + : resultOk({ isAvailable: true }) 90 + }
+4
app/src/lib/resendClient.ts
··· 1 + import { Resend } from 'resend' 2 + import { RESEND_KEY } from '$env/static/private' 3 + 4 + export const resend = new Resend(RESEND_KEY)
+41
app/src/lib/schemas/auth.ts
··· 1 + import z from 'zod' 2 + 3 + /* auth primitive schemas */ 4 + // TODO: fix this schema, because zod's email primitives are weird 5 + export const emailSchema = z.string() 6 + export const usernameSchema = z 7 + .string() 8 + .refine((s) => /\w/.test(s.charAt(0)), { error: 'Username must start with a letter.' }) 9 + .refine((s) => /[\w\d-_]+/.test(s), { 10 + error: 'Username may only contain letters, digits, hyphen, and underscore.', 11 + }) 12 + export const passwordSchema = z.string().min(8).max(64) 13 + 14 + /* auth form schemas */ 15 + export const signInSchema = z.object({ 16 + email: emailSchema, 17 + password: passwordSchema, 18 + }) 19 + 20 + export const signUpSchema = z.object({ 21 + email: emailSchema, 22 + username: usernameSchema, 23 + password: passwordSchema, 24 + }) 25 + 26 + export const resetPasswordSchema = z.object({ 27 + email: emailSchema, 28 + }) 29 + 30 + export const changePasswordSchema = z.object({ 31 + newPassword: passwordSchema, 32 + }) 33 + 34 + /* compile-time types */ 35 + export type Html5EmailSchema = z.infer<typeof emailSchema> 36 + export type UsernameSchema = z.infer<typeof usernameSchema> 37 + export type PasswordSchema = z.infer<typeof passwordSchema> 38 + export type SignInSchema = z.infer<typeof signInSchema> 39 + export type SignUpSchema = z.infer<typeof signUpSchema> 40 + export type ResetPasswordSchema = z.infer<typeof resetPasswordSchema> 41 + export type ChangePasswordSchema = z.infer<typeof changePasswordSchema>
+38
app/src/lib/utils.ts
··· 1 + import type { SupabaseClient } from '@supabase/supabase-js/dist/index.cjs' 2 + import { clsx, type ClassValue } from 'clsx' 3 + import { twMerge } from 'tailwind-merge' 4 + import type { Database } from '../database.types' 5 + 6 + /** 7 + * Generates a consistent, human-readable page title 8 + * intended for within a `<title>` element. 9 + */ 10 + export const pageTitle = (title?: string) => { 11 + const prefix = 'The Drifting Starlight' 12 + const separator = '\u2022' 13 + 14 + if (title === undefined) { 15 + return prefix 16 + } 17 + 18 + return `${title} ${separator} ${prefix}` 19 + } 20 + 21 + /** 22 + * allows elegantly merging classes (including tailwind classes), 23 + * without conflicting with Svelte's class attribute type 24 + */ 25 + export function cn(...inputs: ClassValue[]) { 26 + return twMerge(clsx(inputs)) 27 + } 28 + 29 + /** 30 + * a postgreSQL table with a strongly typed database schema 31 + */ 32 + export type DbClient = SupabaseClient<Database> 33 + 34 + // eslint-disable-next-line @typescript-eslint/no-explicit-any 35 + export type WithoutChild<T> = T extends { child?: any } ? Omit<T, 'child'> : T 36 + // eslint-disable-next-line @typescript-eslint/no-explicit-any 37 + export type WithoutChildren<T> = T extends { children?: any } ? Omit<T, 'children'> : T 38 + export type WithoutChildrenOrChild<T> = WithoutChildren<WithoutChild<T>>
+29
app/src/routes/(auth)/AuthFooter.svelte
··· 1 + <script lang="ts"> 2 + import DiscordIcon from '@starlight/icons/discord' 3 + import GoogleIcon from '@starlight/icons/google' 4 + import type { ComponentProps } from 'svelte' 5 + import type { SvelteHTMLElements } from 'svelte/elements' 6 + import { Button } from '$ui/Button' 7 + 8 + type AuthFooterRootElement = SvelteHTMLElements['footer'] 9 + type AuthFooterProps = AuthFooterRootElement & { 10 + discordProps: ComponentProps<typeof Button>, 11 + googleProps: ComponentProps<typeof Button>, 12 + } 13 + let { 14 + discordProps, 15 + googleProps, 16 + ...other 17 + }: AuthFooterProps = $props() 18 + </script> 19 + 20 + <footer class="grid grid-cols-2 gap-2" {...other}> 21 + <Button intent="secondary" class="col-span-1" {...discordProps}> 22 + <DiscordIcon class="size-5 fill-hsr-dark dark:fill-white stroke-none" /> 23 + Discord 24 + </Button> 25 + <Button intent="secondary" class="col-span-1" {...googleProps}> 26 + <GoogleIcon class="size-5 fill-hsr-dark dark:fill-white stroke-none" /> 27 + Google 28 + </Button> 29 + </footer>
+22
app/src/routes/(auth)/AuthHeader.svelte
··· 1 + <script lang="ts"> 2 + import type { SvelteHTMLElements } from 'svelte/elements' 3 + import { FormHeader } from '$form/Form' 4 + 5 + type AuthHeaderRootElement = SvelteHTMLElements['header'] 6 + type AuthHeaderProps = AuthHeaderRootElement & { 7 + ctaText?: string 8 + } 9 + let { ctaText }: AuthHeaderProps = $props() 10 + </script> 11 + 12 + <FormHeader> 13 + {#snippet titleText()} 14 + {ctaText} to The Drifting Starlight Campaign 15 + {/snippet} 16 + {#snippet descText()} 17 + To aboard the Astral Express is a blessing. 18 + Very few can fathom such an engineering marvel 19 + capable of taking course through the cosmos. 20 + And yet, it exists beyond all doubt. 21 + {/snippet} 22 + </FormHeader>
+15
app/src/routes/(auth)/AuthPageLayout.svelte
··· 1 + <script lang="ts"> 2 + import type { WithChildren } from 'bits-ui' 3 + import type { SvelteHTMLElements } from 'svelte/elements'; 4 + import { PageLayout } from '$ui/Site' 5 + 6 + type AuthPageRootElement = SvelteHTMLElements['div'] 7 + type AuthPageLayoutProps = WithChildren<AuthPageRootElement> 8 + let { children }: AuthPageLayoutProps = $props() 9 + </script> 10 + 11 + <PageLayout display="flex" direction="col" class="items-center justify-center h-screen"> 12 + <div class="flex flex-col gap-6 text-left w-112.5"> 13 + {@render children?.()} 14 + </div> 15 + </PageLayout>
+3
app/src/routes/(auth)/components.ts
··· 1 + export { default as AuthFooter } from './AuthFooter.svelte' 2 + export { default as AuthHeader } from './AuthHeader.svelte' 3 + export { default as AuthPageLayout } from './AuthPageLayout.svelte'
+49
app/src/routes/(auth)/reset-password/+page.server.ts
··· 1 + import { fail } from '@sveltejs/kit' 2 + import { message, superValidate } from 'sveltekit-superforms' 3 + import { zod4 } from 'sveltekit-superforms/adapters' 4 + import { changePasswordSchema, resetPasswordSchema } from '$lib/schemas/auth' 5 + import { pageTitle } from '$lib/utils' 6 + import type { Actions, PageServerLoad } from './$types' 7 + 8 + export const load: PageServerLoad = async () => { 9 + return { 10 + form: await superValidate(zod4(resetPasswordSchema)), 11 + meta: { 12 + pageTitle: pageTitle('Reset your password'), 13 + }, 14 + } 15 + } 16 + 17 + export const actions: Actions = { 18 + resetPassword: async ({ request, locals: { supabase } }) => { 19 + const form = await superValidate(request, zod4(resetPasswordSchema)) 20 + if (!form.valid) { 21 + return fail(400, { form }) 22 + } 23 + 24 + const { error } = await supabase.auth.resetPasswordForEmail(form.data.email, { 25 + redirectTo: 'https://driftingstarlight.app/reset-password', 26 + }) 27 + if (error) { 28 + return fail(400, { form }) 29 + } 30 + 31 + return message(form, 'Password reset request sent! Check your email to verify.') 32 + }, 33 + 34 + changePassword: async ({ request, locals: { supabase } }) => { 35 + const form = await superValidate(request, zod4(changePasswordSchema)) 36 + if (!form.valid) { 37 + return fail(400, { form }) 38 + } 39 + 40 + const { error } = await supabase.auth.updateUser({ 41 + password: form.data.newPassword, 42 + }) 43 + if (error) { 44 + return fail(400, { form }) 45 + } 46 + 47 + return message(form, 'Password successfully reset.') 48 + }, 49 + }
+58
app/src/routes/(auth)/reset-password/+page.svelte
··· 1 + <script lang="ts"> 2 + import type { WithChildren } from 'bits-ui' 3 + import { untrack } from 'svelte' 4 + import { superForm } from 'sveltekit-superforms' 5 + import { Field, FieldLabel } from '$form/Field' 6 + import { FormHeader } from '$form/Form' 7 + import { TextInput } from '$form/TextInput' 8 + import { Button } from '$ui/Button' 9 + import type { PageProps } from './$types' 10 + import AuthPageLayout from '../AuthPageLayout.svelte' 11 + 12 + type ResetPasswordProps = WithChildren<PageProps> 13 + let { data }: ResetPasswordProps = $props() 14 + 15 + const { supabase, meta: { pageTitle } } = $derived(data) 16 + const { form, errors, constraints, enhance } = superForm(untrack(() => data.form)) 17 + </script> 18 + 19 + <svelte:head> 20 + <title>{pageTitle}</title> 21 + </svelte:head> 22 + 23 + <AuthPageLayout> 24 + <FormHeader> 25 + {#snippet titleText()} 26 + Forgot your password? 27 + {/snippet} 28 + {#snippet descText()} 29 + Enter your email address to receive a password reset link. 30 + {/snippet} 31 + </FormHeader> 32 + <form 33 + class="flex flex-col gap-6" 34 + method="POST" 35 + action="?/resetPassword" 36 + novalidate 37 + rel="next" 38 + use:enhance 39 + > 40 + <Field> 41 + <FieldLabel>Email address</FieldLabel> 42 + <TextInput 43 + type="email" 44 + name="email" 45 + autocomplete="email" 46 + bind:value={$form.email} 47 + {...$constraints.email} /> 48 + </Field> 49 + <div class="flex flex-col gap-2"> 50 + <Button intent="primary"> 51 + Send and continue 52 + </Button> 53 + <Button intent="secondary" href="/signin"> 54 + Return to sign in 55 + </Button> 56 + </div> 57 + </form> 58 + </AuthPageLayout>
+34
app/src/routes/(auth)/signin/+page.server.ts
··· 1 + import { fail, redirect } from '@sveltejs/kit' 2 + import { superValidate } from 'sveltekit-superforms' 3 + import { zod4 } from 'sveltekit-superforms/adapters' 4 + import { signInSchema } from '$lib/schemas/auth' 5 + import { pageTitle } from '$lib/utils' 6 + import type { Actions, PageServerLoad } from './$types' 7 + 8 + export const load: PageServerLoad = async () => { 9 + return { 10 + form: await superValidate(zod4(signInSchema)), 11 + meta: { 12 + pageTitle: pageTitle('Sign in'), 13 + }, 14 + } 15 + } 16 + 17 + export const actions: Actions = { 18 + default: async ({ request, locals: { supabase } }) => { 19 + const form = await superValidate(request, zod4(signInSchema)) 20 + if (!form.valid) { 21 + return fail(400, { form }) 22 + } 23 + 24 + const { error } = await supabase.auth.signInWithPassword({ 25 + email: form.data.email, 26 + password: form.data.password, 27 + }) 28 + if (error) { 29 + return fail(400, { form }) 30 + } 31 + 32 + redirect(303, '/') 33 + }, 34 + }
+81
app/src/routes/(auth)/signin/+page.svelte
··· 1 + <script lang="ts"> 2 + import LogInIcon from '@lucide/svelte/icons/log-in' 3 + import type { WithChildren } from 'bits-ui' 4 + import { untrack } from 'svelte' 5 + import { superForm } from 'sveltekit-superforms' 6 + import { goto } from '$app/navigation' 7 + import { resolve } from '$app/paths' 8 + import { Field, FieldContent, FieldError, FieldLabel } from '$form/Field' 9 + import { TextInput } from '$form/TextInput' 10 + import { Button } from '$ui/Button' 11 + import { Callout } from '$ui/Callout' 12 + import { Link } from '$ui/Link' 13 + import { PhraseSeparator } from '$ui/Separator' 14 + import type { PageProps } from './$types' 15 + import { AuthHeader, AuthFooter, AuthPageLayout } from '../components' 16 + 17 + type SignInProps = WithChildren<PageProps> 18 + let { data }: SignInProps = $props() 19 + 20 + const { supabase, meta: { pageTitle } } = $derived(data) 21 + const { form, errors, constraints, message, enhance } = superForm(untrack(() => data.form), { 22 + applyAction: false, 23 + onResult: ({ result }) => { 24 + if (result.type === 'redirect') { 25 + goto(resolve('/')) 26 + } 27 + } 28 + }) 29 + 30 + const signInWithDiscord = async () => await supabase.auth.signInWithOAuth({ provider: 'discord' }) 31 + const signInWithGoogle = async () => await supabase.auth.signInWithOAuth({ provider: 'google' }) 32 + </script> 33 + 34 + <svelte:head> 35 + <title>{pageTitle}</title> 36 + </svelte:head> 37 + 38 + <AuthPageLayout> 39 + <AuthHeader ctaText={'Sign in'} /> 40 + {#if $message && errors} 41 + <Callout title={'Error'}> 42 + {$message} 43 + </Callout> 44 + {/if} 45 + <form method="POST" class="flex flex-col gap-6" novalidate use:enhance> 46 + <Field> 47 + <FieldLabel for="email">Email address</FieldLabel> 48 + <TextInput 49 + type="email" 50 + name="email" 51 + autocomplete="email" 52 + aria-invalid={$errors.email && true} 53 + bind:value={$form.email} 54 + {...$constraints.email} /> 55 + {#if $errors.email}<FieldError>{$errors.email}</FieldError>{/if} 56 + </Field> 57 + <Field> 58 + <FieldContent class="flex flex-row justify-between"> 59 + <FieldLabel for="password">Password</FieldLabel> 60 + <Link href="/reset-password">Forgot password?</Link> 61 + </FieldContent> 62 + <TextInput 63 + type="password" 64 + name="password" 65 + autocomplete="current-password" 66 + aria-invalid={$errors.password && true} 67 + bind:value={$form.password} 68 + {...$constraints.password} /> 69 + {#if $errors.password}<FieldError>{$errors.password}</FieldError>{/if} 70 + </Field> 71 + <Button type="submit" intent="primary"> 72 + <LogInIcon class="size-4" /> 73 + Sign in 74 + </Button> 75 + </form> 76 + <PhraseSeparator>Or</PhraseSeparator> 77 + <AuthFooter 78 + discordProps={{ onclick: signInWithDiscord }} 79 + googleProps={{ onclick: signInWithGoogle }} /> 80 + <p>Don't have an account? <Link href="/signup">Sign up</Link>.</p> 81 + </AuthPageLayout>
+10
app/src/routes/(auth)/signout/+page.server.ts
··· 1 + import { redirect } from '@sveltejs/kit' 2 + 3 + export async function load({ locals: { supabase } }): Promise<void> { 4 + if ((await supabase.auth.getUser()).error === null) { 5 + await supabase.auth.signOut() 6 + redirect(307, '/') 7 + } else { 8 + redirect(307, '/') 9 + } 10 + }
+48
app/src/routes/(auth)/signup/+page.server.ts
··· 1 + import { fail } from '@sveltejs/kit' 2 + import { message, superValidate } from 'sveltekit-superforms' 3 + import { zod4 } from 'sveltekit-superforms/adapters' 4 + import { signUpSchema } from '$lib/schemas/auth' 5 + import { pageTitle } from '$lib/utils' 6 + import type { Actions, PageServerLoad } from './$types' 7 + import { isUsernameAvailable } from '$lib/queries/isUsernameAvailable' 8 + 9 + export const load: PageServerLoad = async () => { 10 + return { 11 + form: await superValidate(zod4(signUpSchema)), 12 + meta: { 13 + pageTitle: pageTitle('Sign up'), 14 + }, 15 + } 16 + } 17 + 18 + export const actions: Actions = { 19 + default: async ({ request, locals: { supabase } }) => { 20 + const form = await superValidate(request, zod4(signUpSchema)) 21 + if (!form.valid) { 22 + return fail(400, { form }) 23 + } 24 + 25 + const usernameQuery = await isUsernameAvailable(supabase, form.data.username) 26 + if (usernameQuery.error) { 27 + return fail(400, { form }) 28 + } 29 + if (!usernameQuery.data.isAvailable) { 30 + return fail(400, { form }) 31 + } 32 + 33 + const signupQuery = await supabase.auth.signUp({ 34 + email: form.data.email, 35 + password: form.data.password, 36 + options: { 37 + data: { 38 + username: form.data.username, 39 + }, 40 + }, 41 + }) 42 + if (signupQuery.error) { 43 + return fail(400, { form }) 44 + } 45 + 46 + return message(form, 'Account created! Check your email to verify.') 47 + }, 48 + }
+96
app/src/routes/(auth)/signup/+page.svelte
··· 1 + <script lang="ts"> 2 + import UserPlusIcon from '@lucide/svelte/icons/user-plus' 3 + import type { WithChildren } from 'bits-ui' 4 + import { untrack } from 'svelte' 5 + import { superForm } from 'sveltekit-superforms' 6 + import { goto } from '$app/navigation' 7 + import { Field, FieldDescription, FieldError, FieldLabel } from '$form/Field' 8 + import { TextInput } from '$form/TextInput' 9 + import { Button } from '$ui/Button' 10 + import { Callout } from '$ui/Callout' 11 + import { Link } from '$ui/Link' 12 + import { PhraseSeparator } from '$ui/Separator' 13 + import type { PageProps } from './$types' 14 + import { AuthHeader, AuthFooter, AuthPageLayout } from '../components' 15 + import { resolve } from '$app/paths'; 16 + 17 + type SignUpProps = WithChildren<PageProps> 18 + let { data }: SignUpProps = $props() 19 + 20 + const { supabase, meta: { pageTitle } } = $derived(data) 21 + const { form, errors, constraints, message, enhance } = superForm(untrack(() => data.form), { 22 + applyAction: false, 23 + onResult: ({ result }) => { 24 + if (result.type === 'redirect') { 25 + // @ts-expect-error This is fine 26 + goto(resolve(result.location)) 27 + } 28 + }, 29 + onError: ({ result }) => { 30 + $message = result.error.message 31 + }, 32 + }) 33 + 34 + const signInWithDiscord = async () => await supabase.auth.signInWithOAuth({ provider: 'discord' }) 35 + const signInWithGoogle = async () => await supabase.auth.signInWithOAuth({ provider: 'google' }) 36 + </script> 37 + 38 + <svelte:head> 39 + <title>{pageTitle}</title> 40 + </svelte:head> 41 + 42 + <AuthPageLayout> 43 + <AuthHeader ctaText={'Sign up'} /> 44 + {#if $message} 45 + <Callout title={$errors ? 'Error' : 'Success!'}> 46 + {$message} 47 + </Callout> 48 + {/if} 49 + <form method="POST" class="flex flex-col gap-6" novalidate use:enhance> 50 + <Field> 51 + <FieldLabel for="email">Email address</FieldLabel> 52 + <TextInput 53 + type="email" 54 + name="email" 55 + autocomplete="email" 56 + bind:value={$form.email} 57 + {...$constraints.email} /> 58 + {#if $errors.email}<FieldError>{$errors.email}</FieldError>{/if} 59 + </Field> 60 + <Field> 61 + <FieldLabel for="username">Username</FieldLabel> 62 + <TextInput 63 + name="username" 64 + autocomplete="username" 65 + bind:value={$form.username} 66 + {...$constraints.username} /> 67 + <FieldDescription> 68 + The username may only contain alphanumeric characters, hyphens, and underscores, 69 + and may only start with a letter. 70 + </FieldDescription> 71 + {#if $errors.username}<FieldError>{$errors.username}</FieldError>{/if} 72 + </Field> 73 + <Field> 74 + <FieldLabel for="password">Password</FieldLabel> 75 + <TextInput 76 + type="password" 77 + name="password" 78 + autocomplete="new-password" 79 + bind:value={$form.password} 80 + {...$constraints.password} /> 81 + <FieldDescription> 82 + The password must be at least 8 characters long. 83 + </FieldDescription> 84 + {#if $errors.password}<FieldError>{$errors.password}</FieldError>{/if} 85 + </Field> 86 + <Button type="submit" intent="primary"> 87 + <UserPlusIcon class="size-4" /> 88 + Create account 89 + </Button> 90 + </form> 91 + <PhraseSeparator>Or</PhraseSeparator> 92 + <AuthFooter 93 + discordProps={{ onclick: signInWithDiscord }} 94 + googleProps={{ onclick: signInWithGoogle }} /> 95 + <p>Already have an account? <Link href="/signin">Sign in</Link>.</p> 96 + </AuthPageLayout>
+19 -14
app/src/routes/+layout.svelte
··· 8 8 import { DropdownMenu, Tooltip, type WithChildren } from 'bits-ui' 9 9 import { onMount } from 'svelte' 10 10 import { invalidate } from '$app/navigation' 11 - import { Button } from '$ui/Button' 11 + import { pageTitle } from '$lib/utils' 12 + import { LinkButton } from '$ui/Button' 12 13 import { DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '$ui/DropdownMenu' 13 14 import { Header } from '$ui/Site' 14 15 import { Profile, ProfilePicture } from '$ui/Profile' ··· 29 30 }) 30 31 return () => data.subscription.unsubscribe() 31 32 }) 32 - 33 - const signIn = async () => await supabase.auth.signInWithOAuth({ provider: 'discord' }) 34 - const signOut = async () => await supabase.auth.signOut() 35 33 </script> 36 34 37 35 <svelte:head> 38 - <title>The Drifting Starlight</title> 36 + <title>{pageTitle()}</title> 39 37 <meta name="theme-color" content="#00FF08" media="(prefers-color-scheme: light)"> 40 38 <meta name="theme-color" content="#151512" media="(prefers-color-scheme: dark)"> 41 39 </svelte:head> ··· 43 41 {#snippet loggedInDropdown(pfpUrl: string, username: string, userId: string)} 44 42 <DropdownMenu.Root> 45 43 <DropdownMenuTrigger> 46 - <ProfilePicture src={pfpUrl} /> 44 + <ProfilePicture {username} src={pfpUrl} /> 47 45 </DropdownMenuTrigger> 48 46 <DropdownMenu.Portal> 49 47 <DropdownMenuContent> 50 - <Profile pfpUrl={pfpUrl} username={username} /> 48 + <Profile {username} pfpUrl={pfpUrl} /> 51 49 <Separator class="my-2" /> 52 50 <DropdownMenuItem href={'/'}> 53 51 <HouseIcon class="size-5" strokeWidth={1.5} /> ··· 57 55 <UserIcon class="size-5" strokeWidth={1.5} /> 58 56 Profile 59 57 </DropdownMenuItem> 60 - <DropdownMenuItem href={`/characters/new`}> 58 + <DropdownMenuItem href={'/characters/new'}> 61 59 <UserPlusIcon class="size-5" strokeWidth={1.5} /> 62 60 New Character 63 61 </DropdownMenuItem> ··· 66 64 Settings 67 65 </DropdownMenuItem> 68 66 <Separator class="my-2" /> 69 - <DropdownMenuItem onclick={() => signOut()}> 67 + <DropdownMenuItem href={'/signout'}> 70 68 <LogOutIcon class="size-5" strokeWidth={1.5} /> 71 69 Sign Out 72 70 </DropdownMenuItem> ··· 78 76 <Tooltip.Provider> 79 77 <div class={["flex flex-col gap-4 h-screen"]}> 80 78 <Header> 79 + {@const user = session?.user} 81 80 {#if user} 82 81 {@const pfpUrl = user.user_metadata.avatar_url} 83 - {@const username = user.user_metadata.full_name} 82 + {@const username = user.user_metadata.username} 84 83 {@render loggedInDropdown(pfpUrl, username, user.id)} 85 84 {:else} 86 - <Button onclick={() => signIn()}> 87 - <LogInIcon class="size-5" /> 88 - Sign In 89 - </Button> 85 + <div class="flex flex-row gap-2"> 86 + <LinkButton href="/signin" intent="secondary"> 87 + <LogInIcon class="size-5" /> 88 + Sign In 89 + </LinkButton> 90 + <LinkButton href="/signup" intent="primary"> 91 + <UserPlusIcon class="size-5" /> 92 + Sign up 93 + </LinkButton> 94 + </div> 90 95 {/if} 91 96 </Header> 92 97 {@render children?.()}
+2
app/src/routes/+layout.ts
··· 18 18 const { 19 19 data: { session }, 20 20 } = await supabase.auth.getSession() 21 + 21 22 const { 22 23 data: { user }, 23 24 } = await supabase.auth.getUser() 25 + 24 26 return { session, supabase, user } 25 27 }
+5
app/src/routes/.well-known/change-password/+page.server.ts
··· 1 + import { redirect } from '@sveltejs/kit' 2 + 3 + export function load(): void { 4 + redirect(308, '/reset-password') 5 + }
+2 -7
app/src/routes/auth/callback/+server.ts
··· 1 1 import { redirect } from '@sveltejs/kit' 2 2 3 - export const GET = async (event) => { 4 - const { 5 - url, 6 - locals: { supabase }, 7 - } = event 8 - 3 + export const GET = async ({ url, locals: { supabase } }) => { 9 4 const code = url.searchParams.get('code') as string 10 5 const next = url.searchParams.get('next') ?? '/' 11 6 if (code) { ··· 16 11 } 17 12 18 13 // return the user to an error page with instructions 19 - throw redirect(303, '/auth/auth-code-error') 14 + throw redirect(303, '/auth/error') 20 15 }
+2 -1
app/src/routes/combat/+page.svelte
··· 1 1 <script lang="ts"> 2 2 import { Checkbox, CheckboxGroup, CheckboxGroupLabel } from '$form/Checkbox' 3 + import { pageTitle } from '$lib/utils' 3 4 import { AbilityCard } from '$patterns/AbilityCard' 4 5 import { PageLayout } from '$ui/Site' 5 6 import type { PageProps } from './$types' ··· 19 20 </script> 20 21 21 22 <svelte:head> 22 - <title>The Drifting Starlight | Combat</title> 23 + <title>{pageTitle('Combat')}</title> 23 24 </svelte:head> 24 25 25 26 <PageLayout
+5 -4
app/src/routes/species/new/+page.svelte
··· 1 1 <script lang="ts"> 2 2 import { AbilityShortArray, getAbilityName, getAbilityDesc } from '@starlight/types/dnd' 3 3 import { CheckboxCard } from '$form/Checkbox' 4 - import { TextAreaInput, TextInput } from '$form/TextInput' 5 - import { FormButton } from '$ui/Button' 4 + import { TextAreaInput } from '$form/TextInput' 5 + import { TextInput } from '$form/TextInput' 6 + import { Button } from '$ui/Button' 6 7 import { Heading, HeadingGroup, SubHeading } from '$ui/Heading' 7 8 import { PageLayout } from '$ui/Site' 8 9 </script> ··· 22 23 name="description" 23 24 label="Species description" 24 25 placeholder="Describe the species..." 25 - help="What do they look like? What are they capable of?" 26 + desc="What do they look like? What are they capable of?" 26 27 rows={7} /> 27 28 <div class="flex flex-col gap-6"> 28 29 <div class="leading-relaxed"> ··· 45 46 </div> 46 47 </div> 47 48 <div class="flex flex-row gap-4"> 48 - <FormButton type="submit" value="Register species" /> 49 + <Button intent="primary" type="submit">Register species</Button> 49 50 </div> 50 51 </form> 51 52 </PageLayout>
-7
app/src/routes/u/[page]/+page.svelte
··· 1 - <script> 2 - import { PageLayout } from '$ui/Site' 3 - </script> 4 - 5 - <PageLayout direction="col" class="gap-36"> 6 - 7 - </PageLayout>
+11
app/src/routes/users/[page]/+page.svelte
··· 1 + <script lang="ts"> 2 + import { PageLayout } from '$ui/Site' 3 + import type { PageProps } from './$types' 4 + 5 + type UserProfileProps = PageProps 6 + let { data, params }: UserProfileProps = $props() 7 + </script> 8 + 9 + <PageLayout display="flex" direction="col"> 10 + 11 + </PageLayout>
app/src/routes/users/settings/+page.svelte

This is a binary file and will not be displayed.

+4
app/supabase/migrations/20251227061516_initial_schema.sql
··· 1 + CREATE TABLE IF NOT EXISTS user_profile ( 2 + username VARCHAR(48) GENERATED ALWAYS AS IDENTITY PRIMARY KEY UNIQUE, 3 + email_address VARCHAR(48) REFERENCES users(user_id) 4 + );
+3 -3
package.json
··· 9 9 "type": "module", 10 10 "scripts": { 11 11 "clean": "rm -rf ./node_modules ./package-lock.json", 12 - "dev": "pnpm run dev --workspace=app", 12 + "dev": "pnpm --filter ./app dev", 13 13 "build": "tsdown && pnpm --filter \"icons\" build && pnpm --filter \"website\" build", 14 - "build-storybook": "pnpm run storybook --workspace=app", 15 - "check": "pnpm run check --workspace=app", 14 + "build-storybook": "pnpm --filter app storybook", 15 + "check": "pnpm --filter app check", 16 16 "fmt": "oxfmt", 17 17 "fmt-ci": "oxfmt --check", 18 18 "lint": "oxlint",
+8
packages/icons/package.json
··· 18 18 "types": "./dist/index.d.ts", 19 19 "svelte": "./dist/index.js" 20 20 }, 21 + "./discord": { 22 + "types": "./dist/DiscordIcon.svelte.d.ts", 23 + "svelte": "./dist/DiscordIcon.svelte" 24 + }, 21 25 "./element": { 22 26 "types": "./dist/ElementIcon.svelte.d.ts", 23 27 "svelte": "./dist/ElementIcon.svelte" 28 + }, 29 + "./google": { 30 + "types": "./dist/GoogleIcon.svelte.d.ts", 31 + "svelte": "./dist/GoogleIcon.svelte" 24 32 }, 25 33 "./mechanic": { 26 34 "types": "./dist/MechanicIcon.svelte.d.ts",
+15
packages/icons/src/lib/DiscordIcon.svelte
··· 1 + <script lang="ts"> 2 + import { Icon } from '@lucide/svelte' 3 + import type { IconNode, IconProps } from '@lucide/svelte' 4 + 5 + const iconNode: IconNode = [ 6 + ['path', { d: 'M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z' }], 7 + ] 8 + 9 + type DiscordIconProps = IconProps 10 + let props: DiscordIconProps = $props() 11 + </script> 12 + 13 + <Icon name="discord" {...props} iconNode={iconNode}> 14 + {@render props.children?.()} 15 + </Icon>
+15
packages/icons/src/lib/GoogleIcon.svelte
··· 1 + <script lang="ts"> 2 + import { Icon } from '@lucide/svelte' 3 + import type { IconNode, IconProps } from '@lucide/svelte' 4 + 5 + const iconNode: IconNode = [ 6 + ['path', { d: 'M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z' }], 7 + ] 8 + 9 + type GoogleIconProps = IconProps 10 + let props: GoogleIconProps = $props() 11 + </script> 12 + 13 + <Icon name="google" {...props} iconNode={iconNode}> 14 + {@render props.children?.()} 15 + </Icon>
+12
packages/icons/stories/DiscordIcon.stories.svelte
··· 1 + <script module> 2 + import { defineMeta } from '@storybook/addon-svelte-csf' 3 + import DiscordIcon from './../src/lib/DiscordIcon.svelte' 4 + 5 + const { Story } = defineMeta({ 6 + component: DiscordIcon, 7 + tags: ['autodocs'], 8 + }) 9 + 10 + </script> 11 + 12 + <Story name="DiscordIcon" />
+12
packages/icons/stories/GoogleIcon.stories.svelte
··· 1 + <script module> 2 + import { defineMeta } from '@storybook/addon-svelte-csf' 3 + import GoogleIcon from './../src/lib/GoogleIcon.sveltee' 4 + 5 + const { Story } = defineMeta({ 6 + component: GoogleIcon, 7 + tags: ['autodocs'], 8 + }) 9 + 10 + </script> 11 + 12 + <Story name="GoogleIcon" />
+646 -101
pnpm-lock.yaml
··· 15 15 lorem-ipsum: 16 16 specifier: ^2.0.8 17 17 version: 2.0.8 18 + resend: 19 + specifier: ^6.6.0 20 + version: 6.6.0 18 21 supabase: 19 - specifier: ^2.67.3 20 - version: 2.70.4 22 + specifier: ^2.70.5 23 + version: 2.70.5 21 24 zod: 22 25 specifier: ^4.2.1 23 26 version: 4.2.1 ··· 38 41 specifier: ^5.9.3 39 42 version: 5.9.3 40 43 wrangler: 41 - specifier: ^4.56.0 44 + specifier: ^4.54.0 42 45 version: 4.56.0 43 46 storybook: 44 47 '@storybook/addon-a11y': ··· 63 66 specifier: ^10.1.10 64 67 version: 10.1.10 65 68 chromatic: 66 - specifier: ^13.3.3 69 + specifier: ^13.3.4 67 70 version: 13.3.4 68 71 storybook: 69 72 specifier: ^10.1.10 70 73 version: 10.1.10 71 74 svelte: 72 75 '@lucide/svelte': 73 - specifier: ^0.x 76 + specifier: ^0.562.0 74 77 version: 0.562.0 75 78 '@sveltejs/adapter-auto': 76 79 specifier: ^7.0.0 ··· 88 91 specifier: ^6.2.1 89 92 version: 6.2.1 90 93 '@tanstack/svelte-table': 91 - specifier: npm:tanstack-table-8-svelte-5@^0.1 94 + specifier: npm:tanstack-table-8-svelte-5@^0.1.2 92 95 version: 0.1.2 93 96 bits-ui: 94 - specifier: ^2.14.2 97 + specifier: ^2.14.4 95 98 version: 2.14.4 96 99 mdsvex: 97 100 specifier: ^0.12.6 ··· 100 103 specifier: ^1.1.0 101 104 version: 1.1.0 102 105 svelte: 103 - specifier: ^5.46.0 106 + specifier: ^5.46.1 104 107 version: 5.46.0 105 108 svelte-check: 106 109 specifier: ^4.3.5 107 110 version: 4.3.5 111 + sveltekit-superforms: 112 + specifier: ^2.29.1 113 + version: 2.29.1 108 114 vitest-browser-svelte: 109 115 specifier: ^2.0.1 110 116 version: 2.0.1 ··· 113 119 specifier: ^4.1.18 114 120 version: 4.1.18 115 121 clsx: 116 - specifier: ^2.x 122 + specifier: ^2.1.1 117 123 version: 2.1.1 118 124 tailwind-merge: 119 - specifier: ^3.4.x 125 + specifier: ^3.4.0 120 126 version: 3.4.0 121 127 tailwind-variants: 122 - specifier: ^3.2.x 128 + specifier: ^3.2.2 123 129 version: 3.2.2 124 130 tailwindcss: 125 - specifier: ^4.1.17 131 + specifier: ^4.1.18 126 132 version: 4.1.18 133 + tw-animate-css: 134 + specifier: ^1.4.0 135 + version: 1.4.0 127 136 voidzero: 128 137 '@vitest/browser-playwright': 129 138 specifier: ^4.0.16 ··· 147 156 specifier: ^0.10.0 148 157 version: 0.10.0 149 158 playwright: 150 - specifier: ^1.56.1 159 + specifier: ^1.57.0 151 160 version: 1.57.0 152 161 publint: 153 162 specifier: ^0.3.16 ··· 178 187 version: 10.1.10(@types/react@19.2.7)(esbuild@0.27.2)(rollup@4.54.0)(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) 179 188 '@storybook/addon-svelte-csf': 180 189 specifier: catalog:storybook 181 - version: 5.0.10(@storybook/svelte@10.1.10(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(svelte@5.46.0))(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) 190 + version: 5.0.10(@storybook/svelte@10.1.10(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(svelte@5.46.1))(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) 182 191 '@storybook/addon-themes': 183 192 specifier: catalog:storybook 184 193 version: 10.1.10(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)) ··· 187 196 version: 10.1.10(@vitest/browser-playwright@4.0.16)(@vitest/browser@4.0.16(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))(vitest@4.0.16))(@vitest/runner@4.0.16)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vitest@4.0.16) 188 197 '@storybook/svelte': 189 198 specifier: catalog:storybook 190 - version: 10.1.10(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(svelte@5.46.0) 199 + version: 10.1.10(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(svelte@5.46.1) 191 200 '@storybook/sveltekit': 192 201 specifier: catalog:storybook 193 - version: 10.1.10(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(esbuild@0.27.2)(rollup@4.54.0)(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) 202 + version: 10.1.10(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(esbuild@0.27.2)(rollup@4.54.0)(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) 194 203 '@types/node': 195 204 specifier: catalog:dev 196 205 version: 25.0.3 ··· 205 214 version: 2.1.1 206 215 eslint-plugin-svelte: 207 216 specifier: catalog:dev 208 - version: 3.13.1(eslint@9.39.2(jiti@2.6.1))(svelte@5.46.0) 217 + version: 3.13.1(eslint@9.39.2(jiti@2.6.1))(svelte@5.46.1) 209 218 node-modules-inspector: 210 219 specifier: catalog:dev 211 220 version: 1.2.0 ··· 244 253 version: 4.0.16(@types/node@25.0.3)(@vitest/browser-playwright@4.0.16)(@vitest/ui@4.0.16)(jiti@2.6.1)(lightningcss@1.30.2) 245 254 wrangler: 246 255 specifier: catalog:dev 247 - version: 4.56.0(@cloudflare/workers-types@4.20251224.0) 256 + version: 4.56.0(@cloudflare/workers-types@4.20251225.0) 248 257 249 258 app: 250 259 dependencies: 251 260 '@lucide/svelte': 252 261 specifier: catalog:svelte 253 - version: 0.562.0(svelte@5.46.0) 262 + version: 0.562.0(svelte@5.46.1) 254 263 '@starlight/color': 255 - specifier: workspace:../packages/color 264 + specifier: link:../packages/color 256 265 version: link:../packages/color 257 266 '@starlight/icons': 258 - specifier: workspace:../packages/icons 267 + specifier: link:../packages/icons 259 268 version: link:../packages/icons 260 269 '@starlight/storybook-utils': 261 - specifier: workspace:../packages/storybook-utils 270 + specifier: link:../packages/storybook-utils 262 271 version: link:../packages/storybook-utils 263 272 '@starlight/tokenizer': 264 - specifier: workspace:../packages/tokenizer 273 + specifier: link:../packages/tokenizer 265 274 version: link:../packages/tokenizer 266 275 '@starlight/types': 267 - specifier: workspace:../packages/types 276 + specifier: link:../packages/types 268 277 version: link:../packages/types 269 278 '@supabase/ssr': 270 279 specifier: catalog:app ··· 274 283 version: 2.89.0 275 284 bits-ui: 276 285 specifier: catalog:svelte 277 - version: 2.14.4(@internationalized/date@3.10.1)(@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.0) 286 + version: 2.14.4(@internationalized/date@3.10.1)(@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.1) 278 287 clsx: 279 288 specifier: catalog:tailwind 280 289 version: 2.1.1 ··· 283 292 version: 2.0.8 284 293 mode-watcher: 285 294 specifier: catalog:svelte 286 - version: 1.1.0(svelte@5.46.0) 295 + version: 1.1.0(svelte@5.46.1) 296 + sveltekit-superforms: 297 + specifier: catalog:svelte 298 + version: 2.29.1(@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(@types/json-schema@7.0.15)(svelte@5.46.1)(typescript@5.9.3) 287 299 tailwind-merge: 288 300 specifier: catalog:tailwind 289 301 version: 3.4.0 290 302 tailwind-variants: 291 303 specifier: catalog:tailwind 292 304 version: 3.2.2(tailwind-merge@3.4.0)(tailwindcss@4.1.18) 305 + tw-animate-css: 306 + specifier: catalog:tailwind 307 + version: 1.4.0 308 + zod: 309 + specifier: catalog:app 310 + version: 4.2.1 293 311 devDependencies: 294 312 '@sveltejs/adapter-cloudflare': 295 313 specifier: catalog:svelte 296 - version: 7.2.4(@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(wrangler@4.56.0(@cloudflare/workers-types@4.20251224.0)) 314 + version: 7.2.4(@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(wrangler@4.56.0(@cloudflare/workers-types@4.20251225.0)) 297 315 '@sveltejs/kit': 298 316 specifier: catalog:svelte 299 - version: 2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) 317 + version: 2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) 300 318 '@sveltejs/vite-plugin-svelte': 301 319 specifier: catalog:svelte 302 - version: 6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) 320 + version: 6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) 303 321 '@tailwindcss/vite': 304 322 specifier: catalog:tailwind 305 323 version: 4.1.18(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) 306 324 '@tanstack/svelte-table': 307 325 specifier: catalog:svelte 308 - version: tanstack-table-8-svelte-5@0.1.2(svelte@5.46.0) 326 + version: tanstack-table-8-svelte-5@0.1.2(svelte@5.46.1) 309 327 '@vitest/browser-playwright': 310 328 specifier: catalog:voidzero 311 329 version: 4.0.16(playwright@1.57.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))(vitest@4.0.16) ··· 317 335 version: 1.30.2 318 336 mdsvex: 319 337 specifier: catalog:svelte 320 - version: 0.12.6(svelte@5.46.0) 338 + version: 0.12.6(svelte@5.46.1) 321 339 playwright: 322 340 specifier: catalog:voidzero 323 341 version: 1.57.0 342 + resend: 343 + specifier: catalog:app 344 + version: 6.6.0 324 345 supabase: 325 346 specifier: catalog:app 326 - version: 2.70.4 347 + version: 2.70.5 327 348 svelte: 328 349 specifier: catalog:svelte 329 - version: 5.46.0 350 + version: 5.46.1 330 351 svelte-check: 331 352 specifier: catalog:svelte 332 - version: 4.3.5(picomatch@4.0.3)(svelte@5.46.0)(typescript@5.9.3) 353 + version: 4.3.5(picomatch@4.0.3)(svelte@5.46.1)(typescript@5.9.3) 333 354 tailwindcss: 334 355 specifier: catalog:tailwind 335 356 version: 4.1.18 336 357 vitest-browser-svelte: 337 358 specifier: catalog:svelte 338 - version: 2.0.1(svelte@5.46.0)(vitest@4.0.16) 359 + version: 2.0.1(svelte@5.46.1)(vitest@4.0.16) 339 360 340 361 packages/color: 341 362 devDependencies: ··· 421 442 '@adobe/css-tools@4.4.4': 422 443 resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} 423 444 445 + '@ark/schema@0.56.0': 446 + resolution: {integrity: sha512-ECg3hox/6Z/nLajxXqNhgPtNdHWC9zNsDyskwO28WinoFEnWow4IsERNz9AnXRhTZJnYIlAJ4uGn3nlLk65vZA==} 447 + 448 + '@ark/util@0.56.0': 449 + resolution: {integrity: sha512-BghfRC8b9pNs3vBoDJhcta0/c1J1rsoS1+HgVUreMFPdhz/CRAKReAu57YEllNaSy98rWAdY1gE+gFup7OXpgA==} 450 + 424 451 '@babel/code-frame@7.27.1': 425 452 resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} 426 453 engines: {node: '>=6.9.0'} ··· 497 524 cpu: [x64] 498 525 os: [win32] 499 526 500 - '@cloudflare/workers-types@4.20251224.0': 501 - resolution: {integrity: sha512-6Prvhe2L4iH4wL8hDpWabFxnauGqDZ+o66fMChGRE2gLDa1YYDxu8zw15p+Iq5minz6d5DkJ8M0l5uudx/+d4g==} 527 + '@cloudflare/workers-types@4.20251225.0': 528 + resolution: {integrity: sha512-ZZl0cNLFcsBRFKtMftKWOsfAybUYSeiTMzpQV1NlTVlByHAs1rGQt45Jw/qz8LrfHoq9PGTieSj9W350Gi4Pvg==} 502 529 503 530 '@cspotcode/source-map-support@0.8.1': 504 531 resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} ··· 863 890 resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} 864 891 engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} 865 892 893 + '@exodus/schemasafe@1.3.0': 894 + resolution: {integrity: sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==} 895 + 866 896 '@floating-ui/core@1.7.3': 867 897 resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} 868 898 ··· 872 902 '@floating-ui/utils@0.2.10': 873 903 resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} 874 904 905 + '@hapi/hoek@9.3.0': 906 + resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} 907 + 908 + '@hapi/topo@5.1.0': 909 + resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} 910 + 875 911 '@humanfs/core@0.19.1': 876 912 resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} 877 913 engines: {node: '>=18.18.0'} ··· 1161 1197 '@poppinss/exception@1.2.3': 1162 1198 resolution: {integrity: sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==} 1163 1199 1200 + '@poppinss/macroable@1.1.0': 1201 + resolution: {integrity: sha512-y/YKzZDuG8XrpXpM7Z1RdQpiIc0MAKyva24Ux1PB4aI7RiSI/79K8JVDcdyubriTm7vJ1LhFs8CrZpmPnx/8Pw==} 1202 + 1164 1203 '@publint/pack@0.1.2': 1165 1204 resolution: {integrity: sha512-S+9ANAvUmjutrshV4jZjaiG8XQyuJIZ8a4utWmN/vW1sgQ9IfBnPndwkmQYw53QmouOIytT874u65HEmu6H5jw==} 1166 1205 engines: {node: '>=18'} ··· 1358 1397 cpu: [x64] 1359 1398 os: [win32] 1360 1399 1400 + '@sideway/address@4.1.5': 1401 + resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==} 1402 + 1403 + '@sideway/formula@3.0.1': 1404 + resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==} 1405 + 1406 + '@sideway/pinpoint@2.0.0': 1407 + resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} 1408 + 1361 1409 '@sindresorhus/is@7.1.1': 1362 1410 resolution: {integrity: sha512-rO92VvpgMc3kfiTjGT52LEtJ8Yc5kCWhZjLQ3LwlA4pSgPpQO7bVpYXParOD8Jwf+cVQECJo3yP/4I8aZtUQTQ==} 1363 1411 engines: {node: '>=18'} 1364 1412 1365 1413 '@speed-highlight/core@1.2.12': 1366 1414 resolution: {integrity: sha512-uilwrK0Ygyri5dToHYdZSjcvpS2ZwX0w5aSt3GCEN9hrjxWCoeV4Z2DTXuxjwbntaLQIEEAlCeNQss5SoHvAEA==} 1415 + 1416 + '@stablelib/base64@1.0.1': 1417 + resolution: {integrity: sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==} 1367 1418 1368 1419 '@standard-schema/spec@1.1.0': 1369 1420 resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} ··· 1554 1605 svelte: ^5.0.0 1555 1606 vite: ^6.3.0 || ^7.0.0 1556 1607 1557 - '@swc/helpers@0.5.17': 1558 - resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==} 1608 + '@swc/helpers@0.5.18': 1609 + resolution: {integrity: sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==} 1559 1610 1560 1611 '@tailwindcss/node@4.1.18': 1561 1612 resolution: {integrity: sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==} ··· 1692 1743 '@types/mdx@2.0.13': 1693 1744 resolution: {integrity: sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==} 1694 1745 1746 + '@types/node@22.19.3': 1747 + resolution: {integrity: sha512-1N9SBnWYOJTrNZCdh/yJE+t910Y128BoyY+zBLWhL3r0TYzlTmFdXrPwHL9DyFZmlEXNQQolTZh3KHV31QDhyA==} 1748 + 1695 1749 '@types/node@25.0.3': 1696 1750 resolution: {integrity: sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==} 1697 1751 ··· 1703 1757 1704 1758 '@types/unist@2.0.11': 1705 1759 resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} 1760 + 1761 + '@types/validator@13.15.10': 1762 + resolution: {integrity: sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==} 1706 1763 1707 1764 '@types/ws@8.18.1': 1708 1765 resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} 1709 1766 1767 + '@typeschema/class-validator@0.3.0': 1768 + resolution: {integrity: sha512-OJSFeZDIQ8EK1HTljKLT5CItM2wsbgczLN8tMEfz3I1Lmhc5TBfkZ0eikFzUC16tI3d1Nag7um6TfCgp2I2Bww==} 1769 + peerDependencies: 1770 + class-validator: ^0.14.1 1771 + peerDependenciesMeta: 1772 + class-validator: 1773 + optional: true 1774 + 1775 + '@typeschema/core@0.14.0': 1776 + resolution: {integrity: sha512-Ia6PtZHcL3KqsAWXjMi5xIyZ7XMH4aSnOQes8mfMLx+wGFGtGRNlwe6Y7cYvX+WfNK67OL0/HSe9t8QDygV0/w==} 1777 + peerDependencies: 1778 + '@types/json-schema': ^7.0.15 1779 + peerDependenciesMeta: 1780 + '@types/json-schema': 1781 + optional: true 1782 + 1783 + '@valibot/to-json-schema@1.5.0': 1784 + resolution: {integrity: sha512-GE7DmSr1C2UCWPiV0upRH6mv0cCPsqYGs819fb6srCS1tWhyXrkGGe+zxUiwzn/L1BOfADH4sNjY/YHCuP8phQ==} 1785 + peerDependencies: 1786 + valibot: ^1.2.0 1787 + 1788 + '@vinejs/compiler@3.0.0': 1789 + resolution: {integrity: sha512-v9Lsv59nR56+bmy2p0+czjZxsLHwaibJ+SV5iK9JJfehlJMa501jUJQqqz4X/OqKXrxtE3uTQmSqjUqzF3B2mw==} 1790 + engines: {node: '>=18.0.0'} 1791 + 1792 + '@vinejs/vine@3.0.1': 1793 + resolution: {integrity: sha512-ZtvYkYpZOYdvbws3uaOAvTFuvFXoQGAtmzeiXu+XSMGxi5GVsODpoI9Xu9TplEMuD/5fmAtBbKb9cQHkWkLXDQ==} 1794 + engines: {node: '>=18.16.0'} 1795 + 1710 1796 '@vitest/browser-playwright@4.0.16': 1711 1797 resolution: {integrity: sha512-I2Fy/ANdphi1yI46d15o0M1M4M0UJrUiVKkH5oKeRZZCdPg0fw/cfTKZzv9Ge9eobtJYp4BGblMzXdXH0vcl5g==} 1712 1798 peerDependencies: ··· 1840 1926 resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} 1841 1927 engines: {node: '>= 0.4'} 1842 1928 1929 + arkregex@0.0.5: 1930 + resolution: {integrity: sha512-ncYjBdLlh5/QnVsAA8De16Tc9EqmYM7y/WU9j+236KcyYNUXogpz3sC4ATIZYzzLxwI+0sEOaQLEmLmRleaEXw==} 1931 + 1932 + arktype@2.1.29: 1933 + resolution: {integrity: sha512-jyfKk4xIOzvYNayqnD8ZJQqOwcrTOUbIU4293yrzAjA3O1dWh61j71ArMQ6tS/u4pD7vabSPe7nG3RCyoXW6RQ==} 1934 + 1843 1935 assertion-error@2.0.1: 1844 1936 resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} 1845 1937 engines: {node: '>=12'} ··· 1901 1993 resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} 1902 1994 engines: {node: '>=6'} 1903 1995 1996 + camelcase@8.0.0: 1997 + resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==} 1998 + engines: {node: '>=16'} 1999 + 1904 2000 chai@5.3.3: 1905 2001 resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} 1906 2002 engines: {node: '>=18'} ··· 1941 2037 '@chromatic-com/playwright': 1942 2038 optional: true 1943 2039 2040 + class-validator@0.14.3: 2041 + resolution: {integrity: sha512-rXXekcjofVN1LTOSw+u4u9WXVEUvNBVjORW154q/IdmYWy1nMbOU9aNtZB0t8m+FJQ9q91jlr2f9CwwUFdFMRA==} 2042 + 1944 2043 clsx@2.1.1: 1945 2044 resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} 1946 2045 engines: {node: '>=6'} ··· 2009 2108 resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} 2010 2109 engines: {node: '>= 12'} 2011 2110 2111 + dayjs@1.11.19: 2112 + resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} 2113 + 2012 2114 debug@4.4.3: 2013 2115 resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} 2014 2116 engines: {node: '>=6.0'} ··· 2069 2171 devalue@5.6.1: 2070 2172 resolution: {integrity: sha512-jDwizj+IlEZBunHcOuuFVBnIMPAEHvTsJj0BcIp94xYguLRVBcXO853px/MyIJvbVzWdsGvrRweIUWJw8hBP7A==} 2071 2173 2174 + dlv@1.1.3: 2175 + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} 2176 + 2072 2177 dom-accessibility-api@0.5.16: 2073 2178 resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} 2074 2179 ··· 2084 2189 oxc-resolver: 2085 2190 optional: true 2086 2191 2192 + effect@3.19.13: 2193 + resolution: {integrity: sha512-8MZ783YuHRwHZX2Mmm+bpGxq+7XPd88sWwYAz2Ysry80sEKpftDZXs2Hg9ZyjESi1IBTNHF0oDKe0zJRkUlyew==} 2194 + 2087 2195 empathic@2.0.0: 2088 2196 resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} 2089 2197 engines: {node: '>=14'} ··· 2101 2209 es-toolkit@1.43.0: 2102 2210 resolution: {integrity: sha512-SKCT8AsWvYzBBuUqMk4NPwFlSdqLpJwmy6AP322ERn8W2YLIB6JBXnwMI2Qsh2gfphT3q7EKAxKb23cvFHFwKA==} 2103 2211 2212 + es6-promise@4.2.8: 2213 + resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} 2214 + 2104 2215 esbuild@0.27.0: 2105 2216 resolution: {integrity: sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA==} 2106 2217 engines: {node: '>=18'} ··· 2198 2309 exsolve@1.0.8: 2199 2310 resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} 2200 2311 2312 + fast-check@3.23.2: 2313 + resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==} 2314 + engines: {node: '>=8.0.0'} 2315 + 2201 2316 fast-deep-equal@3.1.3: 2202 2317 resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} 2203 2318 ··· 2209 2324 2210 2325 fast-npm-meta@0.4.7: 2211 2326 resolution: {integrity: sha512-aZU3i3eRcSb2NCq8i6N6IlyiTyF6vqAqzBGl2NBF6ngNx/GIqfYbkLDIKZ4z4P0o/RmtsFnVqHwdrSm13o4tnQ==} 2327 + 2328 + fast-sha256@1.3.0: 2329 + resolution: {integrity: sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==} 2212 2330 2213 2331 fdir@6.5.0: 2214 2332 resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} ··· 2376 2494 jiti@2.6.1: 2377 2495 resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} 2378 2496 hasBin: true 2497 + 2498 + joi@17.13.3: 2499 + resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==} 2379 2500 2380 2501 js-tokens@4.0.0: 2381 2502 resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} ··· 2395 2516 json-buffer@3.0.1: 2396 2517 resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} 2397 2518 2519 + json-schema-to-ts@3.1.1: 2520 + resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==} 2521 + engines: {node: '>=16'} 2522 + 2398 2523 json-schema-traverse@0.4.1: 2399 2524 resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} 2400 2525 ··· 2417 2542 levn@0.4.1: 2418 2543 resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} 2419 2544 engines: {node: '>= 0.8.0'} 2545 + 2546 + libphonenumber-js@1.12.33: 2547 + resolution: {integrity: sha512-r9kw4OA6oDO4dPXkOrXTkArQAafIKAU71hChInV4FxZ69dxCfbwQGDPzqR5/vea94wU705/3AZroEbSoeVWrQw==} 2420 2548 2421 2549 lightningcss-android-arm64@1.30.2: 2422 2550 resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} ··· 2532 2660 peerDependencies: 2533 2661 svelte: ^3.56.0 || ^4.0.0 || ^5.0.0-next.120 2534 2662 2663 + memoize-weak@1.0.2: 2664 + resolution: {integrity: sha512-gj39xkrjEw7nCn4nJ1M5ms6+MyMlyiGmttzsqAUsAKn6bYKwuTHh/AO3cKPF8IBrTIYTxb0wWXFs3E//Y8VoWQ==} 2665 + 2535 2666 mime@3.0.0: 2536 2667 resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} 2537 2668 engines: {node: '>=10.0.0'} ··· 2610 2741 resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} 2611 2742 engines: {node: '>=0.10.0'} 2612 2743 2744 + normalize-url@8.1.0: 2745 + resolution: {integrity: sha512-X06Mfd/5aKsRHc0O0J5CUedwnPmnDtLF2+nq+KN9KSDlJHkPuh0JUviWjEWMe0SW/9TDdSLVPuk7L5gGTIA1/w==} 2746 + engines: {node: '>=14.16'} 2747 + 2613 2748 npm-normalize-package-bin@5.0.0: 2614 2749 resolution: {integrity: sha512-CJi3OS4JLsNMmr2u07OJlhcrPxCeOeP/4xq67aWNai6TNWWbTrlNDgl8NcFKVlcBKp18GPj+EzbNIgrBfZhsag==} 2615 2750 engines: {node: ^20.17.0 || >=22.9.0} ··· 2773 2908 resolution: {integrity: sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==} 2774 2909 engines: {node: ^20.17.0 || >=22.9.0} 2775 2910 2911 + property-expr@2.0.6: 2912 + resolution: {integrity: sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==} 2913 + 2776 2914 publint@0.3.16: 2777 2915 resolution: {integrity: sha512-MFqyfRLAExPVZdTQFwkAQELzA8idyXzROVOytg6nEJ/GEypXBUmMGrVaID8cTuzRS1U5L8yTOdOJtMXgFUJAeA==} 2778 2916 engines: {node: '>=18'} ··· 2782 2920 resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} 2783 2921 engines: {node: '>=6'} 2784 2922 2923 + pure-rand@6.1.0: 2924 + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} 2925 + 2785 2926 quansync@1.0.0: 2786 2927 resolution: {integrity: sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==} 2928 + 2929 + querystringify@2.2.0: 2930 + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} 2787 2931 2788 2932 radix3@1.1.2: 2789 2933 resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} ··· 2823 2967 regexparam@3.0.0: 2824 2968 resolution: {integrity: sha512-RSYAtP31mvYLkAHrOlh25pCNQ5hWnT106VukGaaFfuJrZFkGRX5GhUAdPqpSDXxOhA2c4akmRuplv1mRqnBn6Q==} 2825 2969 engines: {node: '>=8'} 2970 + 2971 + requires-port@1.0.0: 2972 + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} 2973 + 2974 + resend@6.6.0: 2975 + resolution: {integrity: sha512-d1WoOqSxj5x76JtQMrieNAG1kZkh4NU4f+Je1yq4++JsDpLddhEwnJlNfvkCzvUuZy9ZquWmMMAm2mENd2JvRw==} 2976 + engines: {node: '>=20'} 2977 + peerDependencies: 2978 + '@react-email/render': '*' 2979 + peerDependenciesMeta: 2980 + '@react-email/render': 2981 + optional: true 2826 2982 2827 2983 resolve-from@4.0.0: 2828 2984 resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} ··· 2972 3128 style-to-object@1.0.14: 2973 3129 resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} 2974 3130 2975 - supabase@2.70.4: 2976 - resolution: {integrity: sha512-6Z5d0Snq5dxjL2K6XY89fPd9PNUJi83p7UpwlurPeSOHYhJfX9DbhzLhBGygrGigLST3M97ITgp4sFDXPd77Iw==} 3131 + supabase@2.70.5: 3132 + resolution: {integrity: sha512-HtMGtYbcL9dxi2Yz4eGWWlxl9nQi76pOyGgCTBeE67p5AeIlv+KJhDOR8oinaNfHHMPKk0Uo1WW7Kxyrz+tdgg==} 2977 3133 engines: {npm: '>=8'} 2978 3134 hasBin: true 3135 + 3136 + superstruct@2.0.2: 3137 + resolution: {integrity: sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==} 3138 + engines: {node: '>=14.0.0'} 2979 3139 2980 3140 supports-color@10.2.2: 2981 3141 resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} ··· 3030 3190 resolution: {integrity: sha512-ZhLtvroYxUxr+HQJfMZEDRsGsmU46x12RvAv/zi9584f5KOX7bUrEbhPJ7cKFmUvZTJXi/CFZUYwDC6M1FigPw==} 3031 3191 engines: {node: '>=18'} 3032 3192 3193 + svelte@5.46.1: 3194 + resolution: {integrity: sha512-ynjfCHD3nP2el70kN5Pmg37sSi0EjOm9FgHYQdC4giWG/hzO3AatzXXJJgP305uIhGQxSufJLuYWtkY8uK/8RA==} 3195 + engines: {node: '>=18'} 3196 + 3197 + sveltekit-superforms@2.29.1: 3198 + resolution: {integrity: sha512-9Cv1beOVPgm8rb8NZBqLdlZ9cBqRBTk0+6/oHn7DWvHQoAFie1EPjh1e4NHO3Qouv1Zq9QTGrZNDbYcetkuOVw==} 3199 + peerDependencies: 3200 + '@sveltejs/kit': 1.x || 2.x 3201 + svelte: 3.x || 4.x || >=5.0.0-next.51 3202 + 3203 + svix@1.76.1: 3204 + resolution: {integrity: sha512-CRuDWBTgYfDnBLRaZdKp9VuoPcNUq9An14c/k+4YJ15Qc5Grvf66vp0jvTltd4t7OIRj+8lM1DAgvSgvf7hdLw==} 3205 + 3033 3206 tabbable@6.3.0: 3034 3207 resolution: {integrity: sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ==} 3035 3208 ··· 3065 3238 tar@7.5.2: 3066 3239 resolution: {integrity: sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==} 3067 3240 engines: {node: '>=18'} 3241 + 3242 + tiny-case@1.0.3: 3243 + resolution: {integrity: sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==} 3068 3244 3069 3245 tiny-invariant@1.3.3: 3070 3246 resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} ··· 3096 3272 resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} 3097 3273 engines: {node: '>=14.0.0'} 3098 3274 3275 + toposort@2.0.2: 3276 + resolution: {integrity: sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==} 3277 + 3099 3278 totalist@3.0.1: 3100 3279 resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} 3101 3280 engines: {node: '>=6'} ··· 3104 3283 resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} 3105 3284 hasBin: true 3106 3285 3286 + ts-algebra@2.0.0: 3287 + resolution: {integrity: sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==} 3288 + 3107 3289 ts-dedent@2.2.0: 3108 3290 resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} 3109 3291 engines: {node: '>=6.10'} 3292 + 3293 + ts-deepmerge@7.0.3: 3294 + resolution: {integrity: sha512-Du/ZW2RfwV/D4cmA5rXafYjBQVuvu4qGiEEla4EmEHVHgRdx68Gftx7i66jn2bzHPwSVZY36Ae6OuDn9el4ZKA==} 3295 + engines: {node: '>=14.13.1'} 3110 3296 3111 3297 tsdown@0.18.2: 3112 3298 resolution: {integrity: sha512-2o6p/9WjcQrgKnz5/VppOstsqXdTER6G6gPe5yhuP57AueIr2y/NQFKdFPHuqMqZpxRLVjm7MP/dXWG7EJpehg==} ··· 3136 3322 tslib@2.8.1: 3137 3323 resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} 3138 3324 3325 + tw-animate-css@1.4.0: 3326 + resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==} 3327 + 3139 3328 type-check@0.4.0: 3140 3329 resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} 3141 3330 engines: {node: '>= 0.8.0'} ··· 3148 3337 resolution: {integrity: sha512-VCn+LMHbd4t6sF3wfU/+HKT63C9OoyrSIf4b+vtWHpt2U7/4InZG467YDNMFMR70DdHjAdpPWmw2lzRdg0Xqqg==} 3149 3338 engines: {node: '>=20'} 3150 3339 3340 + typebox@1.0.69: 3341 + resolution: {integrity: sha512-FwCcidqIxCAXRHxT9UNwiuf0f/EgLGc09K78K1d39uTLwPPmntPVs4YHxmj53RJ340pDkuPBOhOGdzg7cBYX4Q==} 3342 + 3151 3343 typescript@5.9.3: 3152 3344 resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} 3153 3345 engines: {node: '>=14.17'} ··· 3164 3356 3165 3357 uncrypto@0.1.3: 3166 3358 resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} 3359 + 3360 + undici-types@6.21.0: 3361 + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} 3167 3362 3168 3363 undici-types@7.16.0: 3169 3364 resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} ··· 3266 3461 uri-js@4.4.1: 3267 3462 resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} 3268 3463 3464 + url-parse@1.5.10: 3465 + resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} 3466 + 3269 3467 use-sync-external-store@1.6.0: 3270 3468 resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} 3271 3469 peerDependencies: ··· 3274 3472 util-deprecate@1.0.2: 3275 3473 resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} 3276 3474 3475 + uuid@10.0.0: 3476 + resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} 3477 + hasBin: true 3478 + 3479 + valibot@1.2.0: 3480 + resolution: {integrity: sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==} 3481 + peerDependencies: 3482 + typescript: '>=5' 3483 + peerDependenciesMeta: 3484 + typescript: 3485 + optional: true 3486 + 3487 + validator@13.15.26: 3488 + resolution: {integrity: sha512-spH26xU080ydGggxRyR1Yhcbgx+j3y5jbNXk/8L+iRvdIEQ4uTRH2Sgf2dokud6Q4oAtsbNvJ1Ft+9xmm6IZcA==} 3489 + engines: {node: '>= 0.10'} 3490 + 3277 3491 vfile-message@2.0.4: 3278 3492 resolution: {integrity: sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==} 3279 3493 ··· 3398 3612 wrangler@4.56.0: 3399 3613 resolution: {integrity: sha512-Nqi8duQeRbA+31QrD6QlWHW3IZVnuuRxMy7DEg46deUzywivmaRV/euBN5KKXDPtA24VyhYsK7I0tkb7P5DM2w==} 3400 3614 engines: {node: '>=20.0.0'} 3615 + deprecated: Version 4.55.0 and 4.56.0 can incorrectly automatically delegate 'wrangler deploy' to 'opennextjs-cloudflare'. Use an older or newer version. 3401 3616 hasBin: true 3402 3617 peerDependencies: 3403 3618 '@cloudflare/workers-types': ^4.20251217.0 ··· 3459 3674 youch@4.1.0-beta.10: 3460 3675 resolution: {integrity: sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==} 3461 3676 3677 + yup@1.7.1: 3678 + resolution: {integrity: sha512-GKHFX2nXul2/4Dtfxhozv701jLQHdf6J34YDh2cEkpqoo8le5Mg6/LrdseVLrFarmFygZTlfIhHx/QKfb/QWXw==} 3679 + 3462 3680 zimmerframe@1.1.2: 3463 3681 resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==} 3464 3682 3465 3683 zimmerframe@1.1.4: 3466 3684 resolution: {integrity: sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==} 3685 + 3686 + zod-v3-to-json-schema@4.0.0: 3687 + resolution: {integrity: sha512-KixLrhX/uPmRFnDgsZrzrk4x5SSJA+PmaE5adbfID9+3KPJcdxqRobaHU397EfWBqfQircrjKqvEqZ/mW5QH6w==} 3688 + peerDependencies: 3689 + zod: ^3.25 || ^4.0.14 3467 3690 3468 3691 zod@3.22.3: 3469 3692 resolution: {integrity: sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==} ··· 3475 3698 3476 3699 '@adobe/css-tools@4.4.4': {} 3477 3700 3701 + '@ark/schema@0.56.0': 3702 + dependencies: 3703 + '@ark/util': 0.56.0 3704 + optional: true 3705 + 3706 + '@ark/util@0.56.0': 3707 + optional: true 3708 + 3478 3709 '@babel/code-frame@7.27.1': 3479 3710 dependencies: 3480 3711 '@babel/helper-validator-identifier': 7.28.5 ··· 3531 3762 '@cloudflare/workerd-windows-64@1.20251217.0': 3532 3763 optional: true 3533 3764 3534 - '@cloudflare/workers-types@4.20251224.0': {} 3765 + '@cloudflare/workers-types@4.20251225.0': {} 3535 3766 3536 3767 '@cspotcode/source-map-support@0.8.1': 3537 3768 dependencies: ··· 3755 3986 '@eslint/core': 0.17.0 3756 3987 levn: 0.4.1 3757 3988 3989 + '@exodus/schemasafe@1.3.0': 3990 + optional: true 3991 + 3758 3992 '@floating-ui/core@1.7.3': 3759 3993 dependencies: 3760 3994 '@floating-ui/utils': 0.2.10 ··· 3765 3999 '@floating-ui/utils': 0.2.10 3766 4000 3767 4001 '@floating-ui/utils@0.2.10': {} 4002 + 4003 + '@hapi/hoek@9.3.0': 4004 + optional: true 4005 + 4006 + '@hapi/topo@5.1.0': 4007 + dependencies: 4008 + '@hapi/hoek': 9.3.0 4009 + optional: true 3768 4010 3769 4011 '@humanfs/core@0.19.1': {} 3770 4012 ··· 3854 4096 3855 4097 '@internationalized/date@3.10.1': 3856 4098 dependencies: 3857 - '@swc/helpers': 0.5.17 4099 + '@swc/helpers': 0.5.18 3858 4100 3859 4101 '@isaacs/fs-minipass@4.0.1': 3860 4102 dependencies: ··· 3890 4132 dependencies: 3891 4133 svelte: 5.46.0 3892 4134 4135 + '@lucide/svelte@0.562.0(svelte@5.46.1)': 4136 + dependencies: 4137 + svelte: 5.46.1 4138 + 3893 4139 '@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.3)': 3894 4140 dependencies: 3895 4141 '@types/mdx': 2.0.13 ··· 3984 4230 supports-color: 10.2.2 3985 4231 3986 4232 '@poppinss/exception@1.2.3': {} 4233 + 4234 + '@poppinss/macroable@1.1.0': 4235 + optional: true 3987 4236 3988 4237 '@publint/pack@0.1.2': {} 3989 4238 ··· 4100 4349 '@rollup/rollup-win32-x64-msvc@4.54.0': 4101 4350 optional: true 4102 4351 4352 + '@sideway/address@4.1.5': 4353 + dependencies: 4354 + '@hapi/hoek': 9.3.0 4355 + optional: true 4356 + 4357 + '@sideway/formula@3.0.1': 4358 + optional: true 4359 + 4360 + '@sideway/pinpoint@2.0.0': 4361 + optional: true 4362 + 4103 4363 '@sindresorhus/is@7.1.1': {} 4104 4364 4105 4365 '@speed-highlight/core@1.2.12': {} 4366 + 4367 + '@stablelib/base64@1.0.1': {} 4106 4368 4107 4369 '@standard-schema/spec@1.1.0': {} 4108 4370 ··· 4129 4391 - vite 4130 4392 - webpack 4131 4393 4132 - '@storybook/addon-svelte-csf@5.0.10(@storybook/svelte@10.1.10(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(svelte@5.46.0))(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))': 4394 + '@storybook/addon-svelte-csf@5.0.10(@storybook/svelte@10.1.10(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(svelte@5.46.1))(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))': 4133 4395 dependencies: 4134 4396 '@storybook/csf': 0.1.13 4135 - '@storybook/svelte': 10.1.10(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(svelte@5.46.0) 4136 - '@sveltejs/vite-plugin-svelte': 6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) 4397 + '@storybook/svelte': 10.1.10(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(svelte@5.46.1) 4398 + '@sveltejs/vite-plugin-svelte': 6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) 4137 4399 dedent: 1.7.1 4138 4400 es-toolkit: 1.43.0 4139 4401 esrap: 1.4.9 4140 4402 magic-string: 0.30.21 4141 4403 storybook: 10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) 4142 - svelte: 5.46.0 4143 - svelte-ast-print: 0.4.2(svelte@5.46.0) 4404 + svelte: 5.46.1 4405 + svelte-ast-print: 0.4.2(svelte@5.46.1) 4144 4406 vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2) 4145 4407 zimmerframe: 1.1.4 4146 4408 transitivePeerDependencies: ··· 4204 4466 react-dom: 19.2.3(react@19.2.3) 4205 4467 storybook: 10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) 4206 4468 4207 - '@storybook/svelte-vite@10.1.10(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(esbuild@0.27.2)(rollup@4.54.0)(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))': 4469 + '@storybook/svelte-vite@10.1.10(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(esbuild@0.27.2)(rollup@4.54.0)(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))': 4208 4470 dependencies: 4209 4471 '@storybook/builder-vite': 10.1.10(esbuild@0.27.2)(rollup@4.54.0)(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) 4210 - '@storybook/svelte': 10.1.10(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(svelte@5.46.0) 4211 - '@sveltejs/vite-plugin-svelte': 6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) 4472 + '@storybook/svelte': 10.1.10(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(svelte@5.46.1) 4473 + '@sveltejs/vite-plugin-svelte': 6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) 4212 4474 magic-string: 0.30.21 4213 4475 storybook: 10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) 4214 - svelte: 5.46.0 4215 - svelte2tsx: 0.7.46(svelte@5.46.0)(typescript@5.9.3) 4476 + svelte: 5.46.1 4477 + svelte2tsx: 0.7.46(svelte@5.46.1)(typescript@5.9.3) 4216 4478 typescript: 5.9.3 4217 4479 vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2) 4218 4480 transitivePeerDependencies: ··· 4221 4483 - rollup 4222 4484 - webpack 4223 4485 4224 - '@storybook/svelte@10.1.10(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(svelte@5.46.0)': 4486 + '@storybook/svelte@10.1.10(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(svelte@5.46.1)': 4225 4487 dependencies: 4226 4488 storybook: 10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) 4227 - svelte: 5.46.0 4489 + svelte: 5.46.1 4228 4490 ts-dedent: 2.2.0 4229 4491 type-fest: 2.19.0 4230 4492 4231 - '@storybook/sveltekit@10.1.10(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(esbuild@0.27.2)(rollup@4.54.0)(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))': 4493 + '@storybook/sveltekit@10.1.10(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(esbuild@0.27.2)(rollup@4.54.0)(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))': 4232 4494 dependencies: 4233 4495 '@storybook/builder-vite': 10.1.10(esbuild@0.27.2)(rollup@4.54.0)(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) 4234 - '@storybook/svelte': 10.1.10(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(svelte@5.46.0) 4235 - '@storybook/svelte-vite': 10.1.10(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(esbuild@0.27.2)(rollup@4.54.0)(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) 4496 + '@storybook/svelte': 10.1.10(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(svelte@5.46.1) 4497 + '@storybook/svelte-vite': 10.1.10(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(esbuild@0.27.2)(rollup@4.54.0)(storybook@10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) 4236 4498 storybook: 10.1.10(@testing-library/dom@10.4.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) 4237 - svelte: 5.46.0 4499 + svelte: 5.46.1 4238 4500 vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2) 4239 4501 transitivePeerDependencies: 4240 4502 - '@sveltejs/vite-plugin-svelte' ··· 4294 4556 dependencies: 4295 4557 '@sveltejs/kit': 2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) 4296 4558 4297 - '@sveltejs/adapter-cloudflare@7.2.4(@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(wrangler@4.56.0(@cloudflare/workers-types@4.20251224.0))': 4559 + '@sveltejs/adapter-cloudflare@7.2.4(@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(wrangler@4.56.0(@cloudflare/workers-types@4.20251225.0))': 4298 4560 dependencies: 4299 - '@cloudflare/workers-types': 4.20251224.0 4300 - '@sveltejs/kit': 2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) 4561 + '@cloudflare/workers-types': 4.20251225.0 4562 + '@sveltejs/kit': 2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) 4301 4563 worktop: 0.8.0-next.18 4302 - wrangler: 4.56.0(@cloudflare/workers-types@4.20251224.0) 4564 + wrangler: 4.56.0(@cloudflare/workers-types@4.20251225.0) 4303 4565 4304 4566 '@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))': 4305 4567 dependencies: ··· 4320 4582 svelte: 5.46.0 4321 4583 vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2) 4322 4584 4585 + '@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))': 4586 + dependencies: 4587 + '@standard-schema/spec': 1.1.0 4588 + '@sveltejs/acorn-typescript': 1.0.8(acorn@8.15.0) 4589 + '@sveltejs/vite-plugin-svelte': 6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) 4590 + '@types/cookie': 0.6.0 4591 + acorn: 8.15.0 4592 + cookie: 0.6.0 4593 + devalue: 5.6.1 4594 + esm-env: 1.2.2 4595 + kleur: 4.1.5 4596 + magic-string: 0.30.21 4597 + mrmime: 2.0.1 4598 + sade: 1.8.1 4599 + set-cookie-parser: 2.7.2 4600 + sirv: 3.0.2 4601 + svelte: 5.46.1 4602 + vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2) 4603 + 4323 4604 '@sveltejs/package@2.5.7(svelte@5.46.0)(typescript@5.9.3)': 4324 4605 dependencies: 4325 4606 chokidar: 5.0.0 ··· 4340 4621 transitivePeerDependencies: 4341 4622 - supports-color 4342 4623 4624 + '@sveltejs/vite-plugin-svelte-inspector@5.0.1(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))': 4625 + dependencies: 4626 + '@sveltejs/vite-plugin-svelte': 6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) 4627 + debug: 4.4.3 4628 + svelte: 5.46.1 4629 + vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2) 4630 + transitivePeerDependencies: 4631 + - supports-color 4632 + 4343 4633 '@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))': 4344 4634 dependencies: 4345 4635 '@sveltejs/vite-plugin-svelte-inspector': 5.0.1(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) ··· 4352 4642 transitivePeerDependencies: 4353 4643 - supports-color 4354 4644 4355 - '@swc/helpers@0.5.17': 4645 + '@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))': 4646 + dependencies: 4647 + '@sveltejs/vite-plugin-svelte-inspector': 5.0.1(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) 4648 + debug: 4.4.3 4649 + deepmerge: 4.3.1 4650 + magic-string: 0.30.21 4651 + svelte: 5.46.1 4652 + vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2) 4653 + vitefu: 1.1.1(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) 4654 + transitivePeerDependencies: 4655 + - supports-color 4656 + 4657 + '@swc/helpers@0.5.18': 4356 4658 dependencies: 4357 4659 tslib: 2.8.1 4358 4660 ··· 4476 4778 4477 4779 '@types/mdx@2.0.13': {} 4478 4780 4781 + '@types/node@22.19.3': 4782 + dependencies: 4783 + undici-types: 6.21.0 4784 + 4479 4785 '@types/node@25.0.3': 4480 4786 dependencies: 4481 4787 undici-types: 7.16.0 ··· 4488 4794 4489 4795 '@types/unist@2.0.11': {} 4490 4796 4797 + '@types/validator@13.15.10': 4798 + optional: true 4799 + 4491 4800 '@types/ws@8.18.1': 4492 4801 dependencies: 4493 4802 '@types/node': 25.0.3 4494 4803 4804 + '@typeschema/class-validator@0.3.0(@types/json-schema@7.0.15)(class-validator@0.14.3)': 4805 + dependencies: 4806 + '@typeschema/core': 0.14.0(@types/json-schema@7.0.15) 4807 + optionalDependencies: 4808 + class-validator: 0.14.3 4809 + transitivePeerDependencies: 4810 + - '@types/json-schema' 4811 + optional: true 4812 + 4813 + '@typeschema/core@0.14.0(@types/json-schema@7.0.15)': 4814 + optionalDependencies: 4815 + '@types/json-schema': 7.0.15 4816 + optional: true 4817 + 4818 + '@valibot/to-json-schema@1.5.0(valibot@1.2.0(typescript@5.9.3))': 4819 + dependencies: 4820 + valibot: 1.2.0(typescript@5.9.3) 4821 + optional: true 4822 + 4823 + '@vinejs/compiler@3.0.0': 4824 + optional: true 4825 + 4826 + '@vinejs/vine@3.0.1': 4827 + dependencies: 4828 + '@poppinss/macroable': 1.1.0 4829 + '@types/validator': 13.15.10 4830 + '@vinejs/compiler': 3.0.0 4831 + camelcase: 8.0.0 4832 + dayjs: 1.11.19 4833 + dlv: 1.1.3 4834 + normalize-url: 8.1.0 4835 + validator: 13.15.26 4836 + optional: true 4837 + 4495 4838 '@vitest/browser-playwright@4.0.16(playwright@1.57.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))(vitest@4.0.16)': 4496 4839 dependencies: 4497 4840 '@vitest/browser': 4.0.16(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2))(vitest@4.0.16) ··· 4663 5006 4664 5007 aria-query@5.3.2: {} 4665 5008 5009 + arkregex@0.0.5: 5010 + dependencies: 5011 + '@ark/util': 0.56.0 5012 + optional: true 5013 + 5014 + arktype@2.1.29: 5015 + dependencies: 5016 + '@ark/schema': 0.56.0 5017 + '@ark/util': 0.56.0 5018 + arkregex: 0.0.5 5019 + optional: true 5020 + 4666 5021 assertion-error@2.0.1: {} 4667 5022 4668 5023 ast-kit@2.2.0: ··· 4698 5053 4699 5054 birpc@4.0.0: {} 4700 5055 4701 - bits-ui@2.14.4(@internationalized/date@3.10.1)(@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.0): 5056 + bits-ui@2.14.4(@internationalized/date@3.10.1)(@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.1): 4702 5057 dependencies: 4703 5058 '@floating-ui/core': 1.7.3 4704 5059 '@floating-ui/dom': 1.7.4 4705 5060 '@internationalized/date': 3.10.1 4706 5061 esm-env: 1.2.2 4707 - runed: 0.35.1(@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.0) 4708 - svelte: 5.46.0 4709 - svelte-toolbelt: 0.10.6(@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.0) 5062 + runed: 0.35.1(@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.1) 5063 + svelte: 5.46.1 5064 + svelte-toolbelt: 0.10.6(@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.1) 4710 5065 tabbable: 6.3.0 4711 5066 transitivePeerDependencies: 4712 5067 - '@sveltejs/kit' ··· 4726 5081 4727 5082 callsites@3.1.0: {} 4728 5083 5084 + camelcase@8.0.0: 5085 + optional: true 5086 + 4729 5087 chai@5.3.3: 4730 5088 dependencies: 4731 5089 assertion-error: 2.0.1 ··· 4754 5112 chownr@3.0.0: {} 4755 5113 4756 5114 chromatic@13.3.4: {} 5115 + 5116 + class-validator@0.14.3: 5117 + dependencies: 5118 + '@types/validator': 13.15.10 5119 + libphonenumber-js: 1.12.33 5120 + validator: 13.15.26 5121 + optional: true 4757 5122 4758 5123 clsx@2.1.1: {} 4759 5124 ··· 4806 5171 csstype@3.2.3: {} 4807 5172 4808 5173 data-uri-to-buffer@4.0.1: {} 5174 + 5175 + dayjs@1.11.19: 5176 + optional: true 4809 5177 4810 5178 debug@4.4.3: 4811 5179 dependencies: ··· 4840 5208 4841 5209 devalue@5.6.1: {} 4842 5210 5211 + dlv@1.1.3: 5212 + optional: true 5213 + 4843 5214 dom-accessibility-api@0.5.16: {} 4844 5215 4845 5216 dom-accessibility-api@0.6.3: {} 4846 5217 4847 5218 dts-resolver@2.1.3: {} 4848 5219 5220 + effect@3.19.13: 5221 + dependencies: 5222 + '@standard-schema/spec': 1.1.0 5223 + fast-check: 3.23.2 5224 + optional: true 5225 + 4849 5226 empathic@2.0.0: {} 4850 5227 4851 5228 enhanced-resolve@5.18.4: ··· 4858 5235 es-module-lexer@1.7.0: {} 4859 5236 4860 5237 es-toolkit@1.43.0: {} 5238 + 5239 + es6-promise@4.2.8: {} 4861 5240 4862 5241 esbuild@0.27.0: 4863 5242 optionalDependencies: ··· 4919 5298 4920 5299 escape-string-regexp@4.0.0: {} 4921 5300 4922 - eslint-plugin-svelte@3.13.1(eslint@9.39.2(jiti@2.6.1))(svelte@5.46.0): 5301 + eslint-plugin-svelte@3.13.1(eslint@9.39.2(jiti@2.6.1))(svelte@5.46.1): 4923 5302 dependencies: 4924 5303 '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2(jiti@2.6.1)) 4925 5304 '@jridgewell/sourcemap-codec': 1.5.5 ··· 4931 5310 postcss-load-config: 3.1.4(postcss@8.5.6) 4932 5311 postcss-safe-parser: 7.0.1(postcss@8.5.6) 4933 5312 semver: 7.7.3 4934 - svelte-eslint-parser: 1.4.1(svelte@5.46.0) 5313 + svelte-eslint-parser: 1.4.1(svelte@5.46.1) 4935 5314 optionalDependencies: 4936 - svelte: 5.46.0 5315 + svelte: 5.46.1 4937 5316 transitivePeerDependencies: 4938 5317 - ts-node 4939 5318 ··· 5032 5411 5033 5412 exsolve@1.0.8: {} 5034 5413 5414 + fast-check@3.23.2: 5415 + dependencies: 5416 + pure-rand: 6.1.0 5417 + optional: true 5418 + 5035 5419 fast-deep-equal@3.1.3: {} 5036 5420 5037 5421 fast-json-stable-stringify@2.1.0: {} ··· 5040 5424 5041 5425 fast-npm-meta@0.4.7: {} 5042 5426 5427 + fast-sha256@1.3.0: {} 5428 + 5043 5429 fdir@6.5.0(picomatch@4.0.3): 5044 5430 optionalDependencies: 5045 5431 picomatch: 4.0.3 ··· 5186 5572 5187 5573 jiti@2.6.1: {} 5188 5574 5575 + joi@17.13.3: 5576 + dependencies: 5577 + '@hapi/hoek': 9.3.0 5578 + '@hapi/topo': 5.1.0 5579 + '@sideway/address': 4.1.5 5580 + '@sideway/formula': 3.0.1 5581 + '@sideway/pinpoint': 2.0.0 5582 + optional: true 5583 + 5189 5584 js-tokens@4.0.0: {} 5190 5585 5191 5586 js-tokens@9.0.1: {} ··· 5198 5593 5199 5594 json-buffer@3.0.1: {} 5200 5595 5596 + json-schema-to-ts@3.1.1: 5597 + dependencies: 5598 + '@babel/runtime': 7.28.4 5599 + ts-algebra: 2.0.0 5600 + optional: true 5601 + 5201 5602 json-schema-traverse@0.4.1: {} 5202 5603 5203 5604 json-stable-stringify-without-jsonify@1.0.1: {} ··· 5219 5620 dependencies: 5220 5621 prelude-ls: 1.2.1 5221 5622 type-check: 0.4.0 5623 + 5624 + libphonenumber-js@1.12.33: 5625 + optional: true 5222 5626 5223 5627 lightningcss-android-arm64@1.30.2: 5224 5628 optional: true ··· 5303 5707 dependencies: 5304 5708 semver: 7.7.3 5305 5709 5306 - mdsvex@0.12.6(svelte@5.46.0): 5710 + mdsvex@0.12.6(svelte@5.46.1): 5307 5711 dependencies: 5308 5712 '@types/mdast': 4.0.4 5309 5713 '@types/unist': 2.0.11 5310 5714 prism-svelte: 0.4.7 5311 5715 prismjs: 1.30.0 5312 - svelte: 5.46.0 5716 + svelte: 5.46.1 5313 5717 unist-util-visit: 2.0.3 5314 5718 vfile-message: 2.0.4 5315 5719 5720 + memoize-weak@1.0.2: {} 5721 + 5316 5722 mime@3.0.0: {} 5317 5723 5318 5724 min-indent@1.0.1: {} ··· 5352 5758 pkg-types: 1.3.1 5353 5759 ufo: 1.6.1 5354 5760 5355 - mode-watcher@1.1.0(svelte@5.46.0): 5761 + mode-watcher@1.1.0(svelte@5.46.1): 5356 5762 dependencies: 5357 - runed: 0.25.0(svelte@5.46.0) 5358 - svelte: 5.46.0 5359 - svelte-toolbelt: 0.7.1(svelte@5.46.0) 5763 + runed: 0.25.0(svelte@5.46.1) 5764 + svelte: 5.46.1 5765 + svelte-toolbelt: 0.7.1(svelte@5.46.1) 5360 5766 5361 5767 mri@1.2.0: {} 5362 5768 ··· 5438 5844 5439 5845 normalize-path@3.0.0: {} 5440 5846 5847 + normalize-url@8.1.0: 5848 + optional: true 5849 + 5441 5850 npm-normalize-package-bin@5.0.0: {} 5442 5851 5443 5852 obug@2.1.1: {} ··· 5600 6009 5601 6010 proc-log@6.1.0: {} 5602 6011 6012 + property-expr@2.0.6: 6013 + optional: true 6014 + 5603 6015 publint@0.3.16: 5604 6016 dependencies: 5605 6017 '@publint/pack': 0.1.2 ··· 5609 6021 5610 6022 punycode@2.3.1: {} 5611 6023 6024 + pure-rand@6.1.0: 6025 + optional: true 6026 + 5612 6027 quansync@1.0.0: {} 6028 + 6029 + querystringify@2.2.0: {} 5613 6030 5614 6031 radix3@1.1.2: {} 5615 6032 ··· 5642 6059 strip-indent: 3.0.0 5643 6060 5644 6061 regexparam@3.0.0: {} 6062 + 6063 + requires-port@1.0.0: {} 6064 + 6065 + resend@6.6.0: 6066 + dependencies: 6067 + svix: 1.76.1 5645 6068 5646 6069 resolve-from@4.0.0: {} 5647 6070 ··· 5712 6135 5713 6136 run-applescript@7.1.0: {} 5714 6137 5715 - runed@0.23.4(svelte@5.46.0): 6138 + runed@0.23.4(svelte@5.46.1): 5716 6139 dependencies: 5717 6140 esm-env: 1.2.2 5718 - svelte: 5.46.0 6141 + svelte: 5.46.1 5719 6142 5720 - runed@0.25.0(svelte@5.46.0): 6143 + runed@0.25.0(svelte@5.46.1): 5721 6144 dependencies: 5722 6145 esm-env: 1.2.2 5723 - svelte: 5.46.0 6146 + svelte: 5.46.1 5724 6147 5725 - runed@0.35.1(@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.0): 6148 + runed@0.35.1(@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.1): 5726 6149 dependencies: 5727 6150 dequal: 2.0.3 5728 6151 esm-env: 1.2.2 5729 6152 lz-string: 1.5.0 5730 - svelte: 5.46.0 6153 + svelte: 5.46.1 5731 6154 optionalDependencies: 5732 - '@sveltejs/kit': 2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) 6155 + '@sveltejs/kit': 2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) 5733 6156 5734 6157 sade@1.8.1: 5735 6158 dependencies: ··· 5834 6257 dependencies: 5835 6258 inline-style-parser: 0.2.7 5836 6259 5837 - supabase@2.70.4: 6260 + supabase@2.70.5: 5838 6261 dependencies: 5839 6262 bin-links: 6.0.0 5840 6263 https-proxy-agent: 7.0.6 ··· 5842 6265 tar: 7.5.2 5843 6266 transitivePeerDependencies: 5844 6267 - supports-color 6268 + 6269 + superstruct@2.0.2: 6270 + optional: true 5845 6271 5846 6272 supports-color@10.2.2: {} 5847 6273 ··· 5849 6275 dependencies: 5850 6276 has-flag: 4.0.0 5851 6277 5852 - svelte-ast-print@0.4.2(svelte@5.46.0): 6278 + svelte-ast-print@0.4.2(svelte@5.46.1): 5853 6279 dependencies: 5854 6280 esrap: 1.2.2 5855 - svelte: 5.46.0 6281 + svelte: 5.46.1 5856 6282 zimmerframe: 1.1.2 5857 6283 5858 6284 svelte-check@4.3.5(picomatch@4.0.3)(svelte@5.46.0)(typescript@5.9.3): ··· 5867 6293 transitivePeerDependencies: 5868 6294 - picomatch 5869 6295 5870 - svelte-eslint-parser@1.4.1(svelte@5.46.0): 6296 + svelte-check@4.3.5(picomatch@4.0.3)(svelte@5.46.1)(typescript@5.9.3): 6297 + dependencies: 6298 + '@jridgewell/trace-mapping': 0.3.31 6299 + chokidar: 4.0.3 6300 + fdir: 6.5.0(picomatch@4.0.3) 6301 + picocolors: 1.1.1 6302 + sade: 1.8.1 6303 + svelte: 5.46.1 6304 + typescript: 5.9.3 6305 + transitivePeerDependencies: 6306 + - picomatch 6307 + 6308 + svelte-eslint-parser@1.4.1(svelte@5.46.1): 5871 6309 dependencies: 5872 6310 eslint-scope: 8.4.0 5873 6311 eslint-visitor-keys: 4.2.1 ··· 5876 6314 postcss-scss: 4.0.9(postcss@8.5.6) 5877 6315 postcss-selector-parser: 7.1.1 5878 6316 optionalDependencies: 5879 - svelte: 5.46.0 6317 + svelte: 5.46.1 5880 6318 5881 - svelte-toolbelt@0.10.6(@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.0): 6319 + svelte-toolbelt@0.10.6(@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.1): 5882 6320 dependencies: 5883 6321 clsx: 2.1.1 5884 - runed: 0.35.1(@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.0)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.0) 6322 + runed: 0.35.1(@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.1) 5885 6323 style-to-object: 1.0.14 5886 - svelte: 5.46.0 6324 + svelte: 5.46.1 5887 6325 transitivePeerDependencies: 5888 6326 - '@sveltejs/kit' 5889 6327 5890 - svelte-toolbelt@0.7.1(svelte@5.46.0): 6328 + svelte-toolbelt@0.7.1(svelte@5.46.1): 5891 6329 dependencies: 5892 6330 clsx: 2.1.1 5893 - runed: 0.23.4(svelte@5.46.0) 6331 + runed: 0.23.4(svelte@5.46.1) 5894 6332 style-to-object: 1.0.14 5895 - svelte: 5.46.0 6333 + svelte: 5.46.1 5896 6334 5897 6335 svelte2tsx@0.7.46(svelte@5.46.0)(typescript@5.9.3): 5898 6336 dependencies: ··· 5901 6339 svelte: 5.46.0 5902 6340 typescript: 5.9.3 5903 6341 6342 + svelte2tsx@0.7.46(svelte@5.46.1)(typescript@5.9.3): 6343 + dependencies: 6344 + dedent-js: 1.0.1 6345 + scule: 1.3.0 6346 + svelte: 5.46.1 6347 + typescript: 5.9.3 6348 + 5904 6349 svelte@5.46.0: 5905 6350 dependencies: 5906 6351 '@jridgewell/remapping': 2.3.5 ··· 5919 6364 magic-string: 0.30.21 5920 6365 zimmerframe: 1.1.4 5921 6366 6367 + svelte@5.46.1: 6368 + dependencies: 6369 + '@jridgewell/remapping': 2.3.5 6370 + '@jridgewell/sourcemap-codec': 1.5.5 6371 + '@sveltejs/acorn-typescript': 1.0.8(acorn@8.15.0) 6372 + '@types/estree': 1.0.8 6373 + acorn: 8.15.0 6374 + aria-query: 5.3.2 6375 + axobject-query: 4.1.0 6376 + clsx: 2.1.1 6377 + devalue: 5.6.1 6378 + esm-env: 1.2.2 6379 + esrap: 2.2.1 6380 + is-reference: 3.0.3 6381 + locate-character: 3.0.0 6382 + magic-string: 0.30.21 6383 + zimmerframe: 1.1.4 6384 + 6385 + sveltekit-superforms@2.29.1(@sveltejs/kit@2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(@types/json-schema@7.0.15)(svelte@5.46.1)(typescript@5.9.3): 6386 + dependencies: 6387 + '@sveltejs/kit': 2.49.2(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)))(svelte@5.46.1)(vite@7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)) 6388 + devalue: 5.6.1 6389 + memoize-weak: 1.0.2 6390 + svelte: 5.46.1 6391 + ts-deepmerge: 7.0.3 6392 + optionalDependencies: 6393 + '@exodus/schemasafe': 1.3.0 6394 + '@typeschema/class-validator': 0.3.0(@types/json-schema@7.0.15)(class-validator@0.14.3) 6395 + '@valibot/to-json-schema': 1.5.0(valibot@1.2.0(typescript@5.9.3)) 6396 + '@vinejs/vine': 3.0.1 6397 + arktype: 2.1.29 6398 + class-validator: 0.14.3 6399 + effect: 3.19.13 6400 + joi: 17.13.3 6401 + json-schema-to-ts: 3.1.1 6402 + superstruct: 2.0.2 6403 + typebox: 1.0.69 6404 + valibot: 1.2.0(typescript@5.9.3) 6405 + yup: 1.7.1 6406 + zod: 4.2.1 6407 + zod-v3-to-json-schema: 4.0.0(zod@4.2.1) 6408 + transitivePeerDependencies: 6409 + - '@types/json-schema' 6410 + - typescript 6411 + 6412 + svix@1.76.1: 6413 + dependencies: 6414 + '@stablelib/base64': 1.0.1 6415 + '@types/node': 22.19.3 6416 + es6-promise: 4.2.8 6417 + fast-sha256: 1.3.0 6418 + url-parse: 1.5.10 6419 + uuid: 10.0.0 6420 + 5922 6421 tabbable@6.3.0: {} 5923 6422 5924 6423 tagged-tag@1.0.0: {} ··· 5933 6432 5934 6433 tailwindcss@4.1.18: {} 5935 6434 5936 - tanstack-table-8-svelte-5@0.1.2(svelte@5.46.0): 6435 + tanstack-table-8-svelte-5@0.1.2(svelte@5.46.1): 5937 6436 dependencies: 5938 6437 '@tanstack/table-core': 8.21.3 5939 - svelte: 5.46.0 6438 + svelte: 5.46.1 5940 6439 5941 6440 tapable@2.3.0: {} 5942 6441 ··· 5947 6446 minipass: 7.1.2 5948 6447 minizlib: 3.1.0 5949 6448 yallist: 5.0.0 6449 + 6450 + tiny-case@1.0.3: 6451 + optional: true 5950 6452 5951 6453 tiny-invariant@1.3.3: {} 5952 6454 ··· 5967 6469 5968 6470 tinyspy@4.0.4: {} 5969 6471 6472 + toposort@2.0.2: 6473 + optional: true 6474 + 5970 6475 totalist@3.0.1: {} 5971 6476 5972 6477 tree-kill@1.2.2: {} 5973 6478 6479 + ts-algebra@2.0.0: 6480 + optional: true 6481 + 5974 6482 ts-dedent@2.2.0: {} 6483 + 6484 + ts-deepmerge@7.0.3: {} 5975 6485 5976 6486 tsdown@0.18.2(publint@0.3.16)(typescript@5.9.3): 5977 6487 dependencies: ··· 6003 6513 6004 6514 tslib@2.8.1: {} 6005 6515 6516 + tw-animate-css@1.4.0: {} 6517 + 6006 6518 type-check@0.4.0: 6007 6519 dependencies: 6008 6520 prelude-ls: 1.2.1 ··· 6013 6525 dependencies: 6014 6526 tagged-tag: 1.0.0 6015 6527 6528 + typebox@1.0.69: 6529 + optional: true 6530 + 6016 6531 typescript@5.9.3: {} 6017 6532 6018 6533 ufo@1.6.1: {} ··· 6031 6546 unconfig-core: 7.4.2 6032 6547 6033 6548 uncrypto@0.1.3: {} 6549 + 6550 + undici-types@6.21.0: {} 6034 6551 6035 6552 undici-types@7.16.0: {} 6036 6553 ··· 6083 6600 dependencies: 6084 6601 punycode: 2.3.1 6085 6602 6603 + url-parse@1.5.10: 6604 + dependencies: 6605 + querystringify: 2.2.0 6606 + requires-port: 1.0.0 6607 + 6086 6608 use-sync-external-store@1.6.0(react@19.2.3): 6087 6609 dependencies: 6088 6610 react: 19.2.3 6089 6611 6090 6612 util-deprecate@1.0.2: {} 6091 6613 6614 + uuid@10.0.0: {} 6615 + 6616 + valibot@1.2.0(typescript@5.9.3): 6617 + optionalDependencies: 6618 + typescript: 5.9.3 6619 + optional: true 6620 + 6621 + validator@13.15.26: 6622 + optional: true 6623 + 6092 6624 vfile-message@2.0.4: 6093 6625 dependencies: 6094 6626 '@types/unist': 2.0.11 ··· 6112 6644 optionalDependencies: 6113 6645 vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2) 6114 6646 6115 - vitest-browser-svelte@2.0.1(svelte@5.46.0)(vitest@4.0.16): 6647 + vitest-browser-svelte@2.0.1(svelte@5.46.1)(vitest@4.0.16): 6116 6648 dependencies: 6117 - svelte: 5.46.0 6649 + svelte: 5.46.1 6118 6650 vitest: 4.0.16(@types/node@25.0.3)(@vitest/browser-playwright@4.0.16)(@vitest/ui@4.0.16)(jiti@2.6.1)(lightningcss@1.30.2) 6119 6651 6120 6652 vitest@4.0.16(@types/node@25.0.3)(@vitest/browser-playwright@4.0.16)(@vitest/ui@4.0.16)(jiti@2.6.1)(lightningcss@1.30.2): ··· 6184 6716 mrmime: 2.0.1 6185 6717 regexparam: 3.0.0 6186 6718 6187 - wrangler@4.56.0(@cloudflare/workers-types@4.20251224.0): 6719 + wrangler@4.56.0(@cloudflare/workers-types@4.20251225.0): 6188 6720 dependencies: 6189 6721 '@cloudflare/kv-asset-handler': 0.4.1 6190 6722 '@cloudflare/unenv-preset': 2.7.13(unenv@2.0.0-rc.24)(workerd@1.20251217.0) ··· 6195 6727 unenv: 2.0.0-rc.24 6196 6728 workerd: 1.20251217.0 6197 6729 optionalDependencies: 6198 - '@cloudflare/workers-types': 4.20251224.0 6730 + '@cloudflare/workers-types': 4.20251225.0 6199 6731 fsevents: 2.3.3 6200 6732 transitivePeerDependencies: 6201 6733 - bufferutil ··· 6235 6767 cookie: 1.1.1 6236 6768 youch-core: 0.3.3 6237 6769 6770 + yup@1.7.1: 6771 + dependencies: 6772 + property-expr: 2.0.6 6773 + tiny-case: 1.0.3 6774 + toposort: 2.0.2 6775 + type-fest: 2.19.0 6776 + optional: true 6777 + 6238 6778 zimmerframe@1.1.2: {} 6239 6779 6240 6780 zimmerframe@1.1.4: {} 6781 + 6782 + zod-v3-to-json-schema@4.0.0(zod@4.2.1): 6783 + dependencies: 6784 + zod: 4.2.1 6785 + optional: true 6241 6786 6242 6787 zod@3.22.3: {} 6243 6788
+29 -25
pnpm-workspace.yaml
··· 2 2 - packages/** 3 3 - app 4 4 5 - linkWorkspacePackages: deep 6 - onlyBuiltDependencies: 7 - - esbuild 8 - - sharp 9 - - supabase 10 - - workerd 11 - 12 5 catalogs: 6 + app: 7 + '@supabase/ssr': ^0.8.0 8 + '@supabase/supabase-js': ^2.89.0 9 + lorem-ipsum: ^2.0.8 10 + resend: ^6.6.0 11 + supabase: ^2.70.5 12 + zod: ^4.2.1 13 13 dev: 14 14 '@types/node': ^25.0.3 15 15 eslint-plugin-svelte: ^3.13.1 16 16 node-modules-inspector: ^1.2.0 17 - typescript: ^5.9.3 18 17 type-fest: ^5.3.1 19 - wrangler: ^4.56.0 20 - app: 21 - '@supabase/ssr': ^0.8.0 22 - '@supabase/supabase-js': ^2.89.0 23 - lorem-ipsum: ^2.0.8 24 - supabase: ^2.67.3 25 - zod: ^4.2.1 18 + typescript: ^5.9.3 19 + wrangler: ^4.54.0 26 20 storybook: 27 21 '@storybook/addon-a11y': ^10.1.10 28 22 '@storybook/addon-docs': ^10.1.10 ··· 31 25 '@storybook/addon-vitest': ^10.1.10 32 26 '@storybook/svelte': ^10.1.10 33 27 '@storybook/sveltekit': ^10.1.10 34 - chromatic: ^13.3.3 28 + chromatic: ^13.3.4 35 29 storybook: ^10.1.10 36 30 svelte: 37 - '@lucide/svelte': ^0.x 31 + '@lucide/svelte': ^0.562.0 38 32 '@sveltejs/adapter-auto': ^7.0.0 39 33 '@sveltejs/adapter-cloudflare': ^7.2.4 40 34 '@sveltejs/kit': ^2.49.2 41 35 '@sveltejs/package': ^2.5.4 42 36 '@sveltejs/vite-plugin-svelte': ^6.2.1 43 - '@tanstack/svelte-table': npm:tanstack-table-8-svelte-5@^0.1 44 - bits-ui: ^2.14.2 37 + '@tanstack/svelte-table': npm:tanstack-table-8-svelte-5@^0.1.2 38 + bits-ui: ^2.14.4 45 39 mdsvex: ^0.12.6 46 40 mode-watcher: ^1.1.0 47 - svelte: ^5.46.0 41 + svelte: ^5.46.1 48 42 svelte-check: ^4.3.5 43 + sveltekit-superforms: ^2.29.1 49 44 vitest-browser-svelte: ^2.0.1 50 45 tailwind: 51 46 '@tailwindcss/vite': ^4.1.18 52 - clsx: ^2.x 53 - tailwind-merge: ^3.4.x 54 - tailwind-variants: ^3.2.x 55 - tailwindcss: ^4.1.17 47 + clsx: ^2.1.1 48 + tailwind-merge: ^3.4.0 49 + tailwind-variants: ^3.2.2 50 + tailwindcss: ^4.1.18 51 + tw-animate-css: ^1.4.0 56 52 voidzero: 57 53 '@vitest/browser-playwright': ^4.0.16 58 54 '@vitest/coverage-v8': ^4.0.16 ··· 61 57 oxfmt: ^0.19.0 62 58 oxlint: ^1.35.0 63 59 oxlint-tsgolint: ^0.10.0 64 - playwright: ^1.56.1 60 + playwright: ^1.57.0 65 61 publint: ^0.3.16 66 62 tsdown: ^0.18.1 67 63 vite: ^7.3.0 68 64 vitest: ^4.0.16 65 + 66 + linkWorkspacePackages: deep 67 + 68 + onlyBuiltDependencies: 69 + - esbuild 70 + - sharp 71 + - supabase 72 + - workerd