diff --git a/.agents/skills/shadcn-svelte/SKILL.md b/.agents/skills/shadcn-svelte/SKILL.md new file mode 100644 index 00000000..5e123edd --- /dev/null +++ b/.agents/skills/shadcn-svelte/SKILL.md @@ -0,0 +1,227 @@ +--- +name: shadcn-svelte +description: Manages shadcn-svelte components and projects — adding, updating, fixing, debugging, styling, and composing UI. Provides project context, component docs, and usage examples. Applies when working with shadcn-svelte, the CLI, design-system presets, or any project with a components.json file. Also triggers for "shadcn-svelte init", "add component", or registry URLs. +user-invocable: false +allowed-tools: Bash(npx shadcn-svelte@latest *), Bash(pnpm dlx shadcn-svelte@latest *), Bash(bunx --bun shadcn-svelte@latest *) +--- + +# shadcn-svelte + +A framework for building UI, components, and design systems for Svelte. Components are added as source to the user's project via the CLI. + +> **IMPORTANT:** Run all CLI commands using the project's package runner: `npx shadcn-svelte@latest`, `pnpm dlx shadcn-svelte@latest`, or `bunx --bun shadcn-svelte@latest` — based on the project's package manager. Examples below use `npx shadcn-svelte@latest` but substitute the correct runner for the project. + +## Current Project Context + +Read `components.json` at the project root and, when you need the live file layout, list the directory given by the `aliases.ui` path (resolved with the same rules as the CLI). + +## Imports (Svelte) + +Each component lives in its own folder with an `index.ts` barrel. Match the [installation docs](https://shadcn-svelte.com/docs/installation): + +- **Multi-part components** (dialog, select, card, field, tabs, …): `import * as Dialog from "$lib/components/ui/dialog"` then `Dialog.Content`, `Dialog.Title`, `Card.Root`, `Card.Header`, etc. — whatever the barrel exports (short names and/or `Root as …` aliases). +- **Single-component barrels** (only one meaningful component in the folder): **named imports** — `import { Button } from "$lib/components/ui/button"` and ` + + +
+ + + + + U + + + ++20.1% +``` + +## Component Selection + +| Need | Use | +| -------------------------- | --------------------------------------------------------------------------------------------------- | +| Button/action | `Button` with appropriate variant (`import { Button }`) | +| Form inputs | `Input`, `Select`, `Combobox`, `Switch`, `Checkbox`, `RadioGroup`, `Textarea`, `InputOTP`, `Slider` | +| Toggle between 2–5 options | `ToggleGroup.Root` + `ToggleGroup.Item` | +| Data display | `Table`, `Card`, `Badge`, `Avatar` | +| Navigation | `Sidebar`, `NavigationMenu`, `Breadcrumb`, `Tabs`, `Pagination` | +| Overlays | `Dialog` (modal), `Sheet` (side panel), `Drawer` (bottom sheet), `AlertDialog` (confirmation) | +| Feedback | `svelte-sonner` (toast), `Alert`, `Progress`, `Skeleton`, `Spinner` | +| Command palette | `Command` inside `Dialog` | +| Charts | `Chart` (LayerChart) | +| Layout | `Card`, `Separator`, `Resizable`, `ScrollArea`, `Accordion`, `Collapsible` | +| Empty states | `Empty` | +| Menus | `DropdownMenu`, `ContextMenu`, `Menubar` | +| Tooltips/info | `Tooltip`, `HoverCard`, `Popover` | + +## Key Fields + +Use `components.json` and the filesystem — not a separate `info` command: + +- **`aliases`** → use the actual alias prefix from config (e.g. `$lib/`), never hardcode unrelated projects. +- **`tailwind.css`** → the global CSS file where theme variables live. Edit this file for theme tweaks; don't add a second globals file unless the user already uses one. +- **`style`** → visual treatment (e.g. `nova`, `vega`, …) and registry style path. +- **`iconLibrary`** → determines icon packages (`@lucide/svelte`, `@tabler/icons-svelte`, etc.). Never assume `@lucide/svelte`. +- **`registry`** → where the CLI fetches components; default official registry at `shadcn-svelte.com`. +- **`resolvedPaths`** (conceptual) → the CLI resolves `aliases` to absolute paths; list `aliases.ui` on disk to see installed components. + +See [cli.md](./cli.md) for commands and flags. + +## Component Docs, Examples, and Usage + +Open `https://shadcn-svelte.com/docs/components/.md` for docs and examples. **When creating, fixing, debugging, or using a component, read the official page first** so you follow the documented APIs. + +## Workflow + +1. **Get project context** — read `components.json` and list the UI components directory when needed. +2. **Check installed components first** — before running `add`, list files under the resolved `ui` path. Don't import components that haven't been added, and don't re-add ones already present unless updating. +3. **Discover components** — `npx shadcn-svelte@latest add` with no arguments (interactive list), or the docs site. +4. **Install or update** — `npx shadcn-svelte@latest add ` or a registry **URL**. To refresh existing files from the registry, use `npx shadcn-svelte@latest update` (see [cli.md](./cli.md)). +5. **Fix imports in third-party / URL-added items** — After adding from a custom registry URL, check for hardcoded paths that don't match the project's `aliases`. Rewrite imports to use the project's `ui` / `lib` aliases from `components.json`. +6. **Review added components** — After adding, **read the added files** and verify composition (groups, titles, validation attrs). Align icon imports with `iconLibrary`. +7. **Remote registry items** — Adding by URL is explicit; if the user wants a component from an unknown source, confirm the registry URL or item before running `add`. + +## Updating Components + +Use the **`update`** command to pull the latest registry versions of components already in the project. Review changes with `git diff` after `update`. + +1. Commit or stash local work. +2. Run `npx shadcn-svelte@latest update [component]` or `--all`. +3. Resolve merge conflicts if you had customized files. +4. **Never use `--overwrite` on `add` without the user's explicit approval** when it would destroy intentional edits. + +## Quick Reference + +```bash +# Initialize shadcn-svelte in your project. +npx shadcn-svelte@latest init + +# Initialize with a preset string from the docs site builder. +npx shadcn-svelte@latest init --preset + +# Add components (interactive when run with no names). +npx shadcn-svelte@latest add +npx shadcn-svelte@latest add button card dialog +npx shadcn-svelte@latest add --all + +# Update components already installed. +npx shadcn-svelte@latest update button +npx shadcn-svelte@latest update --all --yes + +# Build a custom registry (registry authors). +npx shadcn-svelte@latest registry build +``` + +**Registry:** default `https://shadcn-svelte.com/registry` — override in `components.json` if needed. +**Docs:** [shadcn-svelte.com](https://shadcn-svelte.com) + +## Detailed References + +- [rules/forms.md](./rules/forms.md) — Field.FieldGroup, Field.Field, InputGroup, ToggleGroup, Field.FieldSet, validation states +- [rules/composition.md](./rules/composition.md) — Groups, overlays, Card, Tabs, Avatar, Alert, Empty, Toast, Separator, Skeleton, Badge, Button loading +- [rules/icons.md](./rules/icons.md) — data-icon, icon sizing, passing icon components +- [rules/styling.md](./rules/styling.md) — Semantic colors, variants, class, spacing, size, truncate, dark mode, cn(), z-index +- [cli.md](./cli.md) — Commands, flags, registry +- [customization.md](./customization.md) — Theming, CSS variables, extending components diff --git a/.agents/skills/shadcn-svelte/agents/openai.yml b/.agents/skills/shadcn-svelte/agents/openai.yml new file mode 100644 index 00000000..53b19ff1 --- /dev/null +++ b/.agents/skills/shadcn-svelte/agents/openai.yml @@ -0,0 +1,5 @@ +interface: + display_name: 'shadcn-svelte' + short_description: 'Manages shadcn-svelte components — adding, updating, fixing, debugging, styling, and composing UI.' + icon_small: './assets/shadcn-svelte-small.png' + icon_large: './assets/shadcn-svelte.png' diff --git a/.agents/skills/shadcn-svelte/assets/shadcn-svelte-small.png b/.agents/skills/shadcn-svelte/assets/shadcn-svelte-small.png new file mode 100644 index 00000000..17a8bf5c Binary files /dev/null and b/.agents/skills/shadcn-svelte/assets/shadcn-svelte-small.png differ diff --git a/.agents/skills/shadcn-svelte/assets/shadcn-svelte.png b/.agents/skills/shadcn-svelte/assets/shadcn-svelte.png new file mode 100644 index 00000000..a35eb16e Binary files /dev/null and b/.agents/skills/shadcn-svelte/assets/shadcn-svelte.png differ diff --git a/.agents/skills/shadcn-svelte/cli.md b/.agents/skills/shadcn-svelte/cli.md new file mode 100644 index 00000000..ff19b7cb --- /dev/null +++ b/.agents/skills/shadcn-svelte/cli.md @@ -0,0 +1,166 @@ +# shadcn-svelte CLI Reference + +Configuration is read from `components.json`. See [components.json](https://shadcn-svelte.com/docs/components-json) on the docs site for the full schema. + +> **IMPORTANT:** Always run commands using the project's package runner: `npx shadcn-svelte@latest`, `pnpm dlx shadcn-svelte@latest`, or `bunx --bun shadcn-svelte@latest`. Check `packageManager` from the project (or lockfile) to choose the right one. Examples below use `npx shadcn-svelte@latest` but substitute the correct runner for the project. + +> **IMPORTANT:** Only use the flags documented below. Do not invent or guess flags — if a flag isn't listed here, it doesn't exist. The CLI auto-detects the package manager; there is no `--package-manager` flag. + +## Contents + +- Commands: `init`, `add`, `apply`, `update`, `registry build` +- Proxy / outgoing requests +- Presets (via `init` and `apply`) + +--- + +## Commands + +### `init` — Initialize an existing project + +```bash +npx shadcn-svelte@latest init [options] +``` + +Installs dependencies, adds the `cn` util, creates `components.json`, and sets up CSS variables. Run `init` from the root of your project. + +| Flag | Short | Description | Default | +| --------------------------- | ----- | ------------------------------------------------------------------------- | --------- | +| `--preset ` | — | Encoded design-system preset string from the docs site | — | +| `-c, --cwd ` | `-c` | Working directory | current | +| `-o, --overwrite` | — | Overwrite existing files | `false` | +| `--no-deps` | — | Do not add or install dependencies | — | +| `--skip-preflight` | — | Ignore preflight checks and continue | `false` | +| `--base-color ` | — | Base color: `neutral`, `stone`, `zinc`, `mauve`, `olive`, `mist`, `taupe` | — | +| `--css ` | — | Path to the global CSS file | — | +| `--components-alias ` | — | Import alias for components | — | +| `--lib-alias ` | — | Import alias for lib | — | +| `--utils-alias ` | — | Import alias for utils | — | +| `--hooks-alias ` | — | Import alias for hooks | — | +| `--ui-alias ` | — | Import alias for UI components | — | +| `--proxy ` | — | Fetch registry items through this proxy | env-based | +| `--design-system-url` | — | Optional design-system URL (see docs / preset builder) | — | +| `-h, --help` | `-h` | Help | — | + +--- + +### `add` — Add components + +```bash +npx shadcn-svelte@latest add [options] [components...] +``` + +Adds components from the configured registry. Arguments are component names from the registry index, or a **URL** to a registry JSON item. With **no** component names, the CLI prompts you to pick components interactively. + +| Flag | Short | Description | Default | +| ------------------ | ----- | ----------------------------------------------- | --------- | +| `-c, --cwd ` | `-c` | Working directory | current | +| `--no-deps` | — | Skip adding and installing package dependencies | — | +| `--skip-preflight` | — | Ignore preflight checks and continue | `false` | +| `-a, --all` | — | Install all UI components | `false` | +| `-y, --yes` | — | Skip confirmation prompt | `false` | +| `-o, --overwrite` | — | Overwrite existing files | `false` | +| `--proxy ` | — | Fetch components through this proxy | env-based | +| `-h, --help` | `-h` | Help | — | + +--- + +### `apply` — Apply a preset to an existing project + +```bash +npx shadcn-svelte@latest apply [options] +``` + +Applies a design-system preset to a project that has already been initialized. Updates `components.json` with the preset settings, reinstalls existing components (except `utils`) with the new styles, and installs any required dependencies. + +Use `--only theme` or `--only font` to apply only part of a preset without reinstalling UI components. + +Get a preset code from the builder at [shadcn-svelte.com/create](https://shadcn-svelte.com/create). + +| Flag | Short | Description | Default | +| ------------------- | ----- | ---------------------------------------------- | --------- | +| `--preset ` | — | Encoded design-system preset string (required) | — | +| `--only [parts]` | — | Apply only `theme` or `font` from the preset | — | +| `-c, --cwd ` | `-c` | Working directory | current | +| `-y, --yes` | `-y` | Overwrite existing files without confirmation | `false` | +| `-s, --silent` | `-s` | Mute output | `false` | +| `--skip-preflight` | — | Ignore preflight checks and continue | `false` | +| `--proxy ` | — | Fetch registry items through this proxy | env-based | +| `-h, --help` | `-h` | Help | — | + +Requires an existing `components.json`. Run `init` first if the project is not yet configured. + +--- + +### `update` — Update installed components + +```bash +npx shadcn-svelte@latest update [options] [components...] +``` + +Re-fetches and applies registry content for components **already present** in the project. Run `shadcn-svelte update --help` for options. + +| Flag | Short | Description | Default | +| ------------------ | ----- | ----------------------------------------------- | --------- | +| `-c, --cwd ` | `-c` | Working directory | current | +| `--skip-preflight` | — | Ignore preflight checks and continue | `false` | +| `--no-deps` | — | Skip adding and installing package dependencies | — | +| `-a, --all` | — | Update every installed component | `false` | +| `-y, --yes` | — | Skip confirmation prompt | `false` | +| `--proxy ` | — | Fetch through this proxy | env-based | +| `-h, --help` | `-h` | Help | — | + +Commit your work before updating; overwrites are destructive. + +--- + +### `registry build` — Build a custom registry + +```bash +npx shadcn-svelte@latest registry build [options] [registry] +``` + +Reads a `registry.json` and writes registry JSON files for distribution. Default input: `./registry.json`, default output: `./static/r`. + +| Flag | Short | Description | Default | +| --------------------- | ----- | ------------------------------- | ------------ | +| `-c, --cwd ` | `-c` | Working directory | current | +| `-o, --output ` | `-o` | Output directory for JSON files | `./static/r` | +| `-h, --help` | `-h` | Help | — | + +--- + +## Outgoing Requests + +### Proxy + +The CLI can fetch the registry through a proxy. If `HTTP_PROXY` or `http_proxy` is set, requests respect it. You can also pass `--proxy` on `init`, `add`, `apply`, or `update`. + +```bash +HTTP_PROXY="" npx shadcn-svelte@latest init +``` + +--- + +## Presets + +Design-system options (style, theme, icons, fonts, etc.) can be captured as an encoded **preset** string from the builder on [shadcn-svelte.com/create](https://shadcn-svelte.com/create). + +- **New project:** pass the preset to **`init`** with `--preset `. +- **Existing project:** use **`apply --preset `** to update configuration, restyle installed components, and install any new dependencies. + +--- + +## `components.json` — useful fields for agents + +| Field / path | Meaning | +| -------------------- | ---------------------------------------------------------------- | +| `tailwind.css` | Global CSS file path (Tailwind entry / theme variables) | +| `tailwind.baseColor` | Base palette (cannot change after init) | +| `aliases.*` | Import aliases; must match `svelte.config.js` / `tsconfig` paths | +| `registry` | Base registry URL (default `https://shadcn-svelte.com/registry`) | +| `style` | Registered style name (e.g. `nova`, `vega`, …) | +| `iconLibrary` | Icon set key (`lucide`, `tabler`, …) — drives generated imports | +| `typescript` | Whether TS and optional custom config path | + +Resolved paths (including `tailwindCss`, `ui`, `components`) are computed by the CLI from `components.json` and the filesystem. Read `components.json` and list the UI directory when you need a snapshot of what is installed. diff --git a/.agents/skills/shadcn-svelte/customization.md b/.agents/skills/shadcn-svelte/customization.md new file mode 100644 index 00000000..c278cb52 --- /dev/null +++ b/.agents/skills/shadcn-svelte/customization.md @@ -0,0 +1,211 @@ +# Customization & Theming + +Components reference semantic CSS variable tokens. Change the variables to change every component. + +## Contents + +- How it works (CSS variables → Tailwind utilities → components) +- Color variables and OKLCH format +- Dark mode setup +- Changing the theme (presets, CSS variables) +- Adding custom colors (Tailwind v3 and v4) +- Border radius +- Customizing components (variants, class, wrappers) +- Checking for updates + +--- + +## How It Works + +1. CSS variables defined in `:root` (light) and `.dark` (dark mode). +2. Tailwind maps them to utilities: `bg-primary`, `text-muted-foreground`, etc. +3. Components use these utilities — changing a variable changes all components that reference it. + +--- + +## Color Variables + +Every color follows the `name` / `name-foreground` convention. The base variable is for backgrounds, `-foreground` is for text/icons on that background. + +| Variable | Purpose | +| -------------------------------------------- | -------------------------------- | +| `--background` / `--foreground` | Page background and default text | +| `--card` / `--card-foreground` | Card surfaces | +| `--primary` / `--primary-foreground` | Primary buttons and actions | +| `--secondary` / `--secondary-foreground` | Secondary actions | +| `--muted` / `--muted-foreground` | Muted/disabled states | +| `--accent` / `--accent-foreground` | Hover and accent states | +| `--destructive` / `--destructive-foreground` | Error and destructive actions | +| `--border` | Default border color | +| `--input` | Form input borders | +| `--ring` | Focus ring color | +| `--chart-1` through `--chart-5` | Chart/data visualization | +| `--sidebar-*` | Sidebar-specific colors | +| `--surface` / `--surface-foreground` | Secondary surface | + +Colors use OKLCH: `--primary: oklch(0.205 0 0)` where values are lightness (0–1), chroma (0 = gray), and hue (0–360). + +--- + +## Dark Mode + +Class-based toggle via `.dark` on the root element. In SvelteKit, use [mode-watcher](https://github.com/svecosystem/mode-watcher) (see [Dark mode — Svelte](https://shadcn-svelte.com/docs/dark-mode/svelte)): + +```svelte + + + +{@render children?.()} +``` + +--- + +## Changing the Theme + +Use a **preset** from the design-system builder on [shadcn-svelte.com](https://shadcn-svelte.com) and pass it to `init`: + +```bash +npx shadcn-svelte@latest init --preset +``` + +Or edit CSS variables directly in the file set in `components.json` as `tailwind.css` (for example `src/app.css`). + +To align config and components with a new preset, re-run `init` with `--preset` and confirm overwrites when prompted. + +--- + +## Adding Custom Colors + +Add variables to the global CSS file path in `components.json` (`tailwind.css`). Do not create a second global CSS file for theming unless the project already uses that pattern. + +```css +/* 1. Define in the global CSS file. */ +:root { + --warning: oklch(0.84 0.16 84); + --warning-foreground: oklch(0.28 0.07 46); +} +.dark { + --warning: oklch(0.41 0.11 46); + --warning-foreground: oklch(0.99 0.02 95); +} +``` + +```css +/* 2a. Register with Tailwind v4 (@theme inline). */ +@theme inline { + --color-warning: var(--warning); + --color-warning-foreground: var(--warning-foreground); +} +``` + +On Tailwind v3, register in `tailwind.config.js` (see the [Tailwind v3 docs](https://tw3.shadcn-svelte.com) if you maintain a legacy setup): + +```js +// 2b. Register with Tailwind v3 (tailwind.config.js). +module.exports = { + theme: { + extend: { + colors: { + warning: 'oklch(var(--warning) / )', + 'warning-foreground': 'oklch(var(--warning-foreground) / )' + } + } + } +}; +``` + +```svelte +
Warning
+``` + +--- + +## Border Radius + +`--radius` controls border radius globally. Components derive values from it (`rounded-lg` = `var(--radius)`, `rounded-md` = `calc(var(--radius) - 2px)`). + +--- + +## Customizing Components + +See also: [rules/styling.md](./rules/styling.md) for Incorrect/Correct examples. + +Prefer these approaches in order: + +### 1. Built-in variants + +```svelte + + + +``` + +### 2. Tailwind classes via `class` + +```svelte + + + + ... + +``` + +### 3. Add a new variant + +Edit the component source to add a variant via `tailwind-variants` / `cva` in the `.svelte` or shared variants file: + +```ts +// e.g. in button variants +warning: "bg-warning text-warning-foreground hover:bg-warning/90", +``` + +### 4. Wrapper components + +Compose shadcn-svelte primitives into higher-level `.svelte` files: + +```svelte + + + + + {@render children?.()} + + + + {title} + {description} + + + Cancel + { + onConfirm?.(); + open = false; + }}>Confirm + + + +``` + +--- + +## Checking for Updates + +```bash +npx shadcn-svelte@latest update button +npx shadcn-svelte@latest update --all +``` + +See [Updating Components in SKILL.md](./SKILL.md#updating-components). Review `git diff` after `update` to see what changed. diff --git a/.agents/skills/shadcn-svelte/evals/evals.json b/.agents/skills/shadcn-svelte/evals/evals.json new file mode 100644 index 00000000..2b6067d8 --- /dev/null +++ b/.agents/skills/shadcn-svelte/evals/evals.json @@ -0,0 +1,47 @@ +{ + "skill_name": "shadcn-svelte", + "evals": [ + { + "id": 1, + "prompt": "I'm building a SvelteKit app with shadcn-svelte (nova style, lucide icons). Create a settings form component with fields for: full name, email address, and notification preferences (email, SMS, push notifications as toggle options). Add validation states for required fields.", + "expected_output": "A Svelte component using Field.FieldGroup, Field.Field, ToggleGroup, data-invalid/aria-invalid validation, gap-* spacing, and semantic colors.", + "files": [], + "expectations": [ + "Uses Field.FieldGroup and Field.Field for form layout instead of raw div with space-y", + "Uses Switch for independent on/off notification toggles (not looping Button with manual active state)", + "Uses data-invalid on Field and aria-invalid on the input control for validation states", + "Uses gap-* (e.g. gap-4, gap-6) instead of space-y-* or space-x-* for spacing", + "Uses semantic color tokens (e.g. bg-background, text-muted-foreground, text-destructive) instead of raw colors like bg-red-500", + "No manual dark: color overrides" + ] + }, + { + "id": 2, + "prompt": "Create a dialog component for editing a user profile. It should have the user's avatar at the top, input fields for name and bio, and Save/Cancel buttons with appropriate icons. Using shadcn-svelte with tabler icons.", + "expected_output": "A Svelte component with Dialog.Title, Avatar with Avatar.Fallback, data-icon on icon buttons, no icon sizing classes, @tabler/icons-svelte imports.", + "files": [], + "expectations": [ + "Includes Dialog.Title for accessibility (visible or with sr-only class)", + "Avatar includes Avatar.Fallback", + "Icons on buttons use the data-icon attribute (data-icon=\"inline-start\" or data-icon=\"inline-end\")", + "No sizing classes on icons inside components (no size-4, w-4, h-4, etc.)", + "Uses tabler icons (@tabler/icons-svelte) instead of @lucide/svelte when tabler is configured", + "Uses shadcn-svelte Dialog patterns (e.g. Dialog.Trigger wrapping the control, or bind:open on Dialog.Root)" + ] + }, + { + "id": 3, + "prompt": "Create a dashboard component that shows 4 stat cards in a grid. Each card has a title, large number, percentage change badge, and a loading skeleton state. Using shadcn-svelte with lucide icons.", + "expected_output": "A Svelte component with full Card composition, Skeleton for loading, Badge for changes, semantic colors, gap-* spacing.", + "files": [], + "expectations": [ + "Uses full Card composition with Card.Header, Card.Title, Card.Content (not dumping everything into Card.Content)", + "Uses Skeleton component for loading placeholders instead of custom animate-pulse divs", + "Uses Badge component for percentage change instead of custom styled spans", + "Uses semantic color tokens instead of raw color values like bg-green-500 or text-red-600", + "Uses gap-* instead of space-y-* or space-x-* for spacing", + "Uses size-* when width and height are equal instead of separate w-* h-*" + ] + } + ] +} diff --git a/.agents/skills/shadcn-svelte/rules/composition.md b/.agents/skills/shadcn-svelte/rules/composition.md new file mode 100644 index 00000000..ca8ff45e --- /dev/null +++ b/.agents/skills/shadcn-svelte/rules/composition.md @@ -0,0 +1,242 @@ +# Component Composition + +## Contents + +- Items always inside their Group component +- Callouts use Alert +- Empty states use Empty component +- Toast notifications use svelte-sonner +- Choosing between overlay components +- Dialog, Sheet, and Drawer always need a Title +- Card structure +- Button has no isPending or isLoading prop +- Tabs.Trigger must be inside Tabs.List +- Avatar always needs Avatar.Fallback +- Use Separator instead of raw hr or border divs +- Use Skeleton for loading placeholders +- Use Badge instead of custom styled spans + +--- + +## Items always inside their Group component + +Never render items directly inside the content container. + +**Incorrect:** + +```svelte + + + + Apple + Banana + +``` + +**Correct:** + +```svelte + + + + + Apple + Banana + + +``` + +This applies to all group-based components: + +| Item | Group | +| ------------------------------------------------------------- | -------------------- | +| `Select.Item`, `Select.Label` | `Select.Group` | +| `DropdownMenu.Item`, `DropdownMenu.Label`, `DropdownMenu.Sub` | `DropdownMenu.Group` | +| `Menubar.Item` | `Menubar.Group` | +| `ContextMenu.Item` | `ContextMenu.Group` | +| `Command.Item` | `Command.Group` | + +--- + +## Callouts use Alert + +```svelte + + + + Warning + Something needs attention. + +``` + +--- + +## Empty states use Empty component + +```svelte + + + + + + No projects yet + Get started by creating a new project. + + + + + +``` + +--- + +## Toast notifications use svelte-sonner + +```svelte + +``` + +```ts +toast.success('Changes saved.'); +toast.error('Something went wrong.'); +toast('File deleted.', { + action: { label: 'Undo', onClick: () => undoDelete() } +}); +``` + +Mount the `Toaster` from your UI folder once in the app layout (see [Sonner](https://shadcn-svelte.com/docs/components/sonner)). + +--- + +## Choosing between overlay components + +| Use case | Component | +| ---------------------------------- | ------------- | +| Focused task that requires input | `Dialog` | +| Destructive action confirmation | `AlertDialog` | +| Side panel with details or filters | `Sheet` | +| Mobile-first bottom panel | `Drawer` | +| Quick info on hover | `HoverCard` | +| Small contextual content on click | `Popover` | + +--- + +## Dialog, Sheet, and Drawer always need a Title + +`Dialog.Title`, `Sheet.Title`, `Drawer.Title` are required for accessibility. Use `class="sr-only"` if visually hidden. + +```svelte + + + + + Edit Profile + Update your profile. + + ... + +``` + +--- + +## Card structure + +Use full composition — don't dump everything into `Card.Content`: + +```svelte + + + + + Team Members + Manage your team. + + ... + + + + +``` + +--- + +## Button has no isPending or isLoading prop + +Compose with `Spinner` inside `Button` + `disabled`: + +```svelte + + + +``` + +--- + +## Tabs.Trigger must be inside Tabs.List + +Never render `Tabs.Trigger` directly inside `Tabs.Root` — always wrap in `Tabs.List`: + +```svelte + + + + + Account + Password + + ... + +``` + +--- + +## Avatar always needs Avatar.Fallback + +Always include `Avatar.Fallback` for when the image fails to load: + +```svelte + + + + + JD + +``` + +--- + +## Use existing components instead of custom markup + +| Instead of | Use | +| ---------------------------------------------- | ------------------------------------------------------------------------------------------- | +| `
` or `
` | `` (`import { Separator } from "$lib/components/ui/separator"`) | +| `
` with styled divs | `` (`import { Skeleton } from "$lib/components/ui/skeleton"`) | +| `` | `` (`import { Badge } from "$lib/components/ui/badge"`) | diff --git a/.agents/skills/shadcn-svelte/rules/forms.md b/.agents/skills/shadcn-svelte/rules/forms.md new file mode 100644 index 00000000..933f53c8 --- /dev/null +++ b/.agents/skills/shadcn-svelte/rules/forms.md @@ -0,0 +1,232 @@ +# Forms & Inputs + +## Contents + +- Forms use Field.FieldGroup + Field.Field +- InputGroup requires InputGroup.Input/InputGroup.Textarea +- Buttons inside inputs use InputGroup.Root + InputGroup.Addon +- Option sets (2–7 choices) use ToggleGroup.Root + ToggleGroup.Item +- Field.FieldSet + Field.FieldLegend for grouping related fields +- Field validation and disabled states + +--- + +## Forms use Field.FieldGroup + Field.Field + +Always use `Field.FieldGroup` + `Field.Field` — never raw `div` with `space-y-*`: + +```svelte + + + + + Email + + + + Password + + + +``` + +Use `Field` with `orientation="horizontal"` for settings pages. Use `Field.FieldLabel` with `class="sr-only"` for visually hidden labels. + +**Choosing form controls:** + +- Simple text input → `Input` +- Dropdown with predefined options → `Select` +- Searchable dropdown → `Combobox` +- Native HTML select (no JS) → `native-select` +- Boolean toggle → `Switch` (for settings) or `Checkbox` (for forms) +- Single choice from few options → `RadioGroup` +- Toggle between 2–5 options → `ToggleGroup.Root` + `ToggleGroup.Item` +- OTP/verification code → `InputOTP` +- Multi-line text → `Textarea` + +--- + +## InputGroup requires InputGroup.Input/InputGroup.Textarea + +Never use raw `Input` or `Textarea` inside an `InputGroup.Root`. + +**Incorrect:** + +```svelte + + + + + +``` + +**Correct:** + +```svelte + + + + + +``` + +--- + +## Buttons inside inputs use InputGroup.Root + InputGroup.Addon + +Never place a `Button` directly inside or adjacent to an `Input` with custom positioning. + +**Incorrect:** + +```svelte + + +
+ + +
+``` + +**Correct:** + +```svelte + + + + + + + + +``` + +--- + +## Option sets (2–7 choices) use ToggleGroup.Root + ToggleGroup.Item + +Don't manually loop `Button` components with active state. + +**Incorrect:** + +```svelte + + +
+ {#each ['daily', 'weekly', 'monthly'] as option (option)} + + {/each} +
+``` + +**Correct:** + +```svelte + + + + Daily + Weekly + Monthly + +``` + +Combine with `Field` for labelled toggle groups: + +```svelte + + + + Theme + + Light + Dark + System + + +``` + +--- + +## Field.FieldSet + Field.FieldLegend for grouping related fields + +Use `Field.FieldSet` + `Field.FieldLegend` for related checkboxes, radios, or switches — not `div` with a heading: + +```svelte + + + + Preferences + Select all that apply. + + + + Dark mode + + + +``` + +--- + +## Field validation and disabled states + +Both attributes are needed — `data-invalid`/`data-disabled` styles the field (label, description), while `aria-invalid`/`disabled` styles the control. + +```svelte + + + + + Email + + Invalid email address. + + + + + Email + + +``` + +Works for all controls: `Input`, `Textarea`, `Select`, `Checkbox`, `RadioGroupItem`, `Switch`, `Slider`, `NativeSelect`, `InputOTP`. diff --git a/.agents/skills/shadcn-svelte/rules/icons.md b/.agents/skills/shadcn-svelte/rules/icons.md new file mode 100644 index 00000000..15b54c9c --- /dev/null +++ b/.agents/skills/shadcn-svelte/rules/icons.md @@ -0,0 +1,107 @@ +# Icons + +**Always use the project's configured `iconLibrary` for imports.** Check the `iconLibrary` field in `components.json`: `lucide` → `@lucide/svelte`, `tabler` → `@tabler/icons-svelte`, etc. Never assume `@lucide/svelte`. + +--- + +## Icons in Button use data-icon attribute + +Add `data-icon="inline-start"` (prefix) or `data-icon="inline-end"` (suffix) to the icon. No sizing classes on the icon. + +**Incorrect:** + +```svelte + + + +``` + +**Correct:** + +```svelte + + + + + +``` + +--- + +## No sizing classes on icons inside components + +Components handle icon sizing via CSS. Don't add `size-4`, `w-4 h-4`, or other sizing classes to icons inside ` +``` + +**Correct:** + +```svelte + + + +``` + +The same applies to icons inside `DropdownMenu.Item`, sidebar items, and other menu rows — no extra sizing classes on the icon component. + +--- + +## Pass icons as components, not string keys + +Use a component reference, not a string key to a lookup map. + +**Incorrect:** + +```svelte + + +``` + +**Correct:** + +```svelte + + + + + +``` diff --git a/.agents/skills/shadcn-svelte/rules/styling.md b/.agents/skills/shadcn-svelte/rules/styling.md new file mode 100644 index 00000000..f12415cd --- /dev/null +++ b/.agents/skills/shadcn-svelte/rules/styling.md @@ -0,0 +1,193 @@ +# Styling & Customization + +See [customization.md](../customization.md) for theming, CSS variables, and adding custom colors. + +## Contents + +- Semantic colors +- Built-in variants first +- class for layout only +- No space-x-_ / space-y-_ +- Prefer size-_ over w-_ h-\* when equal +- Prefer truncate shorthand +- No manual dark: color overrides +- Use cn() for conditional classes +- No manual z-index on overlay components + +--- + +## Semantic colors + +**Incorrect:** + +```svelte +
+

Secondary text

+
+``` + +**Correct:** + +```svelte +
+

Secondary text

+
+``` + +--- + +## No raw color values for status/state indicators + +For positive, negative, or status indicators, use Badge variants, semantic tokens like `text-destructive`, or define custom CSS variables — don't reach for raw Tailwind colors. + +**Incorrect:** + +```svelte ++20.1% +Active +-3.2% +``` + +**Correct:** + +```svelte + + ++20.1% +Active +-3.2% +``` + +If you need a success/positive color that doesn't exist as a semantic token, use a Badge variant or ask the user about adding a custom CSS variable to the theme (see [customization.md](../customization.md)). + +--- + +## Built-in variants first + +**Incorrect:** + +```svelte + + + +``` + +**Correct:** + +```svelte + + + +``` + +--- + +## class for layout only + +Use `class` for layout (e.g. `max-w-md`, `mx-auto`, `mt-4`), **not** for overriding component colors or typography. To change colors, use semantic tokens, built-in variants, or CSS variables. + +**Incorrect:** + +```svelte + + + + Dashboard + +``` + +**Correct:** + +```svelte + + + + Dashboard + +``` + +To customize a component's appearance, prefer these approaches in order: + +1. **Built-in variants** — `variant="outline"`, `variant="destructive"`, etc. +2. **Semantic color tokens** — `bg-primary`, `text-muted-foreground`. +3. **CSS variables** — define custom colors in the global CSS file (see [customization.md](../customization.md)). + +--- + +## No space-x-_ / space-y-_ + +Use `gap-*` instead. `space-y-4` → `flex flex-col gap-4`. `space-x-2` → `flex gap-2`. + +```svelte + + +
+ + + +
+``` + +--- + +## Prefer size-_ over w-_ h-\* when equal + +`size-10` not `w-10 h-10`. Applies to icons, avatars, skeletons, etc. + +--- + +## Prefer truncate shorthand + +`truncate` not `overflow-hidden text-ellipsis whitespace-nowrap`. + +--- + +## No manual dark: color overrides + +Use semantic tokens — they handle light/dark via CSS variables. `bg-background text-foreground` not `bg-white dark:bg-gray-950`. + +--- + +## Use cn() for conditional classes + +Use the `cn()` utility from the project for conditional or merged class names. Don't write manual ternaries in `class` strings. + +**Incorrect:** + +```svelte + + +
+``` + +**Correct:** + +```svelte + + +
+``` + +--- + +## No manual z-index on overlay components + +`Dialog`, `Sheet`, `Drawer`, `AlertDialog`, `DropdownMenu`, `Popover`, `Tooltip`, `HoverCard` handle their own stacking. Never add `z-50` or `z-[999]`. diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 00000000..fb29c281 --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,13 @@ +{ + "permissions": { + "allow": [ + "Bash(pnpm check *)", + "Bash(pnpm lint *)", + "Bash(node_modules/.bin/prettier --check *)", + "Bash(npm run check *)", + "Bash(npm run lint *)", + "Bash(pnpm exec prettier --check *)", + "Bash(pnpm vitest --run *)" + ] + } +} diff --git a/.env.example b/.env.example index 6fa6bccc..9b86496a 100644 --- a/.env.example +++ b/.env.example @@ -11,7 +11,6 @@ DB_PATH="./tracktor.db" UPLOADS_DIR="./uploads" # Application Features -BASE_URL=http://localhost:3000 TRACKTOR_DEMO_MODE=false FORCE_DATA_SEED=false TRACKTOR_DISABLE_AUTH=false @@ -29,3 +28,4 @@ BODY_SIZE_LIMIT="10mb" # Security Configuration APP_SECRET="" # Secret key for encrypting sensitive data (generate with: openssl rand -hex 32) +HTTP_MODE="http" # Set to "https" when served over TLS, so auth cookies get the secure flag diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cd30257c..c0fbf30b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,7 @@ jobs: run: pnpm install --frozen-lockfile - name: Compile Paraglide messages - run: pnpm paraglide-js compile --outdir ./src/lib/paraglide + run: pnpm paraglide-js compile --project ./i18n/project.inlang --outdir ./src/lib/paraglide - name: Run linting run: pnpm run lint diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 15da6fec..9d5db66d 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -108,17 +108,54 @@ jobs: - name: Update package version run: npm pkg set version="${{ steps.release-version.outputs.value }}" - - name: Commit version bump + - name: Update OpenWiki docs run: | - if git diff --quiet package.json; then - exit 0 + npm install --global openwiki + openwiki code --update --print + env: + OPENWIKI_PROVIDER: openai-compatible + OPENAI_COMPATIBLE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} + OPENAI_COMPATIBLE_BASE_URL: https://opencode.ai/zen/v1 + OPENWIKI_MODEL_ID: deepseek-v4-flash-free + OPENWIKI_TELEMETRY_DISABLED: true + + - name: Format updated docs + run: | + npm install --global prettier + paths="" + for p in docs/openwiki CLAUDE.md AGENTS.md; do + [ -e "$p" ] && paths="$paths $p" + done + if [ -n "$paths" ]; then + prettier --write $paths fi + - name: Commit version bump and doc updates + id: release-commit + run: | git config user.name 'github-actions[bot]' git config user.email '41898282+github-actions[bot]@users.noreply.github.com' - git add package.json - git commit -m "chore: bump version to ${{ steps.release-version.outputs.value }}" + + paths="package.json" + for p in docs/openwiki CLAUDE.md AGENTS.md; do + [ -e "$p" ] && paths="$paths $p" + done + git add $paths + + if git diff --cached --quiet; then + echo "changed=false" >> "$GITHUB_OUTPUT" + exit 0 + fi + + git commit -m "chore: release ${{ steps.release-version.outputs.value }} (version bump + doc update)" git push origin "HEAD:${{ steps.release-branch.outputs.value }}" + echo "changed=true" >> "$GITHUB_OUTPUT" + + - name: Move release tag to the updated commit + if: steps.release-commit.outputs.changed == 'true' + run: | + git tag -f "$GITHUB_REF_NAME" HEAD + git push origin "refs/tags/$GITHUB_REF_NAME" --force - name: Set up QEMU uses: docker/setup-qemu-action@v3 diff --git a/.gitignore b/.gitignore index 1653a44c..d54df9a2 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,6 @@ uploads/ src/lib/paraglide project.inlang/cache/ .opencode +opencode.json .app/ +docs/planning diff --git a/.prettierignore b/.prettierignore index 5fb313c2..abd030e5 100644 --- a/.prettierignore +++ b/.prettierignore @@ -9,5 +9,9 @@ bun.lockb /static/ # Ignore specific files for linting -project.inlang/.meta.json -project.inlang/README.md \ No newline at end of file +i18n/project.inlang/.meta.json +i18n/project.inlang/README.md + +# Vendored agent skills and local tool config — not ours to reformat +.agents/ +.claude/ diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index 074e254f..00000000 --- a/AGENTS.md +++ /dev/null @@ -1,154 +0,0 @@ -Tracktor repository instructions for agentic coding work. - -## Svelte MCP Usage - -Use the Svelte MCP server for any Svelte, SvelteKit, or `.svelte`/ -`.svelte.ts` work. - -### 1. `list-sections` - -Use this first to discover docs sections. Always start Svelte tasks here. - -### 2. `get-documentation` - -After `list-sections`, inspect `use_cases` and fetch all relevant sections at -once when possible. - -### 3. `svelte-autofixer` - -Use this whenever writing or editing Svelte code. Iterate until clean. - -### 4. `playground-link` - -Only use after the user asks for a playground link. Never use it for code -already written to the repo. - -## Project Snapshot - -- Tracktor is a vehicle management app built with SvelteKit, Svelte 5, Vite, - Tailwind CSS, SQLite, and Drizzle ORM. -- i18n uses inlang / Paraglide. -- TypeScript is the default, with strict checking enabled. - -## Key Paths - -- `src/routes/` pages, layouts, and endpoints. -- `src/lib/components/` reusable UI. -- `src/lib/domain/` business rules and models. -- `src/lib/services/` orchestration and data access. -- `src/lib/helper/` shared helpers. -- `src/lib/config/` app config and feature toggles. -- `src/server/` server-only helpers. -- `messages/`, `project.inlang/`, `migrations/` for i18n and DB work. - -## Core Commands - -- Install: `pnpm install` -- Dev: `pnpm dev` -- Build: `pnpm build` -- Preview: `pnpm preview` -- Check: `pnpm check` -- Watch check: `pnpm check:watch` -- Lint: `pnpm lint` -- Format: `pnpm format` -- Test: `pnpm test` -- Test watch: `pnpm test:watch` -- Coverage: `pnpm test:coverage` -- DB: `pnpm db:generate`, `pnpm db:migrate`, `pnpm db:seed` -- Clean: `pnpm clean` - -## Single-Test Commands - -- Run one file: `pnpm test -- path/to/file.test.ts` -- Run one file directly: `pnpm vitest --run path/to/file.test.ts` -- Run by name: `pnpm test -- -t "test name"` -- Run a focused pattern: `pnpm vitest --run -t "test name"` -- Run a folder: `pnpm vitest --run src/__tests__/feature` - -## Tooling Expectations - -- Use `pnpm` for package commands. -- Prefer repo scripts over raw binaries. -- Run `pnpm check` and `pnpm lint` before finishing. -- For test or logic changes, run the narrowest relevant test first. - -## Code Style - -- Use ESM only; the repo is `type: module`. -- Keep TypeScript strict; avoid `any` unless the surrounding code already uses it. -- Remove unused imports; ESLint fails on them. -- Prefer small, composable functions and clear names. -- Use `camelCase` for values/functions, `PascalCase` for components/types, - and `SCREAMING_SNAKE_CASE` for constants. -- Keep route/server code aligned with SvelteKit conventions. -- Prefer aliases from `svelte.config.js` over long relative paths. -- Group imports: external, aliases, then local. - -## Formatting Rules - -- Follow the existing Prettier + ESLint setup. -- Let `pnpm format` handle spacing, wrapping, and ordering. -- Match the repo's quote and semicolon style. -- Add comments only when something is non-obvious. - -## Svelte Conventions - -- Assume Svelte 5 semantics where the file already uses them. -- Use runes only where the project already expects them. -- Keep props and events simple. -- Prefer derived values/helpers over complex template logic. -- Split busy `.svelte` markup into smaller components. - -## TypeScript Conventions - -- Keep `strict`-compatible types in mind. -- Prefer inference for obvious locals; annotate public APIs and shared helpers. -- Use `unknown` for untrusted data. -- Narrow before accessing API/request/JSON values. -- Preserve file-name casing. - -## Error Handling - -- Fail fast on invalid inputs. -- Prefer existing response helpers over ad hoc shapes. -- Return clear, actionable error messages. -- Log enough context to debug, but never leak secrets or raw user data. -- Prefer typed branches and validation over broad catch-alls. - -## Testing Guidance - -- Keep tests close to the behavior they cover. -- Name tests clearly so `-t` and file filters stay useful. -- Add regression tests for bug fixes when practical. -- Prefer deterministic tests with minimal external dependencies. - -## Repo-Specific Rules - -- Respect boundaries under `src/lib/domain`, `src/lib/services`, and - `src/lib/components`. -- Keep translation changes in `messages/` aligned with inlang. -- Use the Drizzle migration workflow for schema changes. -- Do not edit generated or ignored directories unless required. - -## Existing Guidance To Preserve - -- Copy the intent of `.github/copilot-instructions.md`. -- If `.cursor/rules/` or `.cursorrules` exist, incorporate them too. -- Keep changes consistent with the repo architecture and docs. - -## When In Doubt - -- Read the nearest module, test, or route first. -- Match patterns in the same folder. -- Prefer the smallest safe change. -- Validate with checks/tests before handing work back. - - - -## OpenWiki - -This repository uses OpenWiki for recurring code documentation. Start with `openwiki/quickstart.md`, then follow its links to architecture, workflows, domain concepts, operations, integrations, testing guidance, and source maps. - -The scheduled OpenWiki GitHub Actions workflow refreshes the repository wiki. Do not hand-edit generated OpenWiki pages unless explicitly asked; prefer updating source code/docs and letting OpenWiki regenerate. - - diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..2eaa7586 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,87 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Svelte MCP Usage + +Use the Svelte MCP server for any Svelte, SvelteKit, or `.svelte`/`.svelte.ts` work: + +1. **`list-sections`** — call first to discover docs sections; always start Svelte tasks here. +2. **`get-documentation`** — after `list-sections`, inspect `use_cases` and fetch all relevant sections at once when possible. +3. **`svelte-autofixer`** — use whenever writing or editing Svelte code; iterate until clean. +4. **`playground-link`** — only after the user explicitly asks for one; never for code already written to the repo. + +## Project Snapshot + +Tracktor is a self-hosted vehicle management app (fuel, maintenance, insurance, PUCC/pollution certs, reminders) built with SvelteKit + Svelte 5, Tailwind CSS, SQLite (via `@libsql/client`), and Drizzle ORM. i18n uses inlang/Paraglide. TypeScript is strict throughout. + +## Core Commands + +- Install: `pnpm install` +- Dev server: `pnpm dev` (host mode) / `pnpm local` (localhost only) +- Build: `pnpm build` / Preview build: `pnpm preview` +- Type/svelte check: `pnpm check` (watch: `pnpm check:watch`) +- Lint: `pnpm lint` (eslint + prettier check) / Autofix: `pnpm format` +- Test: `pnpm test` (watch: `pnpm test:watch`, coverage: `pnpm test:coverage`) +- DB: `pnpm db:generate` (drizzle migration from schema changes), `pnpm db:migrate`, `pnpm db:seed` +- Clean: `pnpm clean` (removes build artifacts, db file, node_modules, etc.) + +Always run `pnpm check` and `pnpm lint` before considering a change finished. ESLint fails the build on unused imports/vars. + +### Single-Test Commands + +- Run one file: `pnpm vitest --run path/to/file.test.ts` +- Run by test name: `pnpm vitest --run -t "test name"` +- Run a folder: `pnpm vitest --run src/__tests__/feature` + +Note: test coverage is currently minimal (essentially a placeholder in `src/__tests__/index.test.ts`) — don't assume extensive existing test patterns exist for a given module. + +## Architecture + +### Path aliases (defined in `svelte.config.js`) + +`$lib` → `src/lib`, `$ui` → `src/lib/components/ui`, `$appui` → `src/lib/components/app`, `$layout` → `src/lib/components/layout`, `$feature` → `src/lib/components/feature`, `$stores` → `src/lib/stores`, `$services` → `src/lib/services`, `$helper` → `src/lib/helper`, `$dashboard` → `src/lib/components/dashboard`, `$server` → `src/server`. Prefer these aliases over long relative paths. + +### Two parallel "service" layers — don't confuse them + +- **`src/lib/services/*.service.ts`** — browser/client-side code. Calls the app's own `/api/*` REST endpoints via `$lib/helper/api.helper` (`apiClient`) and returns a `Response` shape (`{ status: 'OK' | 'ERROR', data?, error? }`). Used from `.svelte` pages/components. +- **`src/server/services/*Service.ts`** — server-only code. Talks directly to the Drizzle DB (`src/server/db`), does business logic, and is called from `+server.ts` route handlers (or `+page.server.ts`). Never import these from client-facing `.svelte` code. + +`src/lib/domain/*` holds shared types/models and pure business rules (e.g. `domain/fuel/mileage.ts` mileage math) usable from both client and server code. + +### Request pipeline + +`src/hooks.server.ts` runs one-time app init (ensure directories, `initializeDatabase()` — runs Drizzle migrations, seeding, then patches — and starts the notification scheduler cron) and wires a `MiddlewareChain` (`src/server/middlewares`, chain-of-responsibility pattern via `BaseMiddleware`/`setNext`): `CorsMiddleware` → `AuthMiddleware` → `RateLimitMiddleware` → `LoggingMiddleware`. `AuthMiddleware` checks session cookie/Bearer token against `authService`, bypassing `/api/auth`, `/api/health`, `/api/config/branding`, and everything when `TRACKTOR_DISABLE_AUTH`/`env.DISABLE_AUTH` is set. + +### Data layer + +- Drizzle schema lives in `src/server/db/schema/*.ts` (one file per domain entity: `vehicle`, `fuel-log`, `insurance`, `maintenance-logs`, `pucc`, `reminder`, `notification`, `notification-provider`, `config`, `audit`, `auth`). +- SQLite dialect, `snake_case` column casing, migrations generated to `src/server/db/migrations` via `pnpm db:generate` — never hand-edit generated migrations. +- One-off data fixups live under `src/server/db/patch` and run via `applyPatches()` at startup, after migrations/seeding. + +### Routes + +- `src/routes/(app)/*` — authenticated app pages (dashboard, fuel, maintenance, insurance, pollution, reminders, vehicles, expenses, reports, settings), sharing the app shell (`AppSidebar`, `+layout.svelte`). +- `src/routes/(auth)/*` — login/register, outside the app shell. +- `src/routes/api/*` — REST endpoints as `+server.ts` files; vehicle-scoped resources nest under `api/vehicles/[id]/...`. + +The app recently moved from a `/dashboard/*` nested-route structure to top-level feature routes (`/fuel`, `/insurance`, `/maintenance`, `/pollution`, `/reminders`) with a single sidebar app shell — the old `dashboard/(feature)` routes are being removed in favor of this flatter structure with fleet-wide/vehicle-selector support baked into each page. + +### UI components + +`src/lib/components/ui` is a shadcn-svelte install (`components.json`, baseColor `zinc`, registry `shadcn-svelte.com`) built on `bits-ui` + `tailwind-variants` — treat it as generated/vendored (it's excluded from lint) and prefer composing it from `$feature`/`$dashboard`/`$appui` rather than editing it directly. Charts use `layerchart`/`d3-*`. + +### Feature toggles + +Features (Fuel Log, Maintenance, PUCC, Reminders, Insurance, Overview) are stored as string `'true'/'false'` values in the `configs` table under keys like `featureFuelLog`, and gated in the UI with the `FeatureGate` component (`feature="fuelLog"` or `requireAll={[...]}`). See `docs/feature-toggles.md`. + +## Code Style + +- ESM only (`"type": "module"`); use `pnpm`, not raw `npm`/`yarn`/`npx`. +- `camelCase` for values/functions, `PascalCase` for components/types, `SCREAMING_SNAKE_CASE` for constants. +- Group imports: external, then aliases, then local relative. +- Assume Svelte 5 runes mode where a file already uses it; keep props/events simple; prefer derived values/helpers over complex template logic; split busy `.svelte` markup into smaller components. +- Fail fast on invalid inputs; prefer existing response/error helpers (`$server/exceptions/AppError`, `service-response.helper.ts`) over ad hoc shapes; narrow `unknown` before accessing API/request/JSON values. +- Respect the boundaries between `src/lib/domain`, `src/lib/services`, `src/server/services`, and `src/lib/components` described above. +- Keep translation changes in `messages/` aligned with inlang; regenerate via the Paraglide vite plugin (runs automatically through `vite dev`/`vite build`). +- Add comments only when something is genuinely non-obvious. diff --git a/README.md b/README.md index 0a2c772c..22b7fcc3 100644 --- a/README.md +++ b/README.md @@ -17,74 +17,73 @@
-

- Tracktor is an open-source web application for comprehensive vehicle management.
- Easily track ⛽ fuel consumption, 🛠️ maintenance, 🛡️ insurance, and 📄 regulatory documents for all your vehicles in one place. -

+If you own more than one vehicle, you know the drill: fuel receipts in a drawer, insurance PDFs buried in email, a maintenance date you meant to write down somewhere. Tracktor is a self-hosted app that keeps all of that in one place — fuel logs, service history, insurance and pollution certs, reminders before they lapse, and a dashboard that actually shows you what's going on across your fleet. + +Run it on a Raspberry Pi, a home server, or a $5 VPS. Your data stays yours.

- - - - Dashboard - + Dashboard

-## ✨ Features +## What it does -- 🚗 **Vehicle Management:** Add, edit, and manage multiple vehicles with support for different fuel types. -- ⛽ **Fuel Tracking:** Log fuel refills and monitor fuel efficiency over time. -- 🛠️ **Maintenance Log:** Record and view maintenance history for each vehicle. -- 📄 **Document Tracking:** Track insurance and pollution certificates with renewal dates. -- 🔔 **Reminders:** Set and manage reminders for maintenance, renewals, and other vehicle events. -- 📊 **Dashboard:** Visualize key metrics, analytics, and upcoming renewals. -- 🔒 **User Authentication:** Secure username/password authentication with session management. -- 🎨 **Feature Toggles:** Enable or disable specific features based on your needs. +- **Garage** — Add and manage multiple vehicles, each with its own fuel type and history. +- **Fuel tracking** — Log every fill-up and watch your mileage/efficiency trends over time. +- **Maintenance log** — Keep a full service history per vehicle, and know what's coming up next. +- **Compliance** — Track insurance and pollution (PUCC) certificates, with renewal dates that don't sneak up on you. +- **Reminders** — Get nudged before something expires or a service is due. +- **Expenses & reports** — See what your vehicles actually cost you. +- **Dashboard** — A fleet-wide overview with widgets you can rearrange to your liking. +- **Auth & feature toggles** — Username/password login with sessions, and the ability to turn off features you don't need. +- **10 languages** — English, Hindi, Spanish, French, German, Italian, Arabic, Romanian, Hungarian, and Finnish. -## 🛠️ Tech Stack +## Tech stack -- 🎨 **Frontend:** SvelteKit, Tailwind CSS, Svelte 5 -- 🖥️ **Backend:** SvelteKit Server Routes -- 🗄️ **Database:** SQLite with Drizzle ORM -- 🐳 **Deployment:** Docker & Docker Compose +SvelteKit (Svelte 5) + Tailwind CSS on the frontend, SvelteKit server routes on the backend, SQLite via Drizzle ORM for storage, shipped as a Docker image. -## 🚀 Getting Started +## Getting started -Refer to the [installation guide](./docs/installation.md) for setup instructions. +The fastest way to try Tracktor is Docker Compose: -## 📚 Documentation +```yaml +services: + app: + image: ghcr.io/javedh-dev/tracktor:latest + container_name: tracktor-app + restart: always + ports: + - '3333:3000' + volumes: + - tracktor-data:/data +volumes: + tracktor-data: +``` -- [Installation Guide](./docs/installation.md) - Setup instructions for Docker, local development, and Proxmox LXC -- [Authentication](./docs/authentication.md) - User authentication and session management -- [Environment Variables](./docs/environment.md) - Configuration options -- [Feature Toggles](./docs/feature-toggles.md) - Customizing enabled features -- [Contributing](./docs/contributing.md) - Guidelines for contributing +```bash +docker-compose up -d +``` -## 🤝 Contributing +Then open `http://:3333`. -Contributions are welcome! Please read the [contributing guidelines](./docs/contributing.md) before submitting a pull request. +For local development, Proxmox LXC setup, reverse proxies, and every configuration option, see the [installation guide](./docs/installation.md). -Consider supporting this project by giving it a star ⭐ or [sponsoring](https://github.com/sponsors/javedh-dev). +## Documentation -## 📄 License +- [Installation Guide](./docs/installation.md) — Docker, local dev, Proxmox LXC +- [Environment Variables](./docs/environment.md) — every config option, explained +- [Authentication](./docs/authentication.md) — how login and sessions work +- [Feature Toggles](./docs/feature-toggles.md) — turning features on/off +- [Contributing](./docs/contributing.md) — how to get involved -This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. +## Contributing -## 📊 Repository activity +PRs and issues are welcome — read the [contributing guide](./docs/contributing.md) first. If Tracktor is useful to you, a star ⭐ or a [sponsorship](https://github.com/sponsors/javedh-dev) helps keep it going. -![Activities](https://repobeats.axiom.co/api/embed/d41931a72a5373ee0d2073e72279862171468023.svg 'Repobeats analytics image') +## License -## ⭐ Star History - - - - - - Star History Chart - - +MIT — see [LICENSE](LICENSE). -## 🤝 Contributors +## Contributors diff --git a/docs/environment.md b/docs/environment.md index 8792b232..fed295a3 100644 --- a/docs/environment.md +++ b/docs/environment.md @@ -8,8 +8,8 @@ Configure Tracktor by setting environment variables in a `.env` file in the root Application environment. -- **Values**: `dev`, `production`, `test` -- **Default**: `dev` +- **Values**: `development`, `production`, `test` +- **Default**: `development` ### HOST @@ -70,6 +70,21 @@ Disable authentication (not recommended for production). - **Values**: `true`, `false` - **Default**: `false` +### APP_SECRET + +Secret key used to encrypt stored credentials (e.g. notification provider passwords). Required once you configure any notification provider — the app refuses to store or read credentials without it. + +- **Values**: Any random string +- **Default**: none (must be set to use notification providers) +- **Generate**: `openssl rand -hex 32` + +### HTTP_MODE + +Controls whether auth cookies are marked `secure`. Set to `https` when Tracktor is served over HTTPS (e.g. behind a TLS-terminating reverse proxy) so the session cookie gets the `secure` flag. + +- **Values**: `http`, `https` +- **Default**: `http` + ## Demo Mode ### TRACKTOR_DEMO_MODE @@ -113,8 +128,8 @@ Directory for log files. Limits the upload size of image/documents. -- **values**: Any number (size in bytes) -- **Defaut**: 512Kb +- **Values**: Any number (size in bytes) +- **Default**: 512Kb - **Docker**: Infinity (removes restriction) ## Notes diff --git a/docs/feature-toggles.md b/docs/feature-toggles.md index 2312b123..fdc74b04 100644 --- a/docs/feature-toggles.md +++ b/docs/feature-toggles.md @@ -17,10 +17,9 @@ The following features can be toggled: 1. **Fuel Log** - Track and manage fuel consumption and refueling history 2. **Maintenance** - Record and schedule vehicle maintenance activities -3. **PUCC** - Manage Pollution Under Control Certificate records +3. **Compliance** - Manage insurance and Pollution Under Control Certificate (PUCC) records 4. **Reminders** - Set and receive reminders for important vehicle events -5. **Insurance** - Manage vehicle insurance details and renewals -6. **Overview** - Display overview dashboard with key vehicle metrics +5. **Overview** - Display overview dashboard with key vehicle metrics ## Configuration @@ -32,9 +31,8 @@ Feature toggles are stored in the `configs` table with the following keys: - `featureFuelLog` - `featureMaintenance` -- `featurePucc` +- `featureCompliance` - `featureReminders` -- `featureInsurance` - `featureOverview` Values are stored as strings: `'true'` or `'false'` @@ -61,7 +59,7 @@ The easiest way to conditionally show/hide components based on feature flags: - + @@ -104,7 +102,7 @@ if (areAllFeaturesEnabled([Features.FUEL_LOG, Features.MAINTENANCE])) { } // Check if any feature is enabled -if (isAnyFeatureEnabled([Features.INSURANCE, Features.PUCC])) { +if (isAnyFeatureEnabled([Features.COMPLIANCE, Features.REMINDERS])) { // Show documents section } ``` @@ -128,7 +126,7 @@ You can use feature flags to conditionally show/hide navigation items: {#if configStore.configs.featureFuelLog} - Fuel Log + Fuel Log {/if} {#if configStore.configs.featureMaintenance} diff --git a/docs/i18n.md b/docs/i18n.md index ca0b6d7e..b4d86f9e 100644 --- a/docs/i18n.md +++ b/docs/i18n.md @@ -22,7 +22,7 @@ Tracktor uses Paraglide (inlang) with the Svelte 5 addon for runtime-localized U ## Adding a new language -1. Add the language in your Paraglide source/messages and regenerate the compiled outputs under `src/lib/paraglide/messages/`. +1. Add the language in your Paraglide source/messages `i18n/messages` and regenerate the compiled outputs under `src/lib/paraglide/messages/`. 2. Ensure the new language code is included in Paraglide's generated `locales` array (in `src/lib/paraglide/runtime.js`). 3. Optionally add a human-readable label in `src/lib/components/feature/settings/SettingsForm.svelte` in the `localeLabels` map. 4. Provide translations for your messages via inlang tooling (VS Code Sherlock, Fink, etc.). diff --git a/docs/images/intro.gif b/docs/images/intro.gif new file mode 100644 index 00000000..73ca6067 Binary files /dev/null and b/docs/images/intro.gif differ diff --git a/docs/installation.md b/docs/installation.md index 48713c61..f76bd319 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -171,7 +171,7 @@ For Proxmox LXC container setup, use [Community-Scripts](https://community-scrip ### Prerequisites -- Node.js (v18 or higher) +- Node.js (v22 or higher) - pnpm package manager ### Steps diff --git a/docs/openwiki/architecture/overview.md b/docs/openwiki/architecture/overview.md index 27f2c1da..3d20ce39 100644 --- a/docs/openwiki/architecture/overview.md +++ b/docs/openwiki/architecture/overview.md @@ -1,6 +1,6 @@ --- -type: "Reference" -title: "Architecture Overview" +type: 'Reference' +title: 'Architecture Overview' openwiki_generated: true --- diff --git a/docs/openwiki/architecture/routing-and-api.md b/docs/openwiki/architecture/routing-and-api.md index 122422f0..56547a71 100644 --- a/docs/openwiki/architecture/routing-and-api.md +++ b/docs/openwiki/architecture/routing-and-api.md @@ -1,6 +1,6 @@ --- -type: "Reference" -title: "Routing and API Surface" +type: 'Reference' +title: 'Routing and API Surface' openwiki_generated: true --- diff --git a/docs/openwiki/domain/data-models.md b/docs/openwiki/domain/data-models.md index 4b90133f..52fb3cdf 100644 --- a/docs/openwiki/domain/data-models.md +++ b/docs/openwiki/domain/data-models.md @@ -1,6 +1,6 @@ --- -type: "Reference" -title: "Domain and Data Models" +type: 'Reference' +title: 'Domain and Data Models' openwiki_generated: true --- diff --git a/docs/openwiki/index.md b/docs/openwiki/index.md index c3e4fb36..17db6c7d 100644 --- a/docs/openwiki/index.md +++ b/docs/openwiki/index.md @@ -1,5 +1,5 @@ --- -okf_version: "0.1" +okf_version: '0.1' --- # Files diff --git a/docs/openwiki/operations/runbook.md b/docs/openwiki/operations/runbook.md index 486be341..de387b09 100644 --- a/docs/openwiki/operations/runbook.md +++ b/docs/openwiki/operations/runbook.md @@ -1,6 +1,6 @@ --- -type: "Reference" -title: "Operations Runbook" +type: 'Reference' +title: 'Operations Runbook' openwiki_generated: true --- diff --git a/docs/openwiki/quickstart.md b/docs/openwiki/quickstart.md index 2103187a..f74774f6 100644 --- a/docs/openwiki/quickstart.md +++ b/docs/openwiki/quickstart.md @@ -1,6 +1,6 @@ --- -type: "Reference" -title: "Tracktor — OpenWiki Quickstart" +type: 'Reference' +title: 'Tracktor — OpenWiki Quickstart' openwiki_generated: true --- diff --git a/docs/openwiki/testing.md b/docs/openwiki/testing.md index 4d88bd27..5f93be22 100644 --- a/docs/openwiki/testing.md +++ b/docs/openwiki/testing.md @@ -1,6 +1,6 @@ --- -type: "Reference" -title: "Testing Guidance" +type: 'Reference' +title: 'Testing Guidance' openwiki_generated: true --- diff --git a/docs/openwiki/workflows/authentication.md b/docs/openwiki/workflows/authentication.md index 3c01f9c8..5f122950 100644 --- a/docs/openwiki/workflows/authentication.md +++ b/docs/openwiki/workflows/authentication.md @@ -1,6 +1,6 @@ --- -type: "Reference" -title: "Authentication Workflow" +type: 'Reference' +title: 'Authentication Workflow' openwiki_generated: true --- diff --git a/docs/openwiki/workflows/feature-toggles.md b/docs/openwiki/workflows/feature-toggles.md index d0161596..d50e62ad 100644 --- a/docs/openwiki/workflows/feature-toggles.md +++ b/docs/openwiki/workflows/feature-toggles.md @@ -1,6 +1,6 @@ --- -type: "Reference" -title: "Feature Toggles Workflow" +type: 'Reference' +title: 'Feature Toggles Workflow' openwiki_generated: true --- diff --git a/i18n/messages/en.json b/i18n/messages/en.json index 8ccfa7ee..760b16aa 100644 --- a/i18n/messages/en.json +++ b/i18n/messages/en.json @@ -5,6 +5,10 @@ "app_title": "Your Garage", "app_new_update_available": "New Update is available. Reloading..!", "app_add_vehicle": "Add Vehicle", + "vehicle_scope_all": "All vehicles", + "vehicle_scope_manage": "Manage vehicles", + "form_vehicle_label": "Vehicle", + "form_vehicle_desc": "Which vehicle this record belongs to", "app_empty_select_message": "Select a vehicle to view its details", "app_empty_select_hint": "Choose one from the garage above to load its dashboard.", "demo_banner": "This is a demo instance. Data will be reset periodically and is not saved permanently. Please avoid adding any personal info.", @@ -21,9 +25,12 @@ "auth_password_mismatch": "Passwords do not match!!!", "settings_tab_personalization": "Personalization", "settings_tab_interface": "Interface", + "settings_tab_localization": "Localization", + "settings_tab_advanced": "Advanced", "settings_tab_features": "Features", "settings_tab_units": "Units", "settings_title": "Settings", + "settings_page_description": "Configure appearance, language, regional formats, and interface behavior.", "settings_label_date_format": "Date Format", "settings_label_locale": "Locale", "settings_label_timezone": "Timezone", @@ -31,10 +38,12 @@ "settings_label_unit_distance": "Unit of Distance", "settings_label_unit_volume": "Unit of Fuel", "settings_label_theme": "Theme", + "settings_label_dark_mode": "Dark Mode Style", "settings_label_custom_css": "Custom CSS", "settings_update_button": "Update Settings", "settings_select_unit_system": "Select unit system", "settings_select_theme": "Select theme", + "settings_select_dark_mode": "Select dark mode style", "settings_desc_date_format": "Choose your preferred date format", "settings_desc_locale": "Choose the language for the interface", "settings_desc_timezone": "Choose your timezone for date display", @@ -47,6 +56,7 @@ "settings_mileage_format_fuel_per_distance": "Fuel per Distance (e.g., L/100km)", "settings_mileage_format_uk_mpg": "UK MPG (miles per imperial gallon)", "settings_desc_theme": "Choose your preferred theme", + "settings_desc_dark_mode": "Choose the contrast style used when dark mode is active", "settings_desc_custom_css": "CSS Styles for customizing the interface", "settings_select_language": "Select language", "settings_updated_success": "Configuration updated successfully!", @@ -57,6 +67,13 @@ "common_litre": "Litre", "common_gallon": "Gallon", "common_submit": "Submit", + "common_details": "Details", + "common_close": "Close", + "common_view": "View", + "common_view_all": "View All", + "common_view_less": "Show Less", + "common_loading": "Loading...", + "common_add": "Add", "common_yes": "Yes", "common_no": "No", "common_cancel": "Cancel", @@ -71,15 +88,17 @@ "common_columns": "Columns", "common_rows_per_page": "Rows per page", "common_no_data_available": "No data available", + "common_no_records_found": "No records found", "common_add_new": "Add New", "common_no_match_found": "No match found", "common_search_placeholder": "Search {name}", "common_select_placeholder": "Select {name}...", + "common_date_from": "From", + "common_date_to": "To", + "common_export_csv": "Export CSV", "nav_overview": "Overview", "nav_fuel_logs": "Fuel Logs", "nav_maintenance": "Maintenance", - "nav_insurance": "Insurance", - "nav_pollution": "Pollution Certificate", "nav_reminders": "Reminders", "tools_export_data": "Export Data", "tools_import_data": "Import Data", @@ -94,6 +113,9 @@ "vehicle_form_fuel_type_label": "Fuel Type", "vehicle_form_fuel_type_desc": "Type of fuel used by the vehicle", "vehicle_form_fuel_type_placeholder": "Select fuel type", + "vehicle_form_vehicle_type_label": "Vehicle Type", + "vehicle_form_vehicle_type_desc": "Category of the vehicle", + "vehicle_form_vehicle_type_placeholder": "Select vehicle type", "vehicle_form_odometer_label": "Odometer", "vehicle_form_odometer_desc": "Current vehicle odometer reading", "vehicle_form_license_label": "License Plate", @@ -108,8 +130,6 @@ "vehicle_delete_error": "Some error occurred while deleting vehicle.", "vehicle_action_add_fuel_log": "Add Fuel Log", "vehicle_action_add_maintenance_log": "Add Maintenance Log", - "vehicle_action_add_insurance": "Add Insurance", - "vehicle_action_add_pollution": "Add Pollution Certificate", "vehicle_action_add_reminder": "Add Reminder", "vehicle_action_more_info": "More info", "vehicle_action_update_vehicle": "Update Vehicle", @@ -149,12 +169,8 @@ "feature_fuel_disabled_hint": "Enable this feature in Settings to track fuel consumption", "feature_maintenance_disabled_title": "Maintenance Feature Disabled", "feature_maintenance_disabled_hint": "Enable this feature in Settings to manage maintenance records", - "feature_pucc_disabled_title": "PUCC Feature Disabled", - "feature_pucc_disabled_hint": "Enable this feature in Settings to manage pollution certificates", "feature_reminders_disabled_title": "Reminders Feature Disabled", "feature_reminders_disabled_hint": "Enable this feature in Settings to manage vehicle reminders", - "feature_insurance_disabled_title": "Insurance Feature Disabled", - "feature_insurance_disabled_hint": "Enable this feature in Settings to manage insurance details", "overview_chart_no_data": "No data available", "overview_chart_cost_label": "Cost", "overview_chart_cost_title": "Cost over Time in ({currency})", @@ -200,7 +216,6 @@ "fuel_toast_error_prefix": "Error while saving : ", "notifications_title": "Notifications", "notifications_new": "new", - "notifications_select_vehicle_hint": "Select a vehicle to load reminders and alerts.", "notifications_syncing": "Syncing latest data...", "notifications_caught_up": "You're all caught up.", "notifications_section_reminders": "Reminders", @@ -230,12 +245,8 @@ "feature_desc_fuel": "Track and manage fuel consumption and refueling history", "feature_label_maintenance": "Maintenance", "feature_desc_maintenance": "Record and schedule vehicle maintenance activities", - "feature_label_pucc": "Pollution", - "feature_desc_pucc": "Manage Pollution Under Control Certificate records", "feature_label_reminders": "Reminders", "feature_desc_reminders": "Set and receive reminders for important vehicle events", - "feature_label_insurance": "Insurance", - "feature_desc_insurance": "Manage vehicle insurance details and renewals", "feature_label_overview": "Overview", "feature_desc_overview": "Display overview dashboard with key vehicle metrics", "settings_error_date_format_invalid": "Format not valid", @@ -269,84 +280,6 @@ "maintenance_export_pdf": "Export PDF", "maintenance_delete_success": "Deleted maintenance log.", "maintenance_delete_error": "Some error occurred while deleting maintenance log.", - "insurance_form_provider_label": "Insurance Provider", - "insurance_form_provider_desc": "Name of the insurance company", - "insurance_form_policy_number_label": "Insurance Policy Number", - "insurance_form_policy_number_desc": "Policy number from your insurance document", - "insurance_form_start_date_label": "Insurance Start Date", - "insurance_form_start_date_desc": "Date when coverage begins", - "insurance_form_recurrence_type_label": "How should this insurance renew?", - "insurance_form_recurrence_type_desc": "Renewal type for this insurance", - "insurance_form_recurrence_interval_label": "Renewal Frequency", - "insurance_form_recurrence_interval_desc": "How often the insurance renews", - "insurance_form_end_date_label": "Insurance End Date", - "insurance_form_end_date_desc": "Date when coverage expires", - "insurance_form_cost_label": "Insurance Cost", - "insurance_form_cost_desc": "Annual or policy period cost", - "insurance_form_notes_label": "Additional Notes", - "insurance_form_notes_desc": "Any extra information about the policy", - "insurance_form_notes_placeholder": "Add more details about the insurance...", - "insurance_form_attachment_label": "Policy Document", - "insurance_form_attachment_desc": "Upload policy document", - "insurance_form_error_fix": "Please fix the errors in the form before submitting.", - "insurance_toast_saved": "Insurance saved successfully", - "insurance_toast_updated": "Insurance updated successfully", - "insurance_toast_error_prefix": "Error while saving: ", - "insurance_list_empty": "No Insurance found for this vehicle.", - "insurance_col_policy_number": "Policy Number", - "insurance_col_cost": "Cost", - "insurance_col_start_date": "Start Date", - "insurance_col_end_date": "End Date", - "insurance_col_next_due": "Next Due", - "insurance_col_recurrence": "Recurrence", - "insurance_col_notes": "Notes", - "insurance_menu_open": "Open menu", - "insurance_menu_edit": "Edit", - "insurance_menu_delete": "Delete", - "insurance_menu_sheet_title": "Update Insurance", - "insurance_tab_title": "Insurance Details", - "insurance_add_action": "Add Insurance", - "insurance_delete_success": "Deleted Insurance.", - "insurance_delete_error": "Some error occurred while deleting insurance.", - "insurance_col_view_document": "View Document", - "pollution_form_certificate_number_label": "Certificate Number", - "pollution_form_certificate_number_desc": "Pollution certificate number", - "pollution_form_issue_date_label": "Issue Date", - "pollution_form_issue_date_desc": "Certificate issue date", - "pollution_form_recurrence_type_label": "How should this certificate renew?", - "pollution_form_recurrence_type_desc": "Renewal type for this certificate", - "pollution_form_recurrence_interval_label": "Renewal Frequency", - "pollution_form_recurrence_interval_desc": "How often the certificate renews", - "pollution_form_expiry_date_label": "Expiry Date", - "pollution_form_expiry_date_desc": "PUCC expiry date", - "pollution_form_testing_center_label": "Testing Center", - "pollution_form_testing_center_desc": "Testing center name", - "pollution_form_notes_label": "Additional Notes", - "pollution_form_notes_desc": "Any extra information", - "pollution_form_notes_placeholder": "Add additional notes...", - "pollution_form_attachment_label": "Certificate Document", - "pollution_form_attachment_desc": "Upload certificate document", - "pollution_form_error_fix": "Please fix the errors in the form before submitting.", - "pollution_toast_saved": "Pollution Certificate saved successfully", - "pollution_toast_updated": "Pollution Certificate updated successfully", - "pollution_toast_error_prefix": "Error while saving: ", - "pollution_list_empty": "No Pollution Certificates for this vehicle.", - "pollution_col_certificate_number": "Certificate Number", - "pollution_col_issue_date": "Issue Date", - "pollution_col_expiry_date": "Expiry Date", - "pollution_col_next_due": "Next Due", - "pollution_col_testing_center": "Testing Center", - "pollution_col_notes": "Notes", - "pollution_col_view_certificate": "View Certificate", - "pollution_col_recurrence": "Recurrence", - "pollution_menu_open": "Open menu", - "pollution_menu_edit": "Edit", - "pollution_menu_delete": "Delete", - "pollution_menu_sheet_title": "Update Pollution Certificate", - "pollution_tab_title": "Pollution Certificate Details", - "pollution_add_action": "Add Pollution Certificate", - "pollution_delete_success": "Deleted PUCC.", - "pollution_delete_error": "Some error occurred while deleting PUCC.", "reminder_form_due_date_label": "Due Date", "reminder_form_due_date_desc": "When should this reminder trigger?", "reminder_form_type_label": "Type", @@ -380,7 +313,6 @@ "reminder_menu_delete": "Delete", "reminder_menu_open": "Open menu", "reminder_menu_sheet_title": "Update Reminder", - "reminder_tab_title": "Reminders", "reminder_add_action": "Add Reminder", "reminder_delete_success": "Deleted reminder.", "reminder_delete_error": "Some error occurred while deleting reminder.", @@ -390,8 +322,6 @@ "reminder_status_error": "Unable to update reminder status.", "reminder_toast_error_fallback": "Failed to save reminder.", "settings_sheet_title": "Settings", - "feature_label_pollution": "Pollution", - "feature_desc_pollution": "Manage Pollution Under Control Certificate records", "profile_menu_item": "Profile", "profile_sheet_title": "Profile", "profile_sheet_desc": "Update your username and password", @@ -418,6 +348,7 @@ "custom_fields_empty_message": "No custom fields added. Click \"Add Field\" to get started.", "vehicle_details_vin": "VIN", "vehicle_details_not_specified": "Not specified", + "vehicle_details_not_available": "Not available", "vehicle_details_section_title": "Details", "vehicle_details_license_plate": "License Plate", "vehicle_details_fuel_type": "Fuel Type", @@ -425,6 +356,16 @@ "vehicle_details_not_recorded": "Not recorded", "vehicle_details_color": "Color", "vehicle_details_year": "Year", + "vehicle_type_car": "Car", + "vehicle_type_motorcycle": "Motorcycle", + "vehicle_type_scooter": "Scooter", + "vehicle_type_truck": "Truck", + "vehicle_type_van": "Van", + "vehicle_type_bus": "Bus", + "vehicle_type_farm_vehicle": "Farm Vehicle", + "vehicle_type_yacht": "Yacht", + "vehicle_type_rv": "RV / Caravan", + "vehicle_type_other": "Other", "fuel_type_diesel": "Diesel", "fuel_type_petrol": "Petrol", "fuel_type_electric": "Electric", @@ -448,14 +389,6 @@ "recurrence_interval_months": "months", "recurrence_interval_years": "years", "recurrence_until": "Until", - "insurance_recurrence_type_fixed": "Fixed end date", - "insurance_recurrence_type_yearly": "Renews yearly", - "insurance_recurrence_type_monthly": "Renews monthly", - "insurance_recurrence_type_no_end": "No end date", - "pollution_recurrence_type_fixed": "Fixed end date", - "pollution_recurrence_type_yearly": "Renews yearly", - "pollution_recurrence_type_monthly": "Renews monthly", - "pollution_recurrence_type_no_end": "No end date", "file_drop_existing_note": "Existing attachment (Click to view)", "fuel_import_step_1_title": "Step 1 : Upload CSV file", "fuel_import_step_1_desc": "Select a delimited text file containing your fuel log data to begin the import process.", @@ -529,13 +462,9 @@ "reminder_type_registration": "Registration / Tax", "reminder_type_inspection": "Inspection", "reminder_type_custom": "Custom", - "alert_type_insurance": "Insurance", - "alert_type_pucc": "Pollution Certificate", "alert_status_expired_ago": "{label} expired {days} days ago", "alert_status_expires_in": "{label} expires in {days} days", "alert_status_valid_for": "{label} valid for {days} days", - "alert_insurance_active_no_end": "Insurance is active with no end date", - "alert_pucc_active_no_end": "PUCC is active with no end date", "alert_record_not_found": "{label} record not found. Add details to stay compliant.", "settings_error_format_not_valid": "Format not valid", "common_kilogram_unit": "Kilogram (kg)", @@ -555,6 +484,9 @@ "theme_teal": "Teal", "theme_indigo": "Indigo", "theme_pink": "Pink", + "dark_variant_default": "Default", + "dark_variant_dim": "Dim", + "dark_variant_oled": "OLED (True Black)", "settings_tab_notifications": "Notifications", "settings_personalization_desc": "Customize your experience with themes, languages, and formats.", "settings_section_general": "General", @@ -565,6 +497,17 @@ "settings_section_feature_flags": "Feature Flags", "settings_section_feature_flags_desc": "Enable or disable major app modules", "settings_notifications_desc": "Configure provider subscriptions and the daily processing time for scheduled delivery.", + "settings_localization_desc": "Set your language and regional preferences.", + "settings_advanced_desc": "Fine-tune the interface with custom styles.", + "settings_nav_desc_personalization": "Theme, display and style", + "settings_nav_desc_localization": "Language and regional formats", + "settings_nav_desc_advanced": "Custom CSS and advanced options", + "settings_nav_desc_notifications": "Alerts and reminders", + "settings_nav_desc_units": "Measurement units", + "settings_nav_desc_features": "Feature preferences", + "settings_reset_defaults": "Reset to Defaults", + "settings_cancel_button": "Cancel", + "settings_secure_note": "Your preferences are stored securely and applied across all your devices.", "settings_error_fix_errors": "Please fix the following errors:", "settings_fuel_types_label": "Fuel types", "settings_fuel_types_desc": "Choose the measurement for each fuel.", @@ -690,10 +633,6 @@ "notif_status_read": "Read", "notif_status_unread": "Unread", "notif_due_prefix": "Due: {date}", - "header_home_aria": "Go to home", - "header_settings_aria": "Open settings", - "header_account_aria": "Account menu", - "header_account_title": "Account", "notif_save_provider_failed": "Failed to save provider", "notif_update_provider_failed": "Failed to update provider", "notif_send_all_failed": "Failed to send notifications", @@ -705,5 +644,168 @@ "notif_test_send_desc": "Send a test notification using {name}", "notif_cron_every_n_minutes": "Every {n} minutes", "notif_cron_hourly_at_minute": "Every hour at minute {n}", - "notif_cron_daily_at": "Daily at {time}" + "notif_cron_daily_at": "Daily at {time}", + "vehicle_hub_back_to_vehicles": "Back to Vehicles", + "vehicle_hub_plate_copied": "License plate copied", + "vehicle_hub_insurance_valid_till": "Insurance Valid Till", + "vehicle_hub_vehicle_type": "Vehicle Type", + "vehicle_hub_activity_title": "Recent Activity", + "vehicle_hub_activity_empty": "No recent activity", + "vehicle_hub_activity_fuel_added": "Fuel Added", + "vehicle_hub_activity_maintenance": "Maintenance", + "vehicle_hub_records_count": "{count} records", + "vehicle_hub_valid_till": "Valid till {date}", + "vehicle_hub_upcoming_count": "{count} upcoming", + "vehicle_hub_view_details": "View Details", + "vehicle_hub_manage_title": "Manage Vehicle", + "vehicle_hub_stat_odometer": "Odometer", + "vehicle_hub_stat_mileage": "Overall Mileage", + "vehicle_hub_stat_fuel_logs": "Fuel Logs", + "vehicle_hub_stat_maintenance_logs": "Maintenance Logs", + "col_vehicle": "Vehicle", + "overview_chart_pick_vehicle": "Select a vehicle to see this chart", + "fuel_page_title": "Fuel Tracking", + "fuel_page_description": "Monitor fuel consumption and costs", + "fuel_stat_used": "Fuel Used", + "fuel_stat_spent": "Total Spent", + "fuel_stat_avg_mileage": "Avg Mileage", + "fuel_stat_entries": "Total Entries", + "maintenance_page_title": "Maintenance", + "maintenance_page_description": "Track service history and upcoming maintenance", + "maintenance_stat_last_service": "Last Service", + "maintenance_stat_next_service": "Next Service", + "maintenance_stat_odometer": "Odometer", + "maintenance_stat_total_services": "Total Services", + "maintenance_stat_total_spent": "Total Spent", + "maintenance_stat_due_soon": "Due Soon", + "maintenance_tab_overview": "Overview", + "maintenance_tab_history": "Service History", + "maintenance_timeline_title": "Maintenance Timeline", + "maintenance_upcoming_empty": "Nothing scheduled", + "maintenance_history_empty": "No service history yet", + "maintenance_next_service_fallback": "General maintenance service", + "maintenance_also_upcoming": "Also coming up", + "reminder_page_title": "Reminders", + "reminder_page_description": "Stay on top of upcoming service, insurance and PUC dates", + "reminder_filter_all": "All", + "reminder_filter_all_types": "All Types", + "reminder_filter_service": "Service", + "reminder_filter_puc": "PUC", + "reminder_filter_insurance": "Insurance", + "reminder_filter_others": "Others", + "reminder_section_upcoming": "Upcoming", + "reminder_section_completed": "Completed", + "reminder_section_marked_done": "Marked Done", + "reminder_empty_title": "No reminders set up yet", + "reminder_stat_overdue": "Overdue", + "reminder_stat_due_soon": "Due Soon", + "reminder_stat_upcoming": "Upcoming", + "reminder_stat_completed": "Completed", + "reminder_calendar_title": "Calendar View", + "reminder_quick_actions_title": "Quick Actions", + "reminder_manage_all_action": "Manage all reminders", + "reminder_list_title": "Reminders", + "reminder_list_title_for_date": "Reminders on {date}", + "reminder_clear_filter": "Clear", + "reminder_calendar_empty_day": "No reminders on this date.", + "reports_page_title": "Reports", + "reports_page_description": "Costs and exports for your fleet", + "reports_section_costs": "Costs", + "reports_section_details": "Detailed Report", + "reports_section_exports": "Exports", + "reports_stat_fuel_costs": "Fuel Costs", + "reports_stat_maintenance_costs": "Maintenance Costs", + "reports_chart_breakdown_title": "Expense Breakdown", + "reports_chart_trend_title": "Monthly Expense Trend", + "reports_chart_trend_unavailable": "Monthly trend is only available for all vehicles combined", + "reports_export_maintenance_title": "Maintenance History", + "reports_export_maintenance_description": "Export maintenance history as PDF", + "reports_export_maintenance_hint": "Select a vehicle to export its maintenance history", + "reports_export_data_title": "Full Data Export", + "reports_export_data_description": "Export all fleet data as JSON", + "reports_type_fuel": "Fuel", + "reports_type_maintenance": "Maintenance", + "reports_type_compliance": "Compliance", + "nav_compliance": "Compliance", + "vehicle_action_add_compliance": "Add Compliance Document", + "feature_compliance_disabled_title": "Compliance Feature Disabled", + "feature_compliance_disabled_hint": "Enable this feature in Settings to manage insurance, emissions, roadworthiness and registration records", + "feature_label_compliance": "Compliance", + "feature_desc_compliance": "Manage insurance, emissions, roadworthiness and registration records", + "compliance_type_insurance": "Insurance", + "compliance_type_emissions": "Emissions / Pollution", + "compliance_type_roadworthiness": "Roadworthiness / Safety Inspection", + "compliance_type_registration": "Registration / Road Tax", + "compliance_type_other": "Other", + "compliance_field_policy_number": "Policy Number", + "compliance_field_certificate_number": "Certificate Number", + "compliance_field_registration_number": "Registration Number", + "compliance_field_document_number": "Document Number", + "compliance_field_provider": "Insurance Provider", + "compliance_field_testing_center": "Testing Center", + "compliance_field_inspection_center": "Inspection Center", + "compliance_field_issuing_authority": "Issuing Authority", + "compliance_recurrence_type_fixed": "Fixed end date", + "compliance_recurrence_type_yearly": "Renews yearly", + "compliance_recurrence_type_monthly": "Renews monthly", + "compliance_recurrence_type_no_end": "No end date", + "compliance_form_type_label": "Compliance Type", + "compliance_form_type_desc": "What kind of compliance document is this", + "compliance_form_other_label_label": "Type Name", + "compliance_form_other_label_desc": "Name this compliance type, e.g. \"WOF (New Zealand)\" or \"TÜV (Germany)\"", + "compliance_form_attachment_label": "Document", + "compliance_form_attachment_desc": "Upload the document", + "compliance_form_issuer_desc": "The provider, testing center, or authority that issued this document", + "compliance_form_document_number_desc": "The number printed on the document", + "compliance_form_start_date_label": "Start Date", + "compliance_form_start_date_desc": "Date when this document takes effect", + "compliance_form_recurrence_type_label": "How should this renew?", + "compliance_form_recurrence_type_desc": "Renewal type for this document", + "compliance_form_recurrence_interval_desc": "How often the document renews", + "compliance_form_end_date_label": "End Date", + "compliance_form_end_date_desc": "Date when this document expires", + "compliance_form_cost_label": "Cost", + "compliance_form_cost_desc": "Cost for this document, if any", + "compliance_form_notes_label": "Additional Notes", + "compliance_form_notes_desc": "Any extra information", + "compliance_form_notes_placeholder": "Add more details...", + "compliance_form_error_fix": "Please fix the errors in the form before submitting.", + "compliance_toast_saved": "Compliance document saved successfully", + "compliance_toast_updated": "Compliance document updated successfully", + "compliance_toast_error_prefix": "Error while saving: ", + "compliance_list_empty": "No compliance documents found for this vehicle.", + "compliance_col_cost": "Cost", + "compliance_col_start_date": "Start Date", + "compliance_col_end_date": "End Date", + "compliance_col_next_due": "Next Due", + "compliance_col_recurrence": "Recurrence", + "compliance_col_notes": "Notes", + "compliance_col_view_document": "View Document", + "compliance_menu_open": "Open menu", + "compliance_menu_edit": "Edit", + "compliance_menu_delete": "Delete", + "compliance_menu_sheet_title": "Update Compliance Document", + "compliance_delete_success": "Deleted compliance document.", + "compliance_delete_error": "Some error occurred while deleting the compliance document.", + "compliance_page_title": "Compliance", + "compliance_page_description": "Track insurance, emissions, roadworthiness and registration compliance", + "compliance_add_action": "Add Compliance Document", + "compliance_filter_all_types": "All Types", + "compliance_filter_all": "All", + "compliance_filter_valid": "Valid", + "compliance_filter_expiring_soon": "Expiring Soon", + "compliance_filter_expired": "Expired", + "compliance_stat_total": "Total", + "compliance_stat_valid": "Valid", + "compliance_stat_expiring_soon": "Expiring Soon", + "compliance_stat_expired": "Expired", + "compliance_cta_heading": "Keep your vehicles compliant", + "compliance_cta_description": "Keep your compliance documents updated to avoid penalties and stay road-legal.", + "vehicle_hub_other_compliance_valid_till": "Other Compliance Valid Till", + "vehicle_hub_activity_compliance_updated": "Compliance Document Updated", + "vehicle_hub_activity_document_prefix": "Doc #", + "reports_stat_compliance_costs": "Compliance Costs", + "compliance_col_document": "Compliance", + "compliance_col_status": "Status", + "compliance_col_days_left": "Days Left" } diff --git a/i18n/project.inlang/settings.json b/i18n/project.inlang/settings.json index 073a3605..aed47185 100644 --- a/i18n/project.inlang/settings.json +++ b/i18n/project.inlang/settings.json @@ -8,5 +8,5 @@ "pathPattern": "./messages/{locale}.json" }, "baseLocale": "en", - "locales": ["en", "ar", "hi", "es", "fr", "de", "it", "hu", "fi","ro"] + "locales": ["en", "ar", "hi", "es", "fr", "de", "it", "hu", "fi", "ro"] } diff --git a/package.json b/package.json index 5f9893fa..5ce24eba 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "tracktor", "private": true, - "version": "1.4.1", + "version": "2.0.0", "type": "module", "scripts": { "dev": "vite dev --host", @@ -18,14 +18,14 @@ "clean": "rm -rf build .svelte-kit *.db uploads logs coverage node_modules", "db:generate": "drizzle-kit generate", "db:migrate": "drizzle-kit migrate", - "db:seed": "tsx scripts/seed.ts", "start": "node build" }, "devDependencies": { "@eslint/js": "^10.0.1", - "@inlang/paraglide-js": "^2.22.0", + "@faker-js/faker": "^10.5.0", + "@inlang/paraglide-js": "^2.23.0", "@internationalized/date": "^3.12.2", - "@lucide/svelte": "^1.25.0", + "@lucide/svelte": "^1.27.0", "@sveltejs/adapter-node": "^5.5.7", "@sveltejs/kit": "^2.70.1", "@sveltejs/vite-plugin-svelte": "^7.2.0", @@ -33,19 +33,15 @@ "@tailwindcss/typography": "^0.5.20", "@tailwindcss/vite": "^4.3.3", "@tanstack/table-core": "^8.21.3", - "@testing-library/svelte": "^5.4.2", "@types/node": "^26.1.1", "@types/node-cron": "^3.0.11", "@types/nodemailer": "^8.0.1", "@types/pdfkit": "^0.17.6", - "@types/supertest": "^7.2.1", "@typescript-eslint/eslint-plugin": "^8.65.0", "@typescript-eslint/parser": "^8.65.0", - "@typescript/native": "npm:typescript@^7.0.2", "@vitest/coverage-v8": "^4.1.10", "bits-ui": "^2.18.1", "clsx": "^2.1.1", - "concurrently": "^10.0.3", "currency-codes": "^2.2.0", "d3-array": "^3.2.4", "d3-scale": "^4.0.2", @@ -54,55 +50,45 @@ "date-fns-tz": "^3.2.0", "drizzle-kit": "^0.31.10", "drizzle-orm": "^0.45.2", - "eslint": "^10.7.0", + "eslint": "^10.8.0", "eslint-config-prettier": "^10.1.8", "eslint-plugin-svelte": "^3.22.0", "eslint-plugin-unused-imports": "^4.4.1", "formsnap": "^2.0.1", - "globals": "^17.7.0", - "jsdom": "^29.1.1", + "globals": "^17.8.0", "layerchart": "2.0.2", "prettier": "^3.9.6", "prettier-plugin-svelte": "^4.1.1", "prettier-plugin-tailwindcss": "^0.8.1", - "svelte": "^5.56.7", + "svelte": "^5.56.8", "svelte-awesome-color-picker": "^4.1.3", "svelte-check": "^4.7.3", "svelte-eslint-parser": "^1.8.0", "svelte-sonner": "^1.1.1", "sveltekit-superforms": "^2.30.2", "tailwind-merge": "^3.6.0", - "tailwind-variants": "^3.2.2", + "tailwind-variants": "^3.3.0", "tailwindcss": "^4.3.3", - "tsx": "^4.23.1", "tw-animate-css": "^1.4.0", - "typescript": "npm:@typescript/typescript6@^6.0.2", + "typescript": "npm:typescript@^6.0.3", "vite": "^8.1.5", "vitest": "^4.1.10" }, "dependencies": { - "@faker-js/faker": "^10.5.0", "@libsql/client": "^0.17.4", "@oslojs/crypto": "^1.0.1", "@oslojs/encoding": "^1.1.0", "@types/bcrypt": "^6.0.0", - "@types/cors": "^2.8.19", "@types/d3-array": "^3.2.2", "@types/d3-scale": "^4.0.9", "@types/d3-shape": "^3.1.8", - "@types/express": "^5.0.6", - "@types/multer": "^2.2.0", "bcrypt": "^6.0.0", - "cors": "^2.8.6", "csv-parse": "^7.0.1", - "dotenv": "^17.4.2", - "helmet": "^8.3.0", "mode-watcher": "^1.1.0", - "multer": "^2.2.0", "node-cron": "^4.6.0", "nodemailer": "^9.0.3", "pdfkit": "^0.19.1", - "winston": "^3.19.0", + "svelte-dnd-action": "^0.9.74", "zod": "^4.4.3" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5c251b60..f9a19b30 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,9 +8,6 @@ importers: .: dependencies: - '@faker-js/faker': - specifier: ^10.5.0 - version: 10.5.0 '@libsql/client': specifier: ^0.17.4 version: 0.17.4 @@ -23,9 +20,6 @@ importers: '@types/bcrypt': specifier: ^6.0.0 version: 6.0.0 - '@types/cors': - specifier: ^2.8.19 - version: 2.8.19 '@types/d3-array': specifier: ^3.2.2 version: 3.2.2 @@ -35,33 +29,15 @@ importers: '@types/d3-shape': specifier: ^3.1.8 version: 3.1.8 - '@types/express': - specifier: ^5.0.6 - version: 5.0.6 - '@types/multer': - specifier: ^2.2.0 - version: 2.2.0 bcrypt: specifier: ^6.0.0 version: 6.0.0 - cors: - specifier: ^2.8.6 - version: 2.8.6 csv-parse: specifier: ^7.0.1 version: 7.0.1 - dotenv: - specifier: ^17.4.2 - version: 17.4.2 - helmet: - specifier: ^8.3.0 - version: 8.3.0 mode-watcher: specifier: ^1.1.0 - version: 1.1.0(svelte@5.56.7(@typescript-eslint/types@8.65.0)) - multer: - specifier: ^2.2.0 - version: 2.2.0 + version: 1.1.0(svelte@5.56.8(@typescript-eslint/types@8.65.0)) node-cron: specifier: ^4.6.0 version: 4.6.0 @@ -71,34 +47,37 @@ importers: pdfkit: specifier: ^0.19.1 version: 0.19.1 - winston: - specifier: ^3.19.0 - version: 3.19.0 + svelte-dnd-action: + specifier: ^0.9.74 + version: 0.9.74(svelte@5.56.8(@typescript-eslint/types@8.65.0)) zod: specifier: ^4.4.3 version: 4.4.3 devDependencies: '@eslint/js': specifier: ^10.0.1 - version: 10.0.1(eslint@10.7.0(jiti@2.7.0)) + version: 10.0.1(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2)) + '@faker-js/faker': + specifier: ^10.5.0 + version: 10.5.0 '@inlang/paraglide-js': - specifier: ^2.22.0 - version: 2.22.0(@typescript/typescript6@6.0.2)(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)) + specifier: ^2.23.0 + version: 2.23.0(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)) '@internationalized/date': specifier: ^3.12.2 version: 3.12.2 '@lucide/svelte': - specifier: ^1.25.0 - version: 1.25.0(svelte@5.56.7(@typescript-eslint/types@8.65.0)) + specifier: ^1.27.0 + version: 1.27.0(svelte@5.56.8(@typescript-eslint/types@8.65.0)) '@sveltejs/adapter-node': specifier: ^5.5.7 - version: 5.5.7(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1))) + version: 5.5.7(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1))) '@sveltejs/kit': specifier: ^2.70.1 - version: 2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)) + version: 2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)) '@sveltejs/vite-plugin-svelte': specifier: ^7.2.0 - version: 7.2.0(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)) + version: 7.2.0(svelte@5.56.8(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)) '@tailwindcss/forms': specifier: ^0.5.11 version: 0.5.11(tailwindcss@4.3.3) @@ -111,9 +90,6 @@ importers: '@tanstack/table-core': specifier: ^8.21.3 version: 8.21.3 - '@testing-library/svelte': - specifier: ^5.4.2 - version: 5.4.2(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1))(vitest@4.1.10) '@types/node': specifier: ^26.1.1 version: 26.1.1 @@ -126,30 +102,21 @@ importers: '@types/pdfkit': specifier: ^0.17.6 version: 0.17.6 - '@types/supertest': - specifier: ^7.2.1 - version: 7.2.1 '@typescript-eslint/eslint-plugin': specifier: ^8.65.0 - version: 8.65.0(@typescript-eslint/parser@8.65.0(@typescript/typescript6@6.0.2)(eslint@10.7.0(jiti@2.7.0)))(@typescript/typescript6@6.0.2)(eslint@10.7.0(jiti@2.7.0)) + version: 8.65.0(@typescript-eslint/parser@8.65.0(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) '@typescript-eslint/parser': specifier: ^8.65.0 - version: 8.65.0(@typescript/typescript6@6.0.2)(eslint@10.7.0(jiti@2.7.0)) - '@typescript/native': - specifier: npm:typescript@^7.0.2 - version: typescript@7.0.2 + version: 8.65.0(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) '@vitest/coverage-v8': specifier: ^4.1.10 version: 4.1.10(vitest@4.1.10) bits-ui: specifier: ^2.18.1 - version: 2.18.1(@internationalized/date@3.12.2)(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.7(@typescript-eslint/types@8.65.0)) + version: 2.18.1(@internationalized/date@3.12.2)(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0)) clsx: specifier: ^2.1.1 version: 2.1.1 - concurrently: - specifier: ^10.0.3 - version: 10.0.3 currency-codes: specifier: ^2.2.0 version: 2.2.0 @@ -175,80 +142,74 @@ importers: specifier: ^0.45.2 version: 0.45.2(@libsql/client@0.17.4)(kysely@0.28.16) eslint: - specifier: ^10.7.0 - version: 10.7.0(jiti@2.7.0) + specifier: ^10.8.0 + version: 10.8.0(jiti@2.7.0)(supports-color@10.2.2) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@10.7.0(jiti@2.7.0)) + version: 10.1.8(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2)) eslint-plugin-svelte: specifier: ^3.22.0 - version: 3.22.0(eslint@10.7.0(jiti@2.7.0))(svelte@5.56.7(@typescript-eslint/types@8.65.0)) + version: 3.22.0(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))(svelte@5.56.8(@typescript-eslint/types@8.65.0)) eslint-plugin-unused-imports: specifier: ^4.4.1 - version: 4.4.1(@typescript-eslint/eslint-plugin@8.65.0(@typescript-eslint/parser@8.65.0(@typescript/typescript6@6.0.2)(eslint@10.7.0(jiti@2.7.0)))(@typescript/typescript6@6.0.2)(eslint@10.7.0(jiti@2.7.0)))(eslint@10.7.0(jiti@2.7.0)) + version: 4.4.1(@typescript-eslint/eslint-plugin@8.65.0(@typescript-eslint/parser@8.65.0(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2)) formsnap: specifier: ^2.0.1 - version: 2.0.1(svelte@5.56.7(@typescript-eslint/types@8.65.0))(sveltekit-superforms@2.30.2(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@types/json-schema@7.0.15)(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0))) + version: 2.0.1(svelte@5.56.8(@typescript-eslint/types@8.65.0))(sveltekit-superforms@2.30.2(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@types/json-schema@7.0.15)(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3)) globals: - specifier: ^17.7.0 - version: 17.7.0 - jsdom: - specifier: ^29.1.1 - version: 29.1.1(@noble/hashes@1.8.0) + specifier: ^17.8.0 + version: 17.8.0 layerchart: specifier: 2.0.2 - version: 2.0.2(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.7(@typescript-eslint/types@8.65.0))(zod@4.4.3) + version: 2.0.2(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0))(zod@4.4.3) prettier: specifier: ^3.9.6 version: 3.9.6 prettier-plugin-svelte: specifier: ^4.1.1 - version: 4.1.1(prettier@3.9.6)(svelte@5.56.7(@typescript-eslint/types@8.65.0)) + version: 4.1.1(prettier@3.9.6)(svelte@5.56.8(@typescript-eslint/types@8.65.0)) prettier-plugin-tailwindcss: specifier: ^0.8.1 - version: 0.8.1(prettier-plugin-svelte@4.1.1(prettier@3.9.6)(svelte@5.56.7(@typescript-eslint/types@8.65.0)))(prettier@3.9.6) + version: 0.8.1(prettier-plugin-svelte@4.1.1(prettier@3.9.6)(svelte@5.56.8(@typescript-eslint/types@8.65.0)))(prettier@3.9.6) svelte: - specifier: ^5.56.7 - version: 5.56.7(@typescript-eslint/types@8.65.0) + specifier: ^5.56.8 + version: 5.56.8(@typescript-eslint/types@8.65.0) svelte-awesome-color-picker: specifier: ^4.1.3 - version: 4.1.3(svelte@5.56.7(@typescript-eslint/types@8.65.0)) + version: 4.1.3(svelte@5.56.8(@typescript-eslint/types@8.65.0)) svelte-check: specifier: ^4.7.3 - version: 4.7.3(@typescript/typescript6@6.0.2)(picomatch@4.0.4)(svelte@5.56.7(@typescript-eslint/types@8.65.0)) + version: 4.7.3(picomatch@4.0.4)(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3) svelte-eslint-parser: specifier: ^1.8.0 - version: 1.8.0(svelte@5.56.7(@typescript-eslint/types@8.65.0)) + version: 1.8.0(svelte@5.56.8(@typescript-eslint/types@8.65.0)) svelte-sonner: specifier: ^1.1.1 - version: 1.1.1(svelte@5.56.7(@typescript-eslint/types@8.65.0)) + version: 1.1.1(svelte@5.56.8(@typescript-eslint/types@8.65.0)) sveltekit-superforms: specifier: ^2.30.2 - version: 2.30.2(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@types/json-schema@7.0.15)(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0)) + version: 2.30.2(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@types/json-schema@7.0.15)(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3) tailwind-merge: specifier: ^3.6.0 version: 3.6.0 tailwind-variants: - specifier: ^3.2.2 - version: 3.2.2(tailwind-merge@3.6.0)(tailwindcss@4.3.3) + specifier: ^3.3.0 + version: 3.3.0(tailwind-merge@3.6.0)(tailwindcss@4.3.3) tailwindcss: specifier: ^4.3.3 version: 4.3.3 - tsx: - specifier: ^4.23.1 - version: 4.23.1 tw-animate-css: specifier: ^1.4.0 version: 1.4.0 typescript: - specifier: npm:@typescript/typescript6@^6.0.2 - version: '@typescript/typescript6@6.0.2' + specifier: npm:typescript@^6.0.3 + version: 6.0.3 vite: specifier: ^8.1.5 version: 8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1) vitest: specifier: ^4.1.10 - version: 4.1.10(@types/node@26.1.1)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1(@noble/hashes@1.8.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)) + version: 4.1.10(@types/node@26.1.1)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.0(@noble/hashes@1.8.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)) packages: @@ -258,24 +219,13 @@ packages: '@ark/util@0.56.2': resolution: {integrity: sha512-9kU2sUE38FZEGG7l3hamYMBieLYEJh2L1mrYD2eXpT+78EnQSV1bhjxJhnxGBMSTbtwpBSDNSK+K60WvaI/DTQ==} - '@asamuzakjp/css-color@5.1.11': - resolution: {integrity: sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - - '@asamuzakjp/dom-selector@7.1.1': - resolution: {integrity: sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - - '@asamuzakjp/generational-cache@1.0.1': - resolution: {integrity: sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - - '@asamuzakjp/nwsapi@2.3.9': - resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} + '@asamuzakjp/css-color@6.0.5': + resolution: {integrity: sha512-mbhpPMmnw/kwW19aRNmSUl1QzLbdGo1SCuE49BT98MNwqF6zaHb3o2owssFc/PEO/4t2UjqtCNwocuDtJornzA==} + engines: {node: ^22.13.0 || >=24.0.0} - '@babel/code-frame@7.29.0': - resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} - engines: {node: '>=6.9.0'} + '@asamuzakjp/dom-selector@8.3.0': + resolution: {integrity: sha512-UJLfKXBhrc8i1vH2eJXuYQMwlsLKWFw3O+CPqXSuVEiikeAim3UgrfWX0k4tA/X8cRFM8iZ7OaqBokFGbYusdg==} + engines: {node: ^22.13.0 || >=24.0.0} '@babel/helper-string-parser@7.27.1': resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} @@ -306,23 +256,19 @@ packages: resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} hasBin: true - '@colors/colors@1.6.0': - resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==} - engines: {node: '>=0.1.90'} - - '@csstools/color-helpers@6.0.2': - resolution: {integrity: sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==} + '@csstools/color-helpers@6.1.0': + resolution: {integrity: sha512-064IFJdjTfUqnjpCVpMOdbr8FLQBhinbZj6yRv2An2E41O/pLEXqfFRWqGq/SxlE5PEUYTlvWsG2r8MswAVvkg==} engines: {node: '>=20.19.0'} - '@csstools/css-calc@3.2.0': - resolution: {integrity: sha512-bR9e6o2BDB12jzN/gIbjHa5wLJ4UjD1CB9pM7ehlc0ddk6EBz+yYS1EV2MF55/HUxrHcB/hehAyt5vhsA3hx7w==} + '@csstools/css-calc@3.3.0': + resolution: {integrity: sha512-c5ihYsPkdG6JCkU2zTMm4+k6r7RXuGxtWYhu5DHMIiF1FHzrfmHL5so11AoFpUv/tu61xfcmT4AmKoFfMPoqdQ==} engines: {node: '>=20.19.0'} peerDependencies: '@csstools/css-parser-algorithms': ^4.0.0 '@csstools/css-tokenizer': ^4.0.0 - '@csstools/css-color-parser@4.1.0': - resolution: {integrity: sha512-U0KhLYmy2GVj6q4T3WaAe6NPuFYCPQoE3b0dRGxejWDgcPp8TP7S5rVdM5ZrFaqu4N67X8YaPBw14dQSYx3IyQ==} + '@csstools/css-color-parser@4.1.10': + resolution: {integrity: sha512-UZhQLIUyJaaMepqehrCODwCg2KW25vFvLWBmqYFaPclYvvxzj/sG8LBOhBFCp11i9uE7t1EyS+RAoV9tztPFyw==} engines: {node: '>=20.19.0'} peerDependencies: '@csstools/css-parser-algorithms': ^4.0.0 @@ -334,8 +280,8 @@ packages: peerDependencies: '@csstools/css-tokenizer': ^4.0.0 - '@csstools/css-syntax-patches-for-csstree@1.1.4': - resolution: {integrity: sha512-wgsqt92b7C7tQhIdPNxj0n9zuUbQlvAuI1exyzeNrOKOi62SD7ren8zqszmpVREjAOqg8cD2FqYhQfAuKjk4sw==} + '@csstools/css-syntax-patches-for-csstree@1.1.7': + resolution: {integrity: sha512-fQ+05118eQS1cofO3aJpB5efgpBZMvIzwr/sbC8kDLVA5XLG8q1kJV5yzrUAI1f7lvhPnm8fgIjzFB8/O/5Dig==} peerDependencies: css-tree: ^3.2.1 peerDependenciesMeta: @@ -346,9 +292,6 @@ packages: resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} engines: {node: '>=20.19.0'} - '@dabh/diagnostics@2.0.8': - resolution: {integrity: sha512-R4MSXTVnuMzGD7bzHdW2ZhhdPC/igELENcq5IjEverBvq5hn1SXCWcsi6eSsdWP0/Ur+SItRRjAktmdoX/8R/Q==} - '@dagrejs/dagre@2.0.4': resolution: {integrity: sha512-J6vCWTNpicHF4zFlZG1cS5DkGzMr9941gddYkakjrg3ZNev4bbqEgLHFTWiFrcJm7UCRu7olO3K6IRDd9gSGhA==} @@ -369,11 +312,11 @@ packages: '@esbuild-kit/core-utils@3.3.2': resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} - deprecated: 'Merged into tsx: https://tsx.is' + deprecated: 'Merged into tsx: https://tsx.hirok.io' '@esbuild-kit/esm-loader@2.6.5': resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==} - deprecated: 'Merged into tsx: https://tsx.is' + deprecated: 'Merged into tsx: https://tsx.hirok.io' '@esbuild/aix-ppc64@0.25.12': resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} @@ -833,8 +776,8 @@ packages: resolution: {integrity: sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/config-helpers@0.6.0': - resolution: {integrity: sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==} + '@eslint/config-helpers@0.7.0': + resolution: {integrity: sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} '@eslint/core@1.2.1': @@ -867,6 +810,15 @@ packages: '@noble/hashes': optional: true + '@exodus/bytes@1.15.1': + resolution: {integrity: sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@noble/hashes': ^1.8.0 || ^2.0.0 + peerDependenciesMeta: + '@noble/hashes': + optional: true + '@exodus/schemasafe@1.3.0': resolution: {integrity: sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==} @@ -905,8 +857,8 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} - '@inlang/paraglide-js@2.22.0': - resolution: {integrity: sha512-GSzG7KEKcYAhwuPNJczIPB+DzyndYxr4lsXAkkB7xh00jTrt80NF2KfgjEAkxuJvWcnscqXf7y7d1Q0SWtSu7A==} + '@inlang/paraglide-js@2.23.0': + resolution: {integrity: sha512-q+FQisRAVQqyD+0fdVHPkC7UDfaXENUJqUjim7XGEzWHE6vVMUOO10MFtAOKx5VYAgi8o7rLwe4zjzesCY0Anw==} hasBin: true peerDependencies: typescript: '>=5.6' @@ -1019,8 +971,8 @@ packages: '@lix-js/server-protocol-schema@0.1.1': resolution: {integrity: sha512-jBeALB6prAbtr5q4vTuxnRZZv1M2rKe8iNqRQhFJ4Tv7150unEa0vKyz0hs8Gl3fUGsWaNJBh3J8++fpbrpRBQ==} - '@lucide/svelte@1.25.0': - resolution: {integrity: sha512-v9m+dD68jxVnqkU3K59mG/RSRFlPGzmKCGSyMfnXcaGv9jODDQMyQkcp1CGvk3Y/cUj9v7f8rw1n//K0B53xGQ==} + '@lucide/svelte@1.27.0': + resolution: {integrity: sha512-qzNBHdqy/MKp2qxuy/DcYELuep6h19fjo+4ech8fZsS4GtZeBtg5jgCTRQvLvwhppt0mhRN6qt8Nt8rPb/J4Ag==} peerDependencies: svelte: ^5 @@ -1049,6 +1001,7 @@ packages: '@oslojs/crypto@1.0.1': resolution: {integrity: sha512-7n08G8nWjAr/Yu3vu9zzrd0L9XnrJfpMioQcvCMxBIiF5orECHe5/3J0jmXRVvgfqMm/+4oxlQ+Sq39COYLcNQ==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. '@oslojs/encoding@1.1.0': resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==} @@ -1355,9 +1308,6 @@ packages: '@sinclair/typebox@0.31.28': resolution: {integrity: sha512-/s55Jujywdw/Jpan+vsy6JZs1z2ZTGxTmbZTPiuSL2wz9mfzA2gN1zzaqmvfi4pq+uOt7Du85fkiwv5ymW84aQ==} - '@so-ric/colorspace@1.1.6': - resolution: {integrity: sha512-/KiKkpHNOBgkFJwu9sh48LkHSMYGyuTcSFK/qMBdnOAlrRJzRSXAOFB5qwzaVQuDl8wAvHVMkaASQDReTahxuw==} - '@sqlite.org/sqlite-wasm@3.48.0-build4': resolution: {integrity: sha512-hI6twvUkzOmyGZhQMza1gpfqErZxXRw6JEsiVjUbo7tFanVD+8Oil0Ih3l2nGzHdxPI41zFmfUQG7GHqhciKZQ==} hasBin: true @@ -1513,56 +1463,18 @@ packages: resolution: {integrity: sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==} engines: {node: '>=12'} - '@testing-library/dom@10.4.1': - resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} - engines: {node: '>=18'} - - '@testing-library/svelte-core@1.1.3': - resolution: {integrity: sha512-KkMAvXeWorxN2Yn0kdC1lfoAItxpoj4uOWzxK5leDrNxonLvS5nwBFvztrroyTszQ0Wf/EU6iLT8JhY5qcn22g==} - engines: {node: '>=16'} - peerDependencies: - svelte: ^3 || ^4 || ^5 || ^5.0.0-next.0 - - '@testing-library/svelte@5.4.2': - resolution: {integrity: sha512-4o31E4HGo5BU5KwPkulNRocEden+7Tt9JYm9uhln5ajF7DULeyFA46BBWVfKJ8Ms9B3JmOFPTIiVamH7n3KpuQ==} - engines: {node: '>= 10'} - peerDependencies: - svelte: ^3 || ^4 || ^5 || ^5.0.0-next.0 - vite: '*' - vitest: '*' - peerDependenciesMeta: - vite: - optional: true - vitest: - optional: true - '@tybys/wasm-util@0.10.3': resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} - '@types/aria-query@5.0.4': - resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} - '@types/bcrypt@6.0.0': resolution: {integrity: sha512-/oJGukuH3D2+D+3H4JWLaAsJ/ji86dhRidzZ/Od7H/i8g+aCmvkeCc6Ni/f9uxGLSQVCRZkX2/lqEFG2BvWtlQ==} - '@types/body-parser@1.19.6': - resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} - '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} - '@types/connect@3.4.38': - resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} - '@types/cookie@0.6.0': resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} - '@types/cookiejar@2.1.5': - resolution: {integrity: sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==} - - '@types/cors@2.8.19': - resolution: {integrity: sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==} - '@types/d3-array@3.2.2': resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==} @@ -1590,27 +1502,12 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - '@types/express-serve-static-core@5.1.1': - resolution: {integrity: sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==} - - '@types/express@5.0.6': - resolution: {integrity: sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==} - '@types/geojson@7946.0.16': resolution: {integrity: sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==} - '@types/http-errors@2.0.5': - resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} - '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/methods@1.1.4': - resolution: {integrity: sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==} - - '@types/multer@2.2.0': - resolution: {integrity: sha512-3U1troeqGV8Ntp7Q3klwf4zr23VEoqYVocYXaswm9+8z3O9UHDYAqLxjJ/h550iRADTjKdOdhhasXw6gD6kYtg==} - '@types/node-cron@3.0.11': resolution: {integrity: sha512-0ikrnug3/IyneSHqCBeslAhlK2aBfYek1fGo4bP4QnZPmiqSGRK+Oy7ZMisLWkesffJvQ1cqAcBnJC+8+nxIAg==} @@ -1626,30 +1523,9 @@ packages: '@types/pdfkit@0.17.6': resolution: {integrity: sha512-tIwzxk2uWKp0Cq9JIluQXJid77lYhF52EsIOwhsMF4iWLA6YneoBR1xVKYYdAysHuepUB0OX4tdwMiUDdGKmig==} - '@types/qs@6.15.0': - resolution: {integrity: sha512-JawvT8iBVWpzTrz3EGw9BTQFg3BQNmwERdKE22vlTxawwtbyUSlMppvZYKLZzB5zgACXdXxbD3m1bXaMqP/9ow==} - - '@types/range-parser@1.2.7': - resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} - '@types/resolve@1.20.2': resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} - '@types/send@1.2.1': - resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==} - - '@types/serve-static@2.2.0': - resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==} - - '@types/superagent@8.1.9': - resolution: {integrity: sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==} - - '@types/supertest@7.2.1': - resolution: {integrity: sha512-4CbBvoYVLHL7+yhbYrZET0vsvuyXTC05aRe7dNQkwMzm56auceoy6Yu3K50uZmwfHna1os3CMSgM/3QVkUtPTw==} - - '@types/triple-beam@1.3.5': - resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==} - '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} @@ -1734,130 +1610,6 @@ packages: resolution: {integrity: sha512-8C71BQkGjiMmXtop7pHVJu1l2NNShFdkCyD6a2ezzs5vU/L3LRtb69EtcteFwz0mYMPzIgOw0n6OV4VBUWZd7A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript/typescript-aix-ppc64@7.0.2': - resolution: {integrity: sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==} - engines: {node: '>=16.20.0'} - cpu: [ppc64] - os: [aix] - - '@typescript/typescript-darwin-arm64@7.0.2': - resolution: {integrity: sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==} - engines: {node: '>=16.20.0'} - cpu: [arm64] - os: [darwin] - - '@typescript/typescript-darwin-x64@7.0.2': - resolution: {integrity: sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [darwin] - - '@typescript/typescript-freebsd-arm64@7.0.2': - resolution: {integrity: sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==} - engines: {node: '>=16.20.0'} - cpu: [arm64] - os: [freebsd] - - '@typescript/typescript-freebsd-x64@7.0.2': - resolution: {integrity: sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [freebsd] - - '@typescript/typescript-linux-arm64@7.0.2': - resolution: {integrity: sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==} - engines: {node: '>=16.20.0'} - cpu: [arm64] - os: [linux] - - '@typescript/typescript-linux-arm@7.0.2': - resolution: {integrity: sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==} - engines: {node: '>=16.20.0'} - cpu: [arm] - os: [linux] - - '@typescript/typescript-linux-loong64@7.0.2': - resolution: {integrity: sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==} - engines: {node: '>=16.20.0'} - cpu: [loong64] - os: [linux] - - '@typescript/typescript-linux-mips64el@7.0.2': - resolution: {integrity: sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==} - engines: {node: '>=16.20.0'} - cpu: [mips64el] - os: [linux] - - '@typescript/typescript-linux-ppc64@7.0.2': - resolution: {integrity: sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==} - engines: {node: '>=16.20.0'} - cpu: [ppc64] - os: [linux] - - '@typescript/typescript-linux-riscv64@7.0.2': - resolution: {integrity: sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==} - engines: {node: '>=16.20.0'} - cpu: [riscv64] - os: [linux] - - '@typescript/typescript-linux-s390x@7.0.2': - resolution: {integrity: sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==} - engines: {node: '>=16.20.0'} - cpu: [s390x] - os: [linux] - - '@typescript/typescript-linux-x64@7.0.2': - resolution: {integrity: sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [linux] - - '@typescript/typescript-netbsd-arm64@7.0.2': - resolution: {integrity: sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==} - engines: {node: '>=16.20.0'} - cpu: [arm64] - os: [netbsd] - - '@typescript/typescript-netbsd-x64@7.0.2': - resolution: {integrity: sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [netbsd] - - '@typescript/typescript-openbsd-arm64@7.0.2': - resolution: {integrity: sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==} - engines: {node: '>=16.20.0'} - cpu: [arm64] - os: [openbsd] - - '@typescript/typescript-openbsd-x64@7.0.2': - resolution: {integrity: sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [openbsd] - - '@typescript/typescript-sunos-x64@7.0.2': - resolution: {integrity: sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [sunos] - - '@typescript/typescript-win32-arm64@7.0.2': - resolution: {integrity: sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==} - engines: {node: '>=16.20.0'} - cpu: [arm64] - os: [win32] - - '@typescript/typescript-win32-x64@7.0.2': - resolution: {integrity: sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [win32] - - '@typescript/typescript6@6.0.2': - resolution: {integrity: sha512-mbCddXd+jm7hfx7w2YU64/Av4/NqqeG3GoRZgxPcgoTxYjhrcfJRw9ULch71SS4G+Q3bOXFhRvPqjguN0Hyp5w==} - hasBin: true - '@valibot/to-json-schema@1.7.1': resolution: {integrity: sha512-3qkmU6KXWh8GIThEAW3kuRHPQBMjWkKy+Ppz3WkUucx53DTpOa6siMn4xDGSOhlVyMrDaJTCTMLYPZVAIk1P0A==} peerDependencies: @@ -1922,28 +1674,6 @@ packages: ajv@6.14.0: resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - ansi-regex@6.2.2: - resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} - engines: {node: '>=12'} - - ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} - - ansi-styles@6.2.3: - resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} - engines: {node: '>=12'} - - append-field@1.0.0: - resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==} - - aria-query@5.3.0: - resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} - aria-query@5.3.1: resolution: {integrity: sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==} engines: {node: '>= 0.4'} @@ -1964,12 +1694,6 @@ packages: ast-v8-to-istanbul@1.0.0: resolution: {integrity: sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==} - async@3.2.6: - resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} - - asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - axobject-query@4.1.0: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} @@ -2003,6 +1727,10 @@ packages: resolution: {integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==} engines: {node: 18 || 20 || >=22} + brace-expansion@5.0.8: + resolution: {integrity: sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==} + engines: {node: 20 || >=22} + brotli@1.3.3: resolution: {integrity: sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==} @@ -2012,14 +1740,6 @@ packages: buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - busboy@1.6.0: - resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} - engines: {node: '>=10.16.0'} - - call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} - camelcase@8.0.0: resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==} engines: {node: '>=16'} @@ -2028,10 +1748,6 @@ packages: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} - chalk@5.6.2: - resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} - engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - chokidar@4.0.3: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} @@ -2039,10 +1755,6 @@ packages: class-validator@0.14.4: resolution: {integrity: sha512-AwNusCCam51q703dW82x95tOqQp6oC9HNUl724KxJJOfnKscI8dOloXFgyez7LbTTKWuRBA37FScqVbJEoq8Yw==} - cliui@9.0.1: - resolution: {integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==} - engines: {node: '>=20'} - clone@2.1.2: resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==} engines: {node: '>=0.8'} @@ -2051,29 +1763,9 @@ packages: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} - color-convert@3.1.3: - resolution: {integrity: sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==} - engines: {node: '>=14.6'} - - color-name@2.1.0: - resolution: {integrity: sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==} - engines: {node: '>=12.20'} - - color-string@2.1.4: - resolution: {integrity: sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==} - engines: {node: '>=18'} - - color@5.0.3: - resolution: {integrity: sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA==} - engines: {node: '>=18'} - colord@2.9.3: resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} - combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - commander@11.1.0: resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} engines: {node: '>=16'} @@ -2089,15 +1781,6 @@ packages: commondir@1.0.1: resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} - concat-stream@2.0.0: - resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==} - engines: {'0': node >= 6.0} - - concurrently@10.0.3: - resolution: {integrity: sha512-hc3LH4UaKWd/bbyDK/IGVa4RB6PtQ3CUYwtrkzqHn+wIG3Hr5fhpRlk0L/gCa8ZE1L/Ufj50Zho69cI5w8SQBA==} - engines: {node: '>=22'} - hasBin: true - consola@3.4.0: resolution: {integrity: sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==} engines: {node: ^14.18.0 || >=16.10.0} @@ -2109,10 +1792,6 @@ packages: resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} - cors@2.8.6: - resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} - engines: {node: '>= 0.10'} - cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -2288,10 +1967,6 @@ packages: delaunator@5.0.1: resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} - delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -2313,13 +1988,6 @@ packages: dlv@1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} - dom-accessibility-api@0.5.16: - resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} - - dotenv@17.4.2: - resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} - engines: {node: '>=12'} - drizzle-kit@0.31.10: resolution: {integrity: sha512-7OZcmQUrdGI+DUNNsKBn1aW8qSoKuTH7d0mYgSP8bAzdFzKoovxEFnoGQp2dVs82EOJeYycqRtciopszwUf8bw==} hasBin: true @@ -2416,19 +2084,9 @@ packages: sqlite3: optional: true - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - effect@3.21.4: resolution: {integrity: sha512-B89v/xSgPbl1J2Ai2u18jxq3odpFauU1rC6/eSs4FeNHi72kwKdJp12VGigvRV2lK+kRnx+OOz41XV8guZd4gQ==} - emoji-regex@10.6.0: - resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} - - enabled@2.0.0: - resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==} - enhanced-resolve@5.24.3: resolution: {integrity: sha512-PwKooW9JUzh5chmYfHM3IQl5OkK2u2Nm011MgeZrss3JmFraUx/fqrf78kk8GUMYoibx/14MdwTl/1WKkG7TpQ==} engines: {node: '>=10.13.0'} @@ -2437,25 +2095,9 @@ packages: resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==} engines: {node: '>=20.19.0'} - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - es-module-lexer@2.0.0: resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} - - es-set-tostringtag@2.1.0: - resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} - engines: {node: '>= 0.4'} - esbuild@0.18.20: resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} engines: {node: '>=12'} @@ -2471,10 +2113,6 @@ packages: engines: {node: '>=18'} hasBin: true - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -2524,8 +2162,8 @@ packages: resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - eslint@10.7.0: - resolution: {integrity: sha512-GVTD7s1vdIl6UYvAfriOPeY1Df8LIZjfofLvHwde+erDHGGuHyuM6xoxRxmHiebhYuD2p1vN4wWh0XzPARSGDQ==} + eslint@10.8.0: + resolution: {integrity: sha512-nuKKvN+oIBO0koN7Tm7dlkmnkc21mtt0QJLwAKzjLq14y6lRTdVG36MZHJ8eQHwdJMwZbQNMlPOYedMq/oVJvQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} hasBin: true peerDependencies: @@ -2606,9 +2244,6 @@ packages: picomatch: optional: true - fecha@4.2.3: - resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==} - file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -2627,16 +2262,9 @@ packages: flatted@3.4.2: resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} - fn.name@1.1.0: - resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==} - fontkit@2.0.4: resolution: {integrity: sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g==} - form-data@4.0.5: - resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} - engines: {node: '>= 6'} - formsnap@2.0.1: resolution: {integrity: sha512-iJSe4YKd/W6WhLwKDVJU9FQeaJRpEFuolhju7ZXlRpUVyDdqFdMP8AUBICgnVvQPyP41IPAlBa/v0Eo35iE6wQ==} engines: {node: '>=18', pnpm: '>=8.7.0'} @@ -2652,22 +2280,6 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - - get-east-asian-width@1.6.0: - resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} - engines: {node: '>=18'} - - get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} - - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - get-tsconfig@4.13.6: resolution: {integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==} @@ -2679,14 +2291,10 @@ packages: resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} engines: {node: '>=18'} - globals@17.7.0: - resolution: {integrity: sha512-Czmyns5dUsq4seFBR/Kdydhmo8y9kC79hiSkPn0YcGtNnYWnrgt0vjrSjx9tspoDGWm2CMarffRuLjM4xUz8xg==} + globals@17.8.0: + resolution: {integrity: sha512-Zz/LMDZScFmkakeL2cTHzf+PbWKdpU3uclqkZT7TjDG58j5WPt0PpA+n9uPI24fZtlw07q0OtEi84K+umsRzqQ==} engines: {node: '>=18'} - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -2694,22 +2302,10 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - - has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} - hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - helmet@8.3.0: - resolution: {integrity: sha512-Qgpiaws3Sm30Av8Eah6sjMCZZwjlBu+E68rhpCWBshY1lb09HtLwj5GviX0OyQIn+ulUS0iX0AxN5n3tLZzz1w==} - engines: {node: '>=18.0.0'} - html-encoding-sniffer@6.0.0: resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} @@ -2737,9 +2333,6 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - inline-style-parser@0.2.7: resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} @@ -2774,10 +2367,6 @@ packages: is-reference@3.0.3: resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} - is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -2812,14 +2401,11 @@ packages: js-tokens@10.0.0: resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - jsdom@29.1.1: - resolution: {integrity: sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24.0.0} + jsdom@30.0.0: + resolution: {integrity: sha512-JQHfRGmmKmaZoUAvIgff5jjG/0SzTQlGz8c7t72KzBzo8ZULEjAjnYE0sNwBOUA4QtWwYE2xoYitg8NFsmiYxA==} + engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} peerDependencies: - canvas: ^3.0.0 + canvas: ^3.2.3 peerDependenciesMeta: canvas: optional: true @@ -2852,9 +2438,6 @@ packages: known-css-properties@0.37.0: resolution: {integrity: sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ==} - kuler@2.0.0: - resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==} - kysely@0.28.16: resolution: {integrity: sha512-3i5pmOiZvMDj00qhrIVbH0AnioVTx22DMP7Vn5At4yJO46iy+FM8Y/g61ltenLVSo3fiO8h8Q3QOFgf/gQ72ww==} engines: {node: '>=20.0.0'} @@ -2964,12 +2547,8 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} - logform@2.7.0: - resolution: {integrity: sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==} - engines: {node: '>= 12.0.0'} - - lru-cache@11.3.6: - resolution: {integrity: sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==} + lru-cache@11.5.2: + resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==} engines: {node: 20 || >=22} lz-string@1.5.0: @@ -2986,17 +2565,9 @@ packages: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - mdn-data@2.27.1: resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} - media-typer@0.3.0: - resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} - engines: {node: '>= 0.6'} - memoize-weak@1.0.2: resolution: {integrity: sha512-gj39xkrjEw7nCn4nJ1M5ms6+MyMlyiGmttzsqAUsAKn6bYKwuTHh/AO3cKPF8IBrTIYTxb0wWXFs3E//Y8VoWQ==} @@ -3004,14 +2575,6 @@ packages: resolution: {integrity: sha512-DeC6b7QBrZsRs3Y02A6A7lQyzFbsQbqgjI6UW0GigGWV+u1s25TycMr0XHZE4cJce7rY/vyw2ctMQqfDkIhUEA==} engines: {node: '>=18'} - mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - - mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - mimic-function@5.0.1: resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} engines: {node: '>=18'} @@ -3024,6 +2587,10 @@ packages: resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} engines: {node: 18 || 20 || >=22} + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} + engines: {node: 18 || 20 || >=22} + mode-watcher@1.1.0: resolution: {integrity: sha512-mUT9RRGPDYenk59qJauN1rhsIMKBmWA3xMF+uRwE8MW/tjhaDSCCARqkSuDTq8vr4/2KcAxIGVjACxTjdk5C3g==} peerDependencies: @@ -3040,10 +2607,6 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - multer@2.2.0: - resolution: {integrity: sha512-6rdyFg2kLrMh9Jee7/BMPuV9lEAd7lLW2YUpF9/YxR7njyoUwwQ0ZPh3TaIY50Sw6vlyD2HW3wGOkTS4P79xrQ==} - engines: {node: '>= 10.16.0'} - nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -3085,16 +2648,9 @@ packages: nub@0.0.0: resolution: {integrity: sha512-dK0Ss9C34R/vV0FfYJXuqDAqHlaW9fvWVufq9MmGF2umCuDbd5GRfRD9fpi/LiM0l4ZXf8IBB+RYmZExqCrf0w==} - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - obug@2.1.1: resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} - one-time@1.0.0: - resolution: {integrity: sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==} - optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -3262,10 +2818,6 @@ packages: engines: {node: '>=14'} hasBin: true - pretty-format@27.5.1: - resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - promise-limit@2.7.0: resolution: {integrity: sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==} @@ -3279,13 +2831,6 @@ packages: pure-rand@6.1.0: resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} - react-is@17.0.2: - resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} - - readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} - readdirp@4.1.2: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} @@ -3357,20 +2902,10 @@ packages: rw@1.3.3: resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} - rxjs@7.8.2: - resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} - sade@1.8.1: resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} engines: {node: '>=6'} - safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - - safe-stable-stringify@2.5.0: - resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} - engines: {node: '>=10'} - safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} @@ -3394,10 +2929,6 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - shell-quote@1.8.4: - resolution: {integrity: sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==} - engines: {node: '>= 0.4'} - siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} @@ -3421,30 +2952,12 @@ packages: peerDependencies: kysely: '*' - stack-trace@0.0.10: - resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} - stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} std-env@4.0.0: resolution: {integrity: sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==} - streamsearch@1.1.0: - resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} - engines: {node: '>=10.0.0'} - - string-width@7.2.0: - resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} - engines: {node: '>=18'} - - string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - - strip-ansi@7.2.0: - resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} - engines: {node: '>=12'} - style-to-object@1.0.14: resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} @@ -3483,6 +2996,11 @@ packages: svelte: ^4.0.0 || ^5.0.0-next.0 typescript: '>=5.0.0' + svelte-dnd-action@0.9.74: + resolution: {integrity: sha512-zn//d8plF73Y05joRdj0g9S7Z8KY5zoTyzjHtnaJMqQP//6U6smHAHi0ArZWi60bxpoOwo+im8gKhK/M7Eq1pQ==} + peerDependencies: + svelte: '>=3.23.0 || ^5.0.0-next.0' + svelte-eslint-parser@1.8.0: resolution: {integrity: sha512-mikR1qwIVy3t5WthUoAXkMwxkXvabZP9FJgdx35Ei7EbGWmctva1Pih16Koeor/bdNNq8NXHlwKGS6NkYTawLg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0, pnpm: 10.34.1} @@ -3515,8 +3033,8 @@ packages: peerDependencies: svelte: ^5.0.0 - svelte@5.56.7: - resolution: {integrity: sha512-5qERUZX80oQj6XrDMUmD2Uhd/cIpCPDWWKBK3ZHmyRUC9apPyamWM8xMo31mbWsIQxwG2hVoSnOJ/EcnhVkkzQ==} + svelte@5.56.8: + resolution: {integrity: sha512-PY8LOw7xP6c8IOiVqdo0sbbZVYhXRSfklOQLAUyGBKqjTX0wx/z4l/9J+PmBpmlLnxzEb1NqltxQ5/wZme/Cmg==} engines: {node: '>=18'} sveltekit-superforms@2.30.2: @@ -3534,15 +3052,17 @@ packages: tailwind-merge@3.6.0: resolution: {integrity: sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==} - tailwind-variants@3.2.2: - resolution: {integrity: sha512-Mi4kHeMTLvKlM98XPnK+7HoBPmf4gygdFmqQPaDivc3DpYS6aIY6KiG/PgThrGvii5YZJqRsPz0aPyhoFzmZgg==} - engines: {node: '>=16.x', pnpm: '>=7.x'} + tailwind-variants@3.3.0: + resolution: {integrity: sha512-t1QsB42dcwUdaCEArO0tRZcP0nbCcAmJKRYCs7jmwYSFOCXlGqgO8c0TrCYm9OranYmT6i9YOi8LFo2gxmxnow==} + engines: {node: '>=16.9.x', pnpm: '>=7.x'} peerDependencies: tailwind-merge: '>=3.0.0' tailwindcss: '*' peerDependenciesMeta: tailwind-merge: optional: true + tailwindcss: + optional: true tailwindcss@4.3.3: resolution: {integrity: sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==} @@ -3551,9 +3071,6 @@ packages: resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} engines: {node: '>=6'} - text-hex@1.0.0: - resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==} - tiny-case@1.0.3: resolution: {integrity: sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==} @@ -3593,22 +3110,14 @@ packages: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} - tough-cookie@6.0.1: - resolution: {integrity: sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==} + tough-cookie@6.0.2: + resolution: {integrity: sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==} engines: {node: '>=16'} tr46@6.0.0: resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} engines: {node: '>=20'} - tree-kill@1.2.2: - resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} - hasBin: true - - triple-beam@1.4.1: - resolution: {integrity: sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==} - engines: {node: '>= 14.0.0'} - ts-algebra@2.0.0: resolution: {integrity: sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==} @@ -3641,35 +3150,23 @@ packages: resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} engines: {node: '>=12.20'} - type-is@1.6.18: - resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} - engines: {node: '>= 0.6'} - typebox@1.3.6: resolution: {integrity: sha512-Sc8RA0NCMEFmApHNU9ZMzqcpQj46She44J8ffpLM/bdhLNUZKq7DJumcLcsFx1gRmDfQPgCgOmFFJ7rcnfWNyA==} - typedarray@0.0.6: - resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - typescript@6.0.3: resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} engines: {node: '>=14.17'} hasBin: true - typescript@7.0.2: - resolution: {integrity: sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==} - engines: {node: '>=16.20.0'} - hasBin: true - undici-types@7.24.6: resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} undici-types@8.3.0: resolution: {integrity: sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==} - undici@7.25.0: - resolution: {integrity: sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==} - engines: {node: '>=20.18.1'} + undici@8.9.0: + resolution: {integrity: sha512-aWZpUj7XoGonMClx4gdDRfgBjqeA+F473aDmROQQbM9n6PRfK/u1q/a0X4wMTgcHfT8H6fpbt98PFuDUwFg2YA==} + engines: {node: '>=22.19.0'} unicode-properties@1.4.1: resolution: {integrity: sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==} @@ -3706,10 +3203,6 @@ packages: resolution: {integrity: sha512-spH26xU080ydGggxRyR1Yhcbgx+j3y5jbNXk/8L+iRvdIEQ4uTRH2Sgf2dokud6Q4oAtsbNvJ1Ft+9xmm6IZcA==} engines: {node: '>= 0.10'} - vary@1.1.2: - resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} - engines: {node: '>= 0.8'} - vite@8.1.5: resolution: {integrity: sha512-7ULLwsCdYx/nRyrpiEwvqb5TFHrMVZyBt+rg/OAXT7rgj/z+DtTDyKFeLAdDkubDVDKD8jOsndmy7m55XcfUsw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3821,6 +3314,10 @@ packages: resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + whatwg-url@17.1.0: + resolution: {integrity: sha512-3GeworPmc2ZfEEHP7lEbUfBX/L75wdEsi0rLNhXcXxnoN5jyq0SL5gCy06SGW2cyTIZdTvWIDQNQoza++vKeaw==} + engines: {node: ^22.14.0 || >=24.0.0} + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -3831,22 +3328,10 @@ packages: engines: {node: '>=8'} hasBin: true - winston-transport@4.9.0: - resolution: {integrity: sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==} - engines: {node: '>= 12.0.0'} - - winston@3.19.0: - resolution: {integrity: sha512-LZNJgPzfKR+/J3cHkxcpHKpKKvGfDZVPS4hfJCc4cCG0CgYzvlD6yE/S3CIL/Yt91ak327YCpiF/0MyeZHEHKA==} - engines: {node: '>= 12.0.0'} - word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - wrap-ansi@9.0.2: - resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} - engines: {node: '>=18'} - ws@8.19.0: resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} engines: {node: '>=10.0.0'} @@ -3866,22 +3351,10 @@ packages: xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} - y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - yaml@1.10.2: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} - yargs-parser@22.0.0: - resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} - engines: {node: ^20.19.0 || ^22.12.0 || >=23} - - yargs@18.0.0: - resolution: {integrity: sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==} - engines: {node: ^20.19.0 || ^22.12.0 || >=23} - yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -3910,31 +3383,22 @@ snapshots: '@ark/util@0.56.2': optional: true - '@asamuzakjp/css-color@5.1.11': + '@asamuzakjp/css-color@6.0.5': dependencies: - '@asamuzakjp/generational-cache': 1.0.1 - '@csstools/css-calc': 3.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-color-parser': 4.1.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-calc': 3.3.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-color-parser': 4.1.10(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) '@csstools/css-tokenizer': 4.0.0 + lru-cache: 11.5.2 + optional: true - '@asamuzakjp/dom-selector@7.1.1': + '@asamuzakjp/dom-selector@8.3.0': dependencies: - '@asamuzakjp/generational-cache': 1.0.1 - '@asamuzakjp/nwsapi': 2.3.9 bidi-js: 1.0.3 css-tree: 3.2.1 is-potential-custom-element-name: 1.0.1 - - '@asamuzakjp/generational-cache@1.0.1': {} - - '@asamuzakjp/nwsapi@2.3.9': {} - - '@babel/code-frame@7.29.0': - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - js-tokens: 4.0.0 - picocolors: 1.1.1 + lru-cache: 11.5.2 + optional: true '@babel/helper-string-parser@7.27.1': {} @@ -3944,7 +3408,8 @@ snapshots: dependencies: '@babel/types': 7.29.0 - '@babel/runtime@7.29.2': {} + '@babel/runtime@7.29.2': + optional: true '@babel/types@7.29.0': dependencies: @@ -3956,38 +3421,37 @@ snapshots: '@bramus/specificity@2.4.2': dependencies: css-tree: 3.2.1 + optional: true - '@colors/colors@1.6.0': {} - - '@csstools/color-helpers@6.0.2': {} + '@csstools/color-helpers@6.1.0': + optional: true - '@csstools/css-calc@3.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + '@csstools/css-calc@3.3.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': dependencies: '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) '@csstools/css-tokenizer': 4.0.0 + optional: true - '@csstools/css-color-parser@4.1.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + '@csstools/css-color-parser@4.1.10(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': dependencies: - '@csstools/color-helpers': 6.0.2 - '@csstools/css-calc': 3.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/color-helpers': 6.1.0 + '@csstools/css-calc': 3.3.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) '@csstools/css-tokenizer': 4.0.0 + optional: true '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': dependencies: '@csstools/css-tokenizer': 4.0.0 + optional: true - '@csstools/css-syntax-patches-for-csstree@1.1.4(css-tree@3.2.1)': + '@csstools/css-syntax-patches-for-csstree@1.1.7(css-tree@3.2.1)': optionalDependencies: css-tree: 3.2.1 + optional: true - '@csstools/css-tokenizer@4.0.0': {} - - '@dabh/diagnostics@2.0.8': - dependencies: - '@so-ric/colorspace': 1.1.6 - enabled: 2.0.0 - kuler: 2.0.0 + '@csstools/css-tokenizer@4.0.0': + optional: true '@dagrejs/dagre@2.0.4': dependencies: @@ -4245,22 +3709,22 @@ snapshots: '@esbuild/win32-x64@0.28.0': optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@10.7.0(jiti@2.7.0))': + '@eslint-community/eslint-utils@4.9.1(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))': dependencies: - eslint: 10.7.0(jiti@2.7.0) + eslint: 10.8.0(jiti@2.7.0)(supports-color@10.2.2) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint/config-array@0.23.5': + '@eslint/config-array@0.23.5(supports-color@10.2.2)': dependencies: '@eslint/object-schema': 3.0.5 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) minimatch: 10.2.4 transitivePeerDependencies: - supports-color - '@eslint/config-helpers@0.6.0': + '@eslint/config-helpers@0.7.0': dependencies: '@eslint/core': 1.2.1 @@ -4268,9 +3732,9 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/js@10.0.1(eslint@10.7.0(jiti@2.7.0))': + '@eslint/js@10.0.1(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))': optionalDependencies: - eslint: 10.7.0(jiti@2.7.0) + eslint: 10.8.0(jiti@2.7.0)(supports-color@10.2.2) '@eslint/object-schema@3.0.5': {} @@ -4282,6 +3746,12 @@ snapshots: '@exodus/bytes@1.15.0(@noble/hashes@1.8.0)': optionalDependencies: '@noble/hashes': 1.8.0 + optional: true + + '@exodus/bytes@1.15.1(@noble/hashes@1.8.0)': + optionalDependencies: + '@noble/hashes': 1.8.0 + optional: true '@exodus/schemasafe@1.3.0': optional: true @@ -4318,7 +3788,7 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} - '@inlang/paraglide-js@2.22.0(@typescript/typescript6@6.0.2)(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1))': + '@inlang/paraglide-js@2.23.0(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1))': dependencies: '@inlang/recommend-sherlock': 0.2.1 '@inlang/sdk': 2.10.2 @@ -4328,7 +3798,7 @@ snapshots: unplugin: 2.3.11 urlpattern-polyfill: 10.1.0 optionalDependencies: - typescript: '@typescript/typescript6@6.0.2' + typescript: 6.0.3 vite: 8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1) transitivePeerDependencies: - babel-plugin-macros @@ -4465,9 +3935,9 @@ snapshots: '@lix-js/server-protocol-schema@0.1.1': {} - '@lucide/svelte@1.25.0(svelte@5.56.7(@typescript-eslint/types@8.65.0))': + '@lucide/svelte@1.27.0(svelte@5.56.8(@typescript-eslint/types@8.65.0))': dependencies: - svelte: 5.56.7(@typescript-eslint/types@8.65.0) + svelte: 5.56.8(@typescript-eslint/types@8.65.0) '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': dependencies: @@ -4684,11 +4154,6 @@ snapshots: '@sinclair/typebox@0.31.28': {} - '@so-ric/colorspace@1.1.6': - dependencies: - color: 5.0.3 - text-hex: 1.0.0 - '@sqlite.org/sqlite-wasm@3.48.0-build4': {} '@standard-schema/spec@1.1.0': {} @@ -4697,20 +4162,20 @@ snapshots: dependencies: acorn: 8.16.0 - '@sveltejs/adapter-node@5.5.7(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))': + '@sveltejs/adapter-node@5.5.7(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))': dependencies: '@rollup/plugin-commonjs': 29.0.2(rollup@4.59.0) '@rollup/plugin-json': 6.1.0(rollup@4.59.0) '@rollup/plugin-node-resolve': 16.0.3(rollup@4.59.0) '@rollup/plugin-replace': 6.0.3(rollup@4.59.0) - '@sveltejs/kit': 2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)) + '@sveltejs/kit': 2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)) rollup: 4.59.0 - '@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1))': + '@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1))': dependencies: '@standard-schema/spec': 1.1.0 '@sveltejs/acorn-typescript': 1.0.11(acorn@8.16.0) - '@sveltejs/vite-plugin-svelte': 7.2.0(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)) + '@sveltejs/vite-plugin-svelte': 7.2.0(svelte@5.56.8(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)) '@types/cookie': 0.6.0 acorn: 8.16.0 cookie: 0.6.0 @@ -4721,19 +4186,19 @@ snapshots: mrmime: 2.0.1 set-cookie-parser: 3.0.1 sirv: 3.0.2 - svelte: 5.56.7(@typescript-eslint/types@8.65.0) + svelte: 5.56.8(@typescript-eslint/types@8.65.0) vite: 8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1) optionalDependencies: - typescript: '@typescript/typescript6@6.0.2' + typescript: 6.0.3 '@sveltejs/load-config@0.2.0': {} - '@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1))': + '@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1))': dependencies: deepmerge: 4.3.1 magic-string: 0.30.21 obug: 2.1.1 - svelte: 5.56.7(@typescript-eslint/types@8.65.0) + svelte: 5.56.8(@typescript-eslint/types@8.65.0) vite: 8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1) vitefu: 1.1.2(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)) @@ -4821,63 +4286,22 @@ snapshots: '@tanstack/table-core@8.21.3': {} - '@testing-library/dom@10.4.1': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/runtime': 7.29.2 - '@types/aria-query': 5.0.4 - aria-query: 5.3.0 - dom-accessibility-api: 0.5.16 - lz-string: 1.5.0 - picocolors: 1.1.1 - pretty-format: 27.5.1 - - '@testing-library/svelte-core@1.1.3(svelte@5.56.7(@typescript-eslint/types@8.65.0))': - dependencies: - svelte: 5.56.7(@typescript-eslint/types@8.65.0) - - '@testing-library/svelte@5.4.2(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1))(vitest@4.1.10)': - dependencies: - '@testing-library/dom': 10.4.1 - '@testing-library/svelte-core': 1.1.3(svelte@5.56.7(@typescript-eslint/types@8.65.0)) - svelte: 5.56.7(@typescript-eslint/types@8.65.0) - optionalDependencies: - vite: 8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1) - vitest: 4.1.10(@types/node@26.1.1)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1(@noble/hashes@1.8.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)) - '@tybys/wasm-util@0.10.3': dependencies: tslib: 2.8.1 optional: true - '@types/aria-query@5.0.4': {} - '@types/bcrypt@6.0.0': dependencies: '@types/node': 26.1.1 - '@types/body-parser@1.19.6': - dependencies: - '@types/connect': 3.4.38 - '@types/node': 26.1.1 - '@types/chai@5.2.3': dependencies: '@types/deep-eql': 4.0.2 assertion-error: 2.0.1 - '@types/connect@3.4.38': - dependencies: - '@types/node': 26.1.1 - '@types/cookie@0.6.0': {} - '@types/cookiejar@2.1.5': {} - - '@types/cors@2.8.19': - dependencies: - '@types/node': 26.1.1 - '@types/d3-array@3.2.2': {} '@types/d3-contour@3.0.6': @@ -4903,31 +4327,10 @@ snapshots: '@types/estree@1.0.8': {} - '@types/express-serve-static-core@5.1.1': - dependencies: - '@types/node': 26.1.1 - '@types/qs': 6.15.0 - '@types/range-parser': 1.2.7 - '@types/send': 1.2.1 - - '@types/express@5.0.6': - dependencies: - '@types/body-parser': 1.19.6 - '@types/express-serve-static-core': 5.1.1 - '@types/serve-static': 2.2.0 - '@types/geojson@7946.0.16': {} - '@types/http-errors@2.0.5': {} - '@types/json-schema@7.0.15': {} - '@types/methods@1.1.4': {} - - '@types/multer@2.2.0': - dependencies: - '@types/express': 5.0.6 - '@types/node-cron@3.0.11': {} '@types/node@25.8.0': @@ -4946,35 +4349,8 @@ snapshots: dependencies: '@types/node': 26.1.1 - '@types/qs@6.15.0': {} - - '@types/range-parser@1.2.7': {} - '@types/resolve@1.20.2': {} - '@types/send@1.2.1': - dependencies: - '@types/node': 26.1.1 - - '@types/serve-static@2.2.0': - dependencies: - '@types/http-errors': 2.0.5 - '@types/node': 26.1.1 - - '@types/superagent@8.1.9': - dependencies: - '@types/cookiejar': 2.1.5 - '@types/methods': 1.1.4 - '@types/node': 26.1.1 - form-data: 4.0.5 - - '@types/supertest@7.2.1': - dependencies: - '@types/methods': 1.1.4 - '@types/superagent': 8.1.9 - - '@types/triple-beam@1.3.5': {} - '@types/trusted-types@2.0.7': {} '@types/validator@13.15.10': @@ -4998,40 +4374,40 @@ snapshots: '@types/json-schema': 7.0.15 optional: true - '@typescript-eslint/eslint-plugin@8.65.0(@typescript-eslint/parser@8.65.0(@typescript/typescript6@6.0.2)(eslint@10.7.0(jiti@2.7.0)))(@typescript/typescript6@6.0.2)(eslint@10.7.0(jiti@2.7.0))': + '@typescript-eslint/eslint-plugin@8.65.0(@typescript-eslint/parser@8.65.0(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.65.0(@typescript/typescript6@6.0.2)(eslint@10.7.0(jiti@2.7.0)) + '@typescript-eslint/parser': 8.65.0(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) '@typescript-eslint/scope-manager': 8.65.0 - '@typescript-eslint/type-utils': 8.65.0(@typescript/typescript6@6.0.2)(eslint@10.7.0(jiti@2.7.0)) - '@typescript-eslint/utils': 8.65.0(@typescript/typescript6@6.0.2)(eslint@10.7.0(jiti@2.7.0)) + '@typescript-eslint/type-utils': 8.65.0(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) + '@typescript-eslint/utils': 8.65.0(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) '@typescript-eslint/visitor-keys': 8.65.0 - eslint: 10.7.0(jiti@2.7.0) + eslint: 10.8.0(jiti@2.7.0)(supports-color@10.2.2) ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.5.0(@typescript/typescript6@6.0.2) - typescript: '@typescript/typescript6@6.0.2' + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.65.0(@typescript/typescript6@6.0.2)(eslint@10.7.0(jiti@2.7.0))': + '@typescript-eslint/parser@8.65.0(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)': dependencies: '@typescript-eslint/scope-manager': 8.65.0 '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/typescript-estree': 8.65.0(@typescript/typescript6@6.0.2) + '@typescript-eslint/typescript-estree': 8.65.0(supports-color@10.2.2)(typescript@6.0.3) '@typescript-eslint/visitor-keys': 8.65.0 - debug: 4.4.3 - eslint: 10.7.0(jiti@2.7.0) - typescript: '@typescript/typescript6@6.0.2' + debug: 4.4.3(supports-color@10.2.2) + eslint: 10.8.0(jiti@2.7.0)(supports-color@10.2.2) + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.65.0(@typescript/typescript6@6.0.2)': + '@typescript-eslint/project-service@8.65.0(supports-color@10.2.2)(typescript@6.0.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.65.0(@typescript/typescript6@6.0.2) + '@typescript-eslint/tsconfig-utils': 8.65.0(typescript@6.0.3) '@typescript-eslint/types': 8.65.0 - debug: 4.4.3 - typescript: '@typescript/typescript6@6.0.2' + debug: 4.4.3(supports-color@10.2.2) + typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -5040,47 +4416,47 @@ snapshots: '@typescript-eslint/types': 8.65.0 '@typescript-eslint/visitor-keys': 8.65.0 - '@typescript-eslint/tsconfig-utils@8.65.0(@typescript/typescript6@6.0.2)': + '@typescript-eslint/tsconfig-utils@8.65.0(typescript@6.0.3)': dependencies: - typescript: '@typescript/typescript6@6.0.2' + typescript: 6.0.3 - '@typescript-eslint/type-utils@8.65.0(@typescript/typescript6@6.0.2)(eslint@10.7.0(jiti@2.7.0))': + '@typescript-eslint/type-utils@8.65.0(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)': dependencies: '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/typescript-estree': 8.65.0(@typescript/typescript6@6.0.2) - '@typescript-eslint/utils': 8.65.0(@typescript/typescript6@6.0.2)(eslint@10.7.0(jiti@2.7.0)) - debug: 4.4.3 - eslint: 10.7.0(jiti@2.7.0) - ts-api-utils: 2.5.0(@typescript/typescript6@6.0.2) - typescript: '@typescript/typescript6@6.0.2' + '@typescript-eslint/typescript-estree': 8.65.0(supports-color@10.2.2)(typescript@6.0.3) + '@typescript-eslint/utils': 8.65.0(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) + debug: 4.4.3(supports-color@10.2.2) + eslint: 10.8.0(jiti@2.7.0)(supports-color@10.2.2) + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 transitivePeerDependencies: - supports-color '@typescript-eslint/types@8.65.0': {} - '@typescript-eslint/typescript-estree@8.65.0(@typescript/typescript6@6.0.2)': + '@typescript-eslint/typescript-estree@8.65.0(supports-color@10.2.2)(typescript@6.0.3)': dependencies: - '@typescript-eslint/project-service': 8.65.0(@typescript/typescript6@6.0.2) - '@typescript-eslint/tsconfig-utils': 8.65.0(@typescript/typescript6@6.0.2) + '@typescript-eslint/project-service': 8.65.0(supports-color@10.2.2)(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.65.0(typescript@6.0.3) '@typescript-eslint/types': 8.65.0 '@typescript-eslint/visitor-keys': 8.65.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) minimatch: 10.2.4 semver: 7.7.4 tinyglobby: 0.2.17 - ts-api-utils: 2.5.0(@typescript/typescript6@6.0.2) - typescript: '@typescript/typescript6@6.0.2' + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.65.0(@typescript/typescript6@6.0.2)(eslint@10.7.0(jiti@2.7.0))': + '@typescript-eslint/utils@8.65.0(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.7.0(jiti@2.7.0)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2)) '@typescript-eslint/scope-manager': 8.65.0 '@typescript-eslint/types': 8.65.0 - '@typescript-eslint/typescript-estree': 8.65.0(@typescript/typescript6@6.0.2) - eslint: 10.7.0(jiti@2.7.0) - typescript: '@typescript/typescript6@6.0.2' + '@typescript-eslint/typescript-estree': 8.65.0(supports-color@10.2.2)(typescript@6.0.3) + eslint: 10.8.0(jiti@2.7.0)(supports-color@10.2.2) + typescript: 6.0.3 transitivePeerDependencies: - supports-color @@ -5089,73 +4465,9 @@ snapshots: '@typescript-eslint/types': 8.65.0 eslint-visitor-keys: 5.0.1 - '@typescript/typescript-aix-ppc64@7.0.2': - optional: true - - '@typescript/typescript-darwin-arm64@7.0.2': - optional: true - - '@typescript/typescript-darwin-x64@7.0.2': - optional: true - - '@typescript/typescript-freebsd-arm64@7.0.2': - optional: true - - '@typescript/typescript-freebsd-x64@7.0.2': - optional: true - - '@typescript/typescript-linux-arm64@7.0.2': - optional: true - - '@typescript/typescript-linux-arm@7.0.2': - optional: true - - '@typescript/typescript-linux-loong64@7.0.2': - optional: true - - '@typescript/typescript-linux-mips64el@7.0.2': - optional: true - - '@typescript/typescript-linux-ppc64@7.0.2': - optional: true - - '@typescript/typescript-linux-riscv64@7.0.2': - optional: true - - '@typescript/typescript-linux-s390x@7.0.2': - optional: true - - '@typescript/typescript-linux-x64@7.0.2': - optional: true - - '@typescript/typescript-netbsd-arm64@7.0.2': - optional: true - - '@typescript/typescript-netbsd-x64@7.0.2': - optional: true - - '@typescript/typescript-openbsd-arm64@7.0.2': - optional: true - - '@typescript/typescript-openbsd-x64@7.0.2': - optional: true - - '@typescript/typescript-sunos-x64@7.0.2': - optional: true - - '@typescript/typescript-win32-arm64@7.0.2': - optional: true - - '@typescript/typescript-win32-x64@7.0.2': - optional: true - - '@typescript/typescript6@6.0.2': - dependencies: - '@typescript/old': typescript@6.0.3 - - '@valibot/to-json-schema@1.7.1(valibot@1.4.2(@typescript/typescript6@6.0.2))': + '@valibot/to-json-schema@1.7.1(valibot@1.4.2(typescript@6.0.3))': dependencies: - valibot: 1.4.2(@typescript/typescript6@6.0.2) + valibot: 1.4.2(typescript@6.0.3) optional: true '@vinejs/compiler@3.0.0': @@ -5185,7 +4497,7 @@ snapshots: obug: 2.1.1 std-env: 4.0.0 tinyrainbow: 3.1.0 - vitest: 4.1.10(@types/node@26.1.1)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1(@noble/hashes@1.8.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)) + vitest: 4.1.10(@types/node@26.1.1)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.0(@noble/hashes@1.8.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)) '@vitest/expect@4.1.10': dependencies: @@ -5241,20 +4553,6 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 - ansi-regex@5.0.1: {} - - ansi-regex@6.2.2: {} - - ansi-styles@5.2.0: {} - - ansi-styles@6.2.3: {} - - append-field@1.0.0: {} - - aria-query@5.3.0: - dependencies: - dequal: 2.0.3 - aria-query@5.3.1: {} arkregex@0.0.8: @@ -5279,10 +4577,6 @@ snapshots: estree-walker: 3.0.3 js-tokens: 10.0.0 - async@3.2.6: {} - - asynckit@0.4.0: {} - axobject-query@4.1.0: {} balanced-match@4.0.4: {} @@ -5299,16 +4593,17 @@ snapshots: bidi-js@1.0.3: dependencies: require-from-string: 2.0.2 + optional: true - bits-ui@2.18.1(@internationalized/date@3.12.2)(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.7(@typescript-eslint/types@8.65.0)): + bits-ui@2.18.1(@internationalized/date@3.12.2)(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0)): dependencies: '@floating-ui/core': 1.7.5 '@floating-ui/dom': 1.7.6 '@internationalized/date': 3.12.2 esm-env: 1.2.2 - runed: 0.35.1(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.7(@typescript-eslint/types@8.65.0)) - svelte: 5.56.7(@typescript-eslint/types@8.65.0) - svelte-toolbelt: 0.10.6(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.7(@typescript-eslint/types@8.65.0)) + runed: 0.35.1(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0)) + svelte: 5.56.8(@typescript-eslint/types@8.65.0) + svelte-toolbelt: 0.10.6(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0)) tabbable: 6.4.0 transitivePeerDependencies: - '@sveltejs/kit' @@ -5317,6 +4612,10 @@ snapshots: dependencies: balanced-match: 4.0.4 + brace-expansion@5.0.8: + dependencies: + balanced-match: 4.0.4 + brotli@1.3.3: dependencies: base64-js: 1.5.1 @@ -5327,22 +4626,11 @@ snapshots: buffer-from@1.1.2: {} - busboy@1.6.0: - dependencies: - streamsearch: 1.1.0 - - call-bind-apply-helpers@1.0.2: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - camelcase@8.0.0: optional: true chai@6.2.2: {} - chalk@5.6.2: {} - chokidar@4.0.3: dependencies: readdirp: 4.1.2 @@ -5354,37 +4642,12 @@ snapshots: validator: 13.15.26 optional: true - cliui@9.0.1: - dependencies: - string-width: 7.2.0 - strip-ansi: 7.2.0 - wrap-ansi: 9.0.2 - clone@2.1.2: {} clsx@2.1.1: {} - color-convert@3.1.3: - dependencies: - color-name: 2.1.0 - - color-name@2.1.0: {} - - color-string@2.1.4: - dependencies: - color-name: 2.1.0 - - color@5.0.3: - dependencies: - color-convert: 3.1.3 - color-string: 2.1.4 - colord@2.9.3: {} - combined-stream@1.0.8: - dependencies: - delayed-stream: 1.0.0 - commander@11.1.0: {} commander@7.2.0: {} @@ -5396,33 +4659,12 @@ snapshots: commondir@1.0.1: {} - concat-stream@2.0.0: - dependencies: - buffer-from: 1.1.2 - inherits: 2.0.4 - readable-stream: 3.6.2 - typedarray: 0.0.6 - - concurrently@10.0.3: - dependencies: - chalk: 5.6.2 - rxjs: 7.8.2 - shell-quote: 1.8.4 - supports-color: 10.2.2 - tree-kill: 1.2.2 - yargs: 18.0.0 - consola@3.4.0: {} convert-source-map@2.0.0: {} cookie@0.6.0: {} - cors@2.8.6: - dependencies: - object-assign: 4.1.1 - vary: 1.1.2 - cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -5433,6 +4675,7 @@ snapshots: dependencies: mdn-data: 2.27.1 source-map-js: 1.2.1 + optional: true cssesc@3.0.0: {} @@ -5557,6 +4800,7 @@ snapshots: whatwg-url: 16.0.1(@noble/hashes@1.8.0) transitivePeerDependencies: - '@noble/hashes' + optional: true date-fns-tz@3.2.0(date-fns@4.4.0): dependencies: @@ -5567,11 +4811,14 @@ snapshots: dayjs@1.11.20: optional: true - debug@4.4.3: + debug@4.4.3(supports-color@10.2.2): dependencies: ms: 2.1.3 + optionalDependencies: + supports-color: 10.2.2 - decimal.js@10.6.0: {} + decimal.js@10.6.0: + optional: true dedent@1.5.1: {} @@ -5583,8 +4830,6 @@ snapshots: dependencies: robust-predicates: 3.0.2 - delayed-stream@1.0.0: {} - dequal@2.0.3: {} detect-libc@2.0.2: {} @@ -5598,10 +4843,6 @@ snapshots: dlv@1.1.3: optional: true - dom-accessibility-api@0.5.16: {} - - dotenv@17.4.2: {} - drizzle-kit@0.31.10: dependencies: '@drizzle-team/brocli': 0.10.2 @@ -5614,46 +4855,22 @@ snapshots: '@libsql/client': 0.17.4 kysely: 0.28.16 - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - effect@3.21.4: dependencies: '@standard-schema/spec': 1.1.0 fast-check: 3.23.2 optional: true - emoji-regex@10.6.0: {} - - enabled@2.0.0: {} - enhanced-resolve@5.24.3: dependencies: graceful-fs: 4.2.11 tapable: 2.3.3 - entities@8.0.0: {} - - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} + entities@8.0.0: + optional: true es-module-lexer@2.0.0: {} - es-object-atoms@1.1.1: - dependencies: - es-errors: 1.3.0 - - es-set-tostringtag@2.1.0: - dependencies: - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - esbuild@0.18.20: optionalDependencies: '@esbuild/android-arm': 0.18.20 @@ -5737,19 +4954,17 @@ snapshots: '@esbuild/win32-ia32': 0.28.0 '@esbuild/win32-x64': 0.28.0 - escalade@3.2.0: {} - escape-string-regexp@4.0.0: {} - eslint-config-prettier@10.1.8(eslint@10.7.0(jiti@2.7.0)): + eslint-config-prettier@10.1.8(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2)): dependencies: - eslint: 10.7.0(jiti@2.7.0) + eslint: 10.8.0(jiti@2.7.0)(supports-color@10.2.2) - eslint-plugin-svelte@3.22.0(eslint@10.7.0(jiti@2.7.0))(svelte@5.56.7(@typescript-eslint/types@8.65.0)): + eslint-plugin-svelte@3.22.0(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))(svelte@5.56.8(@typescript-eslint/types@8.65.0)): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.7.0(jiti@2.7.0)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2)) '@jridgewell/sourcemap-codec': 1.5.5 - eslint: 10.7.0(jiti@2.7.0) + eslint: 10.8.0(jiti@2.7.0)(supports-color@10.2.2) esutils: 2.0.3 globals: 16.5.0 known-css-properties: 0.37.0 @@ -5757,17 +4972,17 @@ snapshots: postcss-load-config: 3.1.4(postcss@8.5.16) postcss-safe-parser: 7.0.1(postcss@8.5.16) semver: 7.7.4 - svelte-eslint-parser: 1.8.0(svelte@5.56.7(@typescript-eslint/types@8.65.0)) + svelte-eslint-parser: 1.8.0(svelte@5.56.8(@typescript-eslint/types@8.65.0)) optionalDependencies: - svelte: 5.56.7(@typescript-eslint/types@8.65.0) + svelte: 5.56.8(@typescript-eslint/types@8.65.0) transitivePeerDependencies: - ts-node - eslint-plugin-unused-imports@4.4.1(@typescript-eslint/eslint-plugin@8.65.0(@typescript-eslint/parser@8.65.0(@typescript/typescript6@6.0.2)(eslint@10.7.0(jiti@2.7.0)))(@typescript/typescript6@6.0.2)(eslint@10.7.0(jiti@2.7.0)))(eslint@10.7.0(jiti@2.7.0)): + eslint-plugin-unused-imports@4.4.1(@typescript-eslint/eslint-plugin@8.65.0(@typescript-eslint/parser@8.65.0(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2)): dependencies: - eslint: 10.7.0(jiti@2.7.0) + eslint: 10.8.0(jiti@2.7.0)(supports-color@10.2.2) optionalDependencies: - '@typescript-eslint/eslint-plugin': 8.65.0(@typescript-eslint/parser@8.65.0(@typescript/typescript6@6.0.2)(eslint@10.7.0(jiti@2.7.0)))(@typescript/typescript6@6.0.2)(eslint@10.7.0(jiti@2.7.0)) + '@typescript-eslint/eslint-plugin': 8.65.0(@typescript-eslint/parser@8.65.0(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) eslint-scope@8.4.0: dependencies: @@ -5787,12 +5002,12 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@10.7.0(jiti@2.7.0): + eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.7.0(jiti@2.7.0)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.8.0(jiti@2.7.0)(supports-color@10.2.2)) '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.23.5 - '@eslint/config-helpers': 0.6.0 + '@eslint/config-array': 0.23.5(supports-color@10.2.2) + '@eslint/config-helpers': 0.7.0 '@eslint/core': 1.2.1 '@eslint/plugin-kit': 0.7.2 '@humanfs/node': 0.16.7 @@ -5801,7 +5016,7 @@ snapshots: '@types/estree': 1.0.8 ajv: 6.14.0 cross-spawn: 7.0.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) escape-string-regexp: 4.0.0 eslint-scope: 9.1.2 eslint-visitor-keys: 5.0.1 @@ -5816,7 +5031,7 @@ snapshots: imurmurhash: 0.1.4 is-glob: 4.0.3 json-stable-stringify-without-jsonify: 1.0.1 - minimatch: 10.2.4 + minimatch: 10.2.5 natural-compare: 1.4.0 optionator: 0.9.4 optionalDependencies: @@ -5885,8 +5100,6 @@ snapshots: optionalDependencies: picomatch: 4.0.5 - fecha@4.2.3: {} - file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -5905,8 +5118,6 @@ snapshots: flatted@3.4.2: {} - fn.name@1.1.0: {} - fontkit@2.0.4: dependencies: '@swc/helpers': 0.5.19 @@ -5919,47 +5130,17 @@ snapshots: unicode-properties: 1.4.1 unicode-trie: 2.0.0 - form-data@4.0.5: + formsnap@2.0.1(svelte@5.56.8(@typescript-eslint/types@8.65.0))(sveltekit-superforms@2.30.2(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@types/json-schema@7.0.15)(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3)): dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - es-set-tostringtag: 2.1.0 - hasown: 2.0.2 - mime-types: 2.1.35 - - formsnap@2.0.1(svelte@5.56.7(@typescript-eslint/types@8.65.0))(sveltekit-superforms@2.30.2(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@types/json-schema@7.0.15)(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0))): - dependencies: - svelte: 5.56.7(@typescript-eslint/types@8.65.0) - svelte-toolbelt: 0.5.0(svelte@5.56.7(@typescript-eslint/types@8.65.0)) - sveltekit-superforms: 2.30.2(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@types/json-schema@7.0.15)(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0)) + svelte: 5.56.8(@typescript-eslint/types@8.65.0) + svelte-toolbelt: 0.5.0(svelte@5.56.8(@typescript-eslint/types@8.65.0)) + sveltekit-superforms: 2.30.2(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@types/json-schema@7.0.15)(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3) fsevents@2.3.3: optional: true function-bind@1.1.2: {} - get-caller-file@2.0.5: {} - - get-east-asian-width@1.6.0: {} - - get-intrinsic@1.3.0: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - math-intrinsics: 1.1.0 - - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - get-tsconfig@4.13.6: dependencies: resolve-pkg-maps: 1.0.0 @@ -5970,31 +5151,22 @@ snapshots: globals@16.5.0: {} - globals@17.7.0: {} - - gopd@1.2.0: {} + globals@17.8.0: {} graceful-fs@4.2.11: {} has-flag@4.0.0: {} - has-symbols@1.1.0: {} - - has-tostringtag@1.0.2: - dependencies: - has-symbols: 1.1.0 - hasown@2.0.2: dependencies: function-bind: 1.1.2 - helmet@8.3.0: {} - html-encoding-sniffer@6.0.0(@noble/hashes@1.8.0): dependencies: '@exodus/bytes': 1.15.0(@noble/hashes@1.8.0) transitivePeerDependencies: - '@noble/hashes' + optional: true html-escaper@2.0.2: {} @@ -6010,8 +5182,6 @@ snapshots: imurmurhash@0.1.4: {} - inherits@2.0.4: {} - inline-style-parser@0.2.7: {} internmap@1.0.1: {} @@ -6030,7 +5200,8 @@ snapshots: is-module@1.0.0: {} - is-potential-custom-element-name@1.0.1: {} + is-potential-custom-element-name@1.0.1: + optional: true is-reference@1.2.1: dependencies: @@ -6040,8 +5211,6 @@ snapshots: dependencies: '@types/estree': 1.0.8 - is-stream@2.0.1: {} - isexe@2.0.0: {} istanbul-lib-coverage@3.2.2: {} @@ -6076,33 +5245,32 @@ snapshots: js-tokens@10.0.0: {} - js-tokens@4.0.0: {} - - jsdom@29.1.1(@noble/hashes@1.8.0): + jsdom@30.0.0(@noble/hashes@1.8.0): dependencies: - '@asamuzakjp/css-color': 5.1.11 - '@asamuzakjp/dom-selector': 7.1.1 + '@asamuzakjp/css-color': 6.0.5 + '@asamuzakjp/dom-selector': 8.3.0 '@bramus/specificity': 2.4.2 - '@csstools/css-syntax-patches-for-csstree': 1.1.4(css-tree@3.2.1) - '@exodus/bytes': 1.15.0(@noble/hashes@1.8.0) + '@csstools/css-syntax-patches-for-csstree': 1.1.7(css-tree@3.2.1) + '@exodus/bytes': 1.15.1(@noble/hashes@1.8.0) css-tree: 3.2.1 data-urls: 7.0.0(@noble/hashes@1.8.0) decimal.js: 10.6.0 html-encoding-sniffer: 6.0.0(@noble/hashes@1.8.0) is-potential-custom-element-name: 1.0.1 - lru-cache: 11.3.6 + lru-cache: 11.5.2 parse5: 8.0.1 saxes: 6.0.0 symbol-tree: 3.2.4 - tough-cookie: 6.0.1 - undici: 7.25.0 + tough-cookie: 6.0.2 + undici: 8.9.0 w3c-xmlserializer: 5.0.0 webidl-conversions: 8.0.1 whatwg-mimetype: 5.0.0 - whatwg-url: 16.0.1(@noble/hashes@1.8.0) + whatwg-url: 17.1.0(@noble/hashes@1.8.0) xml-name-validator: 5.0.0 transitivePeerDependencies: - '@noble/hashes' + optional: true json-buffer@3.0.1: {} @@ -6126,11 +5294,9 @@ snapshots: known-css-properties@0.37.0: {} - kuler@2.0.0: {} - kysely@0.28.16: {} - layerchart@2.0.2(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.7(@typescript-eslint/types@8.65.0))(zod@4.4.3): + layerchart@2.0.2(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0))(zod@4.4.3): dependencies: '@dagrejs/dagre': 2.0.4 '@layerstack/svelte-actions': 1.0.1-next.18 @@ -6160,8 +5326,8 @@ snapshots: d3-tile: 1.0.0 d3-time: 3.1.0 memoize: 10.2.0 - runed: 0.37.1(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.7(@typescript-eslint/types@8.65.0))(zod@4.4.3) - svelte: 5.56.7(@typescript-eslint/types@8.65.0) + runed: 0.37.1(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0))(zod@4.4.3) + svelte: 5.56.8(@typescript-eslint/types@8.65.0) transitivePeerDependencies: - '@sveltejs/kit' - zod @@ -6251,16 +5417,8 @@ snapshots: dependencies: p-locate: 5.0.0 - logform@2.7.0: - dependencies: - '@colors/colors': 1.6.0 - '@types/triple-beam': 1.3.5 - fecha: 4.2.3 - ms: 2.1.3 - safe-stable-stringify: 2.5.0 - triple-beam: 1.4.1 - - lru-cache@11.3.6: {} + lru-cache@11.5.2: + optional: true lz-string@1.5.0: {} @@ -6278,11 +5436,8 @@ snapshots: dependencies: semver: 7.7.4 - math-intrinsics@1.1.0: {} - - mdn-data@2.27.1: {} - - media-typer@0.3.0: {} + mdn-data@2.27.1: + optional: true memoize-weak@1.0.2: {} @@ -6290,12 +5445,6 @@ snapshots: dependencies: mimic-function: 5.0.1 - mime-db@1.52.0: {} - - mime-types@2.1.35: - dependencies: - mime-db: 1.52.0 - mimic-function@5.0.1: {} mini-svg-data-uri@1.4.4: {} @@ -6304,11 +5453,15 @@ snapshots: dependencies: brace-expansion: 5.0.4 - mode-watcher@1.1.0(svelte@5.56.7(@typescript-eslint/types@8.65.0)): + minimatch@10.2.5: dependencies: - runed: 0.25.0(svelte@5.56.7(@typescript-eslint/types@8.65.0)) - svelte: 5.56.7(@typescript-eslint/types@8.65.0) - svelte-toolbelt: 0.7.1(svelte@5.56.7(@typescript-eslint/types@8.65.0)) + brace-expansion: 5.0.8 + + mode-watcher@1.1.0(svelte@5.56.8(@typescript-eslint/types@8.65.0)): + dependencies: + runed: 0.25.0(svelte@5.56.8(@typescript-eslint/types@8.65.0)) + svelte: 5.56.8(@typescript-eslint/types@8.65.0) + svelte-toolbelt: 0.7.1(svelte@5.56.8(@typescript-eslint/types@8.65.0)) mri@1.2.0: {} @@ -6316,13 +5469,6 @@ snapshots: ms@2.1.3: {} - multer@2.2.0: - dependencies: - append-field: 1.0.0 - busboy: 1.6.0 - concat-stream: 2.0.0 - type-is: 1.6.18 - nanoid@3.3.11: {} nanoid@3.3.15: {} @@ -6344,14 +5490,8 @@ snapshots: nub@0.0.0: {} - object-assign@4.1.1: {} - obug@2.1.1: {} - one-time@1.0.0: - dependencies: - fn.name: 1.1.0 - optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -6376,6 +5516,7 @@ snapshots: parse5@8.0.1: dependencies: entities: 8.0.0 + optional: true path-exists@4.0.0: {} @@ -6449,25 +5590,19 @@ snapshots: prelude-ls@1.2.1: {} - prettier-plugin-svelte@4.1.1(prettier@3.9.6)(svelte@5.56.7(@typescript-eslint/types@8.65.0)): + prettier-plugin-svelte@4.1.1(prettier@3.9.6)(svelte@5.56.8(@typescript-eslint/types@8.65.0)): dependencies: prettier: 3.9.6 - svelte: 5.56.7(@typescript-eslint/types@8.65.0) + svelte: 5.56.8(@typescript-eslint/types@8.65.0) - prettier-plugin-tailwindcss@0.8.1(prettier-plugin-svelte@4.1.1(prettier@3.9.6)(svelte@5.56.7(@typescript-eslint/types@8.65.0)))(prettier@3.9.6): + prettier-plugin-tailwindcss@0.8.1(prettier-plugin-svelte@4.1.1(prettier@3.9.6)(svelte@5.56.8(@typescript-eslint/types@8.65.0)))(prettier@3.9.6): dependencies: prettier: 3.9.6 optionalDependencies: - prettier-plugin-svelte: 4.1.1(prettier@3.9.6)(svelte@5.56.7(@typescript-eslint/types@8.65.0)) + prettier-plugin-svelte: 4.1.1(prettier@3.9.6)(svelte@5.56.8(@typescript-eslint/types@8.65.0)) prettier@3.9.6: {} - pretty-format@27.5.1: - dependencies: - ansi-regex: 5.0.1 - ansi-styles: 5.2.0 - react-is: 17.0.2 - promise-limit@2.7.0: {} property-expr@2.0.6: @@ -6478,17 +5613,10 @@ snapshots: pure-rand@6.1.0: optional: true - react-is@17.0.2: {} - - readable-stream@3.6.2: - dependencies: - inherits: 2.0.4 - string_decoder: 1.3.0 - util-deprecate: 1.0.2 - readdirp@4.1.2: {} - require-from-string@2.0.2: {} + require-from-string@2.0.2: + optional: true resolve-pkg-maps@1.0.0: {} @@ -6554,59 +5682,52 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.59.0 fsevents: 2.3.3 - runed@0.23.4(svelte@5.56.7(@typescript-eslint/types@8.65.0)): + runed@0.23.4(svelte@5.56.8(@typescript-eslint/types@8.65.0)): dependencies: esm-env: 1.2.2 - svelte: 5.56.7(@typescript-eslint/types@8.65.0) + svelte: 5.56.8(@typescript-eslint/types@8.65.0) - runed@0.25.0(svelte@5.56.7(@typescript-eslint/types@8.65.0)): + runed@0.25.0(svelte@5.56.8(@typescript-eslint/types@8.65.0)): dependencies: esm-env: 1.2.2 - svelte: 5.56.7(@typescript-eslint/types@8.65.0) + svelte: 5.56.8(@typescript-eslint/types@8.65.0) - runed@0.28.0(svelte@5.56.7(@typescript-eslint/types@8.65.0)): + runed@0.28.0(svelte@5.56.8(@typescript-eslint/types@8.65.0)): dependencies: esm-env: 1.2.2 - svelte: 5.56.7(@typescript-eslint/types@8.65.0) + svelte: 5.56.8(@typescript-eslint/types@8.65.0) - runed@0.35.1(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.7(@typescript-eslint/types@8.65.0)): + runed@0.35.1(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0)): dependencies: dequal: 2.0.3 esm-env: 1.2.2 lz-string: 1.5.0 - svelte: 5.56.7(@typescript-eslint/types@8.65.0) + svelte: 5.56.8(@typescript-eslint/types@8.65.0) optionalDependencies: - '@sveltejs/kit': 2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)) + '@sveltejs/kit': 2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)) - runed@0.37.1(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.7(@typescript-eslint/types@8.65.0))(zod@4.4.3): + runed@0.37.1(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0))(zod@4.4.3): dependencies: dequal: 2.0.3 esm-env: 1.2.2 lz-string: 1.5.0 - svelte: 5.56.7(@typescript-eslint/types@8.65.0) + svelte: 5.56.8(@typescript-eslint/types@8.65.0) optionalDependencies: - '@sveltejs/kit': 2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)) + '@sveltejs/kit': 2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)) zod: 4.4.3 rw@1.3.3: {} - rxjs@7.8.2: - dependencies: - tslib: 2.8.1 - sade@1.8.1: dependencies: mri: 1.2.0 - safe-buffer@5.2.1: {} - - safe-stable-stringify@2.5.0: {} - safer-buffer@2.1.2: {} saxes@6.0.0: dependencies: xmlchars: 2.2.0 + optional: true semver@7.7.4: {} @@ -6618,8 +5739,6 @@ snapshots: shebang-regex@3.0.0: {} - shell-quote@1.8.4: {} - siginfo@2.0.0: {} sirv@3.0.2: @@ -6642,28 +5761,10 @@ snapshots: '@sqlite.org/sqlite-wasm': 3.48.0-build4 kysely: 0.28.16 - stack-trace@0.0.10: {} - stackback@0.0.2: {} std-env@4.0.0: {} - streamsearch@1.1.0: {} - - string-width@7.2.0: - dependencies: - emoji-regex: 10.6.0 - get-east-asian-width: 1.6.0 - strip-ansi: 7.2.0 - - string_decoder@1.3.0: - dependencies: - safe-buffer: 5.2.1 - - strip-ansi@7.2.0: - dependencies: - ansi-regex: 6.2.2 - style-to-object@1.0.14: dependencies: inline-style-parser: 0.2.7 @@ -6671,7 +5772,8 @@ snapshots: superstruct@2.0.2: optional: true - supports-color@10.2.2: {} + supports-color@10.2.2: + optional: true supports-color@7.2.0: dependencies: @@ -6679,17 +5781,17 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - svelte-awesome-color-picker@4.1.3(svelte@5.56.7(@typescript-eslint/types@8.65.0)): + svelte-awesome-color-picker@4.1.3(svelte@5.56.8(@typescript-eslint/types@8.65.0)): dependencies: colord: 2.9.3 - svelte: 5.56.7(@typescript-eslint/types@8.65.0) - svelte-awesome-slider: 2.0.0(svelte@5.56.7(@typescript-eslint/types@8.65.0)) + svelte: 5.56.8(@typescript-eslint/types@8.65.0) + svelte-awesome-slider: 2.0.0(svelte@5.56.8(@typescript-eslint/types@8.65.0)) - svelte-awesome-slider@2.0.0(svelte@5.56.7(@typescript-eslint/types@8.65.0)): + svelte-awesome-slider@2.0.0(svelte@5.56.8(@typescript-eslint/types@8.65.0)): dependencies: - svelte: 5.56.7(@typescript-eslint/types@8.65.0) + svelte: 5.56.8(@typescript-eslint/types@8.65.0) - svelte-check@4.7.3(@typescript/typescript6@6.0.2)(picomatch@4.0.4)(svelte@5.56.7(@typescript-eslint/types@8.65.0)): + svelte-check@4.7.3(picomatch@4.0.4)(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3): dependencies: '@jridgewell/trace-mapping': 0.3.31 '@sveltejs/load-config': 0.2.0 @@ -6697,12 +5799,16 @@ snapshots: fdir: 6.5.0(picomatch@4.0.4) picocolors: 1.1.1 sade: 1.8.1 - svelte: 5.56.7(@typescript-eslint/types@8.65.0) - typescript: '@typescript/typescript6@6.0.2' + svelte: 5.56.8(@typescript-eslint/types@8.65.0) + typescript: 6.0.3 transitivePeerDependencies: - picomatch - svelte-eslint-parser@1.8.0(svelte@5.56.7(@typescript-eslint/types@8.65.0)): + svelte-dnd-action@0.9.74(svelte@5.56.8(@typescript-eslint/types@8.65.0)): + dependencies: + svelte: 5.56.8(@typescript-eslint/types@8.65.0) + + svelte-eslint-parser@1.8.0(svelte@5.56.8(@typescript-eslint/types@8.65.0)): dependencies: eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 @@ -6712,36 +5818,36 @@ snapshots: postcss-selector-parser: 7.1.1 semver: 7.7.4 optionalDependencies: - svelte: 5.56.7(@typescript-eslint/types@8.65.0) + svelte: 5.56.8(@typescript-eslint/types@8.65.0) - svelte-sonner@1.1.1(svelte@5.56.7(@typescript-eslint/types@8.65.0)): + svelte-sonner@1.1.1(svelte@5.56.8(@typescript-eslint/types@8.65.0)): dependencies: - runed: 0.28.0(svelte@5.56.7(@typescript-eslint/types@8.65.0)) - svelte: 5.56.7(@typescript-eslint/types@8.65.0) + runed: 0.28.0(svelte@5.56.8(@typescript-eslint/types@8.65.0)) + svelte: 5.56.8(@typescript-eslint/types@8.65.0) - svelte-toolbelt@0.10.6(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.7(@typescript-eslint/types@8.65.0)): + svelte-toolbelt@0.10.6(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0)): dependencies: clsx: 2.1.1 - runed: 0.35.1(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.7(@typescript-eslint/types@8.65.0)) + runed: 0.35.1(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0)) style-to-object: 1.0.14 - svelte: 5.56.7(@typescript-eslint/types@8.65.0) + svelte: 5.56.8(@typescript-eslint/types@8.65.0) transitivePeerDependencies: - '@sveltejs/kit' - svelte-toolbelt@0.5.0(svelte@5.56.7(@typescript-eslint/types@8.65.0)): + svelte-toolbelt@0.5.0(svelte@5.56.8(@typescript-eslint/types@8.65.0)): dependencies: clsx: 2.1.1 style-to-object: 1.0.14 - svelte: 5.56.7(@typescript-eslint/types@8.65.0) + svelte: 5.56.8(@typescript-eslint/types@8.65.0) - svelte-toolbelt@0.7.1(svelte@5.56.7(@typescript-eslint/types@8.65.0)): + svelte-toolbelt@0.7.1(svelte@5.56.8(@typescript-eslint/types@8.65.0)): dependencies: clsx: 2.1.1 - runed: 0.23.4(svelte@5.56.7(@typescript-eslint/types@8.65.0)) + runed: 0.23.4(svelte@5.56.8(@typescript-eslint/types@8.65.0)) style-to-object: 1.0.14 - svelte: 5.56.7(@typescript-eslint/types@8.65.0) + svelte: 5.56.8(@typescript-eslint/types@8.65.0) - svelte@5.56.7(@typescript-eslint/types@8.65.0): + svelte@5.56.8(@typescript-eslint/types@8.65.0): dependencies: '@jridgewell/remapping': 2.3.5 '@jridgewell/sourcemap-codec': 1.5.5 @@ -6762,18 +5868,18 @@ snapshots: transitivePeerDependencies: - '@typescript-eslint/types' - sveltekit-superforms@2.30.2(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@types/json-schema@7.0.15)(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0)): + sveltekit-superforms@2.30.2(@sveltejs/kit@2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@types/json-schema@7.0.15)(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3): dependencies: - '@sveltejs/kit': 2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(@typescript/typescript6@6.0.2)(svelte@5.56.7(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)) + '@sveltejs/kit': 2.70.1(@sveltejs/vite-plugin-svelte@7.2.0(svelte@5.56.8(@typescript-eslint/types@8.65.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)))(svelte@5.56.8(@typescript-eslint/types@8.65.0))(typescript@6.0.3)(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)) devalue: 5.8.1 memoize-weak: 1.0.2 - svelte: 5.56.7(@typescript-eslint/types@8.65.0) + svelte: 5.56.8(@typescript-eslint/types@8.65.0) ts-deepmerge: 8.0.0 optionalDependencies: '@exodus/schemasafe': 1.3.0 '@standard-schema/spec': 1.1.0 '@typeschema/class-validator': 0.3.0(@types/json-schema@7.0.15)(class-validator@0.14.4) - '@valibot/to-json-schema': 1.7.1(valibot@1.4.2(@typescript/typescript6@6.0.2)) + '@valibot/to-json-schema': 1.7.1(valibot@1.4.2(typescript@6.0.3)) '@vinejs/vine': 3.0.1 arktype: 2.2.3 class-validator: 0.14.4 @@ -6782,7 +5888,7 @@ snapshots: json-schema-to-ts: 3.1.1 superstruct: 2.0.2 typebox: 1.3.6 - valibot: 1.4.2(@typescript/typescript6@6.0.2) + valibot: 1.4.2(typescript@6.0.3) yup: 1.7.1 zod: 4.4.3 zod-v3-to-json-schema: 4.0.0(zod@4.4.3) @@ -6790,24 +5896,22 @@ snapshots: - '@types/json-schema' - typescript - symbol-tree@3.2.4: {} + symbol-tree@3.2.4: + optional: true tabbable@6.4.0: {} tailwind-merge@3.6.0: {} - tailwind-variants@3.2.2(tailwind-merge@3.6.0)(tailwindcss@4.3.3): - dependencies: - tailwindcss: 4.3.3 + tailwind-variants@3.3.0(tailwind-merge@3.6.0)(tailwindcss@4.3.3): optionalDependencies: tailwind-merge: 3.6.0 + tailwindcss: 4.3.3 tailwindcss@4.3.3: {} tapable@2.3.3: {} - text-hex@1.0.0: {} - tiny-case@1.0.3: optional: true @@ -6829,35 +5933,35 @@ snapshots: tinyrainbow@3.1.0: {} - tldts-core@7.0.26: {} + tldts-core@7.0.26: + optional: true tldts@7.0.26: dependencies: tldts-core: 7.0.26 + optional: true toposort@2.0.2: optional: true totalist@3.0.1: {} - tough-cookie@6.0.1: + tough-cookie@6.0.2: dependencies: tldts: 7.0.26 + optional: true tr46@6.0.0: dependencies: punycode: 2.3.1 - - tree-kill@1.2.2: {} - - triple-beam@1.4.1: {} + optional: true ts-algebra@2.0.0: optional: true - ts-api-utils@2.5.0(@typescript/typescript6@6.0.2): + ts-api-utils@2.5.0(typescript@6.0.3): dependencies: - typescript: '@typescript/typescript6@6.0.2' + typescript: 6.0.3 ts-deepmerge@8.0.0: {} @@ -6878,46 +5982,17 @@ snapshots: type-fest@2.19.0: optional: true - type-is@1.6.18: - dependencies: - media-typer: 0.3.0 - mime-types: 2.1.35 - typebox@1.3.6: optional: true - typedarray@0.0.6: {} - typescript@6.0.3: {} - typescript@7.0.2: - optionalDependencies: - '@typescript/typescript-aix-ppc64': 7.0.2 - '@typescript/typescript-darwin-arm64': 7.0.2 - '@typescript/typescript-darwin-x64': 7.0.2 - '@typescript/typescript-freebsd-arm64': 7.0.2 - '@typescript/typescript-freebsd-x64': 7.0.2 - '@typescript/typescript-linux-arm': 7.0.2 - '@typescript/typescript-linux-arm64': 7.0.2 - '@typescript/typescript-linux-loong64': 7.0.2 - '@typescript/typescript-linux-mips64el': 7.0.2 - '@typescript/typescript-linux-ppc64': 7.0.2 - '@typescript/typescript-linux-riscv64': 7.0.2 - '@typescript/typescript-linux-s390x': 7.0.2 - '@typescript/typescript-linux-x64': 7.0.2 - '@typescript/typescript-netbsd-arm64': 7.0.2 - '@typescript/typescript-netbsd-x64': 7.0.2 - '@typescript/typescript-openbsd-arm64': 7.0.2 - '@typescript/typescript-openbsd-x64': 7.0.2 - '@typescript/typescript-sunos-x64': 7.0.2 - '@typescript/typescript-win32-arm64': 7.0.2 - '@typescript/typescript-win32-x64': 7.0.2 - undici-types@7.24.6: {} undici-types@8.3.0: {} - undici@7.25.0: {} + undici@8.9.0: + optional: true unicode-properties@1.4.1: dependencies: @@ -6946,16 +6021,14 @@ snapshots: uuid@14.0.0: {} - valibot@1.4.2(@typescript/typescript6@6.0.2): + valibot@1.4.2(typescript@6.0.3): optionalDependencies: - typescript: '@typescript/typescript6@6.0.2' + typescript: 6.0.3 optional: true validator@13.15.26: optional: true - vary@1.1.2: {} - vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1): dependencies: lightningcss: 1.32.0 @@ -6974,7 +6047,7 @@ snapshots: optionalDependencies: vite: 8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1) - vitest@4.1.10(@types/node@26.1.1)(@vitest/coverage-v8@4.1.10)(jsdom@29.1.1(@noble/hashes@1.8.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)): + vitest@4.1.10(@types/node@26.1.1)(@vitest/coverage-v8@4.1.10)(jsdom@30.0.0(@noble/hashes@1.8.0))(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)): dependencies: '@vitest/expect': 4.1.10 '@vitest/mocker': 4.1.10(vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.23.1)) @@ -6999,19 +6072,22 @@ snapshots: optionalDependencies: '@types/node': 26.1.1 '@vitest/coverage-v8': 4.1.10(vitest@4.1.10) - jsdom: 29.1.1(@noble/hashes@1.8.0) + jsdom: 30.0.0(@noble/hashes@1.8.0) transitivePeerDependencies: - msw w3c-xmlserializer@5.0.0: dependencies: xml-name-validator: 5.0.0 + optional: true - webidl-conversions@8.0.1: {} + webidl-conversions@8.0.1: + optional: true webpack-virtual-modules@0.6.2: {} - whatwg-mimetype@5.0.0: {} + whatwg-mimetype@5.0.0: + optional: true whatwg-url@16.0.1(@noble/hashes@1.8.0): dependencies: @@ -7020,6 +6096,16 @@ snapshots: webidl-conversions: 8.0.1 transitivePeerDependencies: - '@noble/hashes' + optional: true + + whatwg-url@17.1.0(@noble/hashes@1.8.0): + dependencies: + '@exodus/bytes': 1.15.1(@noble/hashes@1.8.0) + tr46: 6.0.0 + webidl-conversions: 8.0.1 + transitivePeerDependencies: + - '@noble/hashes' + optional: true which@2.0.2: dependencies: @@ -7030,55 +6116,18 @@ snapshots: siginfo: 2.0.0 stackback: 0.0.2 - winston-transport@4.9.0: - dependencies: - logform: 2.7.0 - readable-stream: 3.6.2 - triple-beam: 1.4.1 - - winston@3.19.0: - dependencies: - '@colors/colors': 1.6.0 - '@dabh/diagnostics': 2.0.8 - async: 3.2.6 - is-stream: 2.0.1 - logform: 2.7.0 - one-time: 1.0.0 - readable-stream: 3.6.2 - safe-stable-stringify: 2.5.0 - stack-trace: 0.0.10 - triple-beam: 1.4.1 - winston-transport: 4.9.0 - word-wrap@1.2.5: {} - wrap-ansi@9.0.2: - dependencies: - ansi-styles: 6.2.3 - string-width: 7.2.0 - strip-ansi: 7.2.0 - ws@8.19.0: {} - xml-name-validator@5.0.0: {} - - xmlchars@2.2.0: {} + xml-name-validator@5.0.0: + optional: true - y18n@5.0.8: {} + xmlchars@2.2.0: + optional: true yaml@1.10.2: {} - yargs-parser@22.0.0: {} - - yargs@18.0.0: - dependencies: - cliui: 9.0.1 - escalade: 3.2.0 - get-caller-file: 2.0.5 - string-width: 7.2.0 - y18n: 5.0.8 - yargs-parser: 22.0.0 - yocto-queue@0.1.0: {} yup@1.7.1: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 774f5869..45e844bd 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,10 +1,10 @@ allowBuilds: bcrypt: true esbuild: true + better-sqlite3: true + sqlite3: true minimumReleaseAgeExclude: - helmet@8.3.0 -onlyBuiltDependencies: - - bcrypt - - better-sqlite3 - - esbuild - - sqlite3 + - globals@17.8.0 + - jsdom@30.0.0 + - tailwind-variants@3.3.0 diff --git a/skills-lock.json b/skills-lock.json new file mode 100644 index 00000000..abe05c72 --- /dev/null +++ b/skills-lock.json @@ -0,0 +1,11 @@ +{ + "version": 1, + "skills": { + "shadcn-svelte": { + "source": "huntabyte/shadcn-svelte", + "sourceType": "github", + "skillPath": "skills/shadcn-svelte/SKILL.md", + "computedHash": "d4f3f983a71466a86649985a8a7fbce47da29f44de3a9d02540bbcf3167134e0" + } + } +} diff --git a/src/__tests__/file-upload-response.test.ts b/src/__tests__/file-upload-response.test.ts new file mode 100644 index 00000000..32cdd7de --- /dev/null +++ b/src/__tests__/file-upload-response.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, it, vi } from 'vitest'; + +vi.mock('fs/promises', () => ({ writeFile: vi.fn().mockResolvedValue(undefined) })); + +import { POST } from '../routes/api/files/+server'; + +describe('POST /api/files', () => { + it('returns the filename where uploadFile() reads it (res.data.filename)', async () => { + const body = new FormData(); + body.append('file', new File(['x'], 'car.png', { type: 'image/png' })); + + const response = await POST({ + request: new Request('http://localhost/api/files', { method: 'POST', body }) + } as Parameters[0]); + + const payload = await response.json(); + expect(payload.data.filename).toMatch(/car\.png$/); + }); +}); diff --git a/src/__tests__/grid-layout.test.ts b/src/__tests__/grid-layout.test.ts new file mode 100644 index 00000000..32dcf22e --- /dev/null +++ b/src/__tests__/grid-layout.test.ts @@ -0,0 +1,122 @@ +import { describe, expect, it } from 'vitest'; +import { + compactLayout, + moveElement, + resizeElement, + type GridItem +} from '$lib/components/dashboard/grid-layout'; +import { WIDGET_REGISTRY } from '$lib/components/dashboard/widget-registry'; +import { DEFAULT_WIDGET_LAYOUT, widgetMinSize } from '$lib/domain/dashboard'; + +function item(id: string, colStart: number, rowStart: number, colSpan = 6, rowSpan = 4): GridItem { + return { id, colStart, rowStart, colSpan, rowSpan }; +} + +function positions(items: GridItem[]): Record { + return Object.fromEntries(items.map((i) => [i.id, [i.colStart, i.rowStart]])); +} + +describe('compactLayout', () => { + it('pulls items up to close vertical gaps', () => { + const items = [item('a', 1, 1), item('b', 1, 20)]; + expect(positions(compactLayout(items))).toEqual({ a: [1, 1], b: [1, 5] }); + }); + + it('leaves items in separate columns at the top', () => { + const items = [item('a', 1, 1), item('b', 7, 9)]; + expect(positions(compactLayout(items))).toEqual({ a: [1, 1], b: [7, 1] }); + }); + + it('separates items that arrive overlapping', () => { + const items = [item('a', 1, 1), item('b', 1, 1)]; + const packed = compactLayout(items); + expect(packed.find((i) => i.id === 'b')!.rowStart).toBe(5); + }); +}); + +describe('moveElement', () => { + it('swaps with the widget below instead of pushing it further down', () => { + // The old compactor pinned the dragged widget then repacked everything else beneath it, so + // dragging 'a' down shoved 'b' — which was already below — down again instead of swapping. + const items = [item('a', 1, 1), item('b', 1, 5)]; + expect(positions(moveElement(items, 'a', 1, 5))).toEqual({ a: [1, 5], b: [1, 1] }); + }); + + it('swaps with the widget above when dragging up', () => { + const items = [item('a', 1, 1), item('b', 1, 5)]; + expect(positions(moveElement(items, 'b', 1, 1))).toEqual({ a: [1, 5], b: [1, 1] }); + }); + + it('ignores a nudge too small to clear the neighbour', () => { + const items = [item('a', 1, 1), item('b', 1, 5)]; + expect(positions(moveElement(items, 'a', 1, 3))).toEqual({ a: [1, 1], b: [1, 5] }); + }); + + it('leaves untouched columns alone', () => { + const items = [item('a', 1, 1), item('b', 7, 1), item('c', 1, 5)]; + expect(positions(moveElement(items, 'a', 1, 5))).toEqual({ + a: [1, 5], + b: [7, 1], + c: [1, 1] + }); + }); + + it('cascades displaced widgets down without dropping any', () => { + const items = [item('a', 1, 1), item('b', 1, 5), item('c', 1, 9), item('d', 1, 13)]; + const moved = moveElement(items, 'd', 1, 1); + const rows = moved.map((i) => i.rowStart).sort((x, y) => x - y); + expect(rows).toEqual([1, 5, 9, 13]); + expect(moved.find((i) => i.id === 'd')!.rowStart).toBe(1); + }); + + it('clamps a widget dragged past the right edge', () => { + const items = [item('a', 1, 1)]; + expect(moveElement(items, 'a', 99, 1)[0].colStart).toBe(7); + }); +}); + +describe('resizeElement', () => { + it('pushes the widget below down rather than lifting it above', () => { + const items = [item('a', 1, 1), item('b', 1, 5)]; + expect(positions(resizeElement(items, 'a', 6, 8))).toEqual({ a: [1, 1], b: [1, 9] }); + }); + + it('pulls neighbours back up when a widget shrinks', () => { + const items = [item('a', 1, 1, 6, 8), item('b', 1, 9)]; + expect(positions(resizeElement(items, 'a', 6, 4))).toEqual({ a: [1, 1], b: [1, 5] }); + }); + + it('clamps growth to the columns remaining to the right', () => { + const items = [item('a', 7, 1)]; + expect(resizeElement(items, 'a', 12, 4)[0].colSpan).toBe(6); + }); + + it('refuses to shrink a widget below its own minimum', () => { + const items = [item('a', 1, 1)]; + const resized = resizeElement(items, 'a', 1, 1, { minColSpan: 3, minRowSpan: 2 })[0]; + expect([resized.colSpan, resized.rowSpan]).toEqual([3, 2]); + }); + + it('lets the grid edge win over a minimum that cannot fit', () => { + const items = [item('a', 11, 1, 2, 4)]; + expect(resizeElement(items, 'a', 1, 4, { minColSpan: 6, minRowSpan: 1 })[0].colSpan).toBe(2); + }); +}); + +describe('widgetMinSize', () => { + it('keeps every registry default at or above its widget minimum', () => { + for (const def of Object.values(WIDGET_REGISTRY)) { + const { minColSpan, minRowSpan } = widgetMinSize(def.type); + expect(def.defaultColSpan).toBeGreaterThanOrEqual(minColSpan); + expect(def.defaultRowSpan).toBeGreaterThanOrEqual(minRowSpan); + } + }); + + it('ships a default layout that already satisfies the minimums', () => { + for (const layoutItem of DEFAULT_WIDGET_LAYOUT) { + const { minColSpan, minRowSpan } = widgetMinSize(layoutItem.type); + expect(layoutItem.colSpan).toBeGreaterThanOrEqual(minColSpan); + expect(layoutItem.rowSpan).toBeGreaterThanOrEqual(minRowSpan); + } + }); +}); diff --git a/src/__tests__/index.test.ts b/src/__tests__/index.test.ts deleted file mode 100644 index cf0f0739..00000000 --- a/src/__tests__/index.test.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { describe, expect, it } from 'vitest'; - -describe('test', () => { - it('test', () => { - expect(true).toBe(true); - }); -}); diff --git a/src/hooks.server.ts b/src/hooks.server.ts index 13dba86b..3f80bda6 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -1,30 +1,17 @@ import { sequence } from '@sveltejs/kit/hooks'; import { paraglideMiddleware } from '$lib/paraglide/server'; import type { Handle, HandleServerError } from '@sveltejs/kit'; -import { createErrorResponseBody, logError } from './server/utils/errorHandler'; -import { - CorsMiddleware, - RateLimitMiddleware, - AuthMiddleware, - LoggingMiddleware -} from '$server/middlewares'; - -import { MiddlewareChain } from '$server/middlewares/base'; +import { handleCors } from '$server/middlewares/cors'; +import { handleAuth } from '$server/middlewares/auth'; +import { handleLogging } from '$server/middlewares/logging'; import { initializeDatabase } from '$server/db/init'; import { appAsciiArt, appVersion, logger } from '$server/config'; import { env } from '$lib/config/env.server'; +import { getTextDirection } from '$lib/utils'; import { ensureAppDirectories } from '$server/utils/fs'; import { initializeNotificationScheduler } from '$server/services/notificationSchedulerService'; -const middlewareChain = new MiddlewareChain(); -middlewareChain.init([ - new CorsMiddleware(), - new AuthMiddleware(), - new RateLimitMiddleware(), - new LoggingMiddleware() -]); - const envSnapshot = () => ({ APP_VERSION: appVersion, LOG_LEVEL: env.LOG_LEVEL, @@ -90,27 +77,15 @@ const initPromise = (async () => { })(); export const handleError: HandleServerError = async ({ error, event }) => { - logError(error, event); + logger.error(`Error in ${event.request.method} - ${event.url.pathname}`, error); - const body = createErrorResponseBody(error); - - return { message: body.error.message || 'Internal server error' }; + return { message: error instanceof Error ? error.message : 'Internal server error' }; }; -const originalHandle: Handle = async ({ event, resolve }) => { +const handleInit: Handle = async ({ event, resolve }) => { await initPromise; - const middlewareResult = await middlewareChain.handle(event); - - if (middlewareResult.response) { - return middlewareResult.response; - } - - const response = await resolve(event); - - CorsMiddleware.addCorsHeaders(response, event.request); - - return response; + return resolve(event); }; const handleParaglide: Handle = ({ event, resolve }) => @@ -118,15 +93,11 @@ const handleParaglide: Handle = ({ event, resolve }) => event.request = request; return resolve(event, { - transformPageChunk: ({ html }) => { - // Set language and direction attributes based on locale - const rtlLanguages = ['ar', 'he', 'fa', 'ur', 'yi']; - const direction = rtlLanguages.includes(locale) ? 'rtl' : 'ltr'; - return html + transformPageChunk: ({ html }) => + html .replace('%paraglide.lang%', locale) - .replace('dir="%paraglide.lang%"', `dir="${direction}"`); - } + .replace('dir="%paraglide.lang%"', `dir="${getTextDirection(locale)}"`) }); }); -export const handle = sequence(originalHandle, handleParaglide); +export const handle = sequence(handleInit, handleCors, handleAuth, handleLogging, handleParaglide); diff --git a/src/lib/components/app/AttachmentPreview.svelte b/src/lib/components/app/AttachmentPreview.svelte new file mode 100644 index 00000000..685a4b54 --- /dev/null +++ b/src/lib/components/app/AttachmentPreview.svelte @@ -0,0 +1,63 @@ + + +
+ {#if isImage} +
+ {#if !loaded} + + {/if} + {fileName} (loaded = true)} + /> +
+ {:else if isPdf} +
+ {#if !loaded} + + {/if} + +
+ {:else} +
+ +

{m.file_preview_not_available()}

+
+ {/if} +
+ {fileName} + +
+
diff --git a/src/lib/components/app/ChartPoints.svelte b/src/lib/components/app/ChartPoints.svelte new file mode 100644 index 00000000..6bc7e2d4 --- /dev/null +++ b/src/lib/components/app/ChartPoints.svelte @@ -0,0 +1,25 @@ + + + + + diff --git a/src/lib/components/app/CrudActionsMenu.svelte b/src/lib/components/app/CrudActionsMenu.svelte index 8266fd66..c9e5a3d9 100644 --- a/src/lib/components/app/CrudActionsMenu.svelte +++ b/src/lib/components/app/CrudActionsMenu.svelte @@ -53,7 +53,7 @@ ]); -
+
e.stopPropagation()}> ; titleClass?: string; class?: string; + /** Shown as a small pill next to the title — used for the vehicle badge in fleet scope. */ + subtitle?: string; headerExtras?: Snippet; actions?: Snippet; children?: Snippet; @@ -19,6 +21,7 @@ titleIcon: TitleIcon, titleClass = '', class: className = '', + subtitle, headerExtras, actions, children @@ -32,6 +35,13 @@ {title}
+ {#if subtitle} + + {subtitle} + + {/if} {@render headerExtras?.()}
{@render actions?.()} diff --git a/src/lib/components/app/FeatureTabShell.svelte b/src/lib/components/app/FeatureTabShell.svelte index 52d95f17..7e2f5c15 100644 --- a/src/lib/components/app/FeatureTabShell.svelte +++ b/src/lib/components/app/FeatureTabShell.svelte @@ -2,7 +2,6 @@ import type { Component } from 'svelte'; import TabContainer from '$appui/TabContainer.svelte'; import { sheetStore } from '$lib/stores/sheet.svelte'; - import { vehicleStore } from '$lib/stores/vehicle.svelte'; type SheetDataResolver = () => unknown; type AnyComponent = Component; @@ -57,8 +56,7 @@ ) : null} {exportAction} - exportActionDisabled={exportActionDisabled || !vehicleStore.selectedId} - addActionDisabled={!vehicleStore.selectedId} + {exportActionDisabled} > diff --git a/src/lib/components/app/StoreResourceState.svelte b/src/lib/components/app/StoreResourceState.svelte index a52ac7fe..f2a33b27 100644 --- a/src/lib/components/app/StoreResourceState.svelte +++ b/src/lib/components/app/StoreResourceState.svelte @@ -8,18 +8,29 @@ emptyMessage: string; children?: import('svelte').Snippet; skeleton?: import('svelte').Snippet; + /** Rendered above the skeleton/error/empty states only — `children` is expected to carry its own actions. */ + actions?: import('svelte').Snippet; } - let { processing, error, data, emptyMessage, children, skeleton }: Props = $props(); + let { processing, error, data, emptyMessage, children, skeleton, actions }: Props = $props(); {#if processing} + {#if actions} +
{@render actions()}
+ {/if} {#if skeleton} {@render skeleton()} {/if} {:else if error} + {#if actions} +
{@render actions()}
+ {/if} {:else if !data || data.length === 0} + {#if actions} +
{@render actions()}
+ {/if} {:else} {@render children?.()} diff --git a/src/lib/components/dashboard/ActivityFeed.svelte b/src/lib/components/dashboard/ActivityFeed.svelte new file mode 100644 index 00000000..4327f354 --- /dev/null +++ b/src/lib/components/dashboard/ActivityFeed.svelte @@ -0,0 +1,60 @@ + + +{#if loading} +
+ {#each [0, 1, 2, 3] as i (i)} +
+ + + +
+ {/each} +
+{:else if entries.length === 0} +
+ No recent activity +
+{:else} +
+ {#each entries as entry (entry.id)} +
+ {#if entry.type === 'fuel'} + + + + {:else} + + + + {/if} +
+

{entry.vehicleName}

+

+ {entry.description} · {formatDate(entry.date)} +

+
+ {formatCurrency(entry.cost)} +
+ {/each} +
+{/if} diff --git a/src/lib/components/dashboard/CtaBanner.svelte b/src/lib/components/dashboard/CtaBanner.svelte new file mode 100644 index 00000000..dadf02c1 --- /dev/null +++ b/src/lib/components/dashboard/CtaBanner.svelte @@ -0,0 +1,30 @@ + + +
+
+
+

{heading}

+

{description}

+
+ +
diff --git a/src/lib/components/dashboard/DashboardGrid.svelte b/src/lib/components/dashboard/DashboardGrid.svelte new file mode 100644 index 00000000..9f69000f --- /dev/null +++ b/src/lib/components/dashboard/DashboardGrid.svelte @@ -0,0 +1,104 @@ + + +
+ + {#if placeholder && placeholderRect && interaction.enabled} +
+
+ {/if} + + {#each interaction.items as item (item.id)} + {@render children(item)} + {/each} +
+ + diff --git a/src/lib/components/dashboard/DonutChart.svelte b/src/lib/components/dashboard/DonutChart.svelte new file mode 100644 index 00000000..6b9ce786 --- /dev/null +++ b/src/lib/components/dashboard/DonutChart.svelte @@ -0,0 +1,247 @@ + + +{#snippet centerContent()} + {#if centerLabel} +
+ {centerLabel} + {centerValueFormatter(total)} +
+ {/if} +{/snippet} + +
+ {#if title} +
+ {title} +
+ {/if} + + {#if loading} +
+
+ +
+
+ {#each [0, 1, 2] as i (i)} +
+ + +
+ {/each} +
+
+ {:else if data.length === 0} +
+ No data available +
+ {:else if data.length === 1} + {@const size = ringSize} + {@const strokeWidth = size * 0.2} + {@const radius = (size - strokeWidth) / 2} + +
+ + + + {@render centerContent()} +
+ + {#if showLegend} +
+ {#each itemsWithPercent as item (item.name)} +
+ + {item.name} + {item.percentage}% + + {item.value.toLocaleString()} + +
+ {/each} +
+ {/if} + {:else} +
+
+ + d.color} + {innerRadius} + padAngle={0.02} + cornerRadius={4} + > + {#snippet tooltip()} + + {#snippet formatter({ value, name })} + {@const pct = + total > 0 && typeof value === 'number' + ? roundToDec((value / total) * 100, 1) + : 0} + {name} + + {typeof value === 'number' ? value.toLocaleString() : value} ({pct}%) + + {/snippet} + + {/snippet} + + + {@render centerContent()} +
+ + {#if showLegend && itemsWithPercent.length > 0} +
+ {#each itemsWithPercent as item (item.name)} +
+ + {item.name} + {item.percentage}% + + {item.value.toLocaleString()} + +
+ {/each} +
+ {/if} +
+ {/if} +
diff --git a/src/lib/components/dashboard/FilterTabs.svelte b/src/lib/components/dashboard/FilterTabs.svelte new file mode 100644 index 00000000..1b2551aa --- /dev/null +++ b/src/lib/components/dashboard/FilterTabs.svelte @@ -0,0 +1,18 @@ + + + + + {#each tabs as tab (tab.id)} + {tab.label} + {/each} + + diff --git a/src/lib/components/dashboard/PageHeader.svelte b/src/lib/components/dashboard/PageHeader.svelte new file mode 100644 index 00000000..79b20df4 --- /dev/null +++ b/src/lib/components/dashboard/PageHeader.svelte @@ -0,0 +1,25 @@ + + +
+
+

{title}

+ {#if description} +

{description}

+ {/if} +
+ {#if children} +
+ {@render children()} +
+ {/if} +
diff --git a/src/lib/components/dashboard/ProgressRing.svelte b/src/lib/components/dashboard/ProgressRing.svelte new file mode 100644 index 00000000..9628cff7 --- /dev/null +++ b/src/lib/components/dashboard/ProgressRing.svelte @@ -0,0 +1,88 @@ + + +
+ + + + + + + + + + {#if children} +
+ {@render children()} +
+ {:else if showLabel} +
+ + {Math.round(value)}% + + {#if label} + + {label} + + {/if} +
+ {/if} +
diff --git a/src/lib/components/dashboard/StackedAreaChart.svelte b/src/lib/components/dashboard/StackedAreaChart.svelte new file mode 100644 index 00000000..d8564e34 --- /dev/null +++ b/src/lib/components/dashboard/StackedAreaChart.svelte @@ -0,0 +1,136 @@ + + +
+
+ {#if !bare} + {title} + {/if} +
+ {#each SERIES as s (s.key)} + + + {s.label} + + {/each} +
+
+ {#if loading} +
+
+ {#each [40, 65, 45, 80, 55, 70, 50, 85, 60, 75] as height, i (i)} + + {/each} +
+ +
+ {:else if hasData} + + ({ key: s.key, label: s.label, color: s.color }))} + seriesLayout="stack" + axis + props={chartProps} + > + {#snippet tooltip()} + + v.toLocaleDateString('en-IN', { month: 'long', year: 'numeric' })} + indicator="dot" + > + {#snippet formatter({ value, name })} + {name} + + {typeof value === 'number' ? `$${value.toFixed(2)}` : value} + + {/snippet} + + {/snippet} + {#snippet marks({ context }: { context: any })} + {#each context.series.visibleSeries as s (s.key)} + + + {/each} + {/snippet} + + + {:else} +
+ +
+ {/if} +
diff --git a/src/lib/components/dashboard/StatCard.svelte b/src/lib/components/dashboard/StatCard.svelte new file mode 100644 index 00000000..5e084cd8 --- /dev/null +++ b/src/lib/components/dashboard/StatCard.svelte @@ -0,0 +1,85 @@ + + +{#snippet trendBadge()} + {#if trend} + + {trendIcon} + {trend.value} + + {/if} +{/snippet} + +{#if bare} + +
+ {value} + {@render trendBadge()} +
+{:else} +
+ {#if Icon} +
+ +
+ {/if} + +
+ {label} + {value} + {@render trendBadge()} +
+
+{/if} diff --git a/src/lib/components/dashboard/StatusPill.svelte b/src/lib/components/dashboard/StatusPill.svelte new file mode 100644 index 00000000..7a47afc3 --- /dev/null +++ b/src/lib/components/dashboard/StatusPill.svelte @@ -0,0 +1,62 @@ + + + + {displayLabel} + diff --git a/src/lib/components/dashboard/VehicleLeaderboard.svelte b/src/lib/components/dashboard/VehicleLeaderboard.svelte new file mode 100644 index 00000000..a1e7df1e --- /dev/null +++ b/src/lib/components/dashboard/VehicleLeaderboard.svelte @@ -0,0 +1,70 @@ + + +{#if loading} +
+ {#each [0, 1, 2, 3] as i (i)} +
+ + + +
+ {/each} +
+{:else if entries.length === 0} +
+ {emptyLabel} +
+{:else} +
+ {#each entries as entry, i (entry.id)} +
+ + {i + 1} + +
+

{entry.name}

+ {#if entry.plate} +

{entry.plate}

+ {/if} +
+ {entry.formattedValue} +
+ {/each} +
+{/if} diff --git a/src/lib/components/dashboard/WidgetCard.svelte b/src/lib/components/dashboard/WidgetCard.svelte new file mode 100644 index 00000000..9645e23c --- /dev/null +++ b/src/lib/components/dashboard/WidgetCard.svelte @@ -0,0 +1,229 @@ + + +
+ {#if Icon} + +
+
+ +
+ +
+

+ {title} +

+ {@render children()} +
+
+ {:else} + +
+

+ {title} +

+
+ +
+ {@render children()} +
+ {/if} + + + + + +
+ + diff --git a/src/lib/components/dashboard/grid-interaction.svelte.ts b/src/lib/components/dashboard/grid-interaction.svelte.ts new file mode 100644 index 00000000..c20dcd63 --- /dev/null +++ b/src/lib/components/dashboard/grid-interaction.svelte.ts @@ -0,0 +1,319 @@ +import { getContext, setContext } from 'svelte'; +import { + GRID_COLUMNS, + GRID_MAX_ROW_SPAN, + widgetMinSize, + type WidgetLayoutItem, + type WidgetMinSize +} from '$lib/domain/dashboard'; +import { clamp, ROW_UNIT_PX } from './widget-size'; +import { moveElement, resizeElement, type GridRect } from './grid-layout'; + +type GridMode = 'move' | 'resize'; + +/** Pixel geometry of the widget being dragged, relative to the grid's padding box. */ +interface FloatRect { + left: number; + top: number; + width: number; + height: number; +} + +/** Rendered track geometry: `pitch` is one track plus one gap, i.e. the distance between track starts. */ +interface GridMetrics { + colPitch: number; + colGap: number; + rowPitch: number; + rowGap: number; +} + +const EDGE_SCROLL_ZONE_PX = 80; +const EDGE_SCROLL_MAX_PX = 22; + +function readMetrics(grid: HTMLElement): GridMetrics { + const style = getComputedStyle(grid); + const columns = style.gridTemplateColumns + .split(' ') + .map(parseFloat) + .filter((width) => !Number.isNaN(width)); + const colGap = parseFloat(style.columnGap) || 0; + const rowGap = parseFloat(style.rowGap) || 0; + + return { + colGap, + rowGap, + colPitch: (columns[0] ?? grid.clientWidth / GRID_COLUMNS) + colGap, + rowPitch: ROW_UNIT_PX + rowGap + }; +} + +function findScroller(el: HTMLElement | undefined): HTMLElement { + const fallback = (document.scrollingElement as HTMLElement | null) ?? document.documentElement; + for (let node = el?.parentElement; node; node = node.parentElement) { + const overflowY = getComputedStyle(node).overflowY; + if ((overflowY === 'auto' || overflowY === 'scroll') && node.scrollHeight > node.clientHeight) { + return node; + } + } + return fallback; +} + +/** + * Drives pointer-driven move/resize for a widget grid. The widget being manipulated follows the + * pointer in raw pixels while a snapped `draft` layout is recomputed from the committed layout on + * every frame — the dragged item's rect within that draft is the dotted placeholder. Nothing reaches + * the store until the pointer is released, so the live layout never churns mid-gesture. + */ +export class GridInteraction { + #getItems: () => WidgetLayoutItem[]; + #commit: (items: WidgetLayoutItem[]) => void; + + gridEl = $state(); + /** Pointer interaction only applies at the 12-column breakpoint; below it the grid stacks. */ + enabled = $state(false); + + draft = $state(null); + activeId = $state(null); + mode = $state(null); + float = $state(null); + /** Track sizes captured at gesture start; also lets the placeholder be drawn in pixels. */ + metrics = $state(null); + + constructor(getItems: () => WidgetLayoutItem[], commit: (items: WidgetLayoutItem[]) => void) { + this.#getItems = getItems; + this.#commit = commit; + } + + #minSize(item: WidgetLayoutItem): WidgetMinSize { + return widgetMinSize(item.type); + } + + /** Layout to render: the in-flight draft while dragging, otherwise the committed layout. */ + get items(): WidgetLayoutItem[] { + return this.draft ?? this.#getItems(); + } + + get placeholder(): GridRect | null { + if (!this.activeId || !this.draft) return null; + return this.draft.find((item) => item.id === this.activeId) ?? null; + } + + /** + * The placeholder's rect in pixels. Drawing the outline as an absolutely-positioned box instead of + * a grid-placed one keeps a *painted* element from re-flowing grid tracks on every snap step — + * Safari doesn't reliably invalidate the area such an element vacates, which left a dashed ghost + * at every width a shrinking widget passed through. + */ + get placeholderRect(): FloatRect | null { + const rect = this.placeholder; + const metrics = this.metrics; + if (!rect || !metrics) return null; + + return { + left: (rect.colStart - 1) * metrics.colPitch, + top: (rect.rowStart - 1) * metrics.rowPitch, + width: rect.colSpan * metrics.colPitch - metrics.colGap, + height: rect.rowSpan * metrics.rowPitch - metrics.rowGap + }; + } + + isActive(id: string): boolean { + return this.activeId === id; + } + + #snapshot(): WidgetLayoutItem[] { + return this.#getItems().map((item) => ({ ...item })); + } + + start(mode: GridMode, id: string, event: PointerEvent, cardEl: HTMLElement): void { + if (!this.enabled || this.activeId || event.button !== 0) return; + + const grid = this.gridEl; + const source = this.#getItems().find((item) => item.id === id); + if (!grid || !source) return; + + event.preventDefault(); + // The stat layout makes the whole card a drag handle, so the resize corner must not also + // reach it. (The `activeId` guard above already covers this; this keeps it explicit.) + event.stopPropagation(); + + const metrics = readMetrics(grid); + const gridBox = grid.getBoundingClientRect(); + const cardBox = cardEl.getBoundingClientRect(); + const origin: FloatRect = { + left: cardBox.left - gridBox.left, + top: cardBox.top - gridBox.top, + width: cardBox.width, + height: cardBox.height + }; + // Where inside the card the pointer grabbed, so the card doesn't jump to the cursor. + const grab = { x: event.clientX - cardBox.left, y: event.clientY - cardBox.top }; + const scroller = findScroller(grid); + + let pointerX = event.clientX; + let pointerY = event.clientY; + let frame = 0; + + this.activeId = id; + this.mode = mode; + this.float = { ...origin }; + this.metrics = metrics; + this.draft = this.#snapshot(); + const bodyClass = mode === 'move' ? 'grid-moving' : 'grid-resizing'; + document.body.classList.add(bodyClass); + + // Capture on the grid — never the card, which goes `pointer-events: none` while it floats. This + // guarantees the gesture terminates: without it, releasing outside the window drops `pointerup` + // and the draft (and its placeholder) is stranded on screen until the next interaction. + const pointerId = event.pointerId; + try { + grid.setPointerCapture(pointerId); + } catch { + // Capture is best-effort; the window listeners below still cover the common case. + } + + const update = () => { + // Re-read the box every frame so edge auto-scroll doesn't skew the mapping. + const box = grid.getBoundingClientRect(); + + if (mode === 'move') { + const left = pointerX - box.left - grab.x; + const top = pointerY - box.top - grab.y; + this.float = { left, top, width: origin.width, height: origin.height }; + + const colStart = clamp( + Math.round(left / metrics.colPitch) + 1, + 1, + GRID_COLUMNS - source.colSpan + 1 + ); + const rowStart = Math.max(1, Math.round(top / metrics.rowPitch) + 1); + this.draft = moveElement(this.#snapshot(), id, colStart, rowStart); + return; + } + + const min = this.#minSize(source); + const maxColSpan = GRID_COLUMNS - source.colStart + 1; + const minColSpan = Math.min(min.minColSpan, maxColSpan); + const minRowSpan = Math.min(min.minRowSpan, GRID_MAX_ROW_SPAN); + + // The pointer can't drag the ghost below the widget's floor either, so what you see while + // resizing is always a size the widget will actually accept. + const width = clamp( + pointerX - box.left - origin.left, + minColSpan * metrics.colPitch - metrics.colGap, + maxColSpan * metrics.colPitch - metrics.colGap + ); + const height = clamp( + pointerY - box.top - origin.top, + minRowSpan * metrics.rowPitch - metrics.rowGap, + GRID_MAX_ROW_SPAN * metrics.rowPitch - metrics.rowGap + ); + this.float = { left: origin.left, top: origin.top, width, height }; + + const colSpan = Math.round((width + metrics.colGap) / metrics.colPitch); + const rowSpan = Math.round((height + metrics.rowGap) / metrics.rowPitch); + this.draft = resizeElement(this.#snapshot(), id, colSpan, rowSpan, min); + }; + + const autoScroll = () => { + frame = requestAnimationFrame(autoScroll); + + const top = pointerY - EDGE_SCROLL_ZONE_PX; + const bottom = pointerY - (window.innerHeight - EDGE_SCROLL_ZONE_PX); + const delta = + top < 0 + ? (top / EDGE_SCROLL_ZONE_PX) * EDGE_SCROLL_MAX_PX + : bottom > 0 + ? (bottom / EDGE_SCROLL_ZONE_PX) * EDGE_SCROLL_MAX_PX + : 0; + if (delta === 0) return; + + const before = scroller.scrollTop; + scroller.scrollTop = before + delta; + if (scroller.scrollTop !== before) update(); + }; + + const handleMove = (moveEvent: PointerEvent) => { + pointerX = moveEvent.clientX; + pointerY = moveEvent.clientY; + update(); + }; + + const finish = (commit: boolean) => { + cancelAnimationFrame(frame); + window.removeEventListener('pointermove', handleMove); + window.removeEventListener('pointerup', handleUp); + window.removeEventListener('pointercancel', handleCancel); + window.removeEventListener('lostpointercapture', handleUp); + window.removeEventListener('blur', handleCancel); + window.removeEventListener('keydown', handleKey, true); + document.body.classList.remove(bodyClass); + if (grid.hasPointerCapture?.(pointerId)) grid.releasePointerCapture(pointerId); + + const next = this.draft; + this.draft = null; + this.activeId = null; + this.mode = null; + this.float = null; + this.metrics = null; + if (commit && next) this.#commit(next); + }; + + const handleUp = () => finish(true); + const handleCancel = () => finish(false); + const handleKey = (keyEvent: KeyboardEvent) => { + if (keyEvent.key !== 'Escape') return; + keyEvent.preventDefault(); + finish(false); + }; + + window.addEventListener('pointermove', handleMove); + window.addEventListener('pointerup', handleUp); + window.addEventListener('pointercancel', handleCancel); + window.addEventListener('lostpointercapture', handleUp); + window.addEventListener('blur', handleCancel); + window.addEventListener('keydown', handleKey, true); + frame = requestAnimationFrame(autoScroll); + } + + /** Keyboard equivalent of dragging the widget by its handle. */ + nudgeMove(id: string, colDelta: number, rowDelta: number): void { + const source = this.#getItems().find((item) => item.id === id); + if (!source) return; + this.#commit( + moveElement( + this.#snapshot(), + id, + source.colStart + colDelta, + Math.max(1, source.rowStart + rowDelta) + ) + ); + } + + /** Keyboard equivalent of dragging the resize handle. */ + nudgeResize(id: string, colDelta: number, rowDelta: number): void { + const source = this.#getItems().find((item) => item.id === id); + if (!source) return; + this.#commit( + resizeElement( + this.#snapshot(), + id, + source.colSpan + colDelta, + source.rowSpan + rowDelta, + this.#minSize(source) + ) + ); + } +} + +const GRID_INTERACTION_KEY = Symbol('grid-interaction'); + +export function setGridInteraction(interaction: GridInteraction): GridInteraction { + return setContext(GRID_INTERACTION_KEY, interaction); +} + +export function getGridInteraction(): GridInteraction { + const interaction = getContext(GRID_INTERACTION_KEY); + if (!interaction) throw new Error('WidgetCard must be rendered inside DashboardGrid'); + return interaction; +} diff --git a/src/lib/components/dashboard/grid-layout.ts b/src/lib/components/dashboard/grid-layout.ts new file mode 100644 index 00000000..b7b90298 --- /dev/null +++ b/src/lib/components/dashboard/grid-layout.ts @@ -0,0 +1,116 @@ +import { GRID_COLUMNS, GRID_MAX_ROW_SPAN } from '$lib/domain/dashboard'; +import { clamp } from './widget-size'; + +export interface GridRect { + colStart: number; + rowStart: number; + colSpan: number; + rowSpan: number; +} + +export type GridItem = GridRect & { id: string }; + +function overlaps(a: GridItem, b: GridItem): boolean { + return ( + a.id !== b.id && + a.colStart < b.colStart + b.colSpan && + a.colStart + a.colSpan > b.colStart && + a.rowStart < b.rowStart + b.rowSpan && + a.rowStart + a.rowSpan > b.rowStart + ); +} + +function byPosition(a: GridItem, b: GridItem): number { + return a.rowStart - b.rowStart || a.colStart - b.colStart; +} + +function collidesAt(items: GridItem[], item: GridItem, rowStart: number): boolean { + const probe = { ...item, rowStart }; + return items.some((other) => overlaps(other, probe)); +} + +// Vertical gravity: walk items in reading order and settle each one at the highest row it can reach +// without touching anything already settled. Items are only ever compared against items placed +// before them, so a single pass both closes gaps and resolves leftover overlap. +export function compactLayout(items: T[]): T[] { + const settled: T[] = []; + + for (const item of [...items].sort(byPosition)) { + let rowStart = item.rowStart; + while (collidesAt(settled, item, rowStart)) rowStart += 1; + while (rowStart > 1 && !collidesAt(settled, item, rowStart - 1)) rowStart -= 1; + item.rowStart = rowStart; + settled.push(item); + } + + return items; +} + +// Clears space for `target` by displacing whatever it now overlaps. A collider first tries the gap +// the target just vacated (directly above it), which is what makes dragging one widget onto another +// read as a swap; otherwise it drops below the target and cascades into whatever it hits in turn. +function displaceColliders( + items: T[], + target: T, + handled: Set, + options: { movingUp: boolean; allowTuck: boolean } +): void { + const colliders = items.filter((item) => overlaps(item, target)).sort(byPosition); + // Resolve the nearest collider in the direction of travel first so cascades run away from the target. + if (options.movingUp) colliders.reverse(); + + for (const collider of colliders) { + if (handled.has(collider.id)) continue; + handled.add(collider.id); + + const tuckedRow = target.rowStart - collider.rowSpan; + if (options.allowTuck && tuckedRow >= 1 && !collidesAt(items, collider, tuckedRow)) { + collider.rowStart = tuckedRow; + continue; + } + + collider.rowStart = target.rowStart + target.rowSpan; + displaceColliders(items, collider, handled, options); + } +} + +/** Drops the widget at (colStart, rowStart), pushing others out of the way, then applies gravity. */ +export function moveElement( + items: T[], + id: string, + colStart: number, + rowStart: number +): T[] { + const target = items.find((item) => item.id === id); + if (!target) return items; + + const movingUp = rowStart < target.rowStart; + target.colStart = clamp(colStart, 1, GRID_COLUMNS - target.colSpan + 1); + target.rowStart = Math.max(1, rowStart); + + displaceColliders(items, target, new Set([id]), { movingUp, allowTuck: true }); + return compactLayout(items); +} + +/** + * Resizes the widget from its top-left anchor, pushing others down, then applies gravity. + * `min` is the widget's own floor; it wins over the pointer but not over the grid's right edge. + */ +export function resizeElement( + items: T[], + id: string, + colSpan: number, + rowSpan: number, + min: { minColSpan: number; minRowSpan: number } = { minColSpan: 1, minRowSpan: 1 } +): T[] { + const target = items.find((item) => item.id === id); + if (!target) return items; + + const maxColSpan = GRID_COLUMNS - target.colStart + 1; + target.colSpan = clamp(colSpan, Math.min(min.minColSpan, maxColSpan), maxColSpan); + target.rowSpan = clamp(rowSpan, Math.min(min.minRowSpan, GRID_MAX_ROW_SPAN), GRID_MAX_ROW_SPAN); + + // Growing a widget must never lift its neighbours above it, so no tucking here. + displaceColliders(items, target, new Set([id]), { movingUp: false, allowTuck: false }); + return compactLayout(items); +} diff --git a/src/lib/components/dashboard/widget-registry.ts b/src/lib/components/dashboard/widget-registry.ts new file mode 100644 index 00000000..43b056b2 --- /dev/null +++ b/src/lib/components/dashboard/widget-registry.ts @@ -0,0 +1,207 @@ +import type { Component } from 'svelte'; +import type { WidgetColSpan, WidgetRowSpan, WidgetType } from '$lib/domain/dashboard'; +import FleetStatWidget from './widgets/FleetStatWidget.svelte'; +import ExpenseBreakdownWidget from './widgets/ExpenseBreakdownWidget.svelte'; +import MonthlyExpenseTrendWidget from './widgets/MonthlyExpenseTrendWidget.svelte'; +import VehicleLeaderboardWidget from './widgets/VehicleLeaderboardWidget.svelte'; +import FleetFuelTrendWidget from './widgets/FleetFuelTrendWidget.svelte'; +import FuelConsumptionTrendWidget from './widgets/FuelConsumptionTrendWidget.svelte'; +import MileageOverviewWidget from './widgets/MileageOverviewWidget.svelte'; +import StatusDonutWidget from './widgets/StatusDonutWidget.svelte'; +import VehicleHealthWidget from './widgets/VehicleHealthWidget.svelte'; +import UpcomingRemindersWidget from './widgets/UpcomingRemindersWidget.svelte'; +import VehicleQuickListWidget from './widgets/VehicleQuickListWidget.svelte'; +import RecentActivityWidget from './widgets/RecentActivityWidget.svelte'; +import CalendarWidget from './widgets/CalendarWidget.svelte'; +import Car from '@lucide/svelte/icons/car'; +import Route from '@lucide/svelte/icons/route'; +import Fuel from '@lucide/svelte/icons/fuel'; +import DollarSign from '@lucide/svelte/icons/dollar-sign'; +import CircleGauge from '@lucide/svelte/icons/circle-gauge'; + +interface WidgetDefinition { + type: WidgetType; + title: string; + description: string; + component: Component; + extraProps?: Record; + defaultColSpan: WidgetColSpan; + defaultRowSpan: WidgetRowSpan; + /** Only stat-style widgets set these — WidgetCard renders the icon in its header when present. */ + icon?: Component<{ class?: string }>; + iconColor?: string; +} + +export const WIDGET_REGISTRY: Record = { + 'stat-vehicle-count': { + type: 'stat-vehicle-count', + title: 'Total Vehicles', + description: 'Number of vehicles in your garage', + component: FleetStatWidget, + extraProps: { metric: 'vehicle-count' }, + defaultColSpan: 3, + defaultRowSpan: 4, + icon: Car, + iconColor: 'bg-gradient-to-br from-blue-400 to-blue-600 shadow-blue-500/30' + }, + 'stat-total-distance': { + type: 'stat-total-distance', + title: 'Total Distance', + description: 'Distance driven across the whole fleet', + component: FleetStatWidget, + extraProps: { metric: 'total-distance' }, + defaultColSpan: 3, + defaultRowSpan: 4, + icon: Route, + iconColor: 'bg-gradient-to-br from-violet-400 to-violet-600 shadow-violet-500/30' + }, + 'stat-fuel-used': { + type: 'stat-fuel-used', + title: 'Total Fuel Used', + description: 'Fuel consumed across the whole fleet', + component: FleetStatWidget, + extraProps: { metric: 'fuel-used' }, + defaultColSpan: 3, + defaultRowSpan: 4, + icon: Fuel, + iconColor: 'bg-gradient-to-br from-emerald-400 to-emerald-600 shadow-emerald-500/30' + }, + 'stat-total-expenses': { + type: 'stat-total-expenses', + title: 'Total Expenses', + description: 'Fuel, maintenance and insurance spend combined', + component: FleetStatWidget, + extraProps: { metric: 'total-expenses' }, + defaultColSpan: 3, + defaultRowSpan: 4, + icon: DollarSign, + iconColor: 'bg-gradient-to-br from-amber-400 to-amber-600 shadow-amber-500/30' + }, + 'stat-cost-per-distance': { + type: 'stat-cost-per-distance', + title: 'Cost / Distance', + description: 'Overall running cost per unit distance', + component: FleetStatWidget, + extraProps: { metric: 'cost-per-distance' }, + defaultColSpan: 3, + defaultRowSpan: 4, + icon: CircleGauge, + iconColor: 'bg-gradient-to-br from-rose-400 to-rose-600 shadow-rose-500/30' + }, + 'expense-breakdown-donut': { + type: 'expense-breakdown-donut', + title: 'Expenses by Category', + description: 'Fuel vs. maintenance vs. compliance spend', + component: ExpenseBreakdownWidget, + defaultColSpan: 6, + defaultRowSpan: 8 + }, + 'monthly-expense-trend': { + type: 'monthly-expense-trend', + title: 'Monthly Expense Trend', + description: 'Last 12 months of spend by category', + component: MonthlyExpenseTrendWidget, + defaultColSpan: 9, + defaultRowSpan: 8 + }, + 'cost-by-vehicle-leaderboard': { + type: 'cost-by-vehicle-leaderboard', + title: 'Cost by Vehicle', + description: 'Which vehicles cost the most to run', + component: VehicleLeaderboardWidget, + extraProps: { metric: 'cost' }, + defaultColSpan: 6, + defaultRowSpan: 8 + }, + 'fleet-fuel-trend': { + type: 'fleet-fuel-trend', + title: 'Fleet Fuel Trend', + description: 'Daily fuel usage across the fleet', + component: FleetFuelTrendWidget, + defaultColSpan: 9, + defaultRowSpan: 8 + }, + 'fuel-consumption-trend': { + type: 'fuel-consumption-trend', + title: 'Fuel Consumption Trend', + description: 'Fuel usage over time, one line per vehicle', + component: FuelConsumptionTrendWidget, + defaultColSpan: 9, + defaultRowSpan: 8 + }, + 'mileage-overview-trend': { + type: 'mileage-overview-trend', + title: 'Mileage Overview', + description: 'Mileage over time, one line per vehicle', + component: MileageOverviewWidget, + defaultColSpan: 9, + defaultRowSpan: 8 + }, + 'efficiency-leaderboard': { + type: 'efficiency-leaderboard', + title: 'Efficiency Leaderboard', + description: 'Vehicles ranked by fuel efficiency', + component: VehicleLeaderboardWidget, + extraProps: { metric: 'efficiency' }, + defaultColSpan: 6, + defaultRowSpan: 8 + }, + 'pucc-status-donut': { + type: 'pucc-status-donut', + title: 'Other Compliance Status', + description: 'Emissions, roadworthiness & registration status across the fleet', + component: StatusDonutWidget, + extraProps: { metric: 'other' }, + defaultColSpan: 6, + defaultRowSpan: 6 + }, + 'insurance-status-donut': { + type: 'insurance-status-donut', + title: 'Insurance Status', + description: 'Insurance policy status across the fleet', + component: StatusDonutWidget, + extraProps: { metric: 'insurance' }, + defaultColSpan: 6, + defaultRowSpan: 6 + }, + 'vehicle-health-distribution': { + type: 'vehicle-health-distribution', + title: 'Vehicle Health', + description: 'Overall good/attention/needs-action breakdown', + component: VehicleHealthWidget, + defaultColSpan: 6, + defaultRowSpan: 8 + }, + 'upcoming-reminders-list': { + type: 'upcoming-reminders-list', + title: 'Upcoming Reminders', + description: 'Reminders coming due soon', + component: UpcomingRemindersWidget, + defaultColSpan: 6, + defaultRowSpan: 8 + }, + 'vehicle-quick-list': { + type: 'vehicle-quick-list', + title: 'My Vehicles', + description: 'Quick access to your vehicles', + component: VehicleQuickListWidget, + defaultColSpan: 9, + defaultRowSpan: 8 + }, + 'recent-activity-feed': { + type: 'recent-activity-feed', + title: 'Recent Activity', + description: 'Latest fuel and maintenance logs across the fleet', + component: RecentActivityWidget, + defaultColSpan: 6, + defaultRowSpan: 8 + }, + 'activity-calendar': { + type: 'activity-calendar', + title: 'Activity Calendar', + description: 'Upcoming reminders and past fuel/maintenance activity by date', + component: CalendarWidget, + defaultColSpan: 4, + defaultRowSpan: 10 + } +}; diff --git a/src/lib/components/dashboard/widget-size.ts b/src/lib/components/dashboard/widget-size.ts new file mode 100644 index 00000000..55303a6a --- /dev/null +++ b/src/lib/components/dashboard/widget-size.ts @@ -0,0 +1,39 @@ +import { GRID_COLUMNS, GRID_MAX_ROW_SPAN } from '$lib/domain/dashboard'; + +/** Base pixel height of one row unit; a widget's rowSpan is this many units tall (before gaps). */ +export const ROW_UNIT_PX = 28; + +export function clamp(value: number, min: number, max: number): number { + return Math.min(max, Math.max(min, value)); +} + +function clampColSpan(span: number): number { + return clamp(Math.round(span), 1, GRID_COLUMNS); +} + +function clampRowSpan(span: number): number { + return clamp(Math.round(span), 1, GRID_MAX_ROW_SPAN); +} + +function clampColStart(colStart: number, colSpan: number): number { + return clamp(Math.round(colStart), 1, GRID_COLUMNS - clampColSpan(colSpan) + 1); +} + +function clampRowStart(rowStart: number): number { + return Math.max(1, Math.round(rowStart)); +} + +// CSS custom properties for a widget's grid rect; WidgetCard only wires these to grid-column/grid-row at the 12-col breakpoint since colStart/rowStart don't translate to the stacked mobile layout. +export function widgetGridVars(item: { + colStart: number; + rowStart: number; + colSpan: number; + rowSpan: number; +}): string { + return ( + `--wc-col-start: ${clampColStart(item.colStart, item.colSpan)}; ` + + `--wc-col-span: ${clampColSpan(item.colSpan)}; ` + + `--wc-row-start: ${clampRowStart(item.rowStart)}; ` + + `--wc-row-span: ${clampRowSpan(item.rowSpan)};` + ); +} diff --git a/src/lib/components/dashboard/widgets/CalendarWidget.svelte b/src/lib/components/dashboard/widgets/CalendarWidget.svelte new file mode 100644 index 00000000..5c47833e --- /dev/null +++ b/src/lib/components/dashboard/widgets/CalendarWidget.svelte @@ -0,0 +1,175 @@ + + +{#if loading && !summary} +
+ Loading calendar... +
+{:else} +
+ + + {#snippet children({ months, weekdays })} + + + + + + {#each months as month, monthIndex (month)} + + + + + + + + {#each weekdays as weekday (weekday)} + + {weekday.slice(0, 2)} + + {/each} + + + + {#each month.weeks as weekDates (weekDates)} + + {#each weekDates as date (date)} + {@const events = eventsByDate.get(date.toString()) ?? []} + + + {#if events.length} +
+ {#each events.slice(0, 3) as event (event.id)} + + {/each} +
+ {/if} +
+ {/each} +
+ {/each} +
+
+
+ {/each} +
+ {/snippet} +
+ +
+

+ {formatDateForCalendar(selected)} +

+ {#if selectedEvents.length === 0} +

No activity or reminders on this date.

+ {:else} +
    + {#each selectedEvents as event (event.id)} + {@const Icon = KIND_ICONS[event.kind]} +
  • + + + + {event.label} +
  • + {/each} +
+ {/if} +
+
+{/if} diff --git a/src/lib/components/dashboard/widgets/ExpenseBreakdownWidget.svelte b/src/lib/components/dashboard/widgets/ExpenseBreakdownWidget.svelte new file mode 100644 index 00000000..af518ddd --- /dev/null +++ b/src/lib/components/dashboard/widgets/ExpenseBreakdownWidget.svelte @@ -0,0 +1,33 @@ + + + formatCurrency(value)} +/> diff --git a/src/lib/components/dashboard/widgets/FleetFuelTrendWidget.svelte b/src/lib/components/dashboard/widgets/FleetFuelTrendWidget.svelte new file mode 100644 index 00000000..4a6b66ad --- /dev/null +++ b/src/lib/components/dashboard/widgets/FleetFuelTrendWidget.svelte @@ -0,0 +1,24 @@ + + + `${value.toFixed(1)} L`} + xFormatter={(v: Date) => + v.toLocaleDateString('en-IN', { day: '2-digit', month: 'short', year: 'numeric' })} +/> diff --git a/src/lib/components/dashboard/widgets/FleetStatWidget.svelte b/src/lib/components/dashboard/widgets/FleetStatWidget.svelte new file mode 100644 index 00000000..3d0b149a --- /dev/null +++ b/src/lib/components/dashboard/widgets/FleetStatWidget.svelte @@ -0,0 +1,45 @@ + + + + + diff --git a/src/lib/components/dashboard/widgets/FuelConsumptionTrendWidget.svelte b/src/lib/components/dashboard/widgets/FuelConsumptionTrendWidget.svelte new file mode 100644 index 00000000..a95288d5 --- /dev/null +++ b/src/lib/components/dashboard/widgets/FuelConsumptionTrendWidget.svelte @@ -0,0 +1,22 @@ + + + `${value.toFixed(1)} L`} + xFormatter={(v: Date) => + v.toLocaleDateString('en-IN', { day: '2-digit', month: 'short', year: 'numeric' })} +/> diff --git a/src/lib/components/dashboard/widgets/MileageOverviewWidget.svelte b/src/lib/components/dashboard/widgets/MileageOverviewWidget.svelte new file mode 100644 index 00000000..2b456443 --- /dev/null +++ b/src/lib/components/dashboard/widgets/MileageOverviewWidget.svelte @@ -0,0 +1,23 @@ + + + formatMileage(value, series.fuelType)} + xFormatter={(v: Date) => + v.toLocaleDateString('en-IN', { day: '2-digit', month: 'short', year: 'numeric' })} +/> diff --git a/src/lib/components/dashboard/widgets/MonthlyExpenseTrendWidget.svelte b/src/lib/components/dashboard/widgets/MonthlyExpenseTrendWidget.svelte new file mode 100644 index 00000000..8bd49ba1 --- /dev/null +++ b/src/lib/components/dashboard/widgets/MonthlyExpenseTrendWidget.svelte @@ -0,0 +1,13 @@ + + + diff --git a/src/lib/components/dashboard/widgets/RecentActivityWidget.svelte b/src/lib/components/dashboard/widgets/RecentActivityWidget.svelte new file mode 100644 index 00000000..e1414348 --- /dev/null +++ b/src/lib/components/dashboard/widgets/RecentActivityWidget.svelte @@ -0,0 +1,10 @@ + + +
+ +
diff --git a/src/lib/components/dashboard/widgets/StatusDonutWidget.svelte b/src/lib/components/dashboard/widgets/StatusDonutWidget.svelte new file mode 100644 index 00000000..1e63d46d --- /dev/null +++ b/src/lib/components/dashboard/widgets/StatusDonutWidget.svelte @@ -0,0 +1,31 @@ + + + + + diff --git a/src/lib/components/dashboard/widgets/UpcomingRemindersWidget.svelte b/src/lib/components/dashboard/widgets/UpcomingRemindersWidget.svelte new file mode 100644 index 00000000..e268c346 --- /dev/null +++ b/src/lib/components/dashboard/widgets/UpcomingRemindersWidget.svelte @@ -0,0 +1,48 @@ + + +{#if summary && summary.compliance.upcomingReminders.length > 0} +
+ {#each summary.compliance.upcomingReminders.slice(0, 6) as reminder (reminder.id)} +
+ + + +
+

+ {reminder.vehicleName} + {#if reminder.vehiclePlate} + ({reminder.vehiclePlate}) + {/if} +

+

+ {reminder.note || reminder.type} +

+
+ +
+ {/each} +
+{:else if loading} +
Loading reminders...
+{:else} +
+ No upcoming reminders +
+{/if} diff --git a/src/lib/components/dashboard/widgets/VehicleHealthWidget.svelte b/src/lib/components/dashboard/widgets/VehicleHealthWidget.svelte new file mode 100644 index 00000000..e6ddac1b --- /dev/null +++ b/src/lib/components/dashboard/widgets/VehicleHealthWidget.svelte @@ -0,0 +1,62 @@ + + +
+
+ +
+ {#if summary && !loading} +
+
+ + + Good + + {summary.compliance.vehicleHealth.good} +
+
+ + + Attention + + {summary.compliance.vehicleHealth.attention} +
+
+ + + Needs Action + + {summary.compliance.vehicleHealth.needsAction} +
+
+ {:else} +
Loading...
+ {/if} +
diff --git a/src/lib/components/dashboard/widgets/VehicleLeaderboardWidget.svelte b/src/lib/components/dashboard/widgets/VehicleLeaderboardWidget.svelte new file mode 100644 index 00000000..e661bd91 --- /dev/null +++ b/src/lib/components/dashboard/widgets/VehicleLeaderboardWidget.svelte @@ -0,0 +1,51 @@ + + + + +
+ +
diff --git a/src/lib/components/dashboard/widgets/VehicleQuickListWidget.svelte b/src/lib/components/dashboard/widgets/VehicleQuickListWidget.svelte new file mode 100644 index 00000000..ed851aff --- /dev/null +++ b/src/lib/components/dashboard/widgets/VehicleQuickListWidget.svelte @@ -0,0 +1,23 @@ + + +{#if vehicleStore.vehicles && vehicleStore.vehicles.length > 0} +
+ {#each vehicleStore.vehicles.slice(0, 5) as vehicle (vehicle.id)} + { + if (vehicle.id) goto(`/garage/${vehicle.id}`); + }} + actions={false} + /> + {/each} +
+{:else} +
+ No vehicles yet +
+{/if} diff --git a/src/lib/components/feature/compliance/ComplianceContextMenu.svelte b/src/lib/components/feature/compliance/ComplianceContextMenu.svelte new file mode 100644 index 00000000..a3ba871f --- /dev/null +++ b/src/lib/components/feature/compliance/ComplianceContextMenu.svelte @@ -0,0 +1,36 @@ + + + sheetStore.openSheet(ComplianceForm, m.compliance_menu_sheet_title(), '', document)} + onDelete={deleteDoc} +/> diff --git a/src/lib/components/feature/compliance/ComplianceForm.svelte b/src/lib/components/feature/compliance/ComplianceForm.svelte new file mode 100644 index 00000000..593f5762 --- /dev/null +++ b/src/lib/components/feature/compliance/ComplianceForm.svelte @@ -0,0 +1,263 @@ + + +
e.preventDefault()}> +
+ {#if !suppliedVehicleId} + + {/if} + + + {#snippet children({ props })} + {@const TypeIcon = getComplianceTypeIcon($formData.type)} + {m.compliance_form_type_label()} + + +
+ + {getComplianceTypeLabel($formData.type, m)} +
+
+ + {#each Object.keys(COMPLIANCE_TYPES) as value} + {@const ItemIcon = getComplianceTypeIcon(value)} + + + {getComplianceTypeLabel(value, m)} + + {/each} + +
+ {/snippet} +
+ +
+ + {#if $formData.type === 'other'} + + + {#snippet children({ props })} + {m.compliance_form_other_label_label()} + + {/snippet} + + + + {/if} + + + + {m.compliance_form_attachment_label()} + + + + + + + {#snippet children({ props })} + {getComplianceIssuerLabel($formData.type, m)} + + {/snippet} + + + + + + + {#snippet children({ props })} + {getComplianceDocumentNumberLabel($formData.type, m)} + + {/snippet} + + + + + + + {#snippet children({ props })} + {m.compliance_form_start_date_label()} + + {/snippet} + + + + + + + + + {#snippet children({ props })} + {m.compliance_form_cost_label()} + + {/snippet} + + + + + + + {#snippet children({ props })} + {m.compliance_form_notes_label()} +