diff --git a/.claude/launch.json b/.claude/launch.json
index 80eeee4..397d2fa 100644
--- a/.claude/launch.json
+++ b/.claude/launch.json
@@ -3,8 +3,8 @@
"configurations": [
{
"name": "dev",
- "runtimeExecutable": "pnpm",
- "runtimeArgs": ["dev"],
+ "runtimeExecutable": "bun",
+ "runtimeArgs": ["run", "dev"],
"port": 3000
}
]
diff --git a/.cta.json b/.cta.json
index f31929b..d8e3b4b 100644
--- a/.cta.json
+++ b/.cta.json
@@ -3,7 +3,7 @@
"mode": "file-router",
"typescript": true,
"tailwind": true,
- "packageManager": "pnpm",
+ "packageManager": "bun",
"git": false,
"install": true,
"intent": false,
diff --git a/.dockerignore b/.dockerignore
index 06c92a8..d9ea975 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -6,4 +6,5 @@ data
design
.env
.git
-packages
+packages/*/*
+!packages/*/package.json
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index c3a05af..1ecb4f1 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -1,7 +1,7 @@
blank_issues_enabled: true
contact_links:
- name: Security issue
- url: https://github.com/lobbystack/openprofit/blob/main/CONTRIBUTING.md#report-a-security-issue
+ url: https://github.com/morencyr/openprofit/blob/main/CONTRIBUTING.md#report-a-security-issue
about: Email hello@openprofit.dev. Don't report security problems in a public issue.
- name: Setup questions
url: https://openprofit.dev/docs
diff --git a/.github/ISSUE_TEMPLATE/connector.yml b/.github/ISSUE_TEMPLATE/connector.yml
index c012826..2db813c 100644
--- a/.github/ISSUE_TEMPLATE/connector.yml
+++ b/.github/ISSUE_TEMPLATE/connector.yml
@@ -4,7 +4,7 @@ title: "Connector: "
body:
- type: markdown
attributes:
- value: A connector needs an API that returns billing or usage data with a key. Links to the provider's own docs help most. To build it yourself, see [CONTRIBUTING.md](https://github.com/lobbystack/openprofit/blob/main/CONTRIBUTING.md#build-a-connector).
+ value: A connector needs an API that returns billing or usage data with a key. Links to the provider's own docs help most. To build it yourself, see [CONTRIBUTING.md](https://github.com/morencyr/openprofit/blob/main/CONTRIBUTING.md#build-a-connector).
- type: input
id: provider
attributes:
diff --git a/.github/social-preview.png b/.github/social-preview.png
new file mode 100644
index 0000000..1b2752e
Binary files /dev/null and b/.github/social-preview.png differ
diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml
index 59ae4b8..98f848e 100644
--- a/.github/workflows/check.yml
+++ b/.github/workflows/check.yml
@@ -1,22 +1,20 @@
name: Check
+# Pushes to main run this through docker.yml, which deploys only when it passes.
on:
- push:
- branches: [main]
pull_request:
+ workflow_call:
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- - uses: pnpm/action-setup@v4
- - uses: actions/setup-node@v4
+ - uses: oven-sh/setup-bun@v2
with:
- node-version: 22
- cache: pnpm
- - run: pnpm install --frozen-lockfile
- - run: pnpm check
- - run: npx tsc --noEmit
- - run: pnpm build
- - run: pnpm --dir packages/cli build && pnpm --dir packages/cli test
+ bun-version-file: package.json
+ - run: bun install --frozen-lockfile
+ - run: bun run check
+ - run: bunx --bun tsc --noEmit
+ - run: bun run build
+ - run: cd packages/cli && bun run build && bun run test
diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
index 7ae35c0..a957fee 100644
--- a/.github/workflows/docker.yml
+++ b/.github/workflows/docker.yml
@@ -6,7 +6,11 @@ on:
tags: ["v*"]
jobs:
+ check:
+ uses: ./.github/workflows/check.yml
+
build:
+ needs: check
runs-on: ubuntu-latest
permissions:
contents: read
@@ -35,3 +39,15 @@ jobs:
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
+
+ # openprofit.dev runs this image on Dokploy. Its deploy webhook pulls :latest.
+ deploy:
+ needs: build
+ if: github.ref == 'refs/heads/main'
+ runs-on: ubuntu-latest
+ steps:
+ - env:
+ DOKPLOY_DEPLOY_WEBHOOK: ${{ secrets.DOKPLOY_DEPLOY_WEBHOOK }}
+ run: |
+ if [ -z "$DOKPLOY_DEPLOY_WEBHOOK" ]; then echo "DOKPLOY_DEPLOY_WEBHOOK is not set; skipping"; exit 0; fi
+ curl -fsS -X POST "$DOKPLOY_DEPLOY_WEBHOOK"
diff --git a/CLAUDE.md b/CLAUDE.md
index 232aaf3..edb9526 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -2,38 +2,46 @@
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
-OpenProfit: open-source finance for developers. Pulls revenue (Stripe, Polar, Paddle, Lemon Squeezy, RevenueCat) and costs (OpenAI, Anthropic, Vercel, Cloudflare, Railway and more) from provider APIs, assigns them to products, shows profit per product, and turns the same lines into books and tax-form numbers. One TanStack Start app serves the landing page, docs, blog, marketing content and the app. Hosted at openprofit.dev (Railway), self-hostable as one Docker image. Repo: github.com/lobbystack/openprofit. Operator: Lobbystack Inc.
+OpenProfit: open-source finance for developers. Pulls revenue (Stripe, Polar, Paddle, Lemon Squeezy, RevenueCat) and costs (OpenAI, Anthropic, Vercel, Cloudflare, Railway and more) from provider APIs, assigns them to products, shows profit per product, and turns the same lines into books and tax-form numbers. One TanStack Start app serves the landing page, docs, blog, marketing content and the app. Hosted at openprofit.dev (Dokploy on an OVH server, behind Cloudflare), self-hostable as one Docker image. Repo: github.com/morencyr/openprofit. Operator: Lobbystack Inc.
## Commands
```bash
-pnpm dev # http://localhost:3000
-pnpm check # Biome lint + format check (CI runs this)
-npx biome check --write src # apply formatting; Biome rewrites files to tabs/double quotes
-npx tsc --noEmit # typecheck (CI runs this)
-pnpm build # production build into .output (CI runs this)
-pnpm db:generate # write a migration after editing src/db/schema.ts
-pnpm db:seed # demo workspace; `pnpm db:seed --owner=you@example.com` attaches it to a user
+bun run dev # http://localhost:3000
+bun run check # Biome lint + format check (CI runs this)
+bunx biome check --write src # apply formatting; Biome rewrites files to tabs/double quotes
+bunx --bun tsc --noEmit # typecheck (CI runs this)
+bun run build # production build into .output (CI runs this)
+bun run db:generate # write a migration after editing src/db/schema.ts
+bun run db:seed # demo workspace; `bun run db:seed --owner=you@example.com` attaches it to a user
```
-There is no test suite. Verify changes in the browser and with a production build when touching bundling, the database or `src/start.ts`. Books has assert scripts: `DATABASE_URL=/tmp/op-check SYNC_SCHEDULER=off npx tsx scripts/check-books-tax.ts` (also `check-books`, `check-books-close`, `check-books-export`).
+Bun is the package manager and the runtime everywhere:
-`biome.json` excludes every path under `.claude`, so `pnpm check` inside a worktree in `.claude/worktrees/` checks nothing. Run Biome on each changed file through stdin there: `npx biome check --write --stdin-file-path= < `.
+- Vite runs under `bun --bun`, so dev and the prerender run in Bun.
+- Scripts run as TypeScript with `bun scripts/seed.ts`. Bun loads `.env` itself.
+- Nitro builds with its `bun` preset. Production runs `bun .output/server/index.mjs`.
+- `bun run build` runs the app build. `bun build` is Bun's own bundler.
+- `postinstall` points `node_modules/.bin/intent` at `@tanstack/intent`. `@tanstack/devtools-vite` ships a broken `intent` bin, and Bun links that one otherwise.
+
+There is no test suite. Verify changes in the browser and with a production build when touching bundling, the database or `src/start.ts`. Books has assert scripts: `DATABASE_URL=/tmp/op-check SYNC_SCHEDULER=off bun scripts/check-books-tax.ts` (also `check-books`, `check-books-close`, `check-books-export`).
+
+`biome.json` excludes every path under `.claude`, so `bun run check` inside a worktree in `.claude/worktrees/` checks nothing. Run Biome on each changed file through stdin there: `bunx biome check --write --stdin-file-path= < `.
Production-build smoke test with a throwaway embedded DB:
```bash
-PORT=3200 SYNC_SCHEDULER=off DATABASE_URL=/tmp/op-test node .output/server/index.mjs
+PORT=3200 SYNC_SCHEDULER=off DATABASE_URL=/tmp/op-test bun .output/server/index.mjs
```
-Local sign-in without email: request a link on /login (or POST /api/auth/sign-in/magic-link) and read the URL from the dev server log. Same on Railway via `railway logs | grep magic-link`.
+Local sign-in without email: request a link on /login (or POST /api/auth/sign-in/magic-link) and read the URL from the dev server log. In production, search the Dokploy app's logs for `magic-link`.
## Library docs before code
Don't write framework code from memory. TanStack ships versioned agent skills inside its packages, and a project hook (`.claude/settings.json`, `.intent/hooks/`) lists them at session start and blocks edits until the guidance is checked.
-- TanStack Start and Router: load the matching skill first (`pnpm exec intent list`, then `pnpm exec intent load #`). `package.json#intent.skills` lists the allowed skill sources; add a TanStack package there when the app starts using it.
-- Anything the skills don't cover: read the docs for the installed version, e.g. `pnpm dlx @tanstack/cli search-docs "" --library start --framework react` and `pnpm dlx @tanstack/cli doc `. When docs and the installed source disagree, the source in `node_modules` wins.
+- TanStack Start and Router: load the matching skill first (`bunx @tanstack/intent list`, then `bunx @tanstack/intent load #`). `package.json#intent.skills` lists the allowed skill sources; add a TanStack package there when the app starts using it.
+- Anything the skills don't cover: read the docs for the installed version, e.g. `bunx @tanstack/cli search-docs "" --library start --framework react` and `bunx @tanstack/cli doc `. When docs and the installed source disagree, the source in `node_modules` wins.
- Other libraries (Better Auth, Drizzle, PostHog, provider APIs): read their current docs before using an API, and cite the page in a short comment where the behaviour isn't obvious.
@@ -41,8 +49,8 @@ Don't write framework code from memory. TanStack ships versioned agent skills in
Use the repository’s installed Intent. If it is unavailable, report the missing dependency instead of downloading a replacement.
Before editing files for a substantial task:
-- Run `pnpm exec intent list` from the workspace root to see available local skills.
-- If a listed skill matches the task, run `pnpm exec intent load #` before changing files.
+- Run `bunx @tanstack/intent list` from the workspace root to see available local skills.
+- If a listed skill matches the task, run `bunx @tanstack/intent load #` before changing files.
- Use the loaded `SKILL.md` guidance while making the change.
- Monorepos: when working across packages, run the skill check from the workspace root and prefer the local skill for the package being changed.
- Multiple matches: prefer the most specific local skill for the package or concern you are changing; load additional skills only when the task spans multiple packages or concerns.
@@ -50,9 +58,9 @@ Before editing files for a substantial task:
## Database
-- Postgres everywhere through Drizzle (`src/db/schema.ts`, `src/db/auth-schema.ts`). `DATABASE_URL` starting with `postgres://` uses `pg`; anything else is a directory for **PGlite** (embedded Postgres, default `./data/openprofit`). Hosted uses Railway Postgres.
+- Postgres everywhere through Drizzle (`src/db/schema.ts`, `src/db/auth-schema.ts`). `DATABASE_URL` starting with `postgres://` uses `pg`; anything else is a directory for **PGlite** (embedded Postgres, default `./data/openprofit`). Hosted uses a Postgres 18 service on Dokploy.
- Migrations in `./drizzle` run at import time of `src/db/index.ts` (skip with `SKIP_MIGRATIONS=1`). Don't use `drizzle-kit push`; PGlite rejects its multi-statement queries.
-- **PGlite allows one process per data directory.** Running a script (`db:seed`, a tsx one-off) while `pnpm dev` is up hangs or fails. Killing a process mid-write (`kill -9`) can corrupt the directory. Stop dev cleanly first. One-off scripts must end with `process.exit(0)` or PGlite keeps them alive. SIGTERM and SIGINT close the database and exit (`src/db/index.ts`); without that, PGlite's timer keeps the process alive until Docker kills it.
+- **PGlite allows one process per data directory.** Running a script (`db:seed`, a one-off script) while `bun run dev` is up hangs or fails. Killing a process mid-write (`kill -9`) can corrupt the directory. Stop dev cleanly first. One-off scripts must end with `process.exit(0)` or PGlite keeps them alive. SIGTERM and SIGINT close the database and exit (`src/db/index.ts`); without that, PGlite's timer keeps the process alive until Docker kills it.
- PGlite is excluded from Vite `optimizeDeps` and externalized from the Nitro server bundle in `vite.config.ts`; bundling it drops its wasm/data files and the server crashes on start. Keep both. `@resvg/resvg-wasm` (social images, `src/server/images.server.ts`) is externalized for the same reason.
- Money is integer cents. Each line stores the source amount and a `*_base_cents` amount in the workspace's base currency (Frankfurter/ECB daily rates, cached in `fx_rates`; conversions into CAD use the Bank of Canada's rates, as the CRA asks, in `src/server/fx.server.ts`). Changing the base currency reconverts every line (`settings.functions.ts`).
- Every table carries `workspace_id`.
@@ -67,10 +75,10 @@ Before editing files for a substantial task:
- **Overview** (`src/server/overview.server.ts`): grouped monthly sums over 24 months; tiles compare the selected period with the equal period before, the chart's dotted line is the same months a year earlier. Period comes from the `?period=` search param.
- **Books** (spec: `docs/BOOKS.md`; user docs: `src/docs/books.md`). `src/lib/books.ts` is the pure journal engine: accounts, who paid (personal card or company, before or after `incorporated_on`), yearly plans spread over their service period, and adjustments for closed months. `src/server/books.server.ts` loads a month's lines; a whole-workspace export stores it in `journal_exports` and closes the month, and later changes go out as adjustments in the next export. `src/lib/tax.ts` maps the year's totals to T2125, TP-80, GIFI, Schedule C and Form 1120 lines; every mapping cites its official source in a comment, and a line no source names is a judgment call marked `ours`. Changing a tax line means re-reading the source and updating `docs/BOOKS.md`, `src/docs/books.md` and `src/content/blog/tax-lines-for-software-costs.md`. QuickBooks, Xero and plain writers are in `books-export.server.ts`, downloaded from `/api/journal.csv`.
- **Cloud mode** (`APP_MODE=cloud`): plans and limits in `src/lib/plans.ts`, Polar checkout/portal and webhook in `src/server/billing.server.ts` and `src/routes/api/polar/webhook.ts` (Standard Webhooks signature, `whsec_` secrets are base64). Inert in self-host.
-- **Public demo** (`/demo`, `src/server/demo.server.ts`): the app's pages over one `demo = true` workspace with no members, rebuilt hourly by the seed generator (`src/server/seed.server.ts`, also behind `pnpm db:seed`). Read server functions take `{ demo: true }`; `currentWorkspace()` never returns the demo, so mutations can't reach it. On with `APP_MODE=cloud` or `DEMO=on`.
+- **Public demo** (`/demo`, `src/server/demo.server.ts`): the app's pages over one `demo = true` workspace with no members, rebuilt hourly by the seed generator (`src/server/seed.server.ts`, also behind `bun run db:seed`). Read server functions take `{ demo: true }`; `currentWorkspace()` never returns the demo, so mutations can't reach it. On with `APP_MODE=cloud` or `DEMO=on`.
- **Edge middleware** in `src/server/edge.server.ts` (a Nitro plugin that puts itself ahead of Nitro's static files): www to apex redirect, markdown responses for `Accept: text/markdown` (sources mapped in `src/server/markdown.server.ts`; add new public pages there), RFC 8288 `Link` headers, and serving the prerendered pages. It must stay free of database imports, so pages with live data (`/open`, `/p/...`) answer markdown from their own route `GET` handler and call `next()` for HTML.
-- **Request middleware** in `src/start.ts` (`createMiddleware({ type: "request" })`): tracing, gzip of server-rendered HTML/XML/JSON, and `Cache-Control: no-store` on /app, /onboarding and server function responses. Redirect responses must pass through unchanged: Start serializes server function redirects after the middleware. Start's CSRF check for server functions is added there explicitly, because a custom `createStart` drops the default. Request middleware runs under `pnpm dev` too.
-- **Prerendering.** `pnpm build` prerenders the pages that have markdown (landing, docs, integrations, comparisons, changelog, legal) with TanStack Start's `prerender` option; the `PRERENDER` pattern in `vite.config.ts` must match `markdownFor`. Nitro builds its static file list before those files exist, so the edge middleware serves them (brotli or gzip, compressed once per process). Prerendered HTML can't hold per-request data: the root route has no loader, and analytics settings are fetched after hydration. Server routes import the database inside their handlers so the prerender never opens it.
+- **Request middleware** in `src/start.ts` (`createMiddleware({ type: "request" })`): tracing, gzip of server-rendered HTML/XML/JSON, and `Cache-Control: no-store` on /app, /onboarding and server function responses. Redirect responses must pass through unchanged: Start serializes server function redirects after the middleware. Start's CSRF check for server functions is added there explicitly, because a custom `createStart` drops the default. Request middleware runs under `bun run dev` too.
+- **Prerendering.** `bun run build` prerenders the pages that have markdown (landing, docs, integrations, comparisons, changelog, legal) with TanStack Start's `prerender` option; the `PRERENDER` pattern in `vite.config.ts` must match `markdownFor`. Nitro builds its static file list before those files exist, so the edge middleware serves them (brotli or gzip, compressed once per process). Prerendered HTML can't hold per-request data: the root route has no loader, and analytics settings are fetched after hydration. Server routes import the database inside their handlers so the prerender never opens it.
- **Auth:** Better Auth with magic link plus GitHub/Google when their env vars are set (`src/lib/auth.ts`). Emails go through Resend when `RESEND_API_KEY` is set, otherwise they print to the server log.
## Content and SEO
@@ -84,7 +92,7 @@ Before editing files for a substantial task:
- Tokens in `src/styles.css`: paper/ink with neutrals mixed from them, light and dark (`.dark` class, toggled in `src/lib/theme.ts`). Change the system tokens, not individual components.
- One typeface: Geist. `--font-mono` points at Geist; numbers use the `num` utility (tabular figures). No serif or monospaced faces.
- Interaction rules live in `src/styles.css`, not components: press feedback on every button, visible keyboard focus, `display` utility for type 36px and up (tighter tracking), `chrome` for translucent sticky bars, `pressable` for links styled as buttons, `rise` for the one-time landing entrance, and `--ease-out` / `--ease-in-out` curves (UI motion stays under 300 ms; frequent actions like switching metric tiles don't animate beyond the chart), and reduced-motion, reduced-transparency and high-contrast overrides.
-- UI components are shadcn on Base UI (`components.json`: style `base-nova`), with their source in `src/components/ui/`. Each file is tuned to the tokens (no shadows, the app's heights and type sizes), so pages use variants such as `` and never restyle a component at the call site; change the variant in the component file instead. Add components with `pnpm dlx shadcn@latest add ` and answer no when it offers to overwrite an existing file. Base UI specifics: buttons default to `type="button"`, so a submit button needs `type="submit"`; a link that looks like a button is the router `Link` (or the landing `Href`) with `className={buttonVariants(...)}`, not `Button` with `render`, which would give it `role="button"`. `biome.json` relaxes a few lint rules for `src/components/ui` only.
+- UI components are shadcn on Base UI (`components.json`: style `base-nova`), with their source in `src/components/ui/`. Each file is tuned to the tokens (no shadows, the app's heights and type sizes), so pages use variants such as `` and never restyle a component at the call site; change the variant in the component file instead. Add components with `bunx shadcn@latest add ` and answer no when it offers to overwrite an existing file. Base UI specifics: buttons default to `type="button"`, so a submit button needs `type="submit"`; a link that looks like a button is the router `Link` (or the landing `Href`) with `className={buttonVariants(...)}`, not `Button` with `render`, which would give it `role="button"`. `biome.json` relaxes a few lint rules for `src/components/ui` only.
- Charts are shadcn `Chart` (Recharts) in `src/components/dashboard/area-chart-recharts.tsx`, loaded lazily through `area-chart.tsx` so pages don't wait for Recharts.
- Destructive actions (removing a connection, product or flat cost) confirm first in an `AlertDialog` (`useConfirm` in `src/components/app/confirm.tsx`) and say what happens to the data.
- No all-caps text anywhere. Headings weight 400. No shadows or gradients on the marketing pages, no emoji.
@@ -95,4 +103,6 @@ Before editing files for a substantial task:
## Deploy
-Push to `main` runs CI (`.github/workflows/check.yml`) and publishes `ghcr.io/lobbystack/openprofit:latest`. Railway's `web` service (project `openprofit`, plus a Postgres service) deploys from the repo's `main` branch with Wait for CI on: each push waits for the GitHub checks, then deploys, and a failed check blocks it. Don't deploy production with `railway up`; it uploads the local working tree, uncommitted changes included. Railway's edge caches `.xml` responses, so give those an explicit `Cache-Control`.
+Pull requests run `.github/workflows/check.yml`. A push to `main` runs `.github/workflows/docker.yml`: the same checks, then it publishes `ghcr.io/morencyr/openprofit:latest`, then calls the Dokploy deploy webhook (secret `DOKPLOY_DEPLOY_WEBHOOK`). A failed check stops the image and the deploy.
+
+Production runs on Dokploy at deploy.lobbystack.com: project `OpenProfit`, application `web` (Docker source, that image, port 3000) and a `postgres` service (Postgres 18, reached over `dokploy-network`). Env vars live on the Dokploy application. The server's firewall admits ports 80 and 443 from Cloudflare only, so openprofit.dev's DNS is on Cloudflare (proxied, SSL mode Full). The domain is registered through Railway Domains (workspace level, not tied to a project), with its nameservers delegated to Cloudflare and the app reads the client's address from `CLIENT_IP_HEADER=cf-connecting-ip`. Records for mail (iCloud), Resend (`send`) and the PostHog proxy (`e`) stay DNS-only. Cloudflare may cache `.xml` responses, so give those an explicit `Cache-Control`.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 13eef6f..760551b 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,29 +1,29 @@
# Contributing to OpenProfit
-Issues and pull requests are welcome. Connectors are the most useful contribution. Most of this guide covers how to build one: the files to touch, the data to return, and how to test against a real account. To ask for a connector without building it, [open a connector request](https://github.com/lobbystack/openprofit/issues/new?template=connector.yml).
+Issues and pull requests are welcome. Connectors are the most useful contribution. Most of this guide covers how to build one: the files to touch, the data to return, and how to test against a real account. To ask for a connector without building it, [open a connector request](https://github.com/morencyr/openprofit/issues/new?template=connector.yml).
## Set up a development environment
-You need Node 22 and pnpm. Install the dependencies, copy `.env.example`, and generate a key with the `node` line:
+You need [Bun](https://bun.com) 1.3 or later. Install the dependencies, copy `.env.example`, and generate a key with the `bun -e` line:
```bash
-pnpm install
+bun install
cp .env.example .env
-node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
-pnpm dev
+bun -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
+bun run dev
```
Paste the key into `SECRET_KEY` in `.env` before you start the server. It encrypts provider credentials, and saving a connection fails without it. The app runs at http://localhost:3000.
-To sign in without an email provider, enter any address on `/login`. With `RESEND_API_KEY` unset, the server prints the sign-in link to the `pnpm dev` output. Open it, then create a workspace on the onboarding page.
+To sign in without an email provider, enter any address on `/login`. With `RESEND_API_KEY` unset, the server prints the sign-in link to the `bun run dev` output. Open it, then create a workspace on the onboarding page.
-For a workspace with a year of demo numbers, stop `pnpm dev` and run `pnpm db:seed`. After you sign in once, `pnpm db:seed --owner=you@example.com` adds your user to it.
+For a workspace with a year of demo numbers, stop `bun run dev` and run `bun run db:seed`. After you sign in once, `bun run db:seed --owner=you@example.com` adds your user to it.
### The local database
Local development uses PGlite, an embedded Postgres stored in `./data/openprofit`. Only one process can open that directory at a time:
-- Stop `pnpm dev` before you run `pnpm db:seed` or any script that imports `src/db`, or the script hangs
+- Stop `bun run dev` before you run `bun run db:seed` or any script that imports `src/db`, or the script hangs
- Stop processes with Ctrl+C. A `kill -9` during a write can corrupt the directory
- End one-off scripts with `process.exit(0)`, or PGlite keeps them running
- Delete `./data/openprofit` to start over
@@ -33,12 +33,12 @@ Local development uses PGlite, an embedded Postgres stored in `./data/openprofit
CI runs three commands on every pull request. Run them before you push:
```bash
-pnpm check # Biome lint and format
-npx tsc --noEmit # typecheck
-pnpm build # production build
+bun run check # Biome lint and format
+bunx --bun tsc --noEmit # typecheck
+bun run build # production build
```
-`npx biome check --write src` fixes formatting. Biome uses tabs and double quotes. The repository has no test suite, so check your change in the browser as well.
+`bunx biome check --write src` fixes formatting. Biome uses tabs and double quotes. The repository has no test suite, so check your change in the browser as well.
## Build a connector
@@ -246,7 +246,7 @@ Never log credentials, put them in a URL, or include them in an error message. S
### Test against a real account
-Call the connector from a one-off script before you try the UI. Importing `#/connectors` doesn't open the database, so the script runs alongside `pnpm dev`. Save it as `check.ts` at the repository root and keep it out of your commit:
+Call the connector from a one-off script before you try the UI. Importing `#/connectors` doesn't open the database, so the script runs alongside `bun run dev`. Save it as `check.ts` at the repository root and keep it out of your commit:
```ts
import { connector } from "#/connectors";
@@ -265,12 +265,12 @@ console.log(lines?.length, "lines");
Run it with `EXAMPLE_TOKEN` in `.env`:
```bash
-npx tsx --env-file=.env check.ts
+bun check.ts
```
Compare the totals with the provider's billing page for the same month. Run it twice and check that both runs return the same `externalId` values.
-Then test the full flow in `pnpm dev`:
+Then test the full flow in `bun run dev`:
1. Open **Connections**, pick your provider, paste the key and click **Test**. Check the label.
2. Click **Connect**. The first sync runs before the page returns. If it fails, the dev server log shows `[sync] first sync example:` with the error.
diff --git a/Dockerfile b/Dockerfile
index ccf9623..236c84a 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,21 +1,21 @@
# Single-container self-host. PGlite data lives on the /app/data volume.
-FROM node:22-alpine AS build
+FROM oven/bun:1.4.4-alpine AS build
WORKDIR /app
-RUN corepack enable
-COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
-RUN pnpm install --frozen-lockfile
+COPY package.json bun.lock ./
+COPY packages/cli/package.json packages/cli/
+RUN bun install --frozen-lockfile
COPY . .
-RUN pnpm build
+RUN bun run build
-FROM node:22-alpine
+FROM oven/bun:1.4.4-alpine
WORKDIR /app
ENV NODE_ENV=production
ENV DATABASE_URL=/app/data/openprofit
ENV PORT=3000
-RUN corepack enable
-COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
-RUN pnpm install --frozen-lockfile --prod
+COPY package.json bun.lock ./
+COPY packages/cli/package.json packages/cli/
+RUN bun install --frozen-lockfile --production --ignore-scripts
COPY drizzle ./drizzle
COPY --from=build /app/.output ./.output
EXPOSE 3000
-CMD ["node", ".output/server/index.mjs"]
+CMD ["bun", ".output/server/index.mjs"]
diff --git a/README.md b/README.md
index 7622c96..5ef4b0a 100644
--- a/README.md
+++ b/README.md
@@ -4,12 +4,12 @@
### Finance for developers
-[Website](https://openprofit.dev) · [Docs](https://openprofit.dev/docs) · [Self-host](https://openprofit.dev/docs/self-host) · [Connectors](https://openprofit.dev/docs/connectors) · [Security](https://openprofit.dev/security) · [Issues](https://github.com/lobbystack/openprofit/issues)
+[Website](https://openprofit.dev) · [Docs](https://openprofit.dev/docs) · [Self-host](https://openprofit.dev/docs/self-host) · [Connectors](https://openprofit.dev/docs/connectors) · [Security](https://openprofit.dev/security) · [Issues](https://github.com/morencyr/openprofit/issues)
-[](https://github.com/lobbystack/openprofit/actions/workflows/check.yml)
+[](https://github.com/morencyr/openprofit/actions/workflows/check.yml)
[](LICENSE)
-[](https://github.com/lobbystack/openprofit/pkgs/container/openprofit)
-[](https://github.com/lobbystack/openprofit)
+[](https://github.com/morencyr/openprofit/pkgs/container/openprofit)
+[](https://github.com/morencyr/openprofit)
@@ -96,7 +96,7 @@ MIT licensed. One Docker image with Postgres inside, or point it at your own. Yo
| MongoDB Atlas | Cost | Daily invoice line items per project |
| Flat costs | Cost | Any monthly, yearly or one-time amount, typed in |
-App Store, Google Play and Supabase are next. A connector is one file in [`src/connectors`](src/connectors) that implements `verify` and `fetchRevenue` or `fetchCosts`. If you want one that is not here, [open an issue](https://github.com/lobbystack/openprofit/issues) with a link to the provider's billing API, or send a pull request.
+App Store, Google Play and Supabase are next. A connector is one file in [`src/connectors`](src/connectors) that implements `verify` and `fetchRevenue` or `fetchCosts`. If you want one that is not here, [open an issue](https://github.com/morencyr/openprofit/issues) with a link to the provider's billing API, or send a pull request.
## Getting started
@@ -115,12 +115,12 @@ docker run -d \
-v openprofit_data:/app/data \
-e SECRET_KEY=$(node -e "console.log(require('crypto').randomBytes(32).toString('base64'))") \
-e APP_URL=http://localhost:3000 \
- ghcr.io/lobbystack/openprofit:latest
+ ghcr.io/morencyr/openprofit:latest
```
Open http://localhost:3000/login and enter your email. Without an email provider the sign-in link prints in `docker logs openprofit`. Set `RESEND_API_KEY` and `EMAIL_FROM` to send it by mail. Point `DATABASE_URL` at a `postgres://` server to use your own database.
-The [self-host guide](https://openprofit.dev/docs/self-host) covers updates and Railway. The [environment reference](https://openprofit.dev/docs/environment) lists every variable.
+The [self-host guide](https://openprofit.dev/docs/self-host) covers updates, Dokploy and Railway. The [environment reference](https://openprofit.dev/docs/environment) lists every variable.
## How it works
@@ -137,22 +137,22 @@ Postgres everywhere: PGlite embedded for self-host and local development, a Post
## Development
-Node 22 and pnpm.
+[Bun](https://bun.com) 1.3 or later.
```bash
-pnpm install
+bun install
cp .env.example .env # set SECRET_KEY
-pnpm db:seed # a demo workspace with a year of numbers
-pnpm dev
+bun run db:seed # a demo workspace with a year of numbers
+bun run dev
```
Sign in once at http://localhost:3000/login, then attach the demo workspace to your user:
```bash
-pnpm db:seed --owner=you@example.com
+bun run db:seed --owner=you@example.com
```
-Checks: `pnpm check` (Biome), `npx tsc --noEmit`, `pnpm build`. After a schema change, `pnpm db:generate` writes a migration; migrations run when the server starts.
+Checks: `bun run check` (Biome), `bunx --bun tsc --noEmit`, `bun run build`. After a schema change, `bun run db:generate` writes a migration; migrations run when the server starts.
## Contributing
diff --git a/bun.lock b/bun.lock
new file mode 100644
index 0000000..932985f
--- /dev/null
+++ b/bun.lock
@@ -0,0 +1,1216 @@
+{
+ "lockfileVersion": 1,
+ "configVersion": 1,
+ "workspaces": {
+ "": {
+ "name": "openprofit-app",
+ "dependencies": {
+ "@base-ui/react": "^1.8.0",
+ "@better-auth/drizzle-adapter": "^1.7.7",
+ "@electric-sql/pglite": "^0.5.8",
+ "@fontsource-variable/geist": "^5.3.0",
+ "@modelcontextprotocol/server": "^2.3.1",
+ "@opentelemetry/api": "^1.9.1",
+ "@opentelemetry/api-logs": "^0.222.0",
+ "@opentelemetry/exporter-logs-otlp-http": "^0.222.0",
+ "@opentelemetry/exporter-trace-otlp-http": "^0.222.0",
+ "@opentelemetry/resources": "^2.11.0",
+ "@opentelemetry/sdk-logs": "^0.222.0",
+ "@opentelemetry/sdk-trace-base": "^2.11.0",
+ "@resvg/resvg-wasm": "2.6.2",
+ "@tailwindcss/vite": "^4.1.18",
+ "@tanstack/react-devtools": "0.10.13",
+ "@tanstack/react-router": "1.170.41",
+ "@tanstack/react-router-devtools": "1.167.2",
+ "@tanstack/react-start": "1.168.60",
+ "better-auth": "^1.7.7",
+ "class-variance-authority": "^0.7.1",
+ "cmdk": "^1.1.1",
+ "cn": "^0.4.0",
+ "croner": "^10.0.1",
+ "drizzle-orm": "^0.45.3",
+ "lucide-react": "^0.577.0",
+ "marked": "^18.0.14",
+ "nitro": "3.0.260610-beta",
+ "pg": "^8.23.1",
+ "posthog-js": "^1.436.1",
+ "posthog-node": "^5.55.0",
+ "react": "^19.2.0",
+ "react-dom": "^19.2.0",
+ "recharts": "3.8.0",
+ "simple-icons": "^16.34.0",
+ "tailwindcss": "^4.1.18",
+ "tw-animate-css": "^1.3.6",
+ "zod": "^4.6.5",
+ },
+ "devDependencies": {
+ "@biomejs/biome": "2.4.5",
+ "@tailwindcss/typography": "^0.5.16",
+ "@tanstack/devtools-vite": "0.8.5",
+ "@tanstack/intent": "^0.5.4",
+ "@tanstack/router-cli": "^1.132.0",
+ "@types/node": "^22.10.2",
+ "@types/pg": "^8.23.1",
+ "@types/react": "^19.2.0",
+ "@types/react-dom": "^19.2.0",
+ "@vitejs/plugin-react": "^6.0.1",
+ "drizzle-kit": "^0.31.11",
+ "typescript": "^6.0.2",
+ "vite": "^8.0.0",
+ },
+ },
+ "packages/cli": {
+ "name": "openprofit",
+ "version": "0.1.0",
+ "bin": {
+ "openprofit": "dist/cli.js",
+ },
+ "dependencies": {
+ "@modelcontextprotocol/client": "^2.3.1",
+ "@modelcontextprotocol/server": "^2.3.1",
+ "zod": "^4.6.5",
+ },
+ "devDependencies": {
+ "@types/node": "^22.20.5",
+ "typescript": "^6.0.3",
+ },
+ },
+ },
+ "packages": {
+ "@babel/code-frame": ["@babel/code-frame@7.29.7", "", { "dependencies": { "@babel/helper-validator-identifier": "7.29.7", "js-tokens": "4.0.0", "picocolors": "1.1.1" } }, "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw=="],
+
+ "@babel/compat-data": ["@babel/compat-data@7.29.7", "", {}, "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg=="],
+
+ "@babel/core": ["@babel/core@7.29.7", "", { "dependencies": { "@babel/code-frame": "7.29.7", "@babel/generator": "7.29.8", "@babel/helper-compilation-targets": "7.29.7", "@babel/helper-module-transforms": "7.29.7", "@babel/helpers": "7.29.7", "@babel/parser": "7.29.9", "@babel/template": "7.29.7", "@babel/traverse": "7.29.8", "@babel/types": "7.29.8", "@jridgewell/remapping": "2.3.5", "convert-source-map": "2.0.0", "debug": "4.4.3", "gensync": "1.0.0-beta.2", "json5": "2.2.3", "semver": "6.3.1" } }, "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA=="],
+
+ "@babel/generator": ["@babel/generator@7.29.8", "", { "dependencies": { "@babel/parser": "7.29.9", "@babel/types": "7.29.8", "@jridgewell/gen-mapping": "0.3.13", "@jridgewell/trace-mapping": "0.3.31", "jsesc": "3.1.0" } }, "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg=="],
+
+ "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.29.7", "", { "dependencies": { "@babel/compat-data": "7.29.7", "@babel/helper-validator-option": "7.29.7", "browserslist": "4.29.3", "lru-cache": "5.1.1", "semver": "6.3.1" } }, "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g=="],
+
+ "@babel/helper-globals": ["@babel/helper-globals@7.29.7", "", {}, "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA=="],
+
+ "@babel/helper-module-imports": ["@babel/helper-module-imports@7.29.7", "", { "dependencies": { "@babel/traverse": "7.29.8", "@babel/types": "7.29.8" } }, "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g=="],
+
+ "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.29.7", "", { "dependencies": { "@babel/helper-module-imports": "7.29.7", "@babel/helper-validator-identifier": "7.29.7", "@babel/traverse": "7.29.8" }, "peerDependencies": { "@babel/core": "7.29.7" } }, "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg=="],
+
+ "@babel/helper-string-parser": ["@babel/helper-string-parser@7.29.7", "", {}, "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw=="],
+
+ "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.29.7", "", {}, "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg=="],
+
+ "@babel/helper-validator-option": ["@babel/helper-validator-option@7.29.7", "", {}, "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw=="],
+
+ "@babel/helpers": ["@babel/helpers@7.29.7", "", { "dependencies": { "@babel/template": "7.29.7", "@babel/types": "7.29.8" } }, "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg=="],
+
+ "@babel/parser": ["@babel/parser@7.29.9", "", { "dependencies": { "@babel/types": "7.29.8" }, "bin": "./bin/babel-parser.js" }, "sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA=="],
+
+ "@babel/runtime": ["@babel/runtime@7.29.7", "", {}, "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw=="],
+
+ "@babel/template": ["@babel/template@7.29.7", "", { "dependencies": { "@babel/code-frame": "7.29.7", "@babel/parser": "7.29.9", "@babel/types": "7.29.8" } }, "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg=="],
+
+ "@babel/traverse": ["@babel/traverse@7.29.8", "", { "dependencies": { "@babel/code-frame": "7.29.7", "@babel/generator": "7.29.8", "@babel/helper-globals": "7.29.7", "@babel/parser": "7.29.9", "@babel/template": "7.29.7", "@babel/types": "7.29.8", "debug": "4.4.3" } }, "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg=="],
+
+ "@babel/types": ["@babel/types@7.29.8", "", { "dependencies": { "@babel/helper-string-parser": "7.29.7", "@babel/helper-validator-identifier": "7.29.7" } }, "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg=="],
+
+ "@base-ui/react": ["@base-ui/react@1.8.0", "", { "dependencies": { "@babel/runtime": "7.29.7", "@base-ui/utils": "0.4.0", "@floating-ui/react-dom": "2.1.9", "@floating-ui/utils": "0.2.12", "use-sync-external-store": "1.7.0" }, "optionalDependencies": { "@types/react": "19.3.0" }, "peerDependencies": { "react": "19.3.0", "react-dom": "19.3.0" } }, "sha512-P0/1sxo6SBVZOklKMIedvTWqw2s2IQzi9x5bIVsXu980cuSOD4NeuRSs+/L7LZQfDkZP/uRZyGPyfFl/B1oH+Q=="],
+
+ "@base-ui/utils": ["@base-ui/utils@0.4.0", "", { "dependencies": { "@babel/runtime": "7.29.7", "@floating-ui/utils": "0.2.12", "reselect": "5.3.0", "use-sync-external-store": "1.7.0" }, "optionalDependencies": { "@types/react": "19.3.0" }, "peerDependencies": { "react": "19.3.0", "react-dom": "19.3.0" } }, "sha512-bO9fz25kKtPf+aZVyfQrC0PDmJdmVni31W2hCS5/Owb+inwdIL3XU26pCPRPlt4LSxZrBgLwubXQXQlKaFEZzw=="],
+
+ "@better-auth/core": ["@better-auth/core@1.7.7", "", { "dependencies": { "@opentelemetry/semantic-conventions": "1.43.0", "@standard-schema/spec": "1.1.0", "zod": "4.6.5" }, "optionalDependencies": { "@opentelemetry/api": "1.9.1" }, "peerDependencies": { "@better-auth/utils": "0.4.2", "@better-fetch/fetch": "1.3.2", "better-call": "1.4.0", "jose": "6.2.12", "kysely": "0.29.6", "nanostores": "1.5.4" } }, "sha512-srgFzHEjB2WWlokFz1i4BfG41sNhsA105Pukgqu6RrEh5A+LSkzf1mCHydVipkjt9l5qswtBMi7IL6ouHbZL4Q=="],
+
+ "@better-auth/drizzle-adapter": ["@better-auth/drizzle-adapter@1.7.7", "", { "optionalDependencies": { "drizzle-orm": "0.45.3" }, "peerDependencies": { "@better-auth/core": "1.7.7", "@better-auth/utils": "0.4.2" } }, "sha512-qon0U94PR5FQysuyGoAlGVQpIIiNg5dtDpwjE63sN/HjoRWZadZzHPcS9mn7JsJyQZK6iTNhd7LD0AaXt2f78w=="],
+
+ "@better-auth/kysely-adapter": ["@better-auth/kysely-adapter@1.7.7", "", { "optionalDependencies": { "kysely": "0.29.6" }, "peerDependencies": { "@better-auth/core": "1.7.7", "@better-auth/utils": "0.4.2" } }, "sha512-9FONOCgOcrQI9wJ5v1oDGIg9sT7pa9RjZZQ4fsCTudo8R87SrIGNUvUxDFTJhZvUblvFfGaIBR9Vb8LA+8bqLQ=="],
+
+ "@better-auth/memory-adapter": ["@better-auth/memory-adapter@1.7.7", "", { "peerDependencies": { "@better-auth/core": "1.7.7", "@better-auth/utils": "0.4.2" } }, "sha512-FqKFEe+b5tXXV0gRbyirca+qXgMpLOeJ8Wk19yykb/scQKy0WJ4k22WzEV3TTPctQV9DZhwCXPlDtQhnlOv5Gg=="],
+
+ "@better-auth/mongo-adapter": ["@better-auth/mongo-adapter@1.7.7", "", { "peerDependencies": { "@better-auth/core": "1.7.7", "@better-auth/utils": "0.4.2" } }, "sha512-ZnVDuRrXqbf0oHphrEN27oTImNH5NTO26dtWatq5cXyYAsH7goof9QIoTOmxTbBxUQahKBw9T6+9h6n+RtOE+g=="],
+
+ "@better-auth/prisma-adapter": ["@better-auth/prisma-adapter@1.7.7", "", { "peerDependencies": { "@better-auth/core": "1.7.7", "@better-auth/utils": "0.4.2" } }, "sha512-4YcnrcVdvWiAZw0sZl63tWUClPXg5r3QsLn7C2sG7kKEBY06zOng0ibecyxRBixKq1zE1ceHuEUqez5Rhi+nQA=="],
+
+ "@better-auth/telemetry": ["@better-auth/telemetry@1.7.7", "", { "peerDependencies": { "@better-auth/core": "1.7.7", "@better-auth/utils": "0.4.2", "@better-fetch/fetch": "1.3.2" } }, "sha512-PaRA6i+kAioVYmza2gHPcdrxP0hAotph4KV9hft2GeNJq+AZXDiBu3FuLM9HxvcmiZeUT74Vufqd9ypmB8veTA=="],
+
+ "@better-auth/utils": ["@better-auth/utils@0.4.2", "", { "dependencies": { "@noble/hashes": "2.4.0" } }, "sha512-AUxrvu+HaaODsUyzDxFgwd/8RZ1yZaYo42LXKSrU2oGgR38pS1ij8nqQKNgtTWoYGpNevNXtCfgTy6loHveW9A=="],
+
+ "@better-fetch/fetch": ["@better-fetch/fetch@1.3.2", "", {}, "sha512-Gs7n99b5tqUC6cQAPbV0uED3IraHB6xQbHLQ/C3l7ZFafHScOx9pQ+DYmP5blbLFShVWLqxNUlI9wi4xU/X+ow=="],
+
+ "@biomejs/biome": ["@biomejs/biome@2.4.5", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.4.5", "@biomejs/cli-darwin-x64": "2.4.5", "@biomejs/cli-linux-arm64": "2.4.5", "@biomejs/cli-linux-arm64-musl": "2.4.5", "@biomejs/cli-linux-x64": "2.4.5", "@biomejs/cli-linux-x64-musl": "2.4.5", "@biomejs/cli-win32-arm64": "2.4.5", "@biomejs/cli-win32-x64": "2.4.5" }, "bin": { "biome": "bin/biome" } }, "sha512-OWNCyMS0Q011R6YifXNOg6qsOg64IVc7XX6SqGsrGszPbkVCoaO7Sr/lISFnXZ9hjQhDewwZ40789QmrG0GYgQ=="],
+
+ "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.4.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-lGS4Nd5O3KQJ6TeWv10mElnx1phERhBxqGP/IKq0SvZl78kcWDFMaTtVK+w3v3lusRFxJY78n07PbKplirsU5g=="],
+
+ "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.4.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-6MoH4tyISIBNkZ2Q5T1R7dLd5BsITb2yhhhrU9jHZxnNSNMWl+s2Mxu7NBF8Y3a7JJcqq9nsk8i637z4gqkJxQ=="],
+
+ "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.4.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-U1GAG6FTjhAO04MyH4xn23wRNBkT6H7NentHh+8UxD6ShXKBm5SY4RedKJzkUThANxb9rUKIPc7B8ew9Xo/cWg=="],
+
+ "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.4.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-iqLDgpzobG7gpBF0fwEVS/LT8kmN7+S0E2YKFDtqliJfzNLnAiV2Nnyb+ehCDCJgAZBASkYHR2o60VQWikpqIg=="],
+
+ "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.4.5", "", { "os": "linux", "cpu": "x64" }, "sha512-NdODlSugMzTlENPTa4z0xB82dTUlCpsrOxc43///aNkTLblIYH4XpYflBbf5ySlQuP8AA4AZd1qXhV07IdrHdQ=="],
+
+ "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.4.5", "", { "os": "linux", "cpu": "x64" }, "sha512-NlKa7GpbQmNhZf9kakQeddqZyT7itN7jjWdakELeXyTU3pg/83fTysRRDPJD0akTfKDl6vZYNT9Zqn4MYZVBOA=="],
+
+ "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.4.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-EBfrTqRIWOFSd7CQb/0ttjHMR88zm3hGravnDwUA9wHAaCAYsULKDebWcN5RmrEo1KBtl/gDVJMrFjNR0pdGUw=="],
+
+ "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.4.5", "", { "os": "win32", "cpu": "x64" }, "sha512-Pmhv9zT95YzECfjEHNl3mN9Vhusw9VA5KHY0ZvlGsxsjwS5cb7vpRnHzJIv0vG7jB0JI7xEaMH9ddfZm/RozBw=="],
+
+ "@drizzle-team/brocli": ["@drizzle-team/brocli@0.10.2", "", {}, "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="],
+
+ "@electric-sql/pglite": ["@electric-sql/pglite@0.5.8", "", {}, "sha512-n9tsbUOhwx2epK1V0ZG9Ar4SHWUju04dhmzZXiSBXwBoleOvIfals33NAaWgagQVAL4Rbvx/Ptsu3P+pA09f6Q=="],
+
+ "@emnapi/core": ["@emnapi/core@1.11.3", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.3", "tslib": "2.8.1" } }, "sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg=="],
+
+ "@emnapi/runtime": ["@emnapi/runtime@1.11.3", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA=="],
+
+ "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.3", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g=="],
+
+ "@esbuild-kit/core-utils": ["@esbuild-kit/core-utils@3.3.2", "", { "dependencies": { "esbuild": "0.18.20", "source-map-support": "0.5.21" } }, "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ=="],
+
+ "@esbuild-kit/esm-loader": ["@esbuild-kit/esm-loader@2.6.5", "", { "dependencies": { "@esbuild-kit/core-utils": "3.3.2", "get-tsconfig": "4.14.3" } }, "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA=="],
+
+ "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="],
+
+ "@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="],
+
+ "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="],
+
+ "@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="],
+
+ "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="],
+
+ "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="],
+
+ "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="],
+
+ "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="],
+
+ "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="],
+
+ "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="],
+
+ "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="],
+
+ "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="],
+
+ "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="],
+
+ "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="],
+
+ "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="],
+
+ "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="],
+
+ "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="],
+
+ "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="],
+
+ "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="],
+
+ "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="],
+
+ "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="],
+
+ "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg=="],
+
+ "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="],
+
+ "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="],
+
+ "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="],
+
+ "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="],
+
+ "@floating-ui/core": ["@floating-ui/core@1.8.0", "", { "dependencies": { "@floating-ui/utils": "0.2.12" } }, "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ=="],
+
+ "@floating-ui/dom": ["@floating-ui/dom@1.8.0", "", { "dependencies": { "@floating-ui/core": "1.8.0", "@floating-ui/utils": "0.2.12" } }, "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg=="],
+
+ "@floating-ui/react-dom": ["@floating-ui/react-dom@2.1.9", "", { "dependencies": { "@floating-ui/dom": "1.8.0" }, "peerDependencies": { "react": "19.3.0", "react-dom": "19.3.0" } }, "sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg=="],
+
+ "@floating-ui/utils": ["@floating-ui/utils@0.2.12", "", {}, "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww=="],
+
+ "@fontsource-variable/geist": ["@fontsource-variable/geist@5.3.0", "", {}, "sha512-j0m+vLQuG5XAYoHtGCVu0spvlGreR3EzpECUVzkFmI1mTVnAO38l/NEPDCFgZ177JxzYJCLSmTQibIiYPilGrA=="],
+
+ "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "1.6.0", "@jridgewell/trace-mapping": "0.3.31" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
+
+ "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "0.3.13", "@jridgewell/trace-mapping": "0.3.31" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="],
+
+ "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
+
+ "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.6.0", "", {}, "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw=="],
+
+ "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "3.1.2", "@jridgewell/sourcemap-codec": "1.6.0" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
+
+ "@modelcontextprotocol/client": ["@modelcontextprotocol/client@2.3.1", "", { "dependencies": { "@modelcontextprotocol/core": "2.3.1", "cross-spawn": "7.0.6", "eventsource": "3.0.7", "eventsource-parser": "3.1.1", "jose": "6.2.12", "pkce-challenge": "5.0.1", "zod": "4.6.5" } }, "sha512-mIGZXpHsjnZ6lD+gD/WCMpR5k8yVQQ8nNFH1N0Srf7AvnwTUMYD6pvTY8ng2+He5FfV7YMZLmrjL7cLa/cc3dQ=="],
+
+ "@modelcontextprotocol/core": ["@modelcontextprotocol/core@2.3.1", "", { "dependencies": { "zod": "4.6.5" } }, "sha512-laVmIhPGpWi7rG9q+0UigblRN0Hws/Yjlb6qLFtVqryXVLkc4h+yN8z731POD2LnAGQlFe7/tXhUm7Bi0YB91g=="],
+
+ "@modelcontextprotocol/server": ["@modelcontextprotocol/server@2.3.1", "", { "dependencies": { "@modelcontextprotocol/core": "2.3.1", "zod": "4.6.5" } }, "sha512-e59MfWuSssj6DoQ96JCTqdW1AXT5/XtnTl0WWd6MU1Ka434fFUGGosCLJbGNySDhHGvxQWoRWK137FXYFkYNWw=="],
+
+ "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.2.4", "", { "dependencies": { "@tybys/wasm-util": "0.10.4" }, "peerDependencies": { "@emnapi/core": "1.11.3", "@emnapi/runtime": "1.11.3" } }, "sha512-AJxoUD2/15ESHbvpcyjU274nsAPLuOtPHCk0vKJM5pj//Fg/B1FXNWjPnXTT9PymCYYiHo4zPj0ZomXBKhoy7g=="],
+
+ "@neodrag/core": ["@neodrag/core@3.0.0-next.11", "", {}, "sha512-3WQWxyrbxiaK9zS5JU2wJsW2gpoQlZBXVghduBh61JpqaeE0T0cte8R0qYK2RuJo3J2TYQYqxO19CpG/C1i5eg=="],
+
+ "@neodrag/solid": ["@neodrag/solid@3.0.0-next.11", "", { "peerDependencies": { "@neodrag/core": "3.0.0-next.11", "solid-js": "1.9.15" } }, "sha512-vCBIn/pimjWMQ6vhTS2/O1XNAwzVtc4eUhdbQ91WykbZWWqQ5NocDXt/1OdYrEkeRzJcpCv8wEz5PnMkgKP81Q=="],
+
+ "@noble/ciphers": ["@noble/ciphers@2.4.0", "", {}, "sha512-AnjFn0Jv92laAkvMrghlFZq4qQCIN/4DxFV/eooqtC2YTjB7kBeLMS2T9KJX4Dn+ZVXLOwK0lSgqDtx9gvxtiw=="],
+
+ "@noble/hashes": ["@noble/hashes@2.4.0", "", {}, "sha512-X5XaVWZIBCT7HHZGm5I7ZQXDwLG+bGXuSrMQAW+7Zvl87h1kmc1ZB1VSRJcpUfoUrGQp4Fkoxm5kZ+Ms+aW+eA=="],
+
+ "@oozcitak/dom": ["@oozcitak/dom@2.0.2", "", { "dependencies": { "@oozcitak/infra": "2.0.2", "@oozcitak/url": "3.0.0", "@oozcitak/util": "10.0.0" } }, "sha512-GjpKhkSYC3Mj4+lfwEyI1dqnsKTgwGy48ytZEhm4A/xnH/8z9M3ZVXKr/YGQi3uCLs1AEBS+x5T2JPiueEDW8w=="],
+
+ "@oozcitak/infra": ["@oozcitak/infra@2.0.2", "", { "dependencies": { "@oozcitak/util": "10.0.0" } }, "sha512-2g+E7hoE2dgCz/APPOEK5s3rMhJvNxSMBrP+U+j1OWsIbtSpWxxlUjq1lU8RIsFJNYv7NMlnVsCuHcUzJW+8vA=="],
+
+ "@oozcitak/url": ["@oozcitak/url@3.0.0", "", { "dependencies": { "@oozcitak/infra": "2.0.2", "@oozcitak/util": "10.0.0" } }, "sha512-ZKfET8Ak1wsLAiLWNfFkZc/BraDccuTJKR6svTYc7sVjbR+Iu0vtXdiDMY4o6jaFl5TW2TlS7jbLl4VovtAJWQ=="],
+
+ "@oozcitak/util": ["@oozcitak/util@10.0.0", "", {}, "sha512-hAX0pT/73190NLqBPPWSdBVGtbY6VOhWYK3qqHqtXQ1gK7kS2yz4+ivsN07hpJ6I3aeMtKP6J6npsEKOAzuTLA=="],
+
+ "@opentelemetry/api": ["@opentelemetry/api@1.9.1", "", {}, "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q=="],
+
+ "@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.222.0", "", { "dependencies": { "@opentelemetry/api": "1.9.1" } }, "sha512-9mb1If+IF6u0ZVXkHQ6ogEae5HwA6ajIVUgpSDQyRASxft6BSXHvBvPooRle3yFN/fKnCdSOnuu0OC3PLcF6+g=="],
+
+ "@opentelemetry/core": ["@opentelemetry/core@2.11.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "1.43.0" }, "peerDependencies": { "@opentelemetry/api": "1.9.1" } }, "sha512-7YP44XH0tV6+Mb54x2YGf84i7yi+31MBZlE8JwvozkxyTvXbSp10X7cI7YE49ChJ3shMJoBmCJF3+1QFBJctGA=="],
+
+ "@opentelemetry/exporter-logs-otlp-http": ["@opentelemetry/exporter-logs-otlp-http@0.222.0", "", { "dependencies": { "@opentelemetry/otlp-exporter-base": "0.222.0", "@opentelemetry/otlp-transformer": "0.222.0", "@opentelemetry/sdk-logs": "0.222.0" }, "peerDependencies": { "@opentelemetry/api": "1.9.1" } }, "sha512-GqwLZohJTf/sttYlOpT1oFTJ9ScYaKnk0sOx4Qe/+KmXYVOa+v94cfnkUkFKDuvTODWhCL50Hz3gvsZD6ngQpg=="],
+
+ "@opentelemetry/exporter-trace-otlp-http": ["@opentelemetry/exporter-trace-otlp-http@0.222.0", "", { "dependencies": { "@opentelemetry/otlp-exporter-base": "0.222.0", "@opentelemetry/otlp-transformer": "0.222.0", "@opentelemetry/sdk-trace": "2.11.0" }, "peerDependencies": { "@opentelemetry/api": "1.9.1" } }, "sha512-RCnPWcHppwiquQ+cV3nWvNwdf0MG1w26e5jewW2T83nTZOlXgcg88sY9ulCVgagGHcq1mj0L0GP6YHgzk2v8oA=="],
+
+ "@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.222.0", "", { "dependencies": { "@opentelemetry/core": "2.11.0", "@opentelemetry/otlp-transformer": "0.222.0" }, "peerDependencies": { "@opentelemetry/api": "1.9.1" } }, "sha512-YbywG3veEm2Fb6TbdxRkuquWob6eVWXuA8/Ba1tXz9jHfUqpdE3keilOHEtPboC4CvS1bjeeVfNkWGOOrLj+lw=="],
+
+ "@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.222.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.222.0", "@opentelemetry/core": "2.11.0", "@opentelemetry/resources": "2.11.0", "@opentelemetry/sdk-logs": "0.222.0", "@opentelemetry/sdk-metrics": "2.11.0", "@opentelemetry/sdk-trace": "2.11.0" }, "peerDependencies": { "@opentelemetry/api": "1.9.1" } }, "sha512-/F3BZ89+CJQnZkMh2tCrtcdB+XT2Dxhj4FFE+WPQ//413hmFL0/RfEX6vgOIWGhiSzrkHWTK3+6SiT7K5/g/jQ=="],
+
+ "@opentelemetry/resources": ["@opentelemetry/resources@2.11.0", "", { "dependencies": { "@opentelemetry/core": "2.11.0", "@opentelemetry/semantic-conventions": "1.43.0" }, "peerDependencies": { "@opentelemetry/api": "1.9.1" } }, "sha512-Ie7+8q8MDF4FAEQCKVMTx3ReUvxiIAgIiiW3c9JdmP8+HMcDy20puT+AHjexnExgnbvBxjQ9fjkFDWrikJ2jQA=="],
+
+ "@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.222.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.222.0", "@opentelemetry/core": "2.11.0", "@opentelemetry/resources": "2.11.0", "@opentelemetry/semantic-conventions": "1.43.0" }, "peerDependencies": { "@opentelemetry/api": "1.9.1" } }, "sha512-+19YHODIjaUCArxleaJtuufFZVpz/xvvK+VllQqE+W8hHolxdoRwHfK/s667zezwh1hkx6FFF+oYzetYgqK+Bg=="],
+
+ "@opentelemetry/sdk-metrics": ["@opentelemetry/sdk-metrics@2.11.0", "", { "dependencies": { "@opentelemetry/core": "2.11.0", "@opentelemetry/resources": "2.11.0" }, "peerDependencies": { "@opentelemetry/api": "1.9.1" } }, "sha512-7GXXcObyHyDUUSG+L+kJoquty01bzm7ivE7+SSgXXJcHuPzGviptxwARmI2c+bnnxjexGQbJnyNlN8HxBP/Y7A=="],
+
+ "@opentelemetry/sdk-trace": ["@opentelemetry/sdk-trace@2.11.0", "", { "dependencies": { "@opentelemetry/core": "2.11.0", "@opentelemetry/resources": "2.11.0", "@opentelemetry/semantic-conventions": "1.43.0" }, "peerDependencies": { "@opentelemetry/api": "1.9.1" } }, "sha512-fFnTqGm8/G73GQVnxYi7LXa1ZVYEUvgL6XI1LpvV0bPC7WQ/ZGgKxCSl8FnlZBKto9JHHEFTO6s6CUpvvtwFrA=="],
+
+ "@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.11.0", "", { "dependencies": { "@opentelemetry/core": "2.11.0", "@opentelemetry/resources": "2.11.0", "@opentelemetry/sdk-trace": "2.11.0", "@opentelemetry/semantic-conventions": "1.43.0" }, "peerDependencies": { "@opentelemetry/api": "1.9.1" } }, "sha512-H19x/TX/LZdqiYOjM7fqtSxwlplC5pgelavqbQdHbhdq0q/AI/TGkM2dfGuuynTXmJPeF2HoZVoPDu+TGoW78A=="],
+
+ "@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.43.0", "", {}, "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg=="],
+
+ "@oxc-parser/binding-android-arm-eabi": ["@oxc-parser/binding-android-arm-eabi@0.120.0", "", { "os": "android", "cpu": "arm" }, "sha512-WU3qtINx802wOl8RxAF1v0VvmC2O4D9M8Sv486nLeQ7iPHVmncYZrtBhB4SYyX+XZxj2PNnCcN+PW21jHgiOxg=="],
+
+ "@oxc-parser/binding-android-arm64": ["@oxc-parser/binding-android-arm64@0.120.0", "", { "os": "android", "cpu": "arm64" }, "sha512-SEf80EHdhlbjZEgzeWm0ZA/br4GKMenDW3QB/gtyeTV1gStvvZeFi40ioHDZvds2m4Z9J1bUAUL8yn1/+A6iGg=="],
+
+ "@oxc-parser/binding-darwin-arm64": ["@oxc-parser/binding-darwin-arm64@0.120.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-xVrrbCai8R8CUIBu3CjryutQnEYhZqs1maIqDvtUCFZb8vY33H7uh9mHpL3a0JBIKoBUKjPH8+rzyAeXnS2d6A=="],
+
+ "@oxc-parser/binding-darwin-x64": ["@oxc-parser/binding-darwin-x64@0.120.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-xyHBbnJ6mydnQUH7MAcafOkkrNzQC6T+LXgDH/3InEq2BWl/g424IMRiJVSpVqGjB+p2bd0h0WRR8iIwzjU7rw=="],
+
+ "@oxc-parser/binding-freebsd-x64": ["@oxc-parser/binding-freebsd-x64@0.120.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-UMnVRllquXUYTeNfFKmxTTEdZ/ix1nLl0ducDzMSREoWYGVIHnOOxoKMWlCOvRr9Wk/HZqo2rh1jeumbPGPV9A=="],
+
+ "@oxc-parser/binding-linux-arm-gnueabihf": ["@oxc-parser/binding-linux-arm-gnueabihf@0.120.0", "", { "os": "linux", "cpu": "arm" }, "sha512-tkvn2CQ7QdcsMnpfiX3fd3wA3EFsWKYlcQzq9cFw/xc89Al7W6Y4O0FgLVkVQpo0Tnq/qtE1XfkJOnRRA9S/NA=="],
+
+ "@oxc-parser/binding-linux-arm-musleabihf": ["@oxc-parser/binding-linux-arm-musleabihf@0.120.0", "", { "os": "linux", "cpu": "arm" }, "sha512-WN5y135Ic42gQDk9grbwY9++fDhqf8knN6fnP+0WALlAUh4odY/BDK1nfTJRSfpJD9P3r1BwU0m3pW2DU89whQ=="],
+
+ "@oxc-parser/binding-linux-arm64-gnu": ["@oxc-parser/binding-linux-arm64-gnu@0.120.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-1GgQBCcXvFMw99EPdMy+4NZ3aYyXsxjf9kbUUg8HuAy3ZBXzOry5KfFEzT9nqmgZI1cuetvApkiJBZLAPo8uaw=="],
+
+ "@oxc-parser/binding-linux-arm64-musl": ["@oxc-parser/binding-linux-arm64-musl@0.120.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-gmMQ70gsPdDBgpcErvJEoWNBr7bJooSLlvOBVBSGfOzlP5NvJ3bFvnUeZZ9d+dPrqSngtonf7nyzWUTUj/U+lw=="],
+
+ "@oxc-parser/binding-linux-ppc64-gnu": ["@oxc-parser/binding-linux-ppc64-gnu@0.120.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-T/kZuU0ajop0xhzVMwH5r3srC9Nqup5HaIo+3uFjIN5uPxa0LvSxC1ZqP4aQGJVW5G0z8/nCkjIfSMS91P/wzw=="],
+
+ "@oxc-parser/binding-linux-riscv64-gnu": ["@oxc-parser/binding-linux-riscv64-gnu@0.120.0", "", { "os": "linux", "cpu": "none" }, "sha512-vn21KXLAXzaI3N5CZWlBr1iWeXLl9QFIMor7S1hUjUGTeUuWCoE6JZB040/ZNDwf+JXPX8Ao9KbmJq9FMC2iGw=="],
+
+ "@oxc-parser/binding-linux-riscv64-musl": ["@oxc-parser/binding-linux-riscv64-musl@0.120.0", "", { "os": "linux", "cpu": "none" }, "sha512-SUbUxlar007LTGmSLGIC5x/WJvwhdX+PwNzFJ9f/nOzZOrCFbOT4ikt7pJIRg1tXVsEfzk5mWpGO1NFiSs4PIw=="],
+
+ "@oxc-parser/binding-linux-s390x-gnu": ["@oxc-parser/binding-linux-s390x-gnu@0.120.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-hYiPJTxyfJY2+lMBFk3p2bo0R9GN+TtpPFlRqVchL1qvLG+pznstramHNvJlw9AjaoRUHwp9IKR7UZQnRPGjgQ=="],
+
+ "@oxc-parser/binding-linux-x64-gnu": ["@oxc-parser/binding-linux-x64-gnu@0.120.0", "", { "os": "linux", "cpu": "x64" }, "sha512-q+5jSVZkprJCIy3dzJpApat0InJaoxQLsJuD6DkX8hrUS61z2lHQ1Fe9L2+TYbKHXCLWbL0zXe7ovkIdopBGMQ=="],
+
+ "@oxc-parser/binding-linux-x64-musl": ["@oxc-parser/binding-linux-x64-musl@0.120.0", "", { "os": "linux", "cpu": "x64" }, "sha512-D9QDDZNnH24e7X4ftSa6ar/2hCavETfW3uk0zgcMIrZNy459O5deTbWrjGzZiVrSWigGtlQwzs2McBP0QsfV1w=="],
+
+ "@oxc-parser/binding-openharmony-arm64": ["@oxc-parser/binding-openharmony-arm64@0.120.0", "", { "os": "none", "cpu": "arm64" }, "sha512-TBU8ZwOUWAOUWVfmI16CYWbvh4uQb9zHnGBHsw5Cp2JUVG044OIY1CSHODLifqzQIMTXvDvLzcL89GGdUIqNrA=="],
+
+ "@oxc-parser/binding-wasm32-wasi": ["@oxc-parser/binding-wasm32-wasi@0.120.0", "", { "dependencies": { "@napi-rs/wasm-runtime": "1.2.4" }, "cpu": "none" }, "sha512-WG/FOZgDJCpJnuF3ToG/K28rcOmSY7FmFmfBKYb2fmLyhDzPpUldFGV7/Fz4ru0Iz/v4KPmf8xVgO8N3lO4KHA=="],
+
+ "@oxc-parser/binding-win32-arm64-msvc": ["@oxc-parser/binding-win32-arm64-msvc@0.120.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-1T0HKGcsz/BKo77t7+89L8Qvu4f9DoleKWHp3C5sJEcbCjDOLx3m9m722bWZTY+hANlUEs+yjlK+lBFsA+vrVQ=="],
+
+ "@oxc-parser/binding-win32-ia32-msvc": ["@oxc-parser/binding-win32-ia32-msvc@0.120.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-L7vfLzbOXsjBXV0rv/6Y3Jd9BRjPeCivINZAqrSyAOZN3moCopDN+Psq9ZrGNZtJzP8946MtlRFZ0Als0wBCOw=="],
+
+ "@oxc-parser/binding-win32-x64-msvc": ["@oxc-parser/binding-win32-x64-msvc@0.120.0", "", { "os": "win32", "cpu": "x64" }, "sha512-ys+upfqNtSu58huAhJMBKl3XCkGzyVFBlMlGPzHeFKgpFF/OdgNs1MMf8oaJIbgMH8ZxgGF7qfue39eJohmKIg=="],
+
+ "@oxc-project/types": ["@oxc-project/types@0.152.0", "", {}, "sha512-oM/5rLBm2tPkg0iBgkH/FOeR3PCDpY19GTgAZjMFM8h9WI9VW7cLgzp6nwtarYKmovavIQZ+Fe/RKX/8C8O/Rw=="],
+
+ "@posthog/browser-common": ["@posthog/browser-common@0.9.1", "", { "dependencies": { "@posthog/core": "1.56.0", "@posthog/types": "1.413.0" } }, "sha512-Dl8uV2OZAxfHfWyC7K0Y3HtT7ld+WGLbXIwgCgAGziOMGDIa/bepCRrCxy7IxsEzqY1HOrq/VDdcoNN7hBTSQQ=="],
+
+ "@posthog/core": ["@posthog/core@1.56.0", "", { "dependencies": { "@posthog/types": "1.413.0" } }, "sha512-WNlOoFQbOZyJzX54DhAslSpTjwDyXX5VLuRFNJjv172uOE9qHVUvtZAPP9dHZdq2HZkkLjbY27idH7UhzKSBVA=="],
+
+ "@posthog/types": ["@posthog/types@1.413.0", "", {}, "sha512-tYAVzNojWckuG/wxBB0fwE70sFruQQq4xbhkci7eH2ARU3mMfUTkvpN1HwBMpm0AtbxidLiH0IFvagmdJ8opPw=="],
+
+ "@radix-ui/primitive": ["@radix-ui/primitive@1.1.7", "", {}, "sha512-rqWnm76nYT8HoNNqEjpgJ7Pw/DrBj5iBTrmEPo6HTX5+VJyBNOqTdv4g89G63HuR5g0AaENoAcH7Is5fF2kZ8Q=="],
+
+ "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.5", "", { "optionalDependencies": { "@types/react": "19.3.0" }, "peerDependencies": { "react": "19.3.0" } }, "sha512-+48PbAAbq3didjJxa+OaWY2ZwgAKsNiRGyeHKszblZMQ+kcpd9pAaT11cMkGEie0vsOi3QdeTE6d5Fe3Gn61kA=="],
+
+ "@radix-ui/react-context": ["@radix-ui/react-context@1.2.2", "", { "optionalDependencies": { "@types/react": "19.3.0" }, "peerDependencies": { "react": "19.3.0" } }, "sha512-RHCUGwKHDr0hDGg4X7ma4JG4/+12qxw8rkh5QKdDldlCvtja6nUx1Ef/8HVrJze81lEsgLQlqjzjGNHantgnQA=="],
+
+ "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.2.0", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-context": "1.2.2", "@radix-ui/react-dismissable-layer": "1.1.20", "@radix-ui/react-focus-guards": "1.1.6", "@radix-ui/react-focus-scope": "1.2.0", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-portal": "1.1.18", "@radix-ui/react-presence": "1.1.11", "@radix-ui/react-primitive": "2.1.11", "@radix-ui/react-slot": "1.4.0", "@radix-ui/react-use-controllable-state": "1.2.6", "@radix-ui/react-use-layout-effect": "1.1.4", "aria-hidden": "1.2.6", "react-remove-scroll": "2.7.2" }, "optionalDependencies": { "@types/react": "19.3.0", "@types/react-dom": "19.3.0" }, "peerDependencies": { "react": "19.3.0", "react-dom": "19.3.0" } }, "sha512-l5CX8HdNL+9cc4s7HkNyplumSA3FIx68sg9dttBHKr286fRBwq1MBniDVTeI/tkof92/APntMQvC1YG1Khb0Cg=="],
+
+ "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.20", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-primitive": "2.1.11", "@radix-ui/react-use-callback-ref": "1.1.4", "@radix-ui/react-use-effect-event": "0.0.5" }, "optionalDependencies": { "@types/react": "19.3.0", "@types/react-dom": "19.3.0" }, "peerDependencies": { "react": "19.3.0", "react-dom": "19.3.0" } }, "sha512-35WHRrycfnj2m4LvPiKMKHGLM3Y2WvUA744CkRdxjs1BGDX1c8PVMfmiSGTUwnHRbqdtIoxveYTXvcJSt7VfgQ=="],
+
+ "@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.6", "", { "optionalDependencies": { "@types/react": "19.3.0" }, "peerDependencies": { "react": "19.3.0" } }, "sha512-RNOJjfZMTyBM6xYmV3IVGXkPjIhcBAuv48POevAXwrGJhkWZ9p1rFoIS1JFooPuT193AZmRsCPhpoVJxx6OPoQ=="],
+
+ "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.2.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-primitive": "2.1.11", "@radix-ui/react-use-callback-ref": "1.1.4" }, "optionalDependencies": { "@types/react": "19.3.0", "@types/react-dom": "19.3.0" }, "peerDependencies": { "react": "19.3.0", "react-dom": "19.3.0" } }, "sha512-I5S7vsAOozx2lWSBAyuXjWIJ/A8qx4fjbv6115WoaRYQSb1yZDaeNHonUAQzXyE8oD+0whJHbQRl4HIE2gQ0Xw=="],
+
+ "@radix-ui/react-id": ["@radix-ui/react-id@1.1.4", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.4" }, "optionalDependencies": { "@types/react": "19.3.0" }, "peerDependencies": { "react": "19.3.0" } }, "sha512-TMQp2llA+RYn7JcjnrMnz7wN4pcVttPZnRZo52PLQsoLVKzNlVwUeHmfePgTgRluXFvlD3GD5g5MOVVTJCO0qA=="],
+
+ "@radix-ui/react-portal": ["@radix-ui/react-portal@1.1.18", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.11", "@radix-ui/react-use-layout-effect": "1.1.4" }, "optionalDependencies": { "@types/react": "19.3.0", "@types/react-dom": "19.3.0" }, "peerDependencies": { "react": "19.3.0", "react-dom": "19.3.0" } }, "sha512-ygFIJ+QXNKf72AAq8x3hd22+ws7pYpmc1S0E4kW0Je+qD4qEb3FvxeKVQRGrVDMOkQaYfsB+Qs+KDh81a1gAOw=="],
+
+ "@radix-ui/react-presence": ["@radix-ui/react-presence@1.1.11", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.4" }, "optionalDependencies": { "@types/react": "19.3.0", "@types/react-dom": "19.3.0" }, "peerDependencies": { "react": "19.3.0", "react-dom": "19.3.0" } }, "sha512-Z7/atlkab36Z8hm+V8zYc79r0W+tiOB1o0tun1By94JyadkekLQmtEAnBSP9XKXBNQsStoStS4+gX10JpS5akA=="],
+
+ "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.11", "", { "dependencies": { "@radix-ui/react-slot": "1.4.0" }, "optionalDependencies": { "@types/react": "19.3.0", "@types/react-dom": "19.3.0" }, "peerDependencies": { "react": "19.3.0", "react-dom": "19.3.0" } }, "sha512-RzcaSw5aKl0OPhBJ1wbolKSF6nVvN+0o/QLeIVq+09npiPdnCkPggy2k6gI6yetxl4ZyrlBPYFgCB8BQJZwXcQ=="],
+
+ "@radix-ui/react-slot": ["@radix-ui/react-slot@1.4.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.5" }, "optionalDependencies": { "@types/react": "19.3.0" }, "peerDependencies": { "react": "19.3.0" } }, "sha512-IuMVHZ+Ah5fkctu3X3qeFrV/ZrBcuWuDTFUUPfS/L5hvoTjzhp/HdWGE14CsQombPdEidsa33HVlYZXi49PZ1Q=="],
+
+ "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.4", "", { "optionalDependencies": { "@types/react": "19.3.0" }, "peerDependencies": { "react": "19.3.0" } }, "sha512-R6OUY2e2fA6Yn6s+VSx5KBV6Nx8LQEhu+cz7LCej18rQ1HLyg9PSC9jP/ZNx0o6FAIK9c0F1kHylzSxKsdlkrQ=="],
+
+ "@radix-ui/react-use-controllable-state": ["@radix-ui/react-use-controllable-state@1.2.6", "", { "dependencies": { "@radix-ui/primitive": "1.1.7", "@radix-ui/react-use-effect-event": "0.0.5", "@radix-ui/react-use-layout-effect": "1.1.4" }, "optionalDependencies": { "@types/react": "19.3.0" }, "peerDependencies": { "react": "19.3.0" } }, "sha512-uEQJGT97ZA/TgP/Hydw47lHu+/vQj6z/0jA+WeTbK1o9Rx45GImjpD0tc3W5ad3D6XTSR6e1yEO0FvGq6WQfVQ=="],
+
+ "@radix-ui/react-use-effect-event": ["@radix-ui/react-use-effect-event@0.0.5", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.4" }, "optionalDependencies": { "@types/react": "19.3.0" }, "peerDependencies": { "react": "19.3.0" } }, "sha512-7cshFL8HGS/7HEiHH+9kL9HBwp2sa9yX18Knwek6KYWmXwM7pegMgta2AXMQKI+rq3JnfSj9x8wYqFMTdG1Jgg=="],
+
+ "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.4", "", { "optionalDependencies": { "@types/react": "19.3.0" }, "peerDependencies": { "react": "19.3.0" } }, "sha512-K20DkRkUwDnxEYMBPcg3Y6voLkEy5p5QQmszZgLngKKiC7dzBR/aEuK3w1qlx2JWDUNH6FluahYdgR3BP+QbYw=="],
+
+ "@reduxjs/toolkit": ["@reduxjs/toolkit@2.13.0", "", { "dependencies": { "@standard-schema/spec": "1.1.0", "@standard-schema/utils": "0.3.0", "immer": "11.1.21", "redux": "5.0.1", "redux-thunk": "3.1.0", "reselect": "5.3.0" }, "optionalDependencies": { "react": "19.3.0", "react-redux": "9.3.0" } }, "sha512-f6jwVRfwW30+tnllz4YcsHHpPYYOE7abcHkyUCovD+P7DyhdAI5prz2Fh/8TLhakjpN+7aIEion1s5L/tvlYlA=="],
+
+ "@resvg/resvg-wasm": ["@resvg/resvg-wasm@2.6.2", "", {}, "sha512-FqALmHI8D4o6lk/LRWDnhw95z5eO+eAa6ORjVg09YRR7BkcM6oPHU9uyC0gtQG5vpFLvgpeU4+zEAz2H8APHNw=="],
+
+ "@rolldown/binding-android-arm-eabi": ["@rolldown/binding-android-arm-eabi@1.2.12", "", { "os": "android", "cpu": "arm" }, "sha512-dB/a1214qKfHMXCpgqR4OZT+jS4kTyEXbQGJPqzobt5EwH5rX080pxE37alt3RzvR1bf1Yz/yGqRfrYAxuPw0A=="],
+
+ "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.2.12", "", { "os": "android", "cpu": "arm64" }, "sha512-7KHFgQ5VJxIHcLlrwrc3Xbds7oTNQT7Pgi9gQCJKrd2VGab/UksIOYp6VD8MzCstGxOKMgNamPwUCfxPdP1OHg=="],
+
+ "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.2.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-3YIhqHD96nA5SaYNRBR16HnGv4oavZvXfD/ayHM+oYZ0WD/8lBAtf6zQua4kEyAvpqrluKXl0lnOBoiNby7x9w=="],
+
+ "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.2.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-UuuJ35MFw4gmFOrE9pEqIV+K3syIKveph+Qc1/ljHZVdoDW4pz/JHR/eMVom+TZGl/5OOvGJOWaOCVt3ZfqhxA=="],
+
+ "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.2.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-uMvssit0a4W+/7D8CbHUvG719mH3R2jwXAlh/XcPvuHTE0g++LymF88DCGNX0HM2rBOn0xrzgXktIB6fLSJBTQ=="],
+
+ "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.2.12", "", { "os": "linux", "cpu": "arm" }, "sha512-XcFu0R0xWnwzSf4IQgFH1rJIckPN1pLy2R+4r9IDB7Yfu/ys9cVqfa4pBrMHj7a3gl8mIR4nRNPg0e5IvEVs6g=="],
+
+ "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.2.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-260UrKgn8tz39ak+SMDOirKzr7V04M9dWPw5llW00SwBivCZoWcRBKV1d8cXnRkUmSZA3BdiUmBHWk7734Ulpw=="],
+
+ "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.2.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-5YK1I9SqDkbPgc1IA8BgDl34suqUS2q0KWnBrirm0E51YjOs6eo6dV6jbQfNE/argHRSvd0QUGgtpIoYx+WWpw=="],
+
+ "@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.2.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-Rkcrmp7eFRg74yL5fXEU91JEWbdEPLevWwGtXpmhbjlD1StScbWTmO94Bhly+Mo+ketKYkdmM1vNUKeWSlx8cQ=="],
+
+ "@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.2.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-qvK4DuAsQc2BSjlx+Xr+IzOIvvxbGZqxFwdWfG6F518Erj0GGISyQbJ6pIappnOxlNPzNHvo/L0BwB30GZ+zVw=="],
+
+ "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.2.12", "", { "os": "linux", "cpu": "x64" }, "sha512-Q9uLBO53Xd4QIq1WOycVQyPP1O4HhraEV2qqb3uTrnVw6QZih9duY4vNXOivL1xoUS1/z+W8eF4NMfl2a8Sdjw=="],
+
+ "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.2.12", "", { "os": "linux", "cpu": "x64" }, "sha512-3IBxWFMjbOZskDPKv8Lf9BCnahlKuHthWkYnyIxOH/QcJrFcS4EmcenthApkwr/5+nEqZlLzeYbxeMaX7A5u4g=="],
+
+ "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.2.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xtX61xg4LKPkPWilZU1ynKClz5Gj4bf74LML4r3eVLWumKnGjoEr1OSHQhMdbBDoYTi+yjrujvpZe2pUnqCrrA=="],
+
+ "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.2.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-At7fPB6PCaIjzgIhEZFxuT+BBFqiQibJDT4d3PhiR3f4E7bbMZF4aKblbFfEM3sETRDd1YiQx/+U/g/B/ou5Ew=="],
+
+ "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.2.12", "", { "os": "win32", "cpu": "x64" }, "sha512-WIw2haVKwjuYdXkHaoC0mF8Le71TuCBxjrdKqLbJGctbBABj+ClfmNvtbOnzpq3RokNo5+V1qhtSzJyXorsklQ=="],
+
+ "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.1", "", {}, "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw=="],
+
+ "@solid-primitives/event-listener": ["@solid-primitives/event-listener@2.4.6", "", { "dependencies": { "@solid-primitives/utils": "6.4.1" }, "peerDependencies": { "solid-js": "1.9.15" } }, "sha512-5I0YJcTVYIWoMmgBSROBZGcz+ymhew/pGTg2dHW74BUjFKsV8Li4bOZYl0YAGP4mHw5o4UBd9/BEesqBci3wxw=="],
+
+ "@solid-primitives/keyboard": ["@solid-primitives/keyboard@1.3.7", "", { "dependencies": { "@solid-primitives/event-listener": "2.4.6", "@solid-primitives/rootless": "1.5.4", "@solid-primitives/utils": "6.4.1" }, "peerDependencies": { "solid-js": "1.9.15" } }, "sha512-558RPNYnXx4nGh537DSqAn4xMrC8iFipl/5+xzgzWoTNFst4RnUN3BOLmtDjJ0UGGoQXVMALYR3bNOHM0xnt1Q=="],
+
+ "@solid-primitives/resize-observer": ["@solid-primitives/resize-observer@2.2.0", "", { "dependencies": { "@solid-primitives/event-listener": "2.4.6", "@solid-primitives/rootless": "1.5.4", "@solid-primitives/static-store": "0.1.4", "@solid-primitives/utils": "6.4.1" }, "peerDependencies": { "solid-js": "1.9.15" } }, "sha512-9Fuu/EWBeGj+atGHRJp70HKhdfalmpjwxY8a32NZixdLNmfCJ45AfhLQNr6uOzETbbiMx4iCKlTrJ8KZCHC2Ww=="],
+
+ "@solid-primitives/rootless": ["@solid-primitives/rootless@1.5.4", "", { "dependencies": { "@solid-primitives/utils": "6.4.1" }, "peerDependencies": { "solid-js": "1.9.15" } }, "sha512-TOIZa1VUfVJ+9nkCcRajw3U4t9vBOP1HxX1WHNTbXq32mXwlqTvUnC4CRIilohcryBkT9u2ZkhUDSHRTaGp55g=="],
+
+ "@solid-primitives/static-store": ["@solid-primitives/static-store@0.1.4", "", { "dependencies": { "@solid-primitives/utils": "6.4.1" }, "peerDependencies": { "solid-js": "1.9.15" } }, "sha512-LgtVaVBtB7EbmS4+M0b8xY5Iq6pUWXBsIC4VgtrFKDGDdyCaDt88sHk0fUlx1Enxm/XZnZyLXJABRoa39RjJqA=="],
+
+ "@solid-primitives/utils": ["@solid-primitives/utils@6.4.1", "", { "peerDependencies": { "solid-js": "1.9.15" } }, "sha512-ISSB5QX1qP2ynrheIpYwc4oKR5Ny4siNuUyf1qZniy+Il+p/PtDB0QK1Dnle8noiHpwRD3gpPdubOC3qI/Zamg=="],
+
+ "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
+
+ "@standard-schema/utils": ["@standard-schema/utils@0.3.0", "", {}, "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g=="],
+
+ "@tailwindcss/node": ["@tailwindcss/node@4.3.3", "", { "dependencies": { "@jridgewell/remapping": "2.3.5", "enhanced-resolve": "5.26.0", "jiti": "2.7.0", "lightningcss": "1.32.0", "magic-string": "0.30.21", "source-map-js": "1.2.2", "tailwindcss": "4.3.3" } }, "sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg=="],
+
+ "@tailwindcss/oxide": ["@tailwindcss/oxide@4.3.3", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.3.3", "@tailwindcss/oxide-darwin-arm64": "4.3.3", "@tailwindcss/oxide-darwin-x64": "4.3.3", "@tailwindcss/oxide-freebsd-x64": "4.3.3", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.3", "@tailwindcss/oxide-linux-arm64-gnu": "4.3.3", "@tailwindcss/oxide-linux-arm64-musl": "4.3.3", "@tailwindcss/oxide-linux-x64-gnu": "4.3.3", "@tailwindcss/oxide-linux-x64-musl": "4.3.3", "@tailwindcss/oxide-wasm32-wasi": "4.3.3", "@tailwindcss/oxide-win32-arm64-msvc": "4.3.3", "@tailwindcss/oxide-win32-x64-msvc": "4.3.3" } }, "sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA=="],
+
+ "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.3.3", "", { "os": "android", "cpu": "arm64" }, "sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw=="],
+
+ "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.3.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw=="],
+
+ "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.3.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw=="],
+
+ "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.3.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw=="],
+
+ "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3", "", { "os": "linux", "cpu": "arm" }, "sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ=="],
+
+ "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w=="],
+
+ "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.3.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA=="],
+
+ "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w=="],
+
+ "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.3.3", "", { "os": "linux", "cpu": "x64" }, "sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img=="],
+
+ "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.3.3", "", { "cpu": "none" }, "sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ=="],
+
+ "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.3.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ=="],
+
+ "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.3.3", "", { "os": "win32", "cpu": "x64" }, "sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw=="],
+
+ "@tailwindcss/typography": ["@tailwindcss/typography@0.5.20", "", { "dependencies": { "postcss-selector-parser": "6.0.10" }, "peerDependencies": { "tailwindcss": "4.3.3" } }, "sha512-hwbzQuNUfcPvbegQFatVPl/MY/tcM9KLl963hQ5laJKPh81TEZ1+dNG9PirGvcaDBkp+BCshExAyKVPW91dozw=="],
+
+ "@tailwindcss/vite": ["@tailwindcss/vite@4.3.3", "", { "dependencies": { "@tailwindcss/node": "4.3.3", "@tailwindcss/oxide": "4.3.3", "tailwindcss": "4.3.3" }, "peerDependencies": { "vite": "8.3.2" } }, "sha512-yYU8cogLeSh/ms2jh8Fj7jaba/EWa7Ja6GoUqYZaraEuCI5YS6ms6ObZgjjedm+jm6XZjdNRWBpPP6Z86oOxcw=="],
+
+ "@tanstack/devtools": ["@tanstack/devtools@0.15.0", "", { "dependencies": { "@neodrag/core": "3.0.0-next.11", "@neodrag/solid": "3.0.0-next.11", "@solid-primitives/event-listener": "2.4.6", "@solid-primitives/keyboard": "1.3.7", "@solid-primitives/resize-observer": "2.2.0", "@tanstack/devtools-client": "0.0.8", "@tanstack/devtools-event-bus": "0.4.3", "@tanstack/devtools-ui": "0.7.1", "clsx": "2.1.1", "goober": "2.1.19" }, "peerDependencies": { "solid-js": "1.9.15" }, "bin": { "intent": "./bin/intent.js" } }, "sha512-KyS7Qi82Eq9yG8C+uae3ikAPb+D5rfzVhvOOjXVAHZ/64s6TWJlDWpREw1FrHIYZaI7paErpsExSSKlF5BKA/A=="],
+
+ "@tanstack/devtools-bundler-core": ["@tanstack/devtools-bundler-core@0.1.3", "", { "dependencies": { "@tanstack/devtools-client": "0.0.8", "@tanstack/devtools-event-bus": "0.4.3", "chalk": "5.6.2", "launch-editor": "2.14.1", "magic-string": "0.30.21", "oxc-parser": "0.120.0", "picomatch": "4.0.7" } }, "sha512-F0tlxIyfFqXkZ1mJP1EjtkiSeJA+ztXY2AYOHf7r4goCIEAOp86N9PFJ/yv8vu1TnmxGS6vKsZCS3Kyls9xQQA=="],
+
+ "@tanstack/devtools-client": ["@tanstack/devtools-client@0.0.8", "", { "dependencies": { "@tanstack/devtools-event-client": "0.5.0" } }, "sha512-cG3iZkGWCwN330bLBKa8+9r4Of2AXNoz2zUqcsy/4XsD3105ghVBx78cGyvJj9fSclNomPxoqAnDGXXhg1WLvA=="],
+
+ "@tanstack/devtools-event-bus": ["@tanstack/devtools-event-bus@0.4.3", "", { "dependencies": { "ws": "8.22.0" } }, "sha512-NeegBt5/n2E5q4DbrXHqECBq42+kDi6JBOp8/+RNqkIE+P4hJpbM36kGyjnGQFMWOoku31qhMyX9/48VuTTdmg=="],
+
+ "@tanstack/devtools-event-client": ["@tanstack/devtools-event-client@0.5.0", "", { "bin": { "intent": "./bin/intent.js" } }, "sha512-H+OH3zC6Vhu/K0NaVfQKknEKawc/+2PT+D3SB3Ox0V8SiMlTo0abbmH2rH0721R2aNYbjdMXA1oENOd8E2UVoA=="],
+
+ "@tanstack/devtools-ui": ["@tanstack/devtools-ui@0.7.1", "", { "dependencies": { "clsx": "2.1.1", "dayjs": "1.11.23", "goober": "2.1.19" }, "peerDependencies": { "solid-js": "1.9.15" } }, "sha512-3xQ/ezZ2qVNszhjpCN2N3jn7uHc2J1PMgcyjHzH4XZBt9xAQyMMcPNoR2cd7rzReyxWoJpZUWiDBmOJiCtLj9A=="],
+
+ "@tanstack/devtools-vite": ["@tanstack/devtools-vite@0.8.5", "", { "dependencies": { "@tanstack/devtools-bundler-core": "0.1.3", "@tanstack/devtools-client": "0.0.8", "@tanstack/devtools-event-bus": "0.4.3", "chalk": "5.6.2" }, "peerDependencies": { "vite": "8.3.2" }, "bin": { "intent": "./bin/intent.js" } }, "sha512-xaifCEmiwwzizlbp973oISXNsnmuU/BugLa66gryAZaPJJ/qo1kJd2DxY5X960eHwmyIS3SN0KYrL3/aRhucmA=="],
+
+ "@tanstack/history": ["@tanstack/history@1.162.4", "", {}, "sha512-utTS5L2OkeYUzXGohL1Z8sefu1GLNOJcxe8Hd6iIdc/Xo1K1nDB2JEp4iSFhvYh33xKC9V91TxrS8qfrpoKobQ=="],
+
+ "@tanstack/intent": ["@tanstack/intent@0.5.4", "", { "bin": { "intent": "dist/cli.mjs" } }, "sha512-veyJDHwIHrylKucn8UgLlMYZbhLZ3gO1OlYiXLcmIKazCd8bTDXRfcWvmwNK3q63jS8K40pYudZV3HQPbHsBWg=="],
+
+ "@tanstack/react-devtools": ["@tanstack/react-devtools@0.10.13", "", { "dependencies": { "@tanstack/devtools": "0.15.0" }, "peerDependencies": { "@types/react": "19.3.0", "@types/react-dom": "19.3.0", "react": "19.3.0", "react-dom": "19.3.0" } }, "sha512-r0cdB/14+st2Vxl/1Bodlyq4VC8pf9SykLQDYbGHDc1+V146WQo5B3KlYLkfyxD9Q/6+9NPRQHZyl8fvZVMdRA=="],
+
+ "@tanstack/react-router": ["@tanstack/react-router@1.170.41", "", { "dependencies": { "@tanstack/history": "1.162.4", "@tanstack/react-store": "0.11.2", "@tanstack/router-core": "1.171.34", "isbot": "5.2.2" }, "peerDependencies": { "react": "19.3.0", "react-dom": "19.3.0" } }, "sha512-Mpvw8Wm5MGDbTqI8Yc9flLKxbOHwoWocv0H2aGKcgw2a017oK5nZWqa954P+DrUx/8fI98YNywnHP5XcD3tQ9w=="],
+
+ "@tanstack/react-router-devtools": ["@tanstack/react-router-devtools@1.167.2", "", { "dependencies": { "@tanstack/router-devtools-core": "1.168.2" }, "optionalDependencies": { "@tanstack/router-core": "1.171.34" }, "peerDependencies": { "@tanstack/react-router": "1.170.41", "react": "19.3.0", "react-dom": "19.3.0" } }, "sha512-VuoqB7OhDUrBa4WOFSKiAQ8xI8sJpeZdo9sYE1hQa89iMuVFUQu1iWE4iCiQhB+6TYOZDZ9e+iHKxYjop4ZVYw=="],
+
+ "@tanstack/react-start": ["@tanstack/react-start@1.168.60", "", { "dependencies": { "@tanstack/react-router": "1.170.41", "@tanstack/react-start-client": "1.168.39", "@tanstack/react-start-rsc": "0.1.59", "@tanstack/react-start-server": "1.167.46", "@tanstack/router-utils": "1.162.3", "@tanstack/start-client-core": "1.170.34", "@tanstack/start-plugin-core": "1.171.49", "@tanstack/start-server-core": "1.169.39", "pathe": "2.0.3" }, "optionalDependencies": { "vite": "8.3.2" }, "peerDependencies": { "react": "19.3.0", "react-dom": "19.3.0" } }, "sha512-WMOM0Xlh2lPbVlbjYM6uOxOpiaWRPvODm/dwkLsGKq5tjyHOHZmKckJgwlrZl7OQUqFlOZHYj8bKUTgoeg8cUQ=="],
+
+ "@tanstack/react-start-client": ["@tanstack/react-start-client@1.168.39", "", { "dependencies": { "@tanstack/react-router": "1.170.41", "@tanstack/router-core": "1.171.34", "@tanstack/start-client-core": "1.170.34" }, "peerDependencies": { "react": "19.3.0", "react-dom": "19.3.0" } }, "sha512-Uby0uo37JlQgUKHU0snDwH9nYiEeAjm9+7pUOFgycU/UszEILC2SO2DSCoNnCMuHKj9z+4URKzBYIP2exT9+wg=="],
+
+ "@tanstack/react-start-rsc": ["@tanstack/react-start-rsc@0.1.59", "", { "dependencies": { "@tanstack/react-router": "1.170.41", "@tanstack/router-core": "1.171.34", "@tanstack/router-utils": "1.162.3", "@tanstack/start-client-core": "1.170.34", "@tanstack/start-fn-stubs": "1.162.0", "@tanstack/start-plugin-core": "1.171.49", "@tanstack/start-storage-context": "1.167.36", "pathe": "2.0.3" }, "peerDependencies": { "react": "19.3.0", "react-dom": "19.3.0" } }, "sha512-M2Lqxkk5C1zQncQs5paqX+/OLdOht51pg6D84YfLMrNsjhU/nzb6wd92MIja0mi5i23+L+fxLLjQYR2DObjBlw=="],
+
+ "@tanstack/react-start-server": ["@tanstack/react-start-server@1.167.46", "", { "dependencies": { "@tanstack/react-router": "1.170.41", "@tanstack/router-core": "1.171.34", "@tanstack/start-server-core": "1.169.39" }, "peerDependencies": { "react": "19.3.0", "react-dom": "19.3.0" } }, "sha512-K7z8xBOEdp8u5CZCxWrbS0tFtk5XZGMdhssLeZlRZKlLDbX7BKLdMtJ7th5sR6QVt9MTUAg3LcoqvJMPSFF+lg=="],
+
+ "@tanstack/react-store": ["@tanstack/react-store@0.11.2", "", { "dependencies": { "@tanstack/store": "0.11.2", "use-sync-external-store": "1.7.0" }, "peerDependencies": { "react": "19.3.0", "react-dom": "19.3.0" } }, "sha512-oj5O5DmiMWE+ih+SioX2ayC1kbK7d3fpLx0B75fPJr9nY3zU+hoW010yr64qXsY/9fyiLVE2bn5mGNV3owm8RQ=="],
+
+ "@tanstack/router-cli": ["@tanstack/router-cli@1.167.40", "", { "dependencies": { "@tanstack/router-generator": "1.167.40", "chokidar": "5.0.0", "yargs": "17.7.3" }, "bin": { "tsr": "bin/tsr.cjs" } }, "sha512-KKX9hedstsc0eEKfUAwrwy7CLNXdSxjiBBq0uojnjMnOnraRXP9Nf+x6/ZsAultxHp7NhWfYddO8VdT0zAtUDg=="],
+
+ "@tanstack/router-core": ["@tanstack/router-core@1.171.34", "", { "dependencies": { "@tanstack/history": "1.162.4", "cookie-es": "3.1.1", "seroval": "1.6.8", "seroval-plugins": "1.6.8" } }, "sha512-X+19pGuuLVPvvAvPYw9v/+ktRk5cCll8AtfpBpOhDRmVgUMrfqze0467xtq8YRVVs/mmo5rVtWn/7Tp32RDBKw=="],
+
+ "@tanstack/router-devtools-core": ["@tanstack/router-devtools-core@1.168.2", "", { "dependencies": { "clsx": "2.1.1", "goober": "2.1.19" }, "optionalDependencies": { "csstype": "3.2.3" }, "peerDependencies": { "@tanstack/router-core": "1.171.34" } }, "sha512-pCCdQ5M/NUeWdiAbPmjyfcNdls6G4vaVlIQbPf1IqZk1FLYFr00aQvi578yUuWFBNM2KNS2QcwM1uPucbtGf5Q=="],
+
+ "@tanstack/router-generator": ["@tanstack/router-generator@1.167.40", "", { "dependencies": { "@babel/types": "7.29.8", "@tanstack/router-core": "1.171.34", "@tanstack/router-utils": "1.162.3", "@tanstack/virtual-file-routes": "1.162.0", "jiti": "2.7.0", "magic-string": "0.30.21", "prettier": "3.9.9", "zod": "4.6.5" } }, "sha512-WkEueqEvsBBudzO0fx1nWfOmRNW8OAvBoVABTGls9bAWzjdC+KDGHvjCNrvn88ofs1F6gqL8aWnzKCbxW3dCyQ=="],
+
+ "@tanstack/router-plugin": ["@tanstack/router-plugin@1.168.42", "", { "dependencies": { "@babel/core": "7.29.7", "@babel/template": "7.29.7", "@babel/types": "7.29.8", "@tanstack/router-core": "1.171.34", "@tanstack/router-generator": "1.167.40", "@tanstack/router-utils": "1.162.3", "chokidar": "5.0.0", "unplugin": "3.4.0", "zod": "4.6.5" }, "optionalDependencies": { "@tanstack/react-router": "1.170.41", "vite": "8.3.2" } }, "sha512-vAR5WXJh/ErseEWQftDhsJcr2c++ucRQ6FbqN3ygMO44+ZxxRfW3sIpZmddHROVSmBk8jc6MrwjTPNjVhd62Vw=="],
+
+ "@tanstack/router-utils": ["@tanstack/router-utils@1.162.3", "", { "dependencies": { "@babel/generator": "7.29.8", "@babel/parser": "7.29.9", "@babel/types": "7.29.8", "ansis": "4.4.0", "babel-dead-code-elimination": "1.0.12", "diff": "8.0.4", "pathe": "2.0.3", "tinyglobby": "0.2.17" } }, "sha512-Icb0xGuG1+54IV0WMLRcc3ErTx2HeJWyPG661FkQ8UT6guoBq1FJjFRqlG/JS0xi4mFFkBhvwO7tbLa32f3yxA=="],
+
+ "@tanstack/start-client-core": ["@tanstack/start-client-core@1.170.34", "", { "dependencies": { "@tanstack/router-core": "1.171.34", "@tanstack/start-fn-stubs": "1.162.0", "@tanstack/start-storage-context": "1.167.36", "seroval": "1.6.8" } }, "sha512-LfwZSbau2MLLZ/uPAoO+NC9fK3J66c0wLhnNQqIa+Goqw7bXPjkHwlsjY7evlUz1AnyhhQ1Qab95v+VmP0TZ9A=="],
+
+ "@tanstack/start-fn-stubs": ["@tanstack/start-fn-stubs@1.162.0", "", {}, "sha512-QWfUZ3Yo923tdQn38LyKMU8rcTw69zc+T4dAvgTWV4O56SqFRsGfS0lSWIMhJRwXIx/bvdi7nTUBDdZtTHtpTQ=="],
+
+ "@tanstack/start-plugin-core": ["@tanstack/start-plugin-core@1.171.49", "", { "dependencies": { "@babel/code-frame": "7.29.7", "@babel/core": "7.29.7", "@babel/types": "7.29.8", "@jridgewell/remapping": "2.3.5", "@tanstack/router-core": "1.171.34", "@tanstack/router-generator": "1.167.40", "@tanstack/router-plugin": "1.168.42", "@tanstack/router-utils": "1.162.3", "@tanstack/start-server-core": "1.169.39", "exsolve": "1.1.3", "lightningcss": "1.33.0", "pathe": "2.0.3", "picomatch": "4.0.7", "seroval": "1.6.8", "source-map": "0.7.6", "srvx": "0.11.22", "tinyglobby": "0.2.17", "ufo": "1.6.4", "vitefu": "1.1.3", "xmlbuilder2": "4.0.3", "zod": "4.6.5" }, "optionalDependencies": { "vite": "8.3.2" } }, "sha512-HPOb7LnMc71k38cd5uvMybPPUU/Q/56KvSqQzSWz7cps1ZDFXaxUM6EFaFHLCdgTWqGexNGDdRE+sUVPVBM4Xg=="],
+
+ "@tanstack/start-server-core": ["@tanstack/start-server-core@1.169.39", "", { "dependencies": { "@tanstack/history": "1.162.4", "@tanstack/router-core": "1.171.34", "@tanstack/start-client-core": "1.170.34", "@tanstack/start-storage-context": "1.167.36", "fetchdts": "0.1.7", "h3-v2": "npm:h3@2.0.1-rc.20", "seroval": "1.6.8" } }, "sha512-pqqkxhXY46nuFSYt6TsMGyABiplUzHFHndKAlRRGC0fWDrJCH1koWxVMoxySa51ZETV79f/z73b5UZ1jfIkXwQ=="],
+
+ "@tanstack/start-storage-context": ["@tanstack/start-storage-context@1.167.36", "", { "dependencies": { "@tanstack/router-core": "1.171.34" } }, "sha512-x+xCXK2GtFzY6NbXqAg8YpU6cwAjDfMeYSNzxfGzntpjbwBRHHrXeC/kYUnBBQCV7wK4kJ8vBBQGP0OyYTasUg=="],
+
+ "@tanstack/store": ["@tanstack/store@0.11.2", "", {}, "sha512-sJ4mjol8uQsHV0gOJzzjwXfh2Fwm+Sz0+8deqiTm4jGbMdjzNSW+xZCFm0kUa870uhd8yi+DpKnZb5Kc4apa0Q=="],
+
+ "@tanstack/virtual-file-routes": ["@tanstack/virtual-file-routes@1.162.0", "", {}, "sha512-uhOeFyxLcU41HzvrxsGpiWdcMbScY1EDgbZ5K7DVRMYInbLYWAC0EA/kx9wXAoSM8q82bUG2hRl8+EAjE6XAbA=="],
+
+ "@tybys/wasm-util": ["@tybys/wasm-util@0.10.4", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A=="],
+
+ "@types/d3-array": ["@types/d3-array@3.2.2", "", {}, "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw=="],
+
+ "@types/d3-color": ["@types/d3-color@3.1.3", "", {}, "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="],
+
+ "@types/d3-ease": ["@types/d3-ease@3.0.2", "", {}, "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA=="],
+
+ "@types/d3-interpolate": ["@types/d3-interpolate@3.0.4", "", { "dependencies": { "@types/d3-color": "3.1.3" } }, "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA=="],
+
+ "@types/d3-path": ["@types/d3-path@3.1.1", "", {}, "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg=="],
+
+ "@types/d3-scale": ["@types/d3-scale@4.0.9", "", { "dependencies": { "@types/d3-time": "3.0.4" } }, "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw=="],
+
+ "@types/d3-shape": ["@types/d3-shape@3.2.0", "", { "dependencies": { "@types/d3-path": "3.1.1" } }, "sha512-kVd74ta9eof3eJOvbNd1vGKS/XERRyQbT26Og63hIsvDO84cjD5gEOhsXf26w3FSoNlPVz84DOFcKv/oou+fMw=="],
+
+ "@types/d3-time": ["@types/d3-time@3.0.4", "", {}, "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g=="],
+
+ "@types/d3-timer": ["@types/d3-timer@3.0.2", "", {}, "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw=="],
+
+ "@types/node": ["@types/node@22.20.5", "", { "dependencies": { "undici-types": "6.21.0" } }, "sha512-U2+DNr+wSjpsTS/wZGYHq7GcwfuSmKiKvoPvK22zwTlRhU91yOniN4qRR5KhIjvif7ysw/dz/hKmfDH0Ris4aA=="],
+
+ "@types/pg": ["@types/pg@8.23.1", "", { "dependencies": { "@types/node": "22.20.5", "pg-protocol": "1.16.1", "pg-types": "2.2.0" } }, "sha512-fKVHpikPdg4GKks3JuLEhvwSyvwzF23hnabPy6DD8ljVbC7+6J5dQzdv4arV6jqq57djnMgs1HKBxX4P8aBI3A=="],
+
+ "@types/react": ["@types/react@19.3.0", "", { "dependencies": { "csstype": "3.2.3" } }, "sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg=="],
+
+ "@types/react-dom": ["@types/react-dom@19.3.0", "", { "peerDependencies": { "@types/react": "19.3.0" } }, "sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q=="],
+
+ "@types/trusted-types": ["@types/trusted-types@2.0.7", "", {}, "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="],
+
+ "@types/use-sync-external-store": ["@types/use-sync-external-store@0.0.6", "", {}, "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg=="],
+
+ "@vitejs/plugin-react": ["@vitejs/plugin-react@6.1.1", "", { "dependencies": { "@rolldown/pluginutils": "1.0.1" }, "peerDependencies": { "vite": "8.3.2" } }, "sha512-yxLaQV9gkhS8ezJqCM6+ndU7mDY6gqAg75NQ+0IjwEI8IYOmQCgkRwHKVSfWXW076DsqMo0Dk+0FK1U+M5RgFw=="],
+
+ "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
+
+ "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
+
+ "ansis": ["ansis@4.4.0", "", {}, "sha512-9k3v7xcHwgdO/DruxGIg4HtjvlAZlcnsX/mzqUb1t3NkYnl9kK2UJ+Gq0io+vQf7iT//BD/HB/NBkUR1LWxoeA=="],
+
+ "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="],
+
+ "aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="],
+
+ "babel-dead-code-elimination": ["babel-dead-code-elimination@1.0.12", "", { "dependencies": { "@babel/core": "7.29.7", "@babel/parser": "7.29.9", "@babel/traverse": "7.29.8", "@babel/types": "7.29.8" } }, "sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig=="],
+
+ "baseline-browser-mapping": ["baseline-browser-mapping@2.11.27", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-ElY12DaROGuan+lMmZ8Cvo/ZUbXPe7Enc/9VU/b1T3Kp4dwytRcNdR8DoSJN5SNJT/CuvcCA0DHDVmMOCePdRQ=="],
+
+ "better-auth": ["better-auth@1.7.7", "", { "dependencies": { "@better-auth/core": "1.7.7", "@better-auth/drizzle-adapter": "1.7.7", "@better-auth/kysely-adapter": "1.7.7", "@better-auth/memory-adapter": "1.7.7", "@better-auth/mongo-adapter": "1.7.7", "@better-auth/prisma-adapter": "1.7.7", "@better-auth/telemetry": "1.7.7", "@better-auth/utils": "0.4.2", "@better-fetch/fetch": "1.3.2", "@noble/ciphers": "2.4.0", "@noble/hashes": "2.4.0", "better-call": "1.4.0", "defu": "6.1.7", "jose": "6.2.12", "kysely": "0.29.6", "nanostores": "1.5.4", "zod": "4.6.5" }, "optionalDependencies": { "@tanstack/react-start": "1.168.60", "drizzle-kit": "0.31.11", "drizzle-orm": "0.45.3", "pg": "8.23.1", "react": "19.3.0", "react-dom": "19.3.0", "solid-js": "1.9.15" } }, "sha512-Zhgxi/c5ylmfB/sX+nwnBbsFf/j6k0L8DvL6CJXZSrXgxc5pPMC/e7j812zNd4L4B4ELmdURCPw3X8nAOUdcjw=="],
+
+ "better-call": ["better-call@1.4.0", "", { "dependencies": { "@better-auth/utils": "0.5.0", "@better-fetch/fetch": "1.3.2", "rou3": "0.9.2", "set-cookie-parser": "3.1.2" }, "optionalDependencies": { "zod": "4.6.5" } }, "sha512-bBKOT4vv1kZLDgxVePdilk/Jwkn+dtRRsmi3DzHcDP+WnswyVl6dR59l2HEeP/0cB+bDoopASAesWDPIdd/zZA=="],
+
+ "browserslist": ["browserslist@4.29.3", "", { "dependencies": { "baseline-browser-mapping": "2.11.27", "caniuse-lite": "1.0.30001814", "electron-to-chromium": "1.5.444", "node-releases": "2.0.57", "update-browserslist-db": "1.3.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-1R4kiYKXGViqEN0CnoDrXc1StD9niAwu+j2dukWzrD4bJgsD4lDmEp0CRbc6E/vYJIfTHwPmwyaKtVSudICdPA=="],
+
+ "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="],
+
+ "caniuse-lite": ["caniuse-lite@1.0.30001814", "", {}, "sha512-/Uaf1lAzr59XcMpW0o96WoEfr+VXK2OX4U9AgFoiSHsVJ4HppnIFUjtYzsyDH2+tgANaQb2/oxYGwCPapN1FpA=="],
+
+ "chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
+
+ "chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "5.1.1" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="],
+
+ "class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="],
+
+ "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "4.2.3", "strip-ansi": "6.0.1", "wrap-ansi": "7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="],
+
+ "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="],
+
+ "cmdk": ["cmdk@1.1.1", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.5", "@radix-ui/react-dialog": "1.2.0", "@radix-ui/react-id": "1.1.4", "@radix-ui/react-primitive": "2.1.11" }, "peerDependencies": { "react": "19.3.0", "react-dom": "19.3.0" } }, "sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg=="],
+
+ "cn": ["cn@0.4.0", "", { "bin": { "cn": "bin/cn.mjs" } }, "sha512-qOAeUhPwPzBxx6jaeQdo646XIKliKHc2j1ZF7Ngb1o0pJZKH5gq8FkA0aVdUdPFUDXNXyUCXpCtoJISo6dhizg=="],
+
+ "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
+
+ "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
+
+ "consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="],
+
+ "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
+
+ "cookie-es": ["cookie-es@3.1.1", "", {}, "sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg=="],
+
+ "core-js": ["core-js@3.50.0", "", {}, "sha512-BRWgOLKkFeCgRudR6zrs8p9XJZcE14grzKMMssoYrk6krtuEZ7MTKPIY5RzOnqsEKIR9kst7wNzphttraT+Yqw=="],
+
+ "croner": ["croner@10.0.1", "", {}, "sha512-ixNtAJndqh173VQ4KodSdJEI6nuioBWI0V1ITNKhZZsO0pEMoDxz539T4FTTbSZ/xIOSuDnzxLVRqBVSvPNE2g=="],
+
+ "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "3.1.1", "shebang-command": "2.0.0", "which": "2.0.2" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
+
+ "crossws": ["crossws@0.4.12", "", { "optionalDependencies": { "srvx": "0.11.22" } }, "sha512-aypfsr6t0uNvkqaZc6zvBfXzC6pLI0/sIulpkV6RwCVtZqG5ebBzv4weImKK0VNCj91Wl9F5j7p5WU4MNrybng=="],
+
+ "cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="],
+
+ "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
+
+ "d3-array": ["d3-array@3.2.4", "", { "dependencies": { "internmap": "2.0.3" } }, "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg=="],
+
+ "d3-color": ["d3-color@3.1.0", "", {}, "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="],
+
+ "d3-ease": ["d3-ease@3.0.1", "", {}, "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w=="],
+
+ "d3-format": ["d3-format@3.1.2", "", {}, "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg=="],
+
+ "d3-interpolate": ["d3-interpolate@3.0.1", "", { "dependencies": { "d3-color": "3.1.0" } }, "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g=="],
+
+ "d3-path": ["d3-path@3.1.0", "", {}, "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ=="],
+
+ "d3-scale": ["d3-scale@4.0.2", "", { "dependencies": { "d3-array": "3.2.4", "d3-format": "3.1.2", "d3-interpolate": "3.0.1", "d3-time": "3.1.0", "d3-time-format": "4.1.0" } }, "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ=="],
+
+ "d3-shape": ["d3-shape@3.2.0", "", { "dependencies": { "d3-path": "3.1.0" } }, "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA=="],
+
+ "d3-time": ["d3-time@3.1.0", "", { "dependencies": { "d3-array": "3.2.4" } }, "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q=="],
+
+ "d3-time-format": ["d3-time-format@4.1.0", "", { "dependencies": { "d3-time": "3.1.0" } }, "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg=="],
+
+ "d3-timer": ["d3-timer@3.0.1", "", {}, "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="],
+
+ "dayjs": ["dayjs@1.11.23", "", {}, "sha512-QDTCU0M0MxR3hQfnlDJfwekQiaanm1ubOD231u73WBckQ/fsamwRLiE2GBz6D3a/xF1NgfiDLJjXBa1hYOYTtQ=="],
+
+ "db0": ["db0@0.3.4", "", { "optionalDependencies": { "@electric-sql/pglite": "0.5.8", "drizzle-orm": "0.45.3" } }, "sha512-RiXXi4WaNzPTHEOu8UPQKMooIbqOEyqA1t7Z6MsdxSCeb8iUC9ko3LcmsLmeUt2SM5bctfArZKkRQggKZz7JNw=="],
+
+ "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
+
+ "decimal.js-light": ["decimal.js-light@2.5.1", "", {}, "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="],
+
+ "defu": ["defu@6.1.7", "", {}, "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ=="],
+
+ "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
+
+ "detect-node-es": ["detect-node-es@1.1.0", "", {}, "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="],
+
+ "diff": ["diff@8.0.4", "", {}, "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw=="],
+
+ "dompurify": ["dompurify@3.4.16", "", { "optionalDependencies": { "@types/trusted-types": "2.0.7" } }, "sha512-sqo+pNp3qRhCIpbgRi1y8Tgk27Bo2Ry7w0dC1NBeNTdZChWjz9Xb/KOoZbRP/R6pQZ80Qw8YhXw13hWWBbMRnQ=="],
+
+ "drizzle-kit": ["drizzle-kit@0.31.11", "", { "dependencies": { "@drizzle-team/brocli": "0.10.2", "@esbuild-kit/esm-loader": "2.6.5", "esbuild": "0.25.12", "tsx": "4.23.15" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-YCYqxTLIB2OCqf6w9/Vef13baBVbwQIPcbT4Y56AfO6B9ajZhDhD8Jkveg/hJvT/iuMloKD/IYYkyMMNhr7Kqg=="],
+
+ "drizzle-orm": ["drizzle-orm@0.45.3", "", { "optionalDependencies": { "@electric-sql/pglite": "0.5.8", "@opentelemetry/api": "1.9.1", "@types/pg": "8.23.1", "kysely": "0.29.6", "pg": "8.23.1" } }, "sha512-CAloER21cDdcgZ1OmjrZX82EeRNsdP+y0onX/eyoYDaYzki/adrAa91lzM5jWh7zZPK4qUbw/6LGv9J+A+uizA=="],
+
+ "electron-to-chromium": ["electron-to-chromium@1.5.444", "", {}, "sha512-5ss/uJfoDYDHT0lfJzT6FbcskIzROIOPf0BbbFkGcvDzoJU7i//9GDrwwIHQVmIsrAGiF3ihpADBRIsrEFt1rQ=="],
+
+ "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
+
+ "enhanced-resolve": ["enhanced-resolve@5.26.0", "", { "dependencies": { "graceful-fs": "4.2.11", "tapable": "2.3.3" } }, "sha512-9vhedylFonb2YGogzUKX6+Ja72gOJbN1QHAqdrvqLwhdl/QWbKopzoUC9EbQNVsAns/bx/4uyqalrQAoy1IByw=="],
+
+ "env-runner": ["env-runner@0.1.16", "", { "dependencies": { "crossws": "0.4.12", "exsolve": "1.1.3", "httpxy": "0.5.5", "srvx": "0.11.22" }, "bin": { "env-runner": "dist/cli.mjs" } }, "sha512-2LRJM4P2KLX6J83QZZrMqvgCDt/D5ea7wPcI3yYiy5cG/9rX5QwdwZFx0D7ktWnjdRyZxYjttGGorb5nFqb1CA=="],
+
+ "es-toolkit": ["es-toolkit@1.52.0", "", {}, "sha512-XTNEJQh1tY1ZJVcf6ayP/2n4ZPyaHlW2FWs7xvw5ddPuhUVjLD3olQVQS7kf58JbAB48iL0uL/jerTrjtV3lDA=="],
+
+ "esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="],
+
+ "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
+
+ "eventemitter3": ["eventemitter3@5.0.4", "", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="],
+
+ "eventsource": ["eventsource@3.0.7", "", { "dependencies": { "eventsource-parser": "3.1.1" } }, "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA=="],
+
+ "eventsource-parser": ["eventsource-parser@3.1.1", "", {}, "sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ=="],
+
+ "exsolve": ["exsolve@1.1.3", "", {}, "sha512-kuzL9zherLQoqDeQaS55AiiIg1kb4KYXaSusTtgZTPlvKP2gGCI82LNmBNh5RjDVUXIcmgx+/Mx7vPwRzBbhJA=="],
+
+ "fdir": ["fdir@6.5.0", "", { "optionalDependencies": { "picomatch": "4.0.7" } }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
+
+ "fetchdts": ["fetchdts@0.1.7", "", {}, "sha512-YoZjBdafyLIop9lSxXVI33oLD5kN31q4Td+CasofLLYeLXRFeOsuOw0Uo+XNRi9PZlbfdlN2GmRtm4tCEQ9/KA=="],
+
+ "fflate": ["fflate@0.4.9", "", {}, "sha512-zdxgIEddhfsyCaWpJ2SdXEP8ZMrKJ6+5jl4OupODcywU0IhRk6gdXuVGcPICyfx2H97hVK7xmJtRLPjkxAX8Vw=="],
+
+ "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
+
+ "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="],
+
+ "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
+
+ "get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="],
+
+ "get-tsconfig": ["get-tsconfig@4.14.3", "", { "dependencies": { "resolve-pkg-maps": "1.0.0" } }, "sha512-++QEw4DIY7WGoukz+/+A/8dGYPT9l9yIadnmSgZ8Rjr3YVSVDipQSO9CdnJo9ePqFqUUqh+wk9uIaoiAwsiPkA=="],
+
+ "goober": ["goober@2.1.19", "", { "peerDependencies": { "csstype": "3.2.3" } }, "sha512-U7veizMqxyKlM58+Z5j2ngJBH/r9siDmxpvNxSw0PylF6WQvrASJEZrxh1hidRBJc2jqoBVSyOban5u8m+6Rxg=="],
+
+ "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="],
+
+ "h3": ["h3@2.0.1-rc.22", "", { "dependencies": { "rou3": "0.8.1", "srvx": "0.11.22" }, "optionalDependencies": { "crossws": "0.4.12" }, "bin": { "h3": "bin/h3.mjs" } }, "sha512-Esv0DMIuPkCTSWCA0vO73vcTqwzH1wjSrAO1TXNu/K3up1sZHa9EKMapbmxCDYBeymC3fVTk4qxp7ogQWQ+KgA=="],
+
+ "h3-v2": ["h3@2.0.1-rc.20", "", { "dependencies": { "rou3": "0.8.1", "srvx": "0.11.22" }, "optionalDependencies": { "crossws": "0.4.12" }, "bin": { "h3": "bin/h3.mjs" } }, "sha512-28ljodXuUp0fZovdiSRq4G9OgrxCztrJe5VdYzXAB7ueRvI7pIUqLU14Xi3XqdYJ/khXjfpUOOD2EQa6CmBgsg=="],
+
+ "hookable": ["hookable@6.1.2", "", {}, "sha512-+abwxtiEA52GCVIsQqut3S/uKTbUwYIp4Pe/vv+6py5XiXBCqMZHg6pA6Y5qhgLSEys0/cYuPbO0z1QFj5ZCmg=="],
+
+ "httpxy": ["httpxy@0.5.5", "", {}, "sha512-uDjmnPyp1q4Sgzf3w+J/Fc6UqcCEj0x4Wjp7OqK5dGhNeDgpyrAmnS6ey8QWrX3SWDon2DMKf9sBa5X9+CVyMA=="],
+
+ "immer": ["immer@10.2.0", "", {}, "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw=="],
+
+ "internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="],
+
+ "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
+
+ "isbot": ["isbot@5.2.2", "", {}, "sha512-iQcBXcd+Rv/pkubRyGh2utW2j1oPG5hZY6TUhVPpqK4G+o3IbxpJNx04hgksjc/N7GK5pEorUxDeg31cFgEk/w=="],
+
+ "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
+
+ "jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="],
+
+ "jose": ["jose@6.2.12", "", {}, "sha512-9NiFmJEex0sy2Dk58j2UGBSHgUs2ypF9eZSu4L6vjOX3Dp96Sw1F3uL+H+D1sx02jZZdzUT0HgvCy59CuvXcWw=="],
+
+ "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
+
+ "js-yaml": ["js-yaml@4.3.2", "", { "dependencies": { "argparse": "2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA=="],
+
+ "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="],
+
+ "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
+
+ "kysely": ["kysely@0.29.6", "", {}, "sha512-hHaB8C/rfzDDtr/t8YZwxAuPJTT0zHyaPoVzcXwDYhYNAgH/4sIfVhi/XLLIY+bL/FqaIJnjATDbi8ObSELmxg=="],
+
+ "launch-editor": ["launch-editor@2.14.1", "", { "dependencies": { "picocolors": "1.1.1", "shell-quote": "1.12.0" } }, "sha512-QWBrQsMpH7gPr965dsKD/3cKWiNoTjpATQf++Xq63N6sKRGMwlVXz41O1IZTMfZQgBctD/K5Zt06+/I6pP6+HA=="],
+
+ "lightningcss": ["lightningcss@1.33.0", "", { "dependencies": { "detect-libc": "2.1.2" }, "optionalDependencies": { "lightningcss-android-arm64": "1.33.0", "lightningcss-darwin-arm64": "1.33.0", "lightningcss-darwin-x64": "1.33.0", "lightningcss-freebsd-x64": "1.33.0", "lightningcss-linux-arm-gnueabihf": "1.33.0", "lightningcss-linux-arm64-gnu": "1.33.0", "lightningcss-linux-arm64-musl": "1.33.0", "lightningcss-linux-x64-gnu": "1.33.0", "lightningcss-linux-x64-musl": "1.33.0", "lightningcss-win32-arm64-msvc": "1.33.0", "lightningcss-win32-x64-msvc": "1.33.0" } }, "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA=="],
+
+ "lightningcss-android-arm64": ["lightningcss-android-arm64@1.33.0", "", { "os": "android", "cpu": "arm64" }, "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg=="],
+
+ "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.33.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg=="],
+
+ "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.33.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ=="],
+
+ "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.33.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg=="],
+
+ "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.33.0", "", { "os": "linux", "cpu": "arm" }, "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ=="],
+
+ "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.33.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg=="],
+
+ "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.33.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ=="],
+
+ "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.33.0", "", { "os": "linux", "cpu": "x64" }, "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg=="],
+
+ "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.33.0", "", { "os": "linux", "cpu": "x64" }, "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw=="],
+
+ "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.33.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA=="],
+
+ "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.33.0", "", { "os": "win32", "cpu": "x64" }, "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA=="],
+
+ "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "3.1.1" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="],
+
+ "lucide-react": ["lucide-react@0.577.0", "", { "peerDependencies": { "react": "19.3.0" } }, "sha512-4LjoFv2eEPwYDPg/CUdBJQSDfPyzXCRrVW1X7jrx/trgxnxkHFjnVZINbzvzxjN70dxychOfg+FTYwBiS3pQ5A=="],
+
+ "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "1.6.0" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
+
+ "marked": ["marked@18.0.14", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-mBHK6FBHuBAlhgRe88w9F0O1AbwwXJUcQibUbC/QcdTbVGAD7aWza+xt3N6oT/jCZx3/OMeS+8rnuiHZcQ9s7A=="],
+
+ "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
+
+ "nanoid": ["nanoid@3.3.19", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug=="],
+
+ "nanostores": ["nanostores@1.5.4", "", {}, "sha512-4UXY7OAJEK0Y6V3SudBU7cXjAzTDc189R78dDOh0Xbm19gpKYto6WizSg58LJf12lTsRxKSLGyE117OiLpM4DQ=="],
+
+ "nf3": ["nf3@0.3.24", "", {}, "sha512-HxLK4bo+5jNsEETZp4w3tJblHOA9MCBY14IN9nZJJV8JDxt9yNIYxuBuLMjTAR5GFa3HL61+8VQDUrXv3/C8fw=="],
+
+ "nitro": ["nitro@3.0.260610-beta", "", { "dependencies": { "consola": "3.4.2", "crossws": "0.4.12", "db0": "0.3.4", "env-runner": "0.1.16", "h3": "2.0.1-rc.22", "hookable": "6.1.2", "nf3": "0.3.24", "ocache": "0.1.5", "ofetch": "2.0.0-alpha.3", "ohash": "2.0.12", "rolldown": "1.2.12", "srvx": "0.11.22", "unenv": "2.0.0-rc.24", "unstorage": "2.0.0-alpha.7" }, "optionalDependencies": { "jiti": "2.7.0", "vite": "8.3.2" }, "bin": { "nitro": "dist/cli/index.mjs" } }, "sha512-KPb4L5yaF/Rx/xoGMpgHRJvZhbhGiqbRKOwwPLCH9jKTKTsEUHLjnJas85AeCzaswqa8Wi52eQBtRsODC4PS0Q=="],
+
+ "node-releases": ["node-releases@2.0.57", "", {}, "sha512-kQK9LGGFiHtrWiNhZtA7Qbw17AQz+dmsEKODRIVTXA9+e5MS/2gZEBhYJt13GrAz5/IOZKddH/0Z3TP/Zgo+yw=="],
+
+ "ocache": ["ocache@0.1.5", "", { "dependencies": { "ohash": "2.0.12" } }, "sha512-kNNnkkVQup/QDvmTz8Q84wc2ntiyoVHDxa6eHWKt5qdGAmFRBIxy83rxgCYEjW0x06UJ9E3P6VgM2yY4rOBH4w=="],
+
+ "ofetch": ["ofetch@2.0.0-alpha.3", "", {}, "sha512-zpYTCs2byOuft65vI3z43Dd6iSdFbOZZLb9/d21aCpx2rGastVU9dOCv0lu4ykc1Ur1anAYjDi3SUvR0vq50JA=="],
+
+ "ohash": ["ohash@2.0.12", "", {}, "sha512-65S/5gk9YSsaRjcyf7Nfa6h/d3E8/1gslpXfI4W7Dxn/oap8IKRuNT5VXkLQ1YFKIEg4apRY4Pj6aiwFzrDdmw=="],
+
+ "openprofit": ["openprofit@workspace:packages/cli"],
+
+ "oxc-parser": ["oxc-parser@0.120.0", "", { "dependencies": { "@oxc-project/types": "0.120.0" }, "optionalDependencies": { "@oxc-parser/binding-android-arm-eabi": "0.120.0", "@oxc-parser/binding-android-arm64": "0.120.0", "@oxc-parser/binding-darwin-arm64": "0.120.0", "@oxc-parser/binding-darwin-x64": "0.120.0", "@oxc-parser/binding-freebsd-x64": "0.120.0", "@oxc-parser/binding-linux-arm-gnueabihf": "0.120.0", "@oxc-parser/binding-linux-arm-musleabihf": "0.120.0", "@oxc-parser/binding-linux-arm64-gnu": "0.120.0", "@oxc-parser/binding-linux-arm64-musl": "0.120.0", "@oxc-parser/binding-linux-ppc64-gnu": "0.120.0", "@oxc-parser/binding-linux-riscv64-gnu": "0.120.0", "@oxc-parser/binding-linux-riscv64-musl": "0.120.0", "@oxc-parser/binding-linux-s390x-gnu": "0.120.0", "@oxc-parser/binding-linux-x64-gnu": "0.120.0", "@oxc-parser/binding-linux-x64-musl": "0.120.0", "@oxc-parser/binding-openharmony-arm64": "0.120.0", "@oxc-parser/binding-wasm32-wasi": "0.120.0", "@oxc-parser/binding-win32-arm64-msvc": "0.120.0", "@oxc-parser/binding-win32-ia32-msvc": "0.120.0", "@oxc-parser/binding-win32-x64-msvc": "0.120.0" } }, "sha512-WyPWZlcIm+Fkte63FGfgFB8mAAk33aH9h5N9lphXVOHSXEBFFsmYdOBedVKly363aWABjZdaj/m9lBfEY4wt+w=="],
+
+ "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
+
+ "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
+
+ "pg": ["pg@8.23.1", "", { "dependencies": { "pg-connection-string": "2.14.1", "pg-pool": "3.14.0", "pg-protocol": "1.16.1", "pg-types": "2.2.0", "pgpass": "1.0.5" }, "optionalDependencies": { "pg-cloudflare": "1.4.1" } }, "sha512-aL96AHANtWjPLDOLqnhx+ngp9+UK7ETEU8VJrDCGvsSSi/mGLcWYsS6Herg7lmaBJe4uwrfqsa7gTEFaSizDoQ=="],
+
+ "pg-cloudflare": ["pg-cloudflare@1.4.1", "", {}, "sha512-6PQbsFWZcp9EmJEwy5cGQ2La+AMWpP46lgbb8X+U/XsHIUweYDNCpeuKck5RxL2MdVFi7krbbEi5nX4Zh7JhrQ=="],
+
+ "pg-connection-string": ["pg-connection-string@2.14.1", "", {}, "sha512-qR3kGNPBLpCNtz0evbKA0Y/MRFXwSSdT+pTJvYp/bXTcReZbvX1kzF0IyTc1QnxqF7AZbOeBhNL8R5mYQZV/MA=="],
+
+ "pg-int8": ["pg-int8@1.0.1", "", {}, "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="],
+
+ "pg-pool": ["pg-pool@3.14.0", "", { "peerDependencies": { "pg": "8.23.1" } }, "sha512-gKtPkFdQPU3DksooVLi9LsjZxrsBUZIpa+7aVx+LV5pNh0KzP4Zleud2po+ConrxbuXGBJ6Hfer6hdgpIBpBaw=="],
+
+ "pg-protocol": ["pg-protocol@1.16.1", "", {}, "sha512-p9VOFMiHB/ZbJATetbg+99PxssTVSQRnyuPSQ67mN1+1KBOjZaZ83ZQzltnxPhJwSsC3nwVjJ10DVJlerbFzLg=="],
+
+ "pg-types": ["pg-types@2.2.0", "", { "dependencies": { "pg-int8": "1.0.1", "postgres-array": "2.0.0", "postgres-bytea": "1.0.1", "postgres-date": "1.0.7", "postgres-interval": "1.2.0" } }, "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA=="],
+
+ "pgpass": ["pgpass@1.0.5", "", { "dependencies": { "split2": "4.2.0" } }, "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug=="],
+
+ "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
+
+ "picomatch": ["picomatch@4.0.7", "", {}, "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA=="],
+
+ "pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="],
+
+ "postcss": ["postcss@8.5.28", "", { "dependencies": { "nanoid": "3.3.19", "picocolors": "1.1.1", "source-map-js": "1.2.2" } }, "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A=="],
+
+ "postcss-selector-parser": ["postcss-selector-parser@6.0.10", "", { "dependencies": { "cssesc": "3.0.0", "util-deprecate": "1.0.2" } }, "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w=="],
+
+ "postgres-array": ["postgres-array@2.0.0", "", {}, "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA=="],
+
+ "postgres-bytea": ["postgres-bytea@1.0.1", "", {}, "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ=="],
+
+ "postgres-date": ["postgres-date@1.0.7", "", {}, "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q=="],
+
+ "postgres-interval": ["postgres-interval@1.2.0", "", { "dependencies": { "xtend": "4.0.2" } }, "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ=="],
+
+ "posthog-js": ["posthog-js@1.436.1", "", { "dependencies": { "@posthog/browser-common": "0.9.1", "@posthog/core": "1.56.0", "@posthog/types": "1.413.0", "core-js": "3.50.0", "dompurify": "3.4.16", "fflate": "0.4.9", "preact": "10.29.8", "query-selector-shadow-dom": "1.0.1", "web-vitals": "6.2.3", "web-vitals-soft-navs": "npm:web-vitals@6.2.1" }, "optionalDependencies": { "@types/react": "19.3.0", "react": "19.3.0" } }, "sha512-+uPcck+hcaBbjtxBwOtiiZ9BcBXyJmewumUMVP5MrIZO36BHHZ+SzvHTxFsA5soNbPo2fuLppsWfpNnuSjbNeA=="],
+
+ "posthog-node": ["posthog-node@5.55.0", "", { "dependencies": { "@posthog/core": "1.56.0" } }, "sha512-8dFtlDTqs0CKGZ8t4mUnk4NdShAgzru3B9D0MfM/NTBzlRyAjctivzWINLtMLRQxYjvgBohxy7RTwiQf4mPycQ=="],
+
+ "preact": ["preact@10.29.8", "", {}, "sha512-ej2aVZ+vZ8WO7tvlQWRM9N63A0KzF9q4mWJfDUHgYaIofWY9hu74QdnQrjoPMmZi2/nZ5gN0bJCQF49xQqx09Q=="],
+
+ "prettier": ["prettier@3.9.9", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-Z/CJHIkdujO/OtN7nXUii0Rf3VT5SRuhjBA82Xvu2XhBUgX3nhP67T0LHceBdQLex7OOFGTox+Q5Yg8Jk2Qivg=="],
+
+ "query-selector-shadow-dom": ["query-selector-shadow-dom@1.0.1", "", {}, "sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw=="],
+
+ "react": ["react@19.3.0", "", {}, "sha512-E8LUcbtBWt20bbl2YoHfx4ZDBdxVTfOKtCZn9cDSJ4l6/nuoApcpIBcj47t2wZoVX8g2ZHuMHbiShgCR1T5Sog=="],
+
+ "react-dom": ["react-dom@19.3.0", "", { "dependencies": { "scheduler": "0.28.0" }, "peerDependencies": { "react": "19.3.0" } }, "sha512-JDk8dgif51OjFoDE70+OT9ICyYr+69HlmihNwp1+Nsfbna3t5sIiCa9ZJktDmQ4/1b/rn26hIAR2uYXDMr5r0Q=="],
+
+ "react-is": ["react-is@19.3.0", "", {}, "sha512-UpMYezM4v5/18F28aC66AEsjXIgE02kyEMH6yLdgLXu/UTfa1Ntwck/nNLrbqJsEXW7gPb0coNO9FQse9WTovA=="],
+
+ "react-redux": ["react-redux@9.3.0", "", { "dependencies": { "@types/use-sync-external-store": "0.0.6", "use-sync-external-store": "1.7.0" }, "optionalDependencies": { "@types/react": "19.3.0", "redux": "5.0.1" }, "peerDependencies": { "react": "19.3.0" } }, "sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g=="],
+
+ "react-remove-scroll": ["react-remove-scroll@2.7.2", "", { "dependencies": { "react-remove-scroll-bar": "2.3.8", "react-style-singleton": "2.2.3", "tslib": "2.8.1", "use-callback-ref": "1.3.3", "use-sidecar": "1.1.3" }, "optionalDependencies": { "@types/react": "19.3.0" }, "peerDependencies": { "react": "19.3.0" } }, "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q=="],
+
+ "react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "2.2.3", "tslib": "2.8.1" }, "optionalDependencies": { "@types/react": "19.3.0" }, "peerDependencies": { "react": "19.3.0" } }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="],
+
+ "react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "1.0.1", "tslib": "2.8.1" }, "optionalDependencies": { "@types/react": "19.3.0" }, "peerDependencies": { "react": "19.3.0" } }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="],
+
+ "readdirp": ["readdirp@5.1.1", "", {}, "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA=="],
+
+ "recharts": ["recharts@3.8.0", "", { "dependencies": { "@reduxjs/toolkit": "2.13.0", "clsx": "2.1.1", "decimal.js-light": "2.5.1", "es-toolkit": "1.52.0", "eventemitter3": "5.0.4", "immer": "10.2.0", "react-redux": "9.3.0", "reselect": "5.1.1", "tiny-invariant": "1.3.3", "use-sync-external-store": "1.7.0", "victory-vendor": "37.3.6" }, "peerDependencies": { "react": "19.3.0", "react-dom": "19.3.0", "react-is": "19.3.0" } }, "sha512-Z/m38DX3L73ExO4Tpc9/iZWHmHnlzWG4njQbxsF5aSjwqmHNDDIm0rdEBArkwsBvR8U6EirlEHiQNYWCVh9sGQ=="],
+
+ "redux": ["redux@5.0.1", "", {}, "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w=="],
+
+ "redux-thunk": ["redux-thunk@3.1.0", "", { "peerDependencies": { "redux": "5.0.1" } }, "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw=="],
+
+ "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="],
+
+ "reselect": ["reselect@5.1.1", "", {}, "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w=="],
+
+ "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="],
+
+ "rolldown": ["rolldown@1.2.12", "", { "dependencies": { "@oxc-project/types": "0.152.0", "@rolldown/pluginutils": "1.0.1" }, "optionalDependencies": { "@rolldown/binding-android-arm-eabi": "1.2.12", "@rolldown/binding-android-arm64": "1.2.12", "@rolldown/binding-darwin-arm64": "1.2.12", "@rolldown/binding-darwin-x64": "1.2.12", "@rolldown/binding-freebsd-x64": "1.2.12", "@rolldown/binding-linux-arm-gnueabihf": "1.2.12", "@rolldown/binding-linux-arm64-gnu": "1.2.12", "@rolldown/binding-linux-arm64-musl": "1.2.12", "@rolldown/binding-linux-ppc64-gnu": "1.2.12", "@rolldown/binding-linux-s390x-gnu": "1.2.12", "@rolldown/binding-linux-x64-gnu": "1.2.12", "@rolldown/binding-linux-x64-musl": "1.2.12", "@rolldown/binding-openharmony-arm64": "1.2.12", "@rolldown/binding-win32-arm64-msvc": "1.2.12", "@rolldown/binding-win32-x64-msvc": "1.2.12" }, "bin": { "rolldown": "./bin/cli.mjs" } }, "sha512-8wafseiaG80xmXSfqidUNqZcylTlhmPZZt+za2m+js2sFZ8dTNlhIOV2WcbIPx2hgwPBJpEUGFAMZ9bgBBLTSQ=="],
+
+ "rou3": ["rou3@0.9.2", "", {}, "sha512-3SOzvaAg8rkHrXtRjpCvCvbyO5to9oOO27Z/XqHEYXfMRVSw/qMIVdmaOk9W2lcRLtR6dlqTjo9hDeJk70QBYQ=="],
+
+ "scheduler": ["scheduler@0.28.0", "", {}, "sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw=="],
+
+ "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
+
+ "seroval": ["seroval@1.6.8", "", {}, "sha512-HlSgSAkTk4EqHcje1ptJjfZi1YDv5KbhVJ/d3P7T/nAXua2VmDu+AKDX5VTdFfZf48nDkWB2TKYt0DrCSa+3wg=="],
+
+ "seroval-plugins": ["seroval-plugins@1.6.8", "", { "peerDependencies": { "seroval": "1.6.8" } }, "sha512-N7mWAMydj89EnYTHtRpS3LBrAz3J9O6oVrqpuXuvlAHfAUG8WEKqtbAd7SBiJNY5NfCAFhSdyAh7wI4Shjqy4g=="],
+
+ "set-cookie-parser": ["set-cookie-parser@3.1.2", "", {}, "sha512-5/r/lTwbJ3zQ+qwdUFZYeRNqda7P5HD8zQKqlSjdGt1/S0cjLAphHusj4Y58ahDtWn/g32xrIS58/ikOvwl0Lw=="],
+
+ "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
+
+ "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
+
+ "shell-quote": ["shell-quote@1.12.0", "", {}, "sha512-PcByqNyT/38F2kDNi006HAMRJaULuBzq/FOsw3qdZvX/GA9W/jamDaRskgHjubHiftXK5sIFxLNkvrXUwcof6Q=="],
+
+ "simple-icons": ["simple-icons@16.34.0", "", {}, "sha512-UTxKn0PVspk84B2hHF3Dqiqht1yDjJmDc/t4cO7PyCQxCMk6OjEu95pnpGjhLaGeQ4qBrGASbefTIe/+czrX7g=="],
+
+ "solid-js": ["solid-js@1.9.15", "", { "dependencies": { "csstype": "3.2.3", "seroval": "1.5.6", "seroval-plugins": "1.5.6" } }, "sha512-EeiY2xfpZJqPLjXspVEKjAII4yv8NyG//NxZ3IpOFHdUNnnTyL0uJOeS9LWGvA7cFCz5y94cjFwYlmw5Luncsg=="],
+
+ "source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="],
+
+ "source-map-js": ["source-map-js@1.2.2", "", {}, "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw=="],
+
+ "source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "1.1.2", "source-map": "0.6.1" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="],
+
+ "split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="],
+
+ "srvx": ["srvx@0.11.22", "", { "bin": { "srvx": "bin/srvx.mjs" } }, "sha512-LqZxxBDMKuMAZzFzJnDCkFOrs9MZQZr0LvHiO/SuSZVdQaXD7xQ5UWTUxheJrQPve1qk9MG2B/yttUvJxw8egQ=="],
+
+ "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "8.0.0", "is-fullwidth-code-point": "3.0.0", "strip-ansi": "6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
+
+ "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
+
+ "tailwindcss": ["tailwindcss@4.3.3", "", {}, "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ=="],
+
+ "tapable": ["tapable@2.3.3", "", {}, "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="],
+
+ "tiny-invariant": ["tiny-invariant@1.3.3", "", {}, "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="],
+
+ "tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "6.5.0", "picomatch": "4.0.7" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="],
+
+ "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
+
+ "tsx": ["tsx@4.23.15", "", { "dependencies": { "esbuild": "0.28.2" }, "optionalDependencies": { "fsevents": "2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-Yiex1Ovn8z2xPpOWckIiysV1SSyRMY9BkLF++q0yKiDxCqRhosKfMg3janKkiLBwZ5c/YryloKwGZcrEmtwxKw=="],
+
+ "tw-animate-css": ["tw-animate-css@1.4.0", "", {}, "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ=="],
+
+ "typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="],
+
+ "ufo": ["ufo@1.6.4", "", {}, "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA=="],
+
+ "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
+
+ "unenv": ["unenv@2.0.0-rc.24", "", { "dependencies": { "pathe": "2.0.3" } }, "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw=="],
+
+ "unplugin": ["unplugin@3.4.0", "", { "dependencies": { "@jridgewell/remapping": "2.3.5", "picomatch": "4.0.7", "webpack-virtual-modules": "0.6.2" }, "optionalDependencies": { "esbuild": "0.28.2", "rolldown": "1.2.12", "vite": "8.3.2" } }, "sha512-9skdIFlCsPdFV7wUfZxNsFInlW+7nJmGu2gkTu0OUhF56aXGsHab9x52/QhdJ4lC7ZDPWTxbiC4ANqVlsuaW3w=="],
+
+ "unstorage": ["unstorage@2.0.0-alpha.7", "", { "optionalDependencies": { "chokidar": "5.0.0", "db0": "0.3.4", "ofetch": "2.0.0-alpha.3" } }, "sha512-ELPztchk2zgFJnakyodVY3vJWGW9jy//keJ32IOJVGUMyaPydwcA1FtVvWqT0TNRch9H+cMNEGllfVFfScImog=="],
+
+ "update-browserslist-db": ["update-browserslist-db@1.3.3", "", { "dependencies": { "escalade": "3.2.0", "picocolors": "1.1.1" }, "peerDependencies": { "browserslist": "4.29.3" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ=="],
+
+ "use-callback-ref": ["use-callback-ref@1.3.3", "", { "dependencies": { "tslib": "2.8.1" }, "optionalDependencies": { "@types/react": "19.3.0" }, "peerDependencies": { "react": "19.3.0" } }, "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg=="],
+
+ "use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "1.1.0", "tslib": "2.8.1" }, "optionalDependencies": { "@types/react": "19.3.0" }, "peerDependencies": { "react": "19.3.0" } }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="],
+
+ "use-sync-external-store": ["use-sync-external-store@1.7.0", "", { "peerDependencies": { "react": "19.3.0" } }, "sha512-6L+EeigHMQhdaIPNIFUKwfWJSwWFQ8gJbJ2DLOs5sDIegTwR9fRxvnM3uciHKjIZhFz+KAv2emhWMRvDmMcY8A=="],
+
+ "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
+
+ "victory-vendor": ["victory-vendor@37.3.6", "", { "dependencies": { "@types/d3-array": "3.2.2", "@types/d3-ease": "3.0.2", "@types/d3-interpolate": "3.0.4", "@types/d3-scale": "4.0.9", "@types/d3-shape": "3.2.0", "@types/d3-time": "3.0.4", "@types/d3-timer": "3.0.2", "d3-array": "3.2.4", "d3-ease": "3.0.1", "d3-interpolate": "3.0.1", "d3-scale": "4.0.2", "d3-shape": "3.2.0", "d3-time": "3.1.0", "d3-timer": "3.0.1" } }, "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ=="],
+
+ "vite": ["vite@8.3.2", "", { "dependencies": { "lightningcss": "1.33.0", "picomatch": "4.0.7", "postcss": "8.5.28", "rolldown": "1.2.12", "tinyglobby": "0.2.17" }, "optionalDependencies": { "@types/node": "22.20.5", "esbuild": "0.28.2", "fsevents": "2.3.3", "jiti": "2.7.0", "tsx": "4.23.15" }, "bin": { "vite": "bin/vite.js" } }, "sha512-SQr1x6W5vVSbROg7vsyXIaxK9b0G7zsT68acdWWRmnBUsgDieLCRG+Rep9WdZgcposvv/GSnr4GUUBqB3vXq6w=="],
+
+ "vitefu": ["vitefu@1.1.3", "", { "optionalDependencies": { "vite": "8.3.2" } }, "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg=="],
+
+ "web-vitals": ["web-vitals@6.2.3", "", {}, "sha512-Dmy+vdO1UPMqXiAtZSNayhl4f794Bxfd94W4HIj2HlYtczEQfEOon969memlcpcHrTuOKLa5baFjX7WbgmOq+A=="],
+
+ "web-vitals-soft-navs": ["web-vitals@6.2.1", "", {}, "sha512-rLcLXA2sx6+9dE88NHFubwTtGxpK4yYBLj6qHPdFoCaLr0cXGb4efOqtKLlm4loGA4OEKHIQKMKzZkKyOh5ctw=="],
+
+ "webpack-virtual-modules": ["webpack-virtual-modules@0.6.2", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="],
+
+ "which": ["which@2.0.2", "", { "dependencies": { "isexe": "2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
+
+ "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "4.3.0", "string-width": "4.2.3", "strip-ansi": "6.0.1" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
+
+ "ws": ["ws@8.22.0", "", {}, "sha512-Ydggc987+RO0AnWtZ/7Wq9FtNvcrL1b/RO0ud9mWjUPgDrsAAwQSF51sm2hm1XofbU/4jkpGEsLFsZZxU+1DOg=="],
+
+ "xmlbuilder2": ["xmlbuilder2@4.0.3", "", { "dependencies": { "@oozcitak/dom": "2.0.2", "@oozcitak/infra": "2.0.2", "@oozcitak/util": "10.0.0", "js-yaml": "4.3.2" } }, "sha512-bx8Q1STctnNaaDymWnkfQLKofs0mGNN7rLLapJlGuV3VlvegD7Ls4ggMjE3aUSWItCCzU0PEv45lI87iSigiCA=="],
+
+ "xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="],
+
+ "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
+
+ "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
+
+ "yargs": ["yargs@17.7.3", "", { "dependencies": { "cliui": "8.0.1", "escalade": "3.2.0", "get-caller-file": "2.0.5", "require-directory": "2.1.1", "string-width": "4.2.3", "y18n": "5.0.8", "yargs-parser": "21.1.1" } }, "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g=="],
+
+ "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
+
+ "zod": ["zod@4.6.5", "", {}, "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q=="],
+
+ "@base-ui/utils/reselect": ["reselect@5.3.0", "", {}, "sha512-XGoLeRAVzUTcJ1qkxPQhDJyIZ5d6zzZD9nT7AEZOaaU9UbWclhycElmhO+VD5bFeLuzhPBaOV2oXC8uG35ZSpg=="],
+
+ "@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="],
+
+ "@reduxjs/toolkit/immer": ["immer@11.1.21", "", {}, "sha512-bZSadeCPGdaY5/qRLgr6mDSH1ra21rD3rqpiWk7+QTr4ayYPTE9qZYdLh/NdPhMe0wSrTvHD/Lk8q5EwhUs0aw=="],
+
+ "@reduxjs/toolkit/reselect": ["reselect@5.3.0", "", {}, "sha512-XGoLeRAVzUTcJ1qkxPQhDJyIZ5d6zzZD9nT7AEZOaaU9UbWclhycElmhO+VD5bFeLuzhPBaOV2oXC8uG35ZSpg=="],
+
+ "@tailwindcss/node/lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "2.1.2" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="],
+
+ "better-call/@better-auth/utils": ["@better-auth/utils@0.5.0", "", { "dependencies": { "@noble/hashes": "2.4.0" } }, "sha512-BL8W4EfIZFwlu0r54m3v1ztjDhu6dDe/amLTm0xybmbZaNgYUqhD3SjpAsnq0q8YD6/ki4iwIgxJNLP/N3TxiA=="],
+
+ "h3/rou3": ["rou3@0.8.1", "", {}, "sha512-ePa+XGk00/3HuCqrEnK3LxJW7I0SdNg6EFzKUJG73hMAdDcOUC/i/aSz7LSDwLrGr33kal/rqOGydzwl6U7zBA=="],
+
+ "h3-v2/rou3": ["rou3@0.8.1", "", {}, "sha512-ePa+XGk00/3HuCqrEnK3LxJW7I0SdNg6EFzKUJG73hMAdDcOUC/i/aSz7LSDwLrGr33kal/rqOGydzwl6U7zBA=="],
+
+ "oxc-parser/@oxc-project/types": ["@oxc-project/types@0.120.0", "", {}, "sha512-k1YNu55DuvAip/MGE1FTsIuU3FUCn6v/ujG9V7Nq5Df/kX2CWb13hhwD0lmJGMGqE+bE1MXvv9SZVnMzEXlWcg=="],
+
+ "solid-js/seroval": ["seroval@1.5.6", "", {}, "sha512-rVQVWjjSvlINzaQPZH5JFqsqEsIWdTxY3iJZCnTL/5gQbXIRooVZKI60tVCkOVfzcRPejboxO2t0P89dg5mQaA=="],
+
+ "solid-js/seroval-plugins": ["seroval-plugins@1.5.6", "", { "peerDependencies": { "seroval": "1.5.6" } }, "sha512-HXuLAX2pu/UByPpaeo/TaMfvMIi+1QqIoPJYCcAtU8QkVNwgR6MPlGuCQTErV1JwraaMbYaWVIBX7mppzGLATQ=="],
+
+ "source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
+
+ "tsx/esbuild": ["esbuild@0.28.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.2", "@esbuild/android-arm": "0.28.2", "@esbuild/android-arm64": "0.28.2", "@esbuild/android-x64": "0.28.2", "@esbuild/darwin-arm64": "0.28.2", "@esbuild/darwin-x64": "0.28.2", "@esbuild/freebsd-arm64": "0.28.2", "@esbuild/freebsd-x64": "0.28.2", "@esbuild/linux-arm": "0.28.2", "@esbuild/linux-arm64": "0.28.2", "@esbuild/linux-ia32": "0.28.2", "@esbuild/linux-loong64": "0.28.2", "@esbuild/linux-mips64el": "0.28.2", "@esbuild/linux-ppc64": "0.28.2", "@esbuild/linux-riscv64": "0.28.2", "@esbuild/linux-s390x": "0.28.2", "@esbuild/linux-x64": "0.28.2", "@esbuild/netbsd-arm64": "0.28.2", "@esbuild/netbsd-x64": "0.28.2", "@esbuild/openbsd-arm64": "0.28.2", "@esbuild/openbsd-x64": "0.28.2", "@esbuild/openharmony-arm64": "0.28.2", "@esbuild/sunos-x64": "0.28.2", "@esbuild/win32-arm64": "0.28.2", "@esbuild/win32-ia32": "0.28.2", "@esbuild/win32-x64": "0.28.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA=="],
+
+ "unplugin/esbuild": ["esbuild@0.28.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.2", "@esbuild/android-arm": "0.28.2", "@esbuild/android-arm64": "0.28.2", "@esbuild/android-x64": "0.28.2", "@esbuild/darwin-arm64": "0.28.2", "@esbuild/darwin-x64": "0.28.2", "@esbuild/freebsd-arm64": "0.28.2", "@esbuild/freebsd-x64": "0.28.2", "@esbuild/linux-arm": "0.28.2", "@esbuild/linux-arm64": "0.28.2", "@esbuild/linux-ia32": "0.28.2", "@esbuild/linux-loong64": "0.28.2", "@esbuild/linux-mips64el": "0.28.2", "@esbuild/linux-ppc64": "0.28.2", "@esbuild/linux-riscv64": "0.28.2", "@esbuild/linux-s390x": "0.28.2", "@esbuild/linux-x64": "0.28.2", "@esbuild/netbsd-arm64": "0.28.2", "@esbuild/netbsd-x64": "0.28.2", "@esbuild/openbsd-arm64": "0.28.2", "@esbuild/openbsd-x64": "0.28.2", "@esbuild/openharmony-arm64": "0.28.2", "@esbuild/sunos-x64": "0.28.2", "@esbuild/win32-arm64": "0.28.2", "@esbuild/win32-ia32": "0.28.2", "@esbuild/win32-x64": "0.28.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA=="],
+
+ "vite/esbuild": ["esbuild@0.28.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.2", "@esbuild/android-arm": "0.28.2", "@esbuild/android-arm64": "0.28.2", "@esbuild/android-x64": "0.28.2", "@esbuild/darwin-arm64": "0.28.2", "@esbuild/darwin-x64": "0.28.2", "@esbuild/freebsd-arm64": "0.28.2", "@esbuild/freebsd-x64": "0.28.2", "@esbuild/linux-arm": "0.28.2", "@esbuild/linux-arm64": "0.28.2", "@esbuild/linux-ia32": "0.28.2", "@esbuild/linux-loong64": "0.28.2", "@esbuild/linux-mips64el": "0.28.2", "@esbuild/linux-ppc64": "0.28.2", "@esbuild/linux-riscv64": "0.28.2", "@esbuild/linux-s390x": "0.28.2", "@esbuild/linux-x64": "0.28.2", "@esbuild/netbsd-arm64": "0.28.2", "@esbuild/netbsd-x64": "0.28.2", "@esbuild/openbsd-arm64": "0.28.2", "@esbuild/openbsd-x64": "0.28.2", "@esbuild/openharmony-arm64": "0.28.2", "@esbuild/sunos-x64": "0.28.2", "@esbuild/win32-arm64": "0.28.2", "@esbuild/win32-ia32": "0.28.2", "@esbuild/win32-x64": "0.28.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.18.20", "", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.18.20", "", { "os": "android", "cpu": "arm64" }, "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.18.20", "", { "os": "android", "cpu": "x64" }, "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.18.20", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.18.20", "", { "os": "darwin", "cpu": "x64" }, "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.18.20", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.18.20", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.18.20", "", { "os": "linux", "cpu": "arm" }, "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.18.20", "", { "os": "linux", "cpu": "arm64" }, "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.18.20", "", { "os": "linux", "cpu": "ia32" }, "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.18.20", "", { "os": "linux", "cpu": "ppc64" }, "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.18.20", "", { "os": "linux", "cpu": "s390x" }, "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.18.20", "", { "os": "linux", "cpu": "x64" }, "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.18.20", "", { "os": "none", "cpu": "x64" }, "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.18.20", "", { "os": "openbsd", "cpu": "x64" }, "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.18.20", "", { "os": "sunos", "cpu": "x64" }, "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.18.20", "", { "os": "win32", "cpu": "arm64" }, "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.18.20", "", { "os": "win32", "cpu": "ia32" }, "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g=="],
+
+ "@esbuild-kit/core-utils/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="],
+
+ "@tailwindcss/node/lightningcss/lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="],
+
+ "@tailwindcss/node/lightningcss/lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.32.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ=="],
+
+ "@tailwindcss/node/lightningcss/lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.32.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w=="],
+
+ "@tailwindcss/node/lightningcss/lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.32.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig=="],
+
+ "@tailwindcss/node/lightningcss/lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.32.0", "", { "os": "linux", "cpu": "arm" }, "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw=="],
+
+ "@tailwindcss/node/lightningcss/lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ=="],
+
+ "@tailwindcss/node/lightningcss/lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg=="],
+
+ "@tailwindcss/node/lightningcss/lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA=="],
+
+ "@tailwindcss/node/lightningcss/lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg=="],
+
+ "@tailwindcss/node/lightningcss/lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.32.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw=="],
+
+ "@tailwindcss/node/lightningcss/lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="],
+
+ "tsx/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ=="],
+
+ "tsx/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.28.2", "", { "os": "android", "cpu": "arm" }, "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg=="],
+
+ "tsx/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.28.2", "", { "os": "android", "cpu": "arm64" }, "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A=="],
+
+ "tsx/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.28.2", "", { "os": "android", "cpu": "x64" }, "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q=="],
+
+ "tsx/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.28.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw=="],
+
+ "tsx/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.28.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw=="],
+
+ "tsx/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.28.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw=="],
+
+ "tsx/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.28.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg=="],
+
+ "tsx/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.28.2", "", { "os": "linux", "cpu": "arm" }, "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w=="],
+
+ "tsx/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.28.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug=="],
+
+ "tsx/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.28.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ=="],
+
+ "tsx/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ=="],
+
+ "tsx/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA=="],
+
+ "tsx/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.28.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ=="],
+
+ "tsx/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA=="],
+
+ "tsx/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.28.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg=="],
+
+ "tsx/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.28.2", "", { "os": "linux", "cpu": "x64" }, "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ=="],
+
+ "tsx/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.28.2", "", { "os": "none", "cpu": "arm64" }, "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw=="],
+
+ "tsx/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.28.2", "", { "os": "none", "cpu": "x64" }, "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw=="],
+
+ "tsx/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.28.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ=="],
+
+ "tsx/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.28.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw=="],
+
+ "tsx/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.28.2", "", { "os": "none", "cpu": "arm64" }, "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q=="],
+
+ "tsx/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.28.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g=="],
+
+ "tsx/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.28.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ=="],
+
+ "tsx/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.28.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA=="],
+
+ "tsx/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.28.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g=="],
+
+ "unplugin/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ=="],
+
+ "unplugin/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.28.2", "", { "os": "android", "cpu": "arm" }, "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg=="],
+
+ "unplugin/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.28.2", "", { "os": "android", "cpu": "arm64" }, "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A=="],
+
+ "unplugin/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.28.2", "", { "os": "android", "cpu": "x64" }, "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q=="],
+
+ "unplugin/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.28.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw=="],
+
+ "unplugin/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.28.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw=="],
+
+ "unplugin/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.28.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw=="],
+
+ "unplugin/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.28.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg=="],
+
+ "unplugin/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.28.2", "", { "os": "linux", "cpu": "arm" }, "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w=="],
+
+ "unplugin/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.28.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug=="],
+
+ "unplugin/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.28.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ=="],
+
+ "unplugin/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ=="],
+
+ "unplugin/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA=="],
+
+ "unplugin/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.28.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ=="],
+
+ "unplugin/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA=="],
+
+ "unplugin/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.28.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg=="],
+
+ "unplugin/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.28.2", "", { "os": "linux", "cpu": "x64" }, "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ=="],
+
+ "unplugin/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.28.2", "", { "os": "none", "cpu": "arm64" }, "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw=="],
+
+ "unplugin/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.28.2", "", { "os": "none", "cpu": "x64" }, "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw=="],
+
+ "unplugin/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.28.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ=="],
+
+ "unplugin/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.28.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw=="],
+
+ "unplugin/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.28.2", "", { "os": "none", "cpu": "arm64" }, "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q=="],
+
+ "unplugin/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.28.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g=="],
+
+ "unplugin/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.28.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ=="],
+
+ "unplugin/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.28.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA=="],
+
+ "unplugin/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.28.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g=="],
+
+ "vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ=="],
+
+ "vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.28.2", "", { "os": "android", "cpu": "arm" }, "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg=="],
+
+ "vite/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.28.2", "", { "os": "android", "cpu": "arm64" }, "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A=="],
+
+ "vite/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.28.2", "", { "os": "android", "cpu": "x64" }, "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q=="],
+
+ "vite/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.28.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw=="],
+
+ "vite/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.28.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw=="],
+
+ "vite/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.28.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw=="],
+
+ "vite/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.28.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg=="],
+
+ "vite/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.28.2", "", { "os": "linux", "cpu": "arm" }, "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w=="],
+
+ "vite/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.28.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug=="],
+
+ "vite/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.28.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ=="],
+
+ "vite/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ=="],
+
+ "vite/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA=="],
+
+ "vite/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.28.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ=="],
+
+ "vite/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.28.2", "", { "os": "linux", "cpu": "none" }, "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA=="],
+
+ "vite/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.28.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg=="],
+
+ "vite/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.28.2", "", { "os": "linux", "cpu": "x64" }, "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ=="],
+
+ "vite/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.28.2", "", { "os": "none", "cpu": "arm64" }, "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw=="],
+
+ "vite/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.28.2", "", { "os": "none", "cpu": "x64" }, "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw=="],
+
+ "vite/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.28.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ=="],
+
+ "vite/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.28.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw=="],
+
+ "vite/esbuild/@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.28.2", "", { "os": "none", "cpu": "arm64" }, "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q=="],
+
+ "vite/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.28.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g=="],
+
+ "vite/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.28.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ=="],
+
+ "vite/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.28.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA=="],
+
+ "vite/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.28.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g=="],
+ }
+}
diff --git a/docs/BOOKS.md b/docs/BOOKS.md
index e19d847..550250c 100644
--- a/docs/BOOKS.md
+++ b/docs/BOOKS.md
@@ -23,7 +23,7 @@ A setting with a start date supports one change. Two changes in a year would nee
## Data the connectors add
-- `revenue_lines.gross_base_cents`, `fees_base_cents`, `refunds_base_cents`: written by the sync at the line's rate, like `net_base_cents`. Older rows are null until the next full sync; readers derive them from the net rate when net is not zero.
+- `revenue_lines.gross_base_cents`, `fees_base_cents`, `refunds_base_cents`: written by the sync at the line's rate, like `net_base_cents`. Older rows are null until the next full sync; readers derive them from the net rate when net is not zero. The books don't read `fees_base_cents`: fees are gross − refunds − net.
- `revenue_lines.service_start`, `service_end`: the period a payment covers, `[start, end)`. Null means the payment is earned on its date.
- `payouts`: money a payment provider sent to a bank account. Stripe only: Polar's API doesn't share payouts.
- Polar revenue from orders and refunds. A token without `orders:read` and `refunds:read` (Polar answers 403) keeps syncing Polar's daily totals from its metrics.
@@ -63,7 +63,7 @@ All amounts are in the workspace currency. Every entry balances. "Payer" is `owe
| Event | Debit | Credit |
|---|---|---|
-| Payment received (on its date) | `balance:` gross − refunds − fees + tax; `payment_fees` fees; `refunds` refunds | `deferred_revenue` gross; `sales_tax_owed` tax (only when the provider does not remit tax) |
+| Payment received (on its date) | `balance:` net + tax; `payment_fees` gross − refunds − net (the provider's fees, its other charges and lost disputes); `refunds` refunds | `deferred_revenue` gross; `sales_tax_owed` tax (only when the provider does not remit tax) |
| Revenue earned (each month of the service period, by days) | `deferred_revenue` | `sales` |
| Payout to a bank account | `company_bank` (incorporated) or `owner_draws` | `balance:` |
| Usage cost (on its date) | expense account | `balance:` |
diff --git a/drizzle/0012_books_resync.sql b/drizzle/0012_books_resync.sql
new file mode 100644
index 0000000..db0e317
--- /dev/null
+++ b/drizzle/0012_books_resync.sql
@@ -0,0 +1,14 @@
+-- Reread the plan's whole history on the next scheduled sync for:
+-- Stripe and Paddle, whose payouts and service periods are new (0010), and
+-- every connection in a CAD workspace, so its stored lines convert at the
+-- Bank of Canada rates (0011).
+-- 1, not null: a last sync that old makes syncRange read the whole history,
+-- while null would count as a first sync, which maps unassigned sub-units to
+-- the connection's product and records first-sync analytics again.
+-- Connections that never synced keep null.
+UPDATE "connections" SET "last_synced_at" = 1
+WHERE "last_synced_at" IS NOT NULL
+ AND (
+ "provider" IN ('stripe', 'paddle')
+ OR "workspace_id" IN (SELECT "id" FROM "workspaces" WHERE "base_currency" = 'CAD')
+ );
diff --git a/drizzle/meta/0012_snapshot.json b/drizzle/meta/0012_snapshot.json
new file mode 100644
index 0000000..310aee0
--- /dev/null
+++ b/drizzle/meta/0012_snapshot.json
@@ -0,0 +1,3005 @@
+{
+ "id": "b82ee309-97fd-4993-8bdd-bbf2710ec14c",
+ "prevId": "751ff482-32f6-45aa-a5bf-159c86616617",
+ "version": "7",
+ "dialect": "postgresql",
+ "tables": {
+ "public.alert_channels": {
+ "name": "alert_channels",
+ "schema": "",
+ "columns": {
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "slack_webhook": {
+ "name": "slack_webhook",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "webhook_url": {
+ "name": "webhook_url",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "webhook_secret": {
+ "name": "webhook_secret",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "sms_phone": {
+ "name": "sms_phone",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "sms_code_hash": {
+ "name": "sms_code_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "sms_code_expires_at": {
+ "name": "sms_code_expires_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "sms_verified_at": {
+ "name": "sms_verified_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "sms_month": {
+ "name": "sms_month",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "sms_count": {
+ "name": "sms_count",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "alert_channels_workspace_id_workspaces_id_fk": {
+ "name": "alert_channels_workspace_id_workspaces_id_fk",
+ "tableFrom": "alert_channels",
+ "columnsFrom": [
+ "workspace_id"
+ ],
+ "tableTo": "workspaces",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "cascade"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.alert_rules": {
+ "name": "alert_rules",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "kind": {
+ "name": "kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "threshold": {
+ "name": "threshold",
+ "type": "double precision",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "channel": {
+ "name": "channel",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'email'"
+ },
+ "enabled": {
+ "name": "enabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "(extract(epoch from now()) * 1000)::bigint"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "alert_rules_workspace_id_workspaces_id_fk": {
+ "name": "alert_rules_workspace_id_workspaces_id_fk",
+ "tableFrom": "alert_rules",
+ "columnsFrom": [
+ "workspace_id"
+ ],
+ "tableTo": "workspaces",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "cascade"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.alerts": {
+ "name": "alerts",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "rule_id": {
+ "name": "rule_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "key": {
+ "name": "key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "title": {
+ "name": "title",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "detail": {
+ "name": "detail",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "tone": {
+ "name": "tone",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'ink'"
+ },
+ "opened_at": {
+ "name": "opened_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "resolved_at": {
+ "name": "resolved_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "alerts_ws_open_key": {
+ "name": "alerts_ws_open_key",
+ "columns": [
+ {
+ "expression": "workspace_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "key",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "with": {},
+ "method": "btree",
+ "where": "\"alerts\".\"resolved_at\" is null",
+ "concurrently": false
+ }
+ },
+ "foreignKeys": {
+ "alerts_workspace_id_workspaces_id_fk": {
+ "name": "alerts_workspace_id_workspaces_id_fk",
+ "tableFrom": "alerts",
+ "columnsFrom": [
+ "workspace_id"
+ ],
+ "tableTo": "workspaces",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "cascade"
+ },
+ "alerts_rule_id_alert_rules_id_fk": {
+ "name": "alerts_rule_id_alert_rules_id_fk",
+ "tableFrom": "alerts",
+ "columnsFrom": [
+ "rule_id"
+ ],
+ "tableTo": "alert_rules",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "set null"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.api_tokens": {
+ "name": "api_tokens",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "scope": {
+ "name": "scope",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'read'"
+ },
+ "token_hash": {
+ "name": "token_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "prefix": {
+ "name": "prefix",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "last_used_at": {
+ "name": "last_used_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "revoked_at": {
+ "name": "revoked_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "oauth_client_id": {
+ "name": "oauth_client_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "refresh_hash": {
+ "name": "refresh_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "(extract(epoch from now()) * 1000)::bigint"
+ }
+ },
+ "indexes": {
+ "api_tokens_hash": {
+ "name": "api_tokens_hash",
+ "columns": [
+ {
+ "expression": "token_hash",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "with": {},
+ "method": "btree",
+ "concurrently": false
+ },
+ "api_tokens_refresh": {
+ "name": "api_tokens_refresh",
+ "columns": [
+ {
+ "expression": "refresh_hash",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "with": {},
+ "method": "btree",
+ "concurrently": false
+ }
+ },
+ "foreignKeys": {
+ "api_tokens_workspace_id_workspaces_id_fk": {
+ "name": "api_tokens_workspace_id_workspaces_id_fk",
+ "tableFrom": "api_tokens",
+ "columnsFrom": [
+ "workspace_id"
+ ],
+ "tableTo": "workspaces",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "cascade"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.audit_events": {
+ "name": "audit_events",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "actor_kind": {
+ "name": "actor_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "actor_id": {
+ "name": "actor_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "source": {
+ "name": "source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "action": {
+ "name": "action",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "target": {
+ "name": "target",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "detail": {
+ "name": "detail",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "(extract(epoch from now()) * 1000)::bigint"
+ }
+ },
+ "indexes": {
+ "audit_ws_created": {
+ "name": "audit_ws_created",
+ "columns": [
+ {
+ "expression": "workspace_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "with": {},
+ "method": "btree",
+ "concurrently": false
+ }
+ },
+ "foreignKeys": {
+ "audit_events_workspace_id_workspaces_id_fk": {
+ "name": "audit_events_workspace_id_workspaces_id_fk",
+ "tableFrom": "audit_events",
+ "columnsFrom": [
+ "workspace_id"
+ ],
+ "tableTo": "workspaces",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "cascade"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.benchmark_snapshots": {
+ "name": "benchmark_snapshots",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "month": {
+ "name": "month",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "band": {
+ "name": "band",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "metric": {
+ "name": "metric",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "n": {
+ "name": "n",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "p25": {
+ "name": "p25",
+ "type": "double precision",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "p50": {
+ "name": "p50",
+ "type": "double precision",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "p75": {
+ "name": "p75",
+ "type": "double precision",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "p90": {
+ "name": "p90",
+ "type": "double precision",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "computed_at": {
+ "name": "computed_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "benchmarks_month_band_metric": {
+ "name": "benchmarks_month_band_metric",
+ "columns": [
+ {
+ "expression": "month",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "band",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "metric",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "with": {},
+ "method": "btree",
+ "concurrently": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.cli_logins": {
+ "name": "cli_logins",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "device_code_hash": {
+ "name": "device_code_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "user_code": {
+ "name": "user_code",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "requested_ip": {
+ "name": "requested_ip",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "approved_at": {
+ "name": "approved_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "api_token_id": {
+ "name": "api_token_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "(extract(epoch from now()) * 1000)::bigint"
+ }
+ },
+ "indexes": {
+ "cli_logins_device": {
+ "name": "cli_logins_device",
+ "columns": [
+ {
+ "expression": "device_code_hash",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "with": {},
+ "method": "btree",
+ "concurrently": false
+ },
+ "cli_logins_user_code": {
+ "name": "cli_logins_user_code",
+ "columns": [
+ {
+ "expression": "user_code",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "with": {},
+ "method": "btree",
+ "concurrently": false
+ }
+ },
+ "foreignKeys": {
+ "cli_logins_workspace_id_workspaces_id_fk": {
+ "name": "cli_logins_workspace_id_workspaces_id_fk",
+ "tableFrom": "cli_logins",
+ "columnsFrom": [
+ "workspace_id"
+ ],
+ "tableTo": "workspaces",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "cascade"
+ },
+ "cli_logins_api_token_id_api_tokens_id_fk": {
+ "name": "cli_logins_api_token_id_api_tokens_id_fk",
+ "tableFrom": "cli_logins",
+ "columnsFrom": [
+ "api_token_id"
+ ],
+ "tableTo": "api_tokens",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "set null"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.connect_links": {
+ "name": "connect_links",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "api_token_id": {
+ "name": "api_token_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "provider": {
+ "name": "provider",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "token_hash": {
+ "name": "token_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "used_at": {
+ "name": "used_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "connection_id": {
+ "name": "connection_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "(extract(epoch from now()) * 1000)::bigint"
+ }
+ },
+ "indexes": {
+ "connect_links_hash": {
+ "name": "connect_links_hash",
+ "columns": [
+ {
+ "expression": "token_hash",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "with": {},
+ "method": "btree",
+ "concurrently": false
+ }
+ },
+ "foreignKeys": {
+ "connect_links_workspace_id_workspaces_id_fk": {
+ "name": "connect_links_workspace_id_workspaces_id_fk",
+ "tableFrom": "connect_links",
+ "columnsFrom": [
+ "workspace_id"
+ ],
+ "tableTo": "workspaces",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "cascade"
+ },
+ "connect_links_api_token_id_api_tokens_id_fk": {
+ "name": "connect_links_api_token_id_api_tokens_id_fk",
+ "tableFrom": "connect_links",
+ "columnsFrom": [
+ "api_token_id"
+ ],
+ "tableTo": "api_tokens",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "cascade"
+ },
+ "connect_links_connection_id_connections_id_fk": {
+ "name": "connect_links_connection_id_connections_id_fk",
+ "tableFrom": "connect_links",
+ "columnsFrom": [
+ "connection_id"
+ ],
+ "tableTo": "connections",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "set null"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.connections": {
+ "name": "connections",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "provider": {
+ "name": "provider",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "kind": {
+ "name": "kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "label": {
+ "name": "label",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "auth_kind": {
+ "name": "auth_kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "credentials": {
+ "name": "credentials",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'active'"
+ },
+ "product_id": {
+ "name": "product_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "cadence_minutes": {
+ "name": "cadence_minutes",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 360
+ },
+ "paid_with": {
+ "name": "paid_with",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'personal'"
+ },
+ "paid_with_since": {
+ "name": "paid_with_since",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_synced_at": {
+ "name": "last_synced_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "last_error": {
+ "name": "last_error",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "(extract(epoch from now()) * 1000)::bigint"
+ }
+ },
+ "indexes": {
+ "connections_ws": {
+ "name": "connections_ws",
+ "columns": [
+ {
+ "expression": "workspace_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "with": {},
+ "method": "btree",
+ "concurrently": false
+ }
+ },
+ "foreignKeys": {
+ "connections_workspace_id_workspaces_id_fk": {
+ "name": "connections_workspace_id_workspaces_id_fk",
+ "tableFrom": "connections",
+ "columnsFrom": [
+ "workspace_id"
+ ],
+ "tableTo": "workspaces",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "cascade"
+ },
+ "connections_product_id_products_id_fk": {
+ "name": "connections_product_id_products_id_fk",
+ "tableFrom": "connections",
+ "columnsFrom": [
+ "product_id"
+ ],
+ "tableTo": "products",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "set null"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.cost_lines": {
+ "name": "cost_lines",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "connection_id": {
+ "name": "connection_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "product_id": {
+ "name": "product_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "provider": {
+ "name": "provider",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "date": {
+ "name": "date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "amount_cents": {
+ "name": "amount_cents",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "amount_base_cents": {
+ "name": "amount_base_cents",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "service": {
+ "name": "service",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "sub_unit_id": {
+ "name": "sub_unit_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "sub_unit_label": {
+ "name": "sub_unit_label",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "source": {
+ "name": "source",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "external_id": {
+ "name": "external_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "(extract(epoch from now()) * 1000)::bigint"
+ }
+ },
+ "indexes": {
+ "cost_ws_ext": {
+ "name": "cost_ws_ext",
+ "columns": [
+ {
+ "expression": "workspace_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "external_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "with": {},
+ "method": "btree",
+ "concurrently": false
+ },
+ "cost_ws_date": {
+ "name": "cost_ws_date",
+ "columns": [
+ {
+ "expression": "workspace_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "date",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "with": {},
+ "method": "btree",
+ "concurrently": false
+ }
+ },
+ "foreignKeys": {
+ "cost_lines_workspace_id_workspaces_id_fk": {
+ "name": "cost_lines_workspace_id_workspaces_id_fk",
+ "tableFrom": "cost_lines",
+ "columnsFrom": [
+ "workspace_id"
+ ],
+ "tableTo": "workspaces",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "cascade"
+ },
+ "cost_lines_connection_id_connections_id_fk": {
+ "name": "cost_lines_connection_id_connections_id_fk",
+ "tableFrom": "cost_lines",
+ "columnsFrom": [
+ "connection_id"
+ ],
+ "tableTo": "connections",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "cascade"
+ },
+ "cost_lines_product_id_products_id_fk": {
+ "name": "cost_lines_product_id_products_id_fk",
+ "tableFrom": "cost_lines",
+ "columnsFrom": [
+ "product_id"
+ ],
+ "tableTo": "products",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "set null"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.flat_costs": {
+ "name": "flat_costs",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "product_id": {
+ "name": "product_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "provider": {
+ "name": "provider",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'manual'"
+ },
+ "amount_cents": {
+ "name": "amount_cents",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "amount_base_cents": {
+ "name": "amount_base_cents",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "interval": {
+ "name": "interval",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "starts_on": {
+ "name": "starts_on",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "ends_on": {
+ "name": "ends_on",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "category": {
+ "name": "category",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "paid_with": {
+ "name": "paid_with",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'personal'"
+ },
+ "paid_with_since": {
+ "name": "paid_with_since",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "(extract(epoch from now()) * 1000)::bigint"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "flat_costs_workspace_id_workspaces_id_fk": {
+ "name": "flat_costs_workspace_id_workspaces_id_fk",
+ "tableFrom": "flat_costs",
+ "columnsFrom": [
+ "workspace_id"
+ ],
+ "tableTo": "workspaces",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "cascade"
+ },
+ "flat_costs_product_id_products_id_fk": {
+ "name": "flat_costs_product_id_products_id_fk",
+ "tableFrom": "flat_costs",
+ "columnsFrom": [
+ "product_id"
+ ],
+ "tableTo": "products",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "set null"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.fx_rates": {
+ "name": "fx_rates",
+ "schema": "",
+ "columns": {
+ "date": {
+ "name": "date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "base": {
+ "name": "base",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "rate": {
+ "name": "rate",
+ "type": "double precision",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {
+ "fx_rates_date_base_currency_pk": {
+ "name": "fx_rates_date_base_currency_pk",
+ "columns": [
+ "date",
+ "base",
+ "currency"
+ ]
+ }
+ },
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.journal_exports": {
+ "name": "journal_exports",
+ "schema": "",
+ "columns": {
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "month": {
+ "name": "month",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "entries": {
+ "name": "entries",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "exported_at": {
+ "name": "exported_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "journal_exports_workspace_id_workspaces_id_fk": {
+ "name": "journal_exports_workspace_id_workspaces_id_fk",
+ "tableFrom": "journal_exports",
+ "columnsFrom": [
+ "workspace_id"
+ ],
+ "tableTo": "workspaces",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "cascade"
+ }
+ },
+ "compositePrimaryKeys": {
+ "journal_exports_workspace_id_month_pk": {
+ "name": "journal_exports_workspace_id_month_pk",
+ "columns": [
+ "workspace_id",
+ "month"
+ ]
+ }
+ },
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.metric_snapshots": {
+ "name": "metric_snapshots",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "connection_id": {
+ "name": "connection_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "date": {
+ "name": "date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "metric": {
+ "name": "metric",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "value": {
+ "name": "value",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "snap_conn_date_metric": {
+ "name": "snap_conn_date_metric",
+ "columns": [
+ {
+ "expression": "connection_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "date",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "metric",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "with": {},
+ "method": "btree",
+ "concurrently": false
+ }
+ },
+ "foreignKeys": {
+ "metric_snapshots_workspace_id_workspaces_id_fk": {
+ "name": "metric_snapshots_workspace_id_workspaces_id_fk",
+ "tableFrom": "metric_snapshots",
+ "columnsFrom": [
+ "workspace_id"
+ ],
+ "tableTo": "workspaces",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "cascade"
+ },
+ "metric_snapshots_connection_id_connections_id_fk": {
+ "name": "metric_snapshots_connection_id_connections_id_fk",
+ "tableFrom": "metric_snapshots",
+ "columnsFrom": [
+ "connection_id"
+ ],
+ "tableTo": "connections",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "cascade"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.oauth_clients": {
+ "name": "oauth_clients",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "redirect_uris": {
+ "name": "redirect_uris",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "(extract(epoch from now()) * 1000)::bigint"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.oauth_codes": {
+ "name": "oauth_codes",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "code_hash": {
+ "name": "code_hash",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "client_id": {
+ "name": "client_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "client_name": {
+ "name": "client_name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "redirect_uri": {
+ "name": "redirect_uri",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "code_challenge": {
+ "name": "code_challenge",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "scope": {
+ "name": "scope",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "api_token_id": {
+ "name": "api_token_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "used_at": {
+ "name": "used_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "(extract(epoch from now()) * 1000)::bigint"
+ }
+ },
+ "indexes": {
+ "oauth_codes_hash": {
+ "name": "oauth_codes_hash",
+ "columns": [
+ {
+ "expression": "code_hash",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "with": {},
+ "method": "btree",
+ "concurrently": false
+ }
+ },
+ "foreignKeys": {
+ "oauth_codes_workspace_id_workspaces_id_fk": {
+ "name": "oauth_codes_workspace_id_workspaces_id_fk",
+ "tableFrom": "oauth_codes",
+ "columnsFrom": [
+ "workspace_id"
+ ],
+ "tableTo": "workspaces",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "cascade"
+ },
+ "oauth_codes_api_token_id_api_tokens_id_fk": {
+ "name": "oauth_codes_api_token_id_api_tokens_id_fk",
+ "tableFrom": "oauth_codes",
+ "columnsFrom": [
+ "api_token_id"
+ ],
+ "tableTo": "api_tokens",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "set null"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.payouts": {
+ "name": "payouts",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "connection_id": {
+ "name": "connection_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "date": {
+ "name": "date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "amount_cents": {
+ "name": "amount_cents",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "amount_base_cents": {
+ "name": "amount_base_cents",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "external_id": {
+ "name": "external_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "(extract(epoch from now()) * 1000)::bigint"
+ }
+ },
+ "indexes": {
+ "payouts_conn_ext": {
+ "name": "payouts_conn_ext",
+ "columns": [
+ {
+ "expression": "connection_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "external_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "with": {},
+ "method": "btree",
+ "concurrently": false
+ },
+ "payouts_ws_date": {
+ "name": "payouts_ws_date",
+ "columns": [
+ {
+ "expression": "workspace_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "date",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "with": {},
+ "method": "btree",
+ "concurrently": false
+ }
+ },
+ "foreignKeys": {
+ "payouts_workspace_id_workspaces_id_fk": {
+ "name": "payouts_workspace_id_workspaces_id_fk",
+ "tableFrom": "payouts",
+ "columnsFrom": [
+ "workspace_id"
+ ],
+ "tableTo": "workspaces",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "cascade"
+ },
+ "payouts_connection_id_connections_id_fk": {
+ "name": "payouts_connection_id_connections_id_fk",
+ "tableFrom": "payouts",
+ "columnsFrom": [
+ "connection_id"
+ ],
+ "tableTo": "connections",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "cascade"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.product_mappings": {
+ "name": "product_mappings",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "connection_id": {
+ "name": "connection_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "sub_unit_id": {
+ "name": "sub_unit_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "sub_unit_label": {
+ "name": "sub_unit_label",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "product_id": {
+ "name": "product_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "mappings_conn_unit": {
+ "name": "mappings_conn_unit",
+ "columns": [
+ {
+ "expression": "connection_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "sub_unit_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "with": {},
+ "method": "btree",
+ "concurrently": false
+ }
+ },
+ "foreignKeys": {
+ "product_mappings_workspace_id_workspaces_id_fk": {
+ "name": "product_mappings_workspace_id_workspaces_id_fk",
+ "tableFrom": "product_mappings",
+ "columnsFrom": [
+ "workspace_id"
+ ],
+ "tableTo": "workspaces",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "cascade"
+ },
+ "product_mappings_connection_id_connections_id_fk": {
+ "name": "product_mappings_connection_id_connections_id_fk",
+ "tableFrom": "product_mappings",
+ "columnsFrom": [
+ "connection_id"
+ ],
+ "tableTo": "connections",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "cascade"
+ },
+ "product_mappings_product_id_products_id_fk": {
+ "name": "product_mappings_product_id_products_id_fk",
+ "tableFrom": "product_mappings",
+ "columnsFrom": [
+ "product_id"
+ ],
+ "tableTo": "products",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "cascade"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.products": {
+ "name": "products",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "slug": {
+ "name": "slug",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "public_page": {
+ "name": "public_page",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'off'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "(extract(epoch from now()) * 1000)::bigint"
+ }
+ },
+ "indexes": {
+ "products_ws_slug": {
+ "name": "products_ws_slug",
+ "columns": [
+ {
+ "expression": "workspace_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "slug",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "with": {},
+ "method": "btree",
+ "concurrently": false
+ }
+ },
+ "foreignKeys": {
+ "products_workspace_id_workspaces_id_fk": {
+ "name": "products_workspace_id_workspaces_id_fk",
+ "tableFrom": "products",
+ "columnsFrom": [
+ "workspace_id"
+ ],
+ "tableTo": "workspaces",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "cascade"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.revenue_lines": {
+ "name": "revenue_lines",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "connection_id": {
+ "name": "connection_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "product_id": {
+ "name": "product_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "date": {
+ "name": "date",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "currency": {
+ "name": "currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "gross_cents": {
+ "name": "gross_cents",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "fees_cents": {
+ "name": "fees_cents",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "refunds_cents": {
+ "name": "refunds_cents",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "net_cents": {
+ "name": "net_cents",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "net_base_cents": {
+ "name": "net_base_cents",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "tax_cents": {
+ "name": "tax_cents",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "tax_base_cents": {
+ "name": "tax_base_cents",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "gross_base_cents": {
+ "name": "gross_base_cents",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "fees_base_cents": {
+ "name": "fees_base_cents",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "refunds_base_cents": {
+ "name": "refunds_base_cents",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "service_start": {
+ "name": "service_start",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "service_end": {
+ "name": "service_end",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "kind": {
+ "name": "kind",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'other'"
+ },
+ "sub_unit_id": {
+ "name": "sub_unit_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "sub_unit_label": {
+ "name": "sub_unit_label",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "external_id": {
+ "name": "external_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "(extract(epoch from now()) * 1000)::bigint"
+ }
+ },
+ "indexes": {
+ "revenue_conn_ext": {
+ "name": "revenue_conn_ext",
+ "columns": [
+ {
+ "expression": "connection_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "external_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": true,
+ "with": {},
+ "method": "btree",
+ "concurrently": false
+ },
+ "revenue_ws_date": {
+ "name": "revenue_ws_date",
+ "columns": [
+ {
+ "expression": "workspace_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "date",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "with": {},
+ "method": "btree",
+ "concurrently": false
+ }
+ },
+ "foreignKeys": {
+ "revenue_lines_workspace_id_workspaces_id_fk": {
+ "name": "revenue_lines_workspace_id_workspaces_id_fk",
+ "tableFrom": "revenue_lines",
+ "columnsFrom": [
+ "workspace_id"
+ ],
+ "tableTo": "workspaces",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "cascade"
+ },
+ "revenue_lines_connection_id_connections_id_fk": {
+ "name": "revenue_lines_connection_id_connections_id_fk",
+ "tableFrom": "revenue_lines",
+ "columnsFrom": [
+ "connection_id"
+ ],
+ "tableTo": "connections",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "cascade"
+ },
+ "revenue_lines_product_id_products_id_fk": {
+ "name": "revenue_lines_product_id_products_id_fk",
+ "tableFrom": "revenue_lines",
+ "columnsFrom": [
+ "product_id"
+ ],
+ "tableTo": "products",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "set null"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.sync_runs": {
+ "name": "sync_runs",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "connection_id": {
+ "name": "connection_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "started_at": {
+ "name": "started_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "finished_at": {
+ "name": "finished_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "status": {
+ "name": "status",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "lines_written": {
+ "name": "lines_written",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "error": {
+ "name": "error",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "sync_runs_connection_id_connections_id_fk": {
+ "name": "sync_runs_connection_id_connections_id_fk",
+ "tableFrom": "sync_runs",
+ "columnsFrom": [
+ "connection_id"
+ ],
+ "tableTo": "connections",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "cascade"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.telemetry_pings": {
+ "name": "telemetry_pings",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "instance": {
+ "name": "instance",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "version": {
+ "name": "version",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "payload": {
+ "name": "payload",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "seen_at": {
+ "name": "seen_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.workspace_members": {
+ "name": "workspace_members",
+ "schema": "",
+ "columns": {
+ "workspace_id": {
+ "name": "workspace_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "role": {
+ "name": "role",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'owner'"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "(extract(epoch from now()) * 1000)::bigint"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {
+ "workspace_members_workspace_id_workspaces_id_fk": {
+ "name": "workspace_members_workspace_id_workspaces_id_fk",
+ "tableFrom": "workspace_members",
+ "columnsFrom": [
+ "workspace_id"
+ ],
+ "tableTo": "workspaces",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "cascade"
+ }
+ },
+ "compositePrimaryKeys": {
+ "workspace_members_workspace_id_user_id_pk": {
+ "name": "workspace_members_workspace_id_user_id_pk",
+ "columns": [
+ "workspace_id",
+ "user_id"
+ ]
+ }
+ },
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.workspaces": {
+ "name": "workspaces",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "slug": {
+ "name": "slug",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "base_currency": {
+ "name": "base_currency",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'USD'"
+ },
+ "plan": {
+ "name": "plan",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'free'"
+ },
+ "weekly_email": {
+ "name": "weekly_email",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "weekly_day": {
+ "name": "weekly_day",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 1
+ },
+ "weekly_hour": {
+ "name": "weekly_hour",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 9
+ },
+ "timezone": {
+ "name": "timezone",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'UTC'"
+ },
+ "weekly_sent_at": {
+ "name": "weekly_sent_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "telemetry": {
+ "name": "telemetry",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "benchmarks": {
+ "name": "benchmarks",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "demo": {
+ "name": "demo",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "incorporated_on": {
+ "name": "incorporated_on",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "country": {
+ "name": "country",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "region": {
+ "name": "region",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "book_accounts": {
+ "name": "book_accounts",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "bigint",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "(extract(epoch from now()) * 1000)::bigint"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "workspaces_slug_unique": {
+ "name": "workspaces_slug_unique",
+ "columns": [
+ "slug"
+ ],
+ "nullsNotDistinct": false
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.account": {
+ "name": "account",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "account_id": {
+ "name": "account_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "provider_id": {
+ "name": "provider_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "access_token": {
+ "name": "access_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "refresh_token": {
+ "name": "refresh_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "id_token": {
+ "name": "id_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "access_token_expires_at": {
+ "name": "access_token_expires_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "refresh_token_expires_at": {
+ "name": "refresh_token_expires_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "scope": {
+ "name": "scope",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "password": {
+ "name": "password",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "account_userId_idx": {
+ "name": "account_userId_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "with": {},
+ "method": "btree",
+ "concurrently": false
+ }
+ },
+ "foreignKeys": {
+ "account_user_id_user_id_fk": {
+ "name": "account_user_id_user_id_fk",
+ "tableFrom": "account",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "tableTo": "user",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "cascade"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.session": {
+ "name": "session",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "token": {
+ "name": "token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "ip_address": {
+ "name": "ip_address",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "user_agent": {
+ "name": "user_agent",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "session_userId_idx": {
+ "name": "session_userId_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "with": {},
+ "method": "btree",
+ "concurrently": false
+ }
+ },
+ "foreignKeys": {
+ "session_user_id_user_id_fk": {
+ "name": "session_user_id_user_id_fk",
+ "tableFrom": "session",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "tableTo": "user",
+ "columnsTo": [
+ "id"
+ ],
+ "onUpdate": "no action",
+ "onDelete": "cascade"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "session_token_unique": {
+ "name": "session_token_unique",
+ "columns": [
+ "token"
+ ],
+ "nullsNotDistinct": false
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.user": {
+ "name": "user",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "email": {
+ "name": "email",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "email_verified": {
+ "name": "email_verified",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "image": {
+ "name": "image",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "analytics": {
+ "name": "analytics",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "user_email_unique": {
+ "name": "user_email_unique",
+ "columns": [
+ "email"
+ ],
+ "nullsNotDistinct": false
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.verification": {
+ "name": "verification",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "identifier": {
+ "name": "identifier",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "value": {
+ "name": "value",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "verification_identifier_idx": {
+ "name": "verification_identifier_idx",
+ "columns": [
+ {
+ "expression": "identifier",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "with": {},
+ "method": "btree",
+ "concurrently": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ }
+ },
+ "enums": {},
+ "schemas": {},
+ "views": {},
+ "sequences": {},
+ "roles": {},
+ "policies": {},
+ "_meta": {
+ "columns": {},
+ "schemas": {},
+ "tables": {}
+ }
+}
\ No newline at end of file
diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json
index 306761c..3702eba 100644
--- a/drizzle/meta/_journal.json
+++ b/drizzle/meta/_journal.json
@@ -85,6 +85,13 @@
"when": 1791431020772,
"tag": "0011_boc_rates",
"breakpoints": true
+ },
+ {
+ "idx": 12,
+ "version": "7",
+ "when": 1792459991866,
+ "tag": "0012_books_resync",
+ "breakpoints": true
}
]
}
\ No newline at end of file
diff --git a/package.json b/package.json
index d5d2953..cf17890 100644
--- a/package.json
+++ b/package.json
@@ -5,18 +5,22 @@
"imports": {
"#/*": "./src/*"
},
+ "workspaces": [
+ "packages/*"
+ ],
"scripts": {
- "dev": "vite dev --port 3000",
+ "dev": "bun --bun vite dev --port 3000",
"generate-routes": "tsr generate",
- "build": "vite build",
- "preview": "vite preview",
+ "build": "bun --bun vite build",
+ "preview": "bun --bun vite preview",
"format": "biome format",
"lint": "biome lint",
"check": "biome check",
- "start": "node .output/server/index.mjs",
- "db:seed": "tsx --env-file=.env scripts/seed.ts",
- "benchmarks": "tsx --env-file=.env scripts/benchmarks.ts",
- "db:generate": "drizzle-kit generate"
+ "start": "bun .output/server/index.mjs",
+ "db:seed": "bun scripts/seed.ts",
+ "benchmarks": "bun scripts/benchmarks.ts",
+ "db:generate": "bun --bun drizzle-kit generate",
+ "postinstall": "ln -sf ../@tanstack/intent/dist/cli.mjs node_modules/.bin/intent"
},
"dependencies": {
"@base-ui/react": "^1.8.0",
@@ -69,11 +73,10 @@
"@types/react-dom": "^19.2.0",
"@vitejs/plugin-react": "^6.0.1",
"drizzle-kit": "^0.31.11",
- "tsx": "^4.23.15",
"typescript": "^6.0.2",
"vite": "^8.0.0"
},
- "packageManager": "pnpm@11.1.3",
+ "packageManager": "bun@1.4.4",
"version": "0.1.0",
"intent": {
"skills": [
diff --git a/packages/cli/package.json b/packages/cli/package.json
index bd34091..a444af4 100644
--- a/packages/cli/package.json
+++ b/packages/cli/package.json
@@ -6,7 +6,7 @@
"homepage": "https://openprofit.dev",
"repository": {
"type": "git",
- "url": "git+https://github.com/lobbystack/openprofit.git",
+ "url": "git+https://github.com/morencyr/openprofit.git",
"directory": "packages/cli"
},
"type": "module",
@@ -19,7 +19,7 @@
},
"scripts": {
"build": "tsc -p .",
- "test": "node --test",
+ "test": "bun test",
"prepack": "tsc -p ."
},
"dependencies": {
diff --git a/packages/cli/test/env.test.mjs b/packages/cli/test/env.test.mjs
index 7a564ba..ddfd7de 100644
--- a/packages/cli/test/env.test.mjs
+++ b/packages/cli/test/env.test.mjs
@@ -1,4 +1,4 @@
-// Run with `pnpm build && pnpm test` in packages/cli.
+// Run with `bun run build && bun run test` in packages/cli.
import assert from "node:assert/strict";
import { test } from "node:test";
import { parseEnv } from "../dist/lib.js";
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
deleted file mode 100644
index d89501b..0000000
--- a/pnpm-lock.yaml
+++ /dev/null
@@ -1,5691 +0,0 @@
-lockfileVersion: '9.0'
-
-settings:
- autoInstallPeers: true
- excludeLinksFromLockfile: false
-
-importers:
-
- .:
- dependencies:
- '@base-ui/react':
- specifier: ^1.8.0
- version: 1.8.0(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
- '@better-auth/drizzle-adapter':
- specifier: ^1.7.7
- version: 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.4))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.3(@electric-sql/pglite@0.5.8)(@opentelemetry/api@1.9.1)(@types/pg@8.23.1)(kysely@0.29.6)(pg@8.23.1))
- '@electric-sql/pglite':
- specifier: ^0.5.8
- version: 0.5.8
- '@fontsource-variable/geist':
- specifier: ^5.3.0
- version: 5.3.0
- '@modelcontextprotocol/server':
- specifier: ^2.3.1
- version: 2.3.1
- '@opentelemetry/api':
- specifier: ^1.9.1
- version: 1.9.1
- '@opentelemetry/api-logs':
- specifier: ^0.222.0
- version: 0.222.0
- '@opentelemetry/exporter-logs-otlp-http':
- specifier: ^0.222.0
- version: 0.222.0(@opentelemetry/api@1.9.1)
- '@opentelemetry/exporter-trace-otlp-http':
- specifier: ^0.222.0
- version: 0.222.0(@opentelemetry/api@1.9.1)
- '@opentelemetry/resources':
- specifier: ^2.11.0
- version: 2.11.0(@opentelemetry/api@1.9.1)
- '@opentelemetry/sdk-logs':
- specifier: ^0.222.0
- version: 0.222.0(@opentelemetry/api@1.9.1)
- '@opentelemetry/sdk-trace-base':
- specifier: ^2.11.0
- version: 2.11.0(@opentelemetry/api@1.9.1)
- '@resvg/resvg-wasm':
- specifier: 2.6.2
- version: 2.6.2
- '@tailwindcss/vite':
- specifier: ^4.1.18
- version: 4.3.3(vite@8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))
- '@tanstack/react-devtools':
- specifier: 0.10.13
- version: 0.10.13(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(csstype@3.2.3)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(solid-js@1.9.15)
- '@tanstack/react-router':
- specifier: 1.170.41
- version: 1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
- '@tanstack/react-router-devtools':
- specifier: 1.167.2
- version: 1.167.2(@tanstack/react-router@1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(@tanstack/router-core@1.171.34)(csstype@3.2.3)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
- '@tanstack/react-start':
- specifier: 1.168.60
- version: 1.168.60(crossws@0.4.12(srvx@0.11.22))(esbuild@0.28.2)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(rolldown@1.2.12)(vite@8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))
- better-auth:
- specifier: ^1.7.7
- version: 1.7.7(@opentelemetry/api@1.9.1)(@tanstack/react-start@1.168.60(crossws@0.4.12(srvx@0.11.22))(esbuild@0.28.2)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(rolldown@1.2.12)(vite@8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)))(drizzle-kit@0.31.11)(drizzle-orm@0.45.3(@electric-sql/pglite@0.5.8)(@opentelemetry/api@1.9.1)(@types/pg@8.23.1)(kysely@0.29.6)(pg@8.23.1))(pg@8.23.1)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(solid-js@1.9.15)
- class-variance-authority:
- specifier: ^0.7.1
- version: 0.7.1
- cmdk:
- specifier: ^1.1.1
- version: 1.1.1(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
- cn:
- specifier: ^0.4.0
- version: 0.4.0
- croner:
- specifier: ^10.0.1
- version: 10.0.1
- drizzle-orm:
- specifier: ^0.45.3
- version: 0.45.3(@electric-sql/pglite@0.5.8)(@opentelemetry/api@1.9.1)(@types/pg@8.23.1)(kysely@0.29.6)(pg@8.23.1)
- lucide-react:
- specifier: ^0.577.0
- version: 0.577.0(react@19.3.0)
- marked:
- specifier: ^18.0.14
- version: 18.0.14
- nitro:
- specifier: 3.0.260610-beta
- version: 3.0.260610-beta(@electric-sql/pglite@0.5.8)(chokidar@5.0.0)(drizzle-orm@0.45.3(@electric-sql/pglite@0.5.8)(@opentelemetry/api@1.9.1)(@types/pg@8.23.1)(kysely@0.29.6)(pg@8.23.1))(jiti@2.7.0)(vite@8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))
- pg:
- specifier: ^8.23.1
- version: 8.23.1
- posthog-js:
- specifier: ^1.436.1
- version: 1.436.1(@types/react@19.3.0)(react@19.3.0)
- posthog-node:
- specifier: ^5.55.0
- version: 5.55.0
- react:
- specifier: ^19.2.0
- version: 19.3.0
- react-dom:
- specifier: ^19.2.0
- version: 19.3.0(react@19.3.0)
- recharts:
- specifier: 3.8.0
- version: 3.8.0(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react-is@19.3.0)(react@19.3.0)(redux@5.0.1)
- simple-icons:
- specifier: ^16.34.0
- version: 16.34.0
- tailwindcss:
- specifier: ^4.1.18
- version: 4.3.3
- tw-animate-css:
- specifier: ^1.3.6
- version: 1.4.0
- zod:
- specifier: ^4.6.5
- version: 4.6.5
- devDependencies:
- '@biomejs/biome':
- specifier: 2.4.5
- version: 2.4.5
- '@tailwindcss/typography':
- specifier: ^0.5.16
- version: 0.5.20(tailwindcss@4.3.3)
- '@tanstack/devtools-vite':
- specifier: 0.8.5
- version: 0.8.5(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(vite@8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))
- '@tanstack/intent':
- specifier: ^0.5.4
- version: 0.5.4
- '@tanstack/router-cli':
- specifier: ^1.132.0
- version: 1.167.40
- '@types/node':
- specifier: ^22.10.2
- version: 22.20.5
- '@types/pg':
- specifier: ^8.23.1
- version: 8.23.1
- '@types/react':
- specifier: ^19.2.0
- version: 19.3.0
- '@types/react-dom':
- specifier: ^19.2.0
- version: 19.3.0(@types/react@19.3.0)
- '@vitejs/plugin-react':
- specifier: ^6.0.1
- version: 6.1.1(vite@8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))
- drizzle-kit:
- specifier: ^0.31.11
- version: 0.31.11
- tsx:
- specifier: ^4.23.15
- version: 4.23.15
- typescript:
- specifier: ^6.0.2
- version: 6.0.3
- vite:
- specifier: ^8.0.0
- version: 8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)
-
- packages/cli:
- dependencies:
- '@modelcontextprotocol/client':
- specifier: ^2.3.1
- version: 2.3.1
- '@modelcontextprotocol/server':
- specifier: ^2.3.1
- version: 2.3.1
- zod:
- specifier: ^4.6.5
- version: 4.6.5
- devDependencies:
- '@types/node':
- specifier: ^22.20.5
- version: 22.20.5
- typescript:
- specifier: ^6.0.3
- version: 6.0.3
-
-packages:
-
- '@babel/code-frame@7.29.7':
- resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/compat-data@7.29.7':
- resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==}
- engines: {node: '>=6.9.0'}
-
- '@babel/core@7.29.7':
- resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==}
- engines: {node: '>=6.9.0'}
-
- '@babel/generator@7.29.8':
- resolution: {integrity: sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-compilation-targets@7.29.7':
- resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-globals@7.29.7':
- resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-module-imports@7.29.7':
- resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-module-transforms@7.29.7':
- resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0
-
- '@babel/helper-string-parser@7.29.7':
- resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-validator-identifier@7.29.7':
- resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helper-validator-option@7.29.7':
- resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/helpers@7.29.7':
- resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==}
- engines: {node: '>=6.9.0'}
-
- '@babel/parser@7.29.9':
- resolution: {integrity: sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==}
- engines: {node: '>=6.0.0'}
- hasBin: true
-
- '@babel/runtime@7.29.7':
- resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==}
- engines: {node: '>=6.9.0'}
-
- '@babel/template@7.29.7':
- resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==}
- engines: {node: '>=6.9.0'}
-
- '@babel/traverse@7.29.8':
- resolution: {integrity: sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==}
- engines: {node: '>=6.9.0'}
-
- '@babel/types@7.29.8':
- resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==}
- engines: {node: '>=6.9.0'}
-
- '@base-ui/react@1.8.0':
- resolution: {integrity: sha512-P0/1sxo6SBVZOklKMIedvTWqw2s2IQzi9x5bIVsXu980cuSOD4NeuRSs+/L7LZQfDkZP/uRZyGPyfFl/B1oH+Q==}
- engines: {node: '>=14.0.0'}
- peerDependencies:
- '@date-fns/tz': ^1.2.0
- '@types/react': ^17 || ^18 || ^19
- date-fns: ^4.0.0
- react: ^17 || ^18 || ^19
- react-dom: ^17 || ^18 || ^19
- peerDependenciesMeta:
- '@date-fns/tz':
- optional: true
- '@types/react':
- optional: true
- date-fns:
- optional: true
-
- '@base-ui/utils@0.4.0':
- resolution: {integrity: sha512-bO9fz25kKtPf+aZVyfQrC0PDmJdmVni31W2hCS5/Owb+inwdIL3XU26pCPRPlt4LSxZrBgLwubXQXQlKaFEZzw==}
- peerDependencies:
- '@types/react': ^17 || ^18 || ^19
- react: ^17 || ^18 || ^19
- react-dom: ^17 || ^18 || ^19
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
- '@better-auth/core@1.7.7':
- resolution: {integrity: sha512-srgFzHEjB2WWlokFz1i4BfG41sNhsA105Pukgqu6RrEh5A+LSkzf1mCHydVipkjt9l5qswtBMi7IL6ouHbZL4Q==}
- peerDependencies:
- '@better-auth/utils': 0.4.2
- '@better-fetch/fetch': 1.3.2
- '@opentelemetry/api': ^1.9.0
- better-call: 1.4.0
- jose: ^6.1.0
- kysely: ^0.28.5 || ^0.29.0
- nanostores: ^1.0.1
- peerDependenciesMeta:
- '@opentelemetry/api':
- optional: true
-
- '@better-auth/drizzle-adapter@1.7.7':
- resolution: {integrity: sha512-qon0U94PR5FQysuyGoAlGVQpIIiNg5dtDpwjE63sN/HjoRWZadZzHPcS9mn7JsJyQZK6iTNhd7LD0AaXt2f78w==}
- peerDependencies:
- '@better-auth/core': ^1.7.7
- '@better-auth/utils': 0.4.2
- drizzle-orm: ^0.45.2 || >=1.0.0-rc.1 <2.0.0
- peerDependenciesMeta:
- drizzle-orm:
- optional: true
-
- '@better-auth/kysely-adapter@1.7.7':
- resolution: {integrity: sha512-9FONOCgOcrQI9wJ5v1oDGIg9sT7pa9RjZZQ4fsCTudo8R87SrIGNUvUxDFTJhZvUblvFfGaIBR9Vb8LA+8bqLQ==}
- peerDependencies:
- '@better-auth/core': ^1.7.7
- '@better-auth/utils': 0.4.2
- kysely: ^0.28.17 || ^0.29.0
- peerDependenciesMeta:
- kysely:
- optional: true
-
- '@better-auth/memory-adapter@1.7.7':
- resolution: {integrity: sha512-FqKFEe+b5tXXV0gRbyirca+qXgMpLOeJ8Wk19yykb/scQKy0WJ4k22WzEV3TTPctQV9DZhwCXPlDtQhnlOv5Gg==}
- peerDependencies:
- '@better-auth/core': ^1.7.7
- '@better-auth/utils': 0.4.2
-
- '@better-auth/mongo-adapter@1.7.7':
- resolution: {integrity: sha512-ZnVDuRrXqbf0oHphrEN27oTImNH5NTO26dtWatq5cXyYAsH7goof9QIoTOmxTbBxUQahKBw9T6+9h6n+RtOE+g==}
- peerDependencies:
- '@better-auth/core': ^1.7.7
- '@better-auth/utils': 0.4.2
- mongodb: ^6.0.0 || ^7.0.0
- peerDependenciesMeta:
- mongodb:
- optional: true
-
- '@better-auth/prisma-adapter@1.7.7':
- resolution: {integrity: sha512-4YcnrcVdvWiAZw0sZl63tWUClPXg5r3QsLn7C2sG7kKEBY06zOng0ibecyxRBixKq1zE1ceHuEUqez5Rhi+nQA==}
- peerDependencies:
- '@better-auth/core': ^1.7.7
- '@better-auth/utils': 0.4.2
- '@prisma/client': ^5.0.0 || ^6.0.0 || ^7.0.0
- prisma: ^5.0.0 || ^6.0.0 || ^7.0.0
- peerDependenciesMeta:
- '@prisma/client':
- optional: true
- prisma:
- optional: true
-
- '@better-auth/telemetry@1.7.7':
- resolution: {integrity: sha512-PaRA6i+kAioVYmza2gHPcdrxP0hAotph4KV9hft2GeNJq+AZXDiBu3FuLM9HxvcmiZeUT74Vufqd9ypmB8veTA==}
- peerDependencies:
- '@better-auth/core': ^1.7.7
- '@better-auth/utils': 0.4.2
- '@better-fetch/fetch': 1.3.2
-
- '@better-auth/utils@0.4.2':
- resolution: {integrity: sha512-AUxrvu+HaaODsUyzDxFgwd/8RZ1yZaYo42LXKSrU2oGgR38pS1ij8nqQKNgtTWoYGpNevNXtCfgTy6loHveW9A==}
-
- '@better-auth/utils@0.5.0':
- resolution: {integrity: sha512-BL8W4EfIZFwlu0r54m3v1ztjDhu6dDe/amLTm0xybmbZaNgYUqhD3SjpAsnq0q8YD6/ki4iwIgxJNLP/N3TxiA==}
-
- '@better-fetch/fetch@1.3.2':
- resolution: {integrity: sha512-Gs7n99b5tqUC6cQAPbV0uED3IraHB6xQbHLQ/C3l7ZFafHScOx9pQ+DYmP5blbLFShVWLqxNUlI9wi4xU/X+ow==}
-
- '@biomejs/biome@2.4.5':
- resolution: {integrity: sha512-OWNCyMS0Q011R6YifXNOg6qsOg64IVc7XX6SqGsrGszPbkVCoaO7Sr/lISFnXZ9hjQhDewwZ40789QmrG0GYgQ==}
- engines: {node: '>=14.21.3'}
- hasBin: true
-
- '@biomejs/cli-darwin-arm64@2.4.5':
- resolution: {integrity: sha512-lGS4Nd5O3KQJ6TeWv10mElnx1phERhBxqGP/IKq0SvZl78kcWDFMaTtVK+w3v3lusRFxJY78n07PbKplirsU5g==}
- engines: {node: '>=14.21.3'}
- cpu: [arm64]
- os: [darwin]
-
- '@biomejs/cli-darwin-x64@2.4.5':
- resolution: {integrity: sha512-6MoH4tyISIBNkZ2Q5T1R7dLd5BsITb2yhhhrU9jHZxnNSNMWl+s2Mxu7NBF8Y3a7JJcqq9nsk8i637z4gqkJxQ==}
- engines: {node: '>=14.21.3'}
- cpu: [x64]
- os: [darwin]
-
- '@biomejs/cli-linux-arm64-musl@2.4.5':
- resolution: {integrity: sha512-iqLDgpzobG7gpBF0fwEVS/LT8kmN7+S0E2YKFDtqliJfzNLnAiV2Nnyb+ehCDCJgAZBASkYHR2o60VQWikpqIg==}
- engines: {node: '>=14.21.3'}
- cpu: [arm64]
- os: [linux]
- libc: [musl]
-
- '@biomejs/cli-linux-arm64@2.4.5':
- resolution: {integrity: sha512-U1GAG6FTjhAO04MyH4xn23wRNBkT6H7NentHh+8UxD6ShXKBm5SY4RedKJzkUThANxb9rUKIPc7B8ew9Xo/cWg==}
- engines: {node: '>=14.21.3'}
- cpu: [arm64]
- os: [linux]
- libc: [glibc]
-
- '@biomejs/cli-linux-x64-musl@2.4.5':
- resolution: {integrity: sha512-NlKa7GpbQmNhZf9kakQeddqZyT7itN7jjWdakELeXyTU3pg/83fTysRRDPJD0akTfKDl6vZYNT9Zqn4MYZVBOA==}
- engines: {node: '>=14.21.3'}
- cpu: [x64]
- os: [linux]
- libc: [musl]
-
- '@biomejs/cli-linux-x64@2.4.5':
- resolution: {integrity: sha512-NdODlSugMzTlENPTa4z0xB82dTUlCpsrOxc43///aNkTLblIYH4XpYflBbf5ySlQuP8AA4AZd1qXhV07IdrHdQ==}
- engines: {node: '>=14.21.3'}
- cpu: [x64]
- os: [linux]
- libc: [glibc]
-
- '@biomejs/cli-win32-arm64@2.4.5':
- resolution: {integrity: sha512-EBfrTqRIWOFSd7CQb/0ttjHMR88zm3hGravnDwUA9wHAaCAYsULKDebWcN5RmrEo1KBtl/gDVJMrFjNR0pdGUw==}
- engines: {node: '>=14.21.3'}
- cpu: [arm64]
- os: [win32]
-
- '@biomejs/cli-win32-x64@2.4.5':
- resolution: {integrity: sha512-Pmhv9zT95YzECfjEHNl3mN9Vhusw9VA5KHY0ZvlGsxsjwS5cb7vpRnHzJIv0vG7jB0JI7xEaMH9ddfZm/RozBw==}
- engines: {node: '>=14.21.3'}
- cpu: [x64]
- os: [win32]
-
- '@drizzle-team/brocli@0.10.2':
- resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==}
-
- '@electric-sql/pglite@0.5.8':
- resolution: {integrity: sha512-n9tsbUOhwx2epK1V0ZG9Ar4SHWUju04dhmzZXiSBXwBoleOvIfals33NAaWgagQVAL4Rbvx/Ptsu3P+pA09f6Q==}
-
- '@emnapi/core@1.11.3':
- resolution: {integrity: sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==}
-
- '@emnapi/runtime@1.11.3':
- resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==}
-
- '@emnapi/wasi-threads@1.2.3':
- resolution: {integrity: sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==}
-
- '@esbuild-kit/core-utils@3.3.2':
- resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==}
- 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.hirok.io'
-
- '@esbuild/aix-ppc64@0.25.12':
- resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==}
- engines: {node: '>=18'}
- cpu: [ppc64]
- os: [aix]
-
- '@esbuild/aix-ppc64@0.28.2':
- resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==}
- engines: {node: '>=18'}
- cpu: [ppc64]
- os: [aix]
-
- '@esbuild/android-arm64@0.18.20':
- resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [android]
-
- '@esbuild/android-arm64@0.25.12':
- resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [android]
-
- '@esbuild/android-arm64@0.28.2':
- resolution: {integrity: sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [android]
-
- '@esbuild/android-arm@0.18.20':
- resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==}
- engines: {node: '>=12'}
- cpu: [arm]
- os: [android]
-
- '@esbuild/android-arm@0.25.12':
- resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==}
- engines: {node: '>=18'}
- cpu: [arm]
- os: [android]
-
- '@esbuild/android-arm@0.28.2':
- resolution: {integrity: sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==}
- engines: {node: '>=18'}
- cpu: [arm]
- os: [android]
-
- '@esbuild/android-x64@0.18.20':
- resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [android]
-
- '@esbuild/android-x64@0.25.12':
- resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [android]
-
- '@esbuild/android-x64@0.28.2':
- resolution: {integrity: sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [android]
-
- '@esbuild/darwin-arm64@0.18.20':
- resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [darwin]
-
- '@esbuild/darwin-arm64@0.25.12':
- resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [darwin]
-
- '@esbuild/darwin-arm64@0.28.2':
- resolution: {integrity: sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [darwin]
-
- '@esbuild/darwin-x64@0.18.20':
- resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [darwin]
-
- '@esbuild/darwin-x64@0.25.12':
- resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [darwin]
-
- '@esbuild/darwin-x64@0.28.2':
- resolution: {integrity: sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [darwin]
-
- '@esbuild/freebsd-arm64@0.18.20':
- resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [freebsd]
-
- '@esbuild/freebsd-arm64@0.25.12':
- resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [freebsd]
-
- '@esbuild/freebsd-arm64@0.28.2':
- resolution: {integrity: sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [freebsd]
-
- '@esbuild/freebsd-x64@0.18.20':
- resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [freebsd]
-
- '@esbuild/freebsd-x64@0.25.12':
- resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [freebsd]
-
- '@esbuild/freebsd-x64@0.28.2':
- resolution: {integrity: sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [freebsd]
-
- '@esbuild/linux-arm64@0.18.20':
- resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [linux]
-
- '@esbuild/linux-arm64@0.25.12':
- resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [linux]
-
- '@esbuild/linux-arm64@0.28.2':
- resolution: {integrity: sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [linux]
-
- '@esbuild/linux-arm@0.18.20':
- resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==}
- engines: {node: '>=12'}
- cpu: [arm]
- os: [linux]
-
- '@esbuild/linux-arm@0.25.12':
- resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==}
- engines: {node: '>=18'}
- cpu: [arm]
- os: [linux]
-
- '@esbuild/linux-arm@0.28.2':
- resolution: {integrity: sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==}
- engines: {node: '>=18'}
- cpu: [arm]
- os: [linux]
-
- '@esbuild/linux-ia32@0.18.20':
- resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==}
- engines: {node: '>=12'}
- cpu: [ia32]
- os: [linux]
-
- '@esbuild/linux-ia32@0.25.12':
- resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==}
- engines: {node: '>=18'}
- cpu: [ia32]
- os: [linux]
-
- '@esbuild/linux-ia32@0.28.2':
- resolution: {integrity: sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==}
- engines: {node: '>=18'}
- cpu: [ia32]
- os: [linux]
-
- '@esbuild/linux-loong64@0.18.20':
- resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==}
- engines: {node: '>=12'}
- cpu: [loong64]
- os: [linux]
-
- '@esbuild/linux-loong64@0.25.12':
- resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==}
- engines: {node: '>=18'}
- cpu: [loong64]
- os: [linux]
-
- '@esbuild/linux-loong64@0.28.2':
- resolution: {integrity: sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==}
- engines: {node: '>=18'}
- cpu: [loong64]
- os: [linux]
-
- '@esbuild/linux-mips64el@0.18.20':
- resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==}
- engines: {node: '>=12'}
- cpu: [mips64el]
- os: [linux]
-
- '@esbuild/linux-mips64el@0.25.12':
- resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==}
- engines: {node: '>=18'}
- cpu: [mips64el]
- os: [linux]
-
- '@esbuild/linux-mips64el@0.28.2':
- resolution: {integrity: sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==}
- engines: {node: '>=18'}
- cpu: [mips64el]
- os: [linux]
-
- '@esbuild/linux-ppc64@0.18.20':
- resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==}
- engines: {node: '>=12'}
- cpu: [ppc64]
- os: [linux]
-
- '@esbuild/linux-ppc64@0.25.12':
- resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==}
- engines: {node: '>=18'}
- cpu: [ppc64]
- os: [linux]
-
- '@esbuild/linux-ppc64@0.28.2':
- resolution: {integrity: sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==}
- engines: {node: '>=18'}
- cpu: [ppc64]
- os: [linux]
-
- '@esbuild/linux-riscv64@0.18.20':
- resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==}
- engines: {node: '>=12'}
- cpu: [riscv64]
- os: [linux]
-
- '@esbuild/linux-riscv64@0.25.12':
- resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==}
- engines: {node: '>=18'}
- cpu: [riscv64]
- os: [linux]
-
- '@esbuild/linux-riscv64@0.28.2':
- resolution: {integrity: sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==}
- engines: {node: '>=18'}
- cpu: [riscv64]
- os: [linux]
-
- '@esbuild/linux-s390x@0.18.20':
- resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==}
- engines: {node: '>=12'}
- cpu: [s390x]
- os: [linux]
-
- '@esbuild/linux-s390x@0.25.12':
- resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==}
- engines: {node: '>=18'}
- cpu: [s390x]
- os: [linux]
-
- '@esbuild/linux-s390x@0.28.2':
- resolution: {integrity: sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==}
- engines: {node: '>=18'}
- cpu: [s390x]
- os: [linux]
-
- '@esbuild/linux-x64@0.18.20':
- resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [linux]
-
- '@esbuild/linux-x64@0.25.12':
- resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [linux]
-
- '@esbuild/linux-x64@0.28.2':
- resolution: {integrity: sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [linux]
-
- '@esbuild/netbsd-arm64@0.25.12':
- resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [netbsd]
-
- '@esbuild/netbsd-arm64@0.28.2':
- resolution: {integrity: sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [netbsd]
-
- '@esbuild/netbsd-x64@0.18.20':
- resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [netbsd]
-
- '@esbuild/netbsd-x64@0.25.12':
- resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [netbsd]
-
- '@esbuild/netbsd-x64@0.28.2':
- resolution: {integrity: sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [netbsd]
-
- '@esbuild/openbsd-arm64@0.25.12':
- resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [openbsd]
-
- '@esbuild/openbsd-arm64@0.28.2':
- resolution: {integrity: sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [openbsd]
-
- '@esbuild/openbsd-x64@0.18.20':
- resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [openbsd]
-
- '@esbuild/openbsd-x64@0.25.12':
- resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [openbsd]
-
- '@esbuild/openbsd-x64@0.28.2':
- resolution: {integrity: sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [openbsd]
-
- '@esbuild/openharmony-arm64@0.25.12':
- resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [openharmony]
-
- '@esbuild/openharmony-arm64@0.28.2':
- resolution: {integrity: sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [openharmony]
-
- '@esbuild/sunos-x64@0.18.20':
- resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [sunos]
-
- '@esbuild/sunos-x64@0.25.12':
- resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [sunos]
-
- '@esbuild/sunos-x64@0.28.2':
- resolution: {integrity: sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [sunos]
-
- '@esbuild/win32-arm64@0.18.20':
- resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [win32]
-
- '@esbuild/win32-arm64@0.25.12':
- resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [win32]
-
- '@esbuild/win32-arm64@0.28.2':
- resolution: {integrity: sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==}
- engines: {node: '>=18'}
- cpu: [arm64]
- os: [win32]
-
- '@esbuild/win32-ia32@0.18.20':
- resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==}
- engines: {node: '>=12'}
- cpu: [ia32]
- os: [win32]
-
- '@esbuild/win32-ia32@0.25.12':
- resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==}
- engines: {node: '>=18'}
- cpu: [ia32]
- os: [win32]
-
- '@esbuild/win32-ia32@0.28.2':
- resolution: {integrity: sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==}
- engines: {node: '>=18'}
- cpu: [ia32]
- os: [win32]
-
- '@esbuild/win32-x64@0.18.20':
- resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [win32]
-
- '@esbuild/win32-x64@0.25.12':
- resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [win32]
-
- '@esbuild/win32-x64@0.28.2':
- resolution: {integrity: sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==}
- engines: {node: '>=18'}
- cpu: [x64]
- os: [win32]
-
- '@floating-ui/core@1.8.0':
- resolution: {integrity: sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==}
-
- '@floating-ui/dom@1.8.0':
- resolution: {integrity: sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==}
-
- '@floating-ui/react-dom@2.1.9':
- resolution: {integrity: sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==}
- peerDependencies:
- react: '>=16.8.0'
- react-dom: '>=16.8.0'
-
- '@floating-ui/utils@0.2.12':
- resolution: {integrity: sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==}
-
- '@fontsource-variable/geist@5.3.0':
- resolution: {integrity: sha512-j0m+vLQuG5XAYoHtGCVu0spvlGreR3EzpECUVzkFmI1mTVnAO38l/NEPDCFgZ177JxzYJCLSmTQibIiYPilGrA==}
-
- '@jridgewell/gen-mapping@0.3.13':
- resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
-
- '@jridgewell/remapping@2.3.5':
- resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
-
- '@jridgewell/resolve-uri@3.1.2':
- resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
- engines: {node: '>=6.0.0'}
-
- '@jridgewell/sourcemap-codec@1.6.0':
- resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==}
-
- '@jridgewell/trace-mapping@0.3.31':
- resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
-
- '@modelcontextprotocol/client@2.3.1':
- resolution: {integrity: sha512-mIGZXpHsjnZ6lD+gD/WCMpR5k8yVQQ8nNFH1N0Srf7AvnwTUMYD6pvTY8ng2+He5FfV7YMZLmrjL7cLa/cc3dQ==}
- engines: {node: '>=20'}
-
- '@modelcontextprotocol/core@2.3.1':
- resolution: {integrity: sha512-laVmIhPGpWi7rG9q+0UigblRN0Hws/Yjlb6qLFtVqryXVLkc4h+yN8z731POD2LnAGQlFe7/tXhUm7Bi0YB91g==}
- engines: {node: '>=20'}
-
- '@modelcontextprotocol/server@2.3.1':
- resolution: {integrity: sha512-e59MfWuSssj6DoQ96JCTqdW1AXT5/XtnTl0WWd6MU1Ka434fFUGGosCLJbGNySDhHGvxQWoRWK137FXYFkYNWw==}
- engines: {node: '>=20'}
-
- '@napi-rs/wasm-runtime@1.2.4':
- resolution: {integrity: sha512-AJxoUD2/15ESHbvpcyjU274nsAPLuOtPHCk0vKJM5pj//Fg/B1FXNWjPnXTT9PymCYYiHo4zPj0ZomXBKhoy7g==}
- engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0}
- peerDependencies:
- '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.4
- '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.4
-
- '@neodrag/core@3.0.0-next.11':
- resolution: {integrity: sha512-3WQWxyrbxiaK9zS5JU2wJsW2gpoQlZBXVghduBh61JpqaeE0T0cte8R0qYK2RuJo3J2TYQYqxO19CpG/C1i5eg==}
-
- '@neodrag/solid@3.0.0-next.11':
- resolution: {integrity: sha512-vCBIn/pimjWMQ6vhTS2/O1XNAwzVtc4eUhdbQ91WykbZWWqQ5NocDXt/1OdYrEkeRzJcpCv8wEz5PnMkgKP81Q==}
- peerDependencies:
- '@neodrag/core': 3.0.0-next.11
- solid-js: ^1.0.0
-
- '@noble/ciphers@2.4.0':
- resolution: {integrity: sha512-AnjFn0Jv92laAkvMrghlFZq4qQCIN/4DxFV/eooqtC2YTjB7kBeLMS2T9KJX4Dn+ZVXLOwK0lSgqDtx9gvxtiw==}
- engines: {node: '>= 20.19.0'}
-
- '@noble/hashes@2.4.0':
- resolution: {integrity: sha512-X5XaVWZIBCT7HHZGm5I7ZQXDwLG+bGXuSrMQAW+7Zvl87h1kmc1ZB1VSRJcpUfoUrGQp4Fkoxm5kZ+Ms+aW+eA==}
- engines: {node: '>= 20.19.0'}
-
- '@oozcitak/dom@2.0.2':
- resolution: {integrity: sha512-GjpKhkSYC3Mj4+lfwEyI1dqnsKTgwGy48ytZEhm4A/xnH/8z9M3ZVXKr/YGQi3uCLs1AEBS+x5T2JPiueEDW8w==}
- engines: {node: '>=20.0'}
-
- '@oozcitak/infra@2.0.2':
- resolution: {integrity: sha512-2g+E7hoE2dgCz/APPOEK5s3rMhJvNxSMBrP+U+j1OWsIbtSpWxxlUjq1lU8RIsFJNYv7NMlnVsCuHcUzJW+8vA==}
- engines: {node: '>=20.0'}
-
- '@oozcitak/url@3.0.0':
- resolution: {integrity: sha512-ZKfET8Ak1wsLAiLWNfFkZc/BraDccuTJKR6svTYc7sVjbR+Iu0vtXdiDMY4o6jaFl5TW2TlS7jbLl4VovtAJWQ==}
- engines: {node: '>=20.0'}
-
- '@oozcitak/util@10.0.0':
- resolution: {integrity: sha512-hAX0pT/73190NLqBPPWSdBVGtbY6VOhWYK3qqHqtXQ1gK7kS2yz4+ivsN07hpJ6I3aeMtKP6J6npsEKOAzuTLA==}
- engines: {node: '>=20.0'}
-
- '@opentelemetry/api-logs@0.222.0':
- resolution: {integrity: sha512-9mb1If+IF6u0ZVXkHQ6ogEae5HwA6ajIVUgpSDQyRASxft6BSXHvBvPooRle3yFN/fKnCdSOnuu0OC3PLcF6+g==}
- engines: {node: '>=8.0.0'}
-
- '@opentelemetry/api@1.9.1':
- resolution: {integrity: sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==}
- engines: {node: '>=8.0.0'}
-
- '@opentelemetry/core@2.11.0':
- resolution: {integrity: sha512-7YP44XH0tV6+Mb54x2YGf84i7yi+31MBZlE8JwvozkxyTvXbSp10X7cI7YE49ChJ3shMJoBmCJF3+1QFBJctGA==}
- engines: {node: ^18.19.0 || >=20.6.0}
- peerDependencies:
- '@opentelemetry/api': '>=1.0.0 <1.10.0'
-
- '@opentelemetry/exporter-logs-otlp-http@0.222.0':
- resolution: {integrity: sha512-GqwLZohJTf/sttYlOpT1oFTJ9ScYaKnk0sOx4Qe/+KmXYVOa+v94cfnkUkFKDuvTODWhCL50Hz3gvsZD6ngQpg==}
- engines: {node: ^18.19.0 || >=20.6.0}
- peerDependencies:
- '@opentelemetry/api': ^1.3.0
-
- '@opentelemetry/exporter-trace-otlp-http@0.222.0':
- resolution: {integrity: sha512-RCnPWcHppwiquQ+cV3nWvNwdf0MG1w26e5jewW2T83nTZOlXgcg88sY9ulCVgagGHcq1mj0L0GP6YHgzk2v8oA==}
- engines: {node: ^18.19.0 || >=20.6.0}
- peerDependencies:
- '@opentelemetry/api': ^1.3.0
-
- '@opentelemetry/otlp-exporter-base@0.222.0':
- resolution: {integrity: sha512-YbywG3veEm2Fb6TbdxRkuquWob6eVWXuA8/Ba1tXz9jHfUqpdE3keilOHEtPboC4CvS1bjeeVfNkWGOOrLj+lw==}
- engines: {node: ^18.19.0 || >=20.6.0}
- peerDependencies:
- '@opentelemetry/api': ^1.3.0
-
- '@opentelemetry/otlp-transformer@0.222.0':
- resolution: {integrity: sha512-/F3BZ89+CJQnZkMh2tCrtcdB+XT2Dxhj4FFE+WPQ//413hmFL0/RfEX6vgOIWGhiSzrkHWTK3+6SiT7K5/g/jQ==}
- engines: {node: ^18.19.0 || >=20.6.0}
- peerDependencies:
- '@opentelemetry/api': ^1.3.0
-
- '@opentelemetry/resources@2.11.0':
- resolution: {integrity: sha512-Ie7+8q8MDF4FAEQCKVMTx3ReUvxiIAgIiiW3c9JdmP8+HMcDy20puT+AHjexnExgnbvBxjQ9fjkFDWrikJ2jQA==}
- engines: {node: ^18.19.0 || >=20.6.0}
- peerDependencies:
- '@opentelemetry/api': '>=1.3.0 <1.10.0'
-
- '@opentelemetry/sdk-logs@0.222.0':
- resolution: {integrity: sha512-+19YHODIjaUCArxleaJtuufFZVpz/xvvK+VllQqE+W8hHolxdoRwHfK/s667zezwh1hkx6FFF+oYzetYgqK+Bg==}
- engines: {node: ^18.19.0 || >=20.6.0}
- peerDependencies:
- '@opentelemetry/api': '>=1.4.0 <1.10.0'
-
- '@opentelemetry/sdk-metrics@2.11.0':
- resolution: {integrity: sha512-7GXXcObyHyDUUSG+L+kJoquty01bzm7ivE7+SSgXXJcHuPzGviptxwARmI2c+bnnxjexGQbJnyNlN8HxBP/Y7A==}
- engines: {node: ^18.19.0 || >=20.6.0}
- peerDependencies:
- '@opentelemetry/api': '>=1.9.0 <1.10.0'
-
- '@opentelemetry/sdk-trace-base@2.11.0':
- resolution: {integrity: sha512-H19x/TX/LZdqiYOjM7fqtSxwlplC5pgelavqbQdHbhdq0q/AI/TGkM2dfGuuynTXmJPeF2HoZVoPDu+TGoW78A==}
- engines: {node: ^18.19.0 || >=20.6.0}
- peerDependencies:
- '@opentelemetry/api': '>=1.3.0 <1.10.0'
-
- '@opentelemetry/sdk-trace@2.11.0':
- resolution: {integrity: sha512-fFnTqGm8/G73GQVnxYi7LXa1ZVYEUvgL6XI1LpvV0bPC7WQ/ZGgKxCSl8FnlZBKto9JHHEFTO6s6CUpvvtwFrA==}
- engines: {node: ^18.19.0 || >=20.6.0}
- peerDependencies:
- '@opentelemetry/api': '>=1.3.0 <1.10.0'
-
- '@opentelemetry/semantic-conventions@1.43.0':
- resolution: {integrity: sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==}
- engines: {node: '>=14'}
-
- '@oxc-parser/binding-android-arm-eabi@0.120.0':
- resolution: {integrity: sha512-WU3qtINx802wOl8RxAF1v0VvmC2O4D9M8Sv486nLeQ7iPHVmncYZrtBhB4SYyX+XZxj2PNnCcN+PW21jHgiOxg==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm]
- os: [android]
-
- '@oxc-parser/binding-android-arm64@0.120.0':
- resolution: {integrity: sha512-SEf80EHdhlbjZEgzeWm0ZA/br4GKMenDW3QB/gtyeTV1gStvvZeFi40ioHDZvds2m4Z9J1bUAUL8yn1/+A6iGg==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [android]
-
- '@oxc-parser/binding-darwin-arm64@0.120.0':
- resolution: {integrity: sha512-xVrrbCai8R8CUIBu3CjryutQnEYhZqs1maIqDvtUCFZb8vY33H7uh9mHpL3a0JBIKoBUKjPH8+rzyAeXnS2d6A==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [darwin]
-
- '@oxc-parser/binding-darwin-x64@0.120.0':
- resolution: {integrity: sha512-xyHBbnJ6mydnQUH7MAcafOkkrNzQC6T+LXgDH/3InEq2BWl/g424IMRiJVSpVqGjB+p2bd0h0WRR8iIwzjU7rw==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [x64]
- os: [darwin]
-
- '@oxc-parser/binding-freebsd-x64@0.120.0':
- resolution: {integrity: sha512-UMnVRllquXUYTeNfFKmxTTEdZ/ix1nLl0ducDzMSREoWYGVIHnOOxoKMWlCOvRr9Wk/HZqo2rh1jeumbPGPV9A==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [x64]
- os: [freebsd]
-
- '@oxc-parser/binding-linux-arm-gnueabihf@0.120.0':
- resolution: {integrity: sha512-tkvn2CQ7QdcsMnpfiX3fd3wA3EFsWKYlcQzq9cFw/xc89Al7W6Y4O0FgLVkVQpo0Tnq/qtE1XfkJOnRRA9S/NA==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm]
- os: [linux]
-
- '@oxc-parser/binding-linux-arm-musleabihf@0.120.0':
- resolution: {integrity: sha512-WN5y135Ic42gQDk9grbwY9++fDhqf8knN6fnP+0WALlAUh4odY/BDK1nfTJRSfpJD9P3r1BwU0m3pW2DU89whQ==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm]
- os: [linux]
-
- '@oxc-parser/binding-linux-arm64-gnu@0.120.0':
- resolution: {integrity: sha512-1GgQBCcXvFMw99EPdMy+4NZ3aYyXsxjf9kbUUg8HuAy3ZBXzOry5KfFEzT9nqmgZI1cuetvApkiJBZLAPo8uaw==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [linux]
- libc: [glibc]
-
- '@oxc-parser/binding-linux-arm64-musl@0.120.0':
- resolution: {integrity: sha512-gmMQ70gsPdDBgpcErvJEoWNBr7bJooSLlvOBVBSGfOzlP5NvJ3bFvnUeZZ9d+dPrqSngtonf7nyzWUTUj/U+lw==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [linux]
- libc: [musl]
-
- '@oxc-parser/binding-linux-ppc64-gnu@0.120.0':
- resolution: {integrity: sha512-T/kZuU0ajop0xhzVMwH5r3srC9Nqup5HaIo+3uFjIN5uPxa0LvSxC1ZqP4aQGJVW5G0z8/nCkjIfSMS91P/wzw==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [ppc64]
- os: [linux]
- libc: [glibc]
-
- '@oxc-parser/binding-linux-riscv64-gnu@0.120.0':
- resolution: {integrity: sha512-vn21KXLAXzaI3N5CZWlBr1iWeXLl9QFIMor7S1hUjUGTeUuWCoE6JZB040/ZNDwf+JXPX8Ao9KbmJq9FMC2iGw==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [riscv64]
- os: [linux]
- libc: [glibc]
-
- '@oxc-parser/binding-linux-riscv64-musl@0.120.0':
- resolution: {integrity: sha512-SUbUxlar007LTGmSLGIC5x/WJvwhdX+PwNzFJ9f/nOzZOrCFbOT4ikt7pJIRg1tXVsEfzk5mWpGO1NFiSs4PIw==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [riscv64]
- os: [linux]
- libc: [musl]
-
- '@oxc-parser/binding-linux-s390x-gnu@0.120.0':
- resolution: {integrity: sha512-hYiPJTxyfJY2+lMBFk3p2bo0R9GN+TtpPFlRqVchL1qvLG+pznstramHNvJlw9AjaoRUHwp9IKR7UZQnRPGjgQ==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [s390x]
- os: [linux]
- libc: [glibc]
-
- '@oxc-parser/binding-linux-x64-gnu@0.120.0':
- resolution: {integrity: sha512-q+5jSVZkprJCIy3dzJpApat0InJaoxQLsJuD6DkX8hrUS61z2lHQ1Fe9L2+TYbKHXCLWbL0zXe7ovkIdopBGMQ==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [x64]
- os: [linux]
- libc: [glibc]
-
- '@oxc-parser/binding-linux-x64-musl@0.120.0':
- resolution: {integrity: sha512-D9QDDZNnH24e7X4ftSa6ar/2hCavETfW3uk0zgcMIrZNy459O5deTbWrjGzZiVrSWigGtlQwzs2McBP0QsfV1w==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [x64]
- os: [linux]
- libc: [musl]
-
- '@oxc-parser/binding-openharmony-arm64@0.120.0':
- resolution: {integrity: sha512-TBU8ZwOUWAOUWVfmI16CYWbvh4uQb9zHnGBHsw5Cp2JUVG044OIY1CSHODLifqzQIMTXvDvLzcL89GGdUIqNrA==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [openharmony]
-
- '@oxc-parser/binding-wasm32-wasi@0.120.0':
- resolution: {integrity: sha512-WG/FOZgDJCpJnuF3ToG/K28rcOmSY7FmFmfBKYb2fmLyhDzPpUldFGV7/Fz4ru0Iz/v4KPmf8xVgO8N3lO4KHA==}
- engines: {node: '>=14.0.0'}
- cpu: [wasm32]
-
- '@oxc-parser/binding-win32-arm64-msvc@0.120.0':
- resolution: {integrity: sha512-1T0HKGcsz/BKo77t7+89L8Qvu4f9DoleKWHp3C5sJEcbCjDOLx3m9m722bWZTY+hANlUEs+yjlK+lBFsA+vrVQ==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [win32]
-
- '@oxc-parser/binding-win32-ia32-msvc@0.120.0':
- resolution: {integrity: sha512-L7vfLzbOXsjBXV0rv/6Y3Jd9BRjPeCivINZAqrSyAOZN3moCopDN+Psq9ZrGNZtJzP8946MtlRFZ0Als0wBCOw==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [ia32]
- os: [win32]
-
- '@oxc-parser/binding-win32-x64-msvc@0.120.0':
- resolution: {integrity: sha512-ys+upfqNtSu58huAhJMBKl3XCkGzyVFBlMlGPzHeFKgpFF/OdgNs1MMf8oaJIbgMH8ZxgGF7qfue39eJohmKIg==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [x64]
- os: [win32]
-
- '@oxc-project/types@0.120.0':
- resolution: {integrity: sha512-k1YNu55DuvAip/MGE1FTsIuU3FUCn6v/ujG9V7Nq5Df/kX2CWb13hhwD0lmJGMGqE+bE1MXvv9SZVnMzEXlWcg==}
-
- '@oxc-project/types@0.152.0':
- resolution: {integrity: sha512-oM/5rLBm2tPkg0iBgkH/FOeR3PCDpY19GTgAZjMFM8h9WI9VW7cLgzp6nwtarYKmovavIQZ+Fe/RKX/8C8O/Rw==}
-
- '@posthog/browser-common@0.9.1':
- resolution: {integrity: sha512-Dl8uV2OZAxfHfWyC7K0Y3HtT7ld+WGLbXIwgCgAGziOMGDIa/bepCRrCxy7IxsEzqY1HOrq/VDdcoNN7hBTSQQ==}
-
- '@posthog/core@1.56.0':
- resolution: {integrity: sha512-WNlOoFQbOZyJzX54DhAslSpTjwDyXX5VLuRFNJjv172uOE9qHVUvtZAPP9dHZdq2HZkkLjbY27idH7UhzKSBVA==}
-
- '@posthog/types@1.413.0':
- resolution: {integrity: sha512-tYAVzNojWckuG/wxBB0fwE70sFruQQq4xbhkci7eH2ARU3mMfUTkvpN1HwBMpm0AtbxidLiH0IFvagmdJ8opPw==}
-
- '@radix-ui/primitive@1.1.7':
- resolution: {integrity: sha512-rqWnm76nYT8HoNNqEjpgJ7Pw/DrBj5iBTrmEPo6HTX5+VJyBNOqTdv4g89G63HuR5g0AaENoAcH7Is5fF2kZ8Q==}
-
- '@radix-ui/react-compose-refs@1.1.5':
- resolution: {integrity: sha512-+48PbAAbq3didjJxa+OaWY2ZwgAKsNiRGyeHKszblZMQ+kcpd9pAaT11cMkGEie0vsOi3QdeTE6d5Fe3Gn61kA==}
- peerDependencies:
- '@types/react': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
- '@radix-ui/react-context@1.2.2':
- resolution: {integrity: sha512-RHCUGwKHDr0hDGg4X7ma4JG4/+12qxw8rkh5QKdDldlCvtja6nUx1Ef/8HVrJze81lEsgLQlqjzjGNHantgnQA==}
- peerDependencies:
- '@types/react': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
- '@radix-ui/react-dialog@1.2.0':
- resolution: {integrity: sha512-l5CX8HdNL+9cc4s7HkNyplumSA3FIx68sg9dttBHKr286fRBwq1MBniDVTeI/tkof92/APntMQvC1YG1Khb0Cg==}
- peerDependencies:
- '@types/react': '*'
- '@types/react-dom': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
- '@types/react-dom':
- optional: true
-
- '@radix-ui/react-dismissable-layer@1.1.20':
- resolution: {integrity: sha512-35WHRrycfnj2m4LvPiKMKHGLM3Y2WvUA744CkRdxjs1BGDX1c8PVMfmiSGTUwnHRbqdtIoxveYTXvcJSt7VfgQ==}
- peerDependencies:
- '@types/react': '*'
- '@types/react-dom': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
- '@types/react-dom':
- optional: true
-
- '@radix-ui/react-focus-guards@1.1.6':
- resolution: {integrity: sha512-RNOJjfZMTyBM6xYmV3IVGXkPjIhcBAuv48POevAXwrGJhkWZ9p1rFoIS1JFooPuT193AZmRsCPhpoVJxx6OPoQ==}
- peerDependencies:
- '@types/react': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
- '@radix-ui/react-focus-scope@1.2.0':
- resolution: {integrity: sha512-I5S7vsAOozx2lWSBAyuXjWIJ/A8qx4fjbv6115WoaRYQSb1yZDaeNHonUAQzXyE8oD+0whJHbQRl4HIE2gQ0Xw==}
- peerDependencies:
- '@types/react': '*'
- '@types/react-dom': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
- '@types/react-dom':
- optional: true
-
- '@radix-ui/react-id@1.1.4':
- resolution: {integrity: sha512-TMQp2llA+RYn7JcjnrMnz7wN4pcVttPZnRZo52PLQsoLVKzNlVwUeHmfePgTgRluXFvlD3GD5g5MOVVTJCO0qA==}
- peerDependencies:
- '@types/react': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
- '@radix-ui/react-portal@1.1.18':
- resolution: {integrity: sha512-ygFIJ+QXNKf72AAq8x3hd22+ws7pYpmc1S0E4kW0Je+qD4qEb3FvxeKVQRGrVDMOkQaYfsB+Qs+KDh81a1gAOw==}
- peerDependencies:
- '@types/react': '*'
- '@types/react-dom': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
- '@types/react-dom':
- optional: true
-
- '@radix-ui/react-presence@1.1.11':
- resolution: {integrity: sha512-Z7/atlkab36Z8hm+V8zYc79r0W+tiOB1o0tun1By94JyadkekLQmtEAnBSP9XKXBNQsStoStS4+gX10JpS5akA==}
- peerDependencies:
- '@types/react': '*'
- '@types/react-dom': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
- '@types/react-dom':
- optional: true
-
- '@radix-ui/react-primitive@2.1.11':
- resolution: {integrity: sha512-RzcaSw5aKl0OPhBJ1wbolKSF6nVvN+0o/QLeIVq+09npiPdnCkPggy2k6gI6yetxl4ZyrlBPYFgCB8BQJZwXcQ==}
- peerDependencies:
- '@types/react': '*'
- '@types/react-dom': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
- '@types/react-dom':
- optional: true
-
- '@radix-ui/react-slot@1.4.0':
- resolution: {integrity: sha512-IuMVHZ+Ah5fkctu3X3qeFrV/ZrBcuWuDTFUUPfS/L5hvoTjzhp/HdWGE14CsQombPdEidsa33HVlYZXi49PZ1Q==}
- peerDependencies:
- '@types/react': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
- '@radix-ui/react-use-callback-ref@1.1.4':
- resolution: {integrity: sha512-R6OUY2e2fA6Yn6s+VSx5KBV6Nx8LQEhu+cz7LCej18rQ1HLyg9PSC9jP/ZNx0o6FAIK9c0F1kHylzSxKsdlkrQ==}
- peerDependencies:
- '@types/react': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
- '@radix-ui/react-use-controllable-state@1.2.6':
- resolution: {integrity: sha512-uEQJGT97ZA/TgP/Hydw47lHu+/vQj6z/0jA+WeTbK1o9Rx45GImjpD0tc3W5ad3D6XTSR6e1yEO0FvGq6WQfVQ==}
- peerDependencies:
- '@types/react': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
- '@radix-ui/react-use-effect-event@0.0.5':
- resolution: {integrity: sha512-7cshFL8HGS/7HEiHH+9kL9HBwp2sa9yX18Knwek6KYWmXwM7pegMgta2AXMQKI+rq3JnfSj9x8wYqFMTdG1Jgg==}
- peerDependencies:
- '@types/react': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
- '@radix-ui/react-use-layout-effect@1.1.4':
- resolution: {integrity: sha512-K20DkRkUwDnxEYMBPcg3Y6voLkEy5p5QQmszZgLngKKiC7dzBR/aEuK3w1qlx2JWDUNH6FluahYdgR3BP+QbYw==}
- peerDependencies:
- '@types/react': '*'
- react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
- '@reduxjs/toolkit@2.13.0':
- resolution: {integrity: sha512-f6jwVRfwW30+tnllz4YcsHHpPYYOE7abcHkyUCovD+P7DyhdAI5prz2Fh/8TLhakjpN+7aIEion1s5L/tvlYlA==}
- peerDependencies:
- react: ^16.9.0 || ^17.0.0 || ^18 || ^19
- react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0
- peerDependenciesMeta:
- react:
- optional: true
- react-redux:
- optional: true
-
- '@resvg/resvg-wasm@2.6.2':
- resolution: {integrity: sha512-FqALmHI8D4o6lk/LRWDnhw95z5eO+eAa6ORjVg09YRR7BkcM6oPHU9uyC0gtQG5vpFLvgpeU4+zEAz2H8APHNw==}
- engines: {node: '>= 10'}
-
- '@rolldown/binding-android-arm-eabi@1.2.12':
- resolution: {integrity: sha512-dB/a1214qKfHMXCpgqR4OZT+jS4kTyEXbQGJPqzobt5EwH5rX080pxE37alt3RzvR1bf1Yz/yGqRfrYAxuPw0A==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm]
- os: [android]
-
- '@rolldown/binding-android-arm64@1.2.12':
- resolution: {integrity: sha512-7KHFgQ5VJxIHcLlrwrc3Xbds7oTNQT7Pgi9gQCJKrd2VGab/UksIOYp6VD8MzCstGxOKMgNamPwUCfxPdP1OHg==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [android]
-
- '@rolldown/binding-darwin-arm64@1.2.12':
- resolution: {integrity: sha512-3YIhqHD96nA5SaYNRBR16HnGv4oavZvXfD/ayHM+oYZ0WD/8lBAtf6zQua4kEyAvpqrluKXl0lnOBoiNby7x9w==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [darwin]
-
- '@rolldown/binding-darwin-x64@1.2.12':
- resolution: {integrity: sha512-UuuJ35MFw4gmFOrE9pEqIV+K3syIKveph+Qc1/ljHZVdoDW4pz/JHR/eMVom+TZGl/5OOvGJOWaOCVt3ZfqhxA==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [x64]
- os: [darwin]
-
- '@rolldown/binding-freebsd-x64@1.2.12':
- resolution: {integrity: sha512-uMvssit0a4W+/7D8CbHUvG719mH3R2jwXAlh/XcPvuHTE0g++LymF88DCGNX0HM2rBOn0xrzgXktIB6fLSJBTQ==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [x64]
- os: [freebsd]
-
- '@rolldown/binding-linux-arm-gnueabihf@1.2.12':
- resolution: {integrity: sha512-XcFu0R0xWnwzSf4IQgFH1rJIckPN1pLy2R+4r9IDB7Yfu/ys9cVqfa4pBrMHj7a3gl8mIR4nRNPg0e5IvEVs6g==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm]
- os: [linux]
-
- '@rolldown/binding-linux-arm64-gnu@1.2.12':
- resolution: {integrity: sha512-260UrKgn8tz39ak+SMDOirKzr7V04M9dWPw5llW00SwBivCZoWcRBKV1d8cXnRkUmSZA3BdiUmBHWk7734Ulpw==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [linux]
- libc: [glibc]
-
- '@rolldown/binding-linux-arm64-musl@1.2.12':
- resolution: {integrity: sha512-5YK1I9SqDkbPgc1IA8BgDl34suqUS2q0KWnBrirm0E51YjOs6eo6dV6jbQfNE/argHRSvd0QUGgtpIoYx+WWpw==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [linux]
- libc: [musl]
-
- '@rolldown/binding-linux-ppc64-gnu@1.2.12':
- resolution: {integrity: sha512-Rkcrmp7eFRg74yL5fXEU91JEWbdEPLevWwGtXpmhbjlD1StScbWTmO94Bhly+Mo+ketKYkdmM1vNUKeWSlx8cQ==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [ppc64]
- os: [linux]
- libc: [glibc]
-
- '@rolldown/binding-linux-s390x-gnu@1.2.12':
- resolution: {integrity: sha512-qvK4DuAsQc2BSjlx+Xr+IzOIvvxbGZqxFwdWfG6F518Erj0GGISyQbJ6pIappnOxlNPzNHvo/L0BwB30GZ+zVw==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [s390x]
- os: [linux]
- libc: [glibc]
-
- '@rolldown/binding-linux-x64-gnu@1.2.12':
- resolution: {integrity: sha512-Q9uLBO53Xd4QIq1WOycVQyPP1O4HhraEV2qqb3uTrnVw6QZih9duY4vNXOivL1xoUS1/z+W8eF4NMfl2a8Sdjw==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [x64]
- os: [linux]
- libc: [glibc]
-
- '@rolldown/binding-linux-x64-musl@1.2.12':
- resolution: {integrity: sha512-3IBxWFMjbOZskDPKv8Lf9BCnahlKuHthWkYnyIxOH/QcJrFcS4EmcenthApkwr/5+nEqZlLzeYbxeMaX7A5u4g==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [x64]
- os: [linux]
- libc: [musl]
-
- '@rolldown/binding-openharmony-arm64@1.2.12':
- resolution: {integrity: sha512-xtX61xg4LKPkPWilZU1ynKClz5Gj4bf74LML4r3eVLWumKnGjoEr1OSHQhMdbBDoYTi+yjrujvpZe2pUnqCrrA==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [openharmony]
-
- '@rolldown/binding-win32-arm64-msvc@1.2.12':
- resolution: {integrity: sha512-At7fPB6PCaIjzgIhEZFxuT+BBFqiQibJDT4d3PhiR3f4E7bbMZF4aKblbFfEM3sETRDd1YiQx/+U/g/B/ou5Ew==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [arm64]
- os: [win32]
-
- '@rolldown/binding-win32-x64-msvc@1.2.12':
- resolution: {integrity: sha512-WIw2haVKwjuYdXkHaoC0mF8Le71TuCBxjrdKqLbJGctbBABj+ClfmNvtbOnzpq3RokNo5+V1qhtSzJyXorsklQ==}
- engines: {node: ^20.19.0 || >=22.12.0}
- cpu: [x64]
- os: [win32]
-
- '@rolldown/pluginutils@1.0.1':
- resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==}
-
- '@solid-primitives/event-listener@2.4.6':
- resolution: {integrity: sha512-5I0YJcTVYIWoMmgBSROBZGcz+ymhew/pGTg2dHW74BUjFKsV8Li4bOZYl0YAGP4mHw5o4UBd9/BEesqBci3wxw==}
- peerDependencies:
- solid-js: ^1.6.12
-
- '@solid-primitives/keyboard@1.3.7':
- resolution: {integrity: sha512-558RPNYnXx4nGh537DSqAn4xMrC8iFipl/5+xzgzWoTNFst4RnUN3BOLmtDjJ0UGGoQXVMALYR3bNOHM0xnt1Q==}
- peerDependencies:
- solid-js: ^1.6.12
-
- '@solid-primitives/resize-observer@2.2.0':
- resolution: {integrity: sha512-9Fuu/EWBeGj+atGHRJp70HKhdfalmpjwxY8a32NZixdLNmfCJ45AfhLQNr6uOzETbbiMx4iCKlTrJ8KZCHC2Ww==}
- peerDependencies:
- solid-js: ^1.6.12
-
- '@solid-primitives/rootless@1.5.4':
- resolution: {integrity: sha512-TOIZa1VUfVJ+9nkCcRajw3U4t9vBOP1HxX1WHNTbXq32mXwlqTvUnC4CRIilohcryBkT9u2ZkhUDSHRTaGp55g==}
- peerDependencies:
- solid-js: ^1.6.12
-
- '@solid-primitives/static-store@0.1.4':
- resolution: {integrity: sha512-LgtVaVBtB7EbmS4+M0b8xY5Iq6pUWXBsIC4VgtrFKDGDdyCaDt88sHk0fUlx1Enxm/XZnZyLXJABRoa39RjJqA==}
- peerDependencies:
- solid-js: ^1.6.12
-
- '@solid-primitives/utils@6.4.1':
- resolution: {integrity: sha512-ISSB5QX1qP2ynrheIpYwc4oKR5Ny4siNuUyf1qZniy+Il+p/PtDB0QK1Dnle8noiHpwRD3gpPdubOC3qI/Zamg==}
- peerDependencies:
- solid-js: ^1.6.12
-
- '@standard-schema/spec@1.1.0':
- resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
-
- '@standard-schema/utils@0.3.0':
- resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==}
-
- '@tailwindcss/node@4.3.3':
- resolution: {integrity: sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==}
-
- '@tailwindcss/oxide-android-arm64@4.3.3':
- resolution: {integrity: sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==}
- engines: {node: '>= 20'}
- cpu: [arm64]
- os: [android]
-
- '@tailwindcss/oxide-darwin-arm64@4.3.3':
- resolution: {integrity: sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==}
- engines: {node: '>= 20'}
- cpu: [arm64]
- os: [darwin]
-
- '@tailwindcss/oxide-darwin-x64@4.3.3':
- resolution: {integrity: sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==}
- engines: {node: '>= 20'}
- cpu: [x64]
- os: [darwin]
-
- '@tailwindcss/oxide-freebsd-x64@4.3.3':
- resolution: {integrity: sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==}
- engines: {node: '>= 20'}
- cpu: [x64]
- os: [freebsd]
-
- '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3':
- resolution: {integrity: sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==}
- engines: {node: '>= 20'}
- cpu: [arm]
- os: [linux]
-
- '@tailwindcss/oxide-linux-arm64-gnu@4.3.3':
- resolution: {integrity: sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==}
- engines: {node: '>= 20'}
- cpu: [arm64]
- os: [linux]
- libc: [glibc]
-
- '@tailwindcss/oxide-linux-arm64-musl@4.3.3':
- resolution: {integrity: sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==}
- engines: {node: '>= 20'}
- cpu: [arm64]
- os: [linux]
- libc: [musl]
-
- '@tailwindcss/oxide-linux-x64-gnu@4.3.3':
- resolution: {integrity: sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==}
- engines: {node: '>= 20'}
- cpu: [x64]
- os: [linux]
- libc: [glibc]
-
- '@tailwindcss/oxide-linux-x64-musl@4.3.3':
- resolution: {integrity: sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==}
- engines: {node: '>= 20'}
- cpu: [x64]
- os: [linux]
- libc: [musl]
-
- '@tailwindcss/oxide-wasm32-wasi@4.3.3':
- resolution: {integrity: sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==}
- engines: {node: '>=14.0.0'}
- cpu: [wasm32]
- bundledDependencies:
- - '@napi-rs/wasm-runtime'
- - '@emnapi/core'
- - '@emnapi/runtime'
- - '@tybys/wasm-util'
- - '@emnapi/wasi-threads'
- - tslib
-
- '@tailwindcss/oxide-win32-arm64-msvc@4.3.3':
- resolution: {integrity: sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==}
- engines: {node: '>= 20'}
- cpu: [arm64]
- os: [win32]
-
- '@tailwindcss/oxide-win32-x64-msvc@4.3.3':
- resolution: {integrity: sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==}
- engines: {node: '>= 20'}
- cpu: [x64]
- os: [win32]
-
- '@tailwindcss/oxide@4.3.3':
- resolution: {integrity: sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==}
- engines: {node: '>= 20'}
-
- '@tailwindcss/typography@0.5.20':
- resolution: {integrity: sha512-hwbzQuNUfcPvbegQFatVPl/MY/tcM9KLl963hQ5laJKPh81TEZ1+dNG9PirGvcaDBkp+BCshExAyKVPW91dozw==}
- peerDependencies:
- tailwindcss: '>=3.0.0 || >=4.0.0 || insiders'
-
- '@tailwindcss/vite@4.3.3':
- resolution: {integrity: sha512-yYU8cogLeSh/ms2jh8Fj7jaba/EWa7Ja6GoUqYZaraEuCI5YS6ms6ObZgjjedm+jm6XZjdNRWBpPP6Z86oOxcw==}
- peerDependencies:
- vite: ^5.2.0 || ^6 || ^7 || ^8
-
- '@tanstack/devtools-bundler-core@0.1.3':
- resolution: {integrity: sha512-F0tlxIyfFqXkZ1mJP1EjtkiSeJA+ztXY2AYOHf7r4goCIEAOp86N9PFJ/yv8vu1TnmxGS6vKsZCS3Kyls9xQQA==}
- engines: {node: '>=18'}
-
- '@tanstack/devtools-client@0.0.8':
- resolution: {integrity: sha512-cG3iZkGWCwN330bLBKa8+9r4Of2AXNoz2zUqcsy/4XsD3105ghVBx78cGyvJj9fSclNomPxoqAnDGXXhg1WLvA==}
- engines: {node: '>=18'}
-
- '@tanstack/devtools-event-bus@0.4.3':
- resolution: {integrity: sha512-NeegBt5/n2E5q4DbrXHqECBq42+kDi6JBOp8/+RNqkIE+P4hJpbM36kGyjnGQFMWOoku31qhMyX9/48VuTTdmg==}
- engines: {node: '>=18'}
-
- '@tanstack/devtools-event-client@0.5.0':
- resolution: {integrity: sha512-H+OH3zC6Vhu/K0NaVfQKknEKawc/+2PT+D3SB3Ox0V8SiMlTo0abbmH2rH0721R2aNYbjdMXA1oENOd8E2UVoA==}
- engines: {node: '>=18'}
- hasBin: true
-
- '@tanstack/devtools-ui@0.7.1':
- resolution: {integrity: sha512-3xQ/ezZ2qVNszhjpCN2N3jn7uHc2J1PMgcyjHzH4XZBt9xAQyMMcPNoR2cd7rzReyxWoJpZUWiDBmOJiCtLj9A==}
- engines: {node: '>=18'}
- peerDependencies:
- solid-js: '>=1.9.7'
-
- '@tanstack/devtools-vite@0.8.5':
- resolution: {integrity: sha512-xaifCEmiwwzizlbp973oISXNsnmuU/BugLa66gryAZaPJJ/qo1kJd2DxY5X960eHwmyIS3SN0KYrL3/aRhucmA==}
- engines: {node: '>=18'}
- hasBin: true
- peerDependencies:
- vite: ^6.0.0 || ^7.0.0 || ^8.0.0
-
- '@tanstack/devtools@0.15.0':
- resolution: {integrity: sha512-KyS7Qi82Eq9yG8C+uae3ikAPb+D5rfzVhvOOjXVAHZ/64s6TWJlDWpREw1FrHIYZaI7paErpsExSSKlF5BKA/A==}
- engines: {node: '>=18'}
- hasBin: true
- peerDependencies:
- solid-js: '>=1.9.7'
-
- '@tanstack/history@1.162.4':
- resolution: {integrity: sha512-utTS5L2OkeYUzXGohL1Z8sefu1GLNOJcxe8Hd6iIdc/Xo1K1nDB2JEp4iSFhvYh33xKC9V91TxrS8qfrpoKobQ==}
- engines: {node: '>=20.19'}
-
- '@tanstack/intent@0.5.4':
- resolution: {integrity: sha512-veyJDHwIHrylKucn8UgLlMYZbhLZ3gO1OlYiXLcmIKazCd8bTDXRfcWvmwNK3q63jS8K40pYudZV3HQPbHsBWg==}
- engines: {node: '>=20.12.0'}
- hasBin: true
-
- '@tanstack/react-devtools@0.10.13':
- resolution: {integrity: sha512-r0cdB/14+st2Vxl/1Bodlyq4VC8pf9SykLQDYbGHDc1+V146WQo5B3KlYLkfyxD9Q/6+9NPRQHZyl8fvZVMdRA==}
- engines: {node: '>=18'}
- peerDependencies:
- '@types/react': '>=16.8'
- '@types/react-dom': '>=16.8'
- react: '>=16.8'
- react-dom: '>=16.8'
-
- '@tanstack/react-router-devtools@1.167.2':
- resolution: {integrity: sha512-VuoqB7OhDUrBa4WOFSKiAQ8xI8sJpeZdo9sYE1hQa89iMuVFUQu1iWE4iCiQhB+6TYOZDZ9e+iHKxYjop4ZVYw==}
- engines: {node: '>=20.19'}
- peerDependencies:
- '@tanstack/react-router': ^1.170.36
- '@tanstack/router-core': ^1.171.30
- react: '>=18.0.0 || >=19.0.0'
- react-dom: '>=18.0.0 || >=19.0.0'
- peerDependenciesMeta:
- '@tanstack/router-core':
- optional: true
-
- '@tanstack/react-router@1.170.41':
- resolution: {integrity: sha512-Mpvw8Wm5MGDbTqI8Yc9flLKxbOHwoWocv0H2aGKcgw2a017oK5nZWqa954P+DrUx/8fI98YNywnHP5XcD3tQ9w==}
- engines: {node: '>=20.19'}
- peerDependencies:
- react: '>=18.0.0 || >=19.0.0'
- react-dom: '>=18.0.0 || >=19.0.0'
-
- '@tanstack/react-start-client@1.168.39':
- resolution: {integrity: sha512-Uby0uo37JlQgUKHU0snDwH9nYiEeAjm9+7pUOFgycU/UszEILC2SO2DSCoNnCMuHKj9z+4URKzBYIP2exT9+wg==}
- engines: {node: '>=22.12.0'}
- peerDependencies:
- react: '>=18.0.0 || >=19.0.0'
- react-dom: '>=18.0.0 || >=19.0.0'
-
- '@tanstack/react-start-rsc@0.1.59':
- resolution: {integrity: sha512-M2Lqxkk5C1zQncQs5paqX+/OLdOht51pg6D84YfLMrNsjhU/nzb6wd92MIja0mi5i23+L+fxLLjQYR2DObjBlw==}
- engines: {node: '>=22.12.0'}
- peerDependencies:
- '@rspack/core': '>=2.0.0-0'
- '@vitejs/plugin-rsc': '>=0.5.30'
- react: '>=18.0.0 || >=19.0.0'
- react-dom: '>=18.0.0 || >=19.0.0'
- react-server-dom-rspack: '>=0.0.2'
- peerDependenciesMeta:
- '@rspack/core':
- optional: true
- '@vitejs/plugin-rsc':
- optional: true
- react-server-dom-rspack:
- optional: true
-
- '@tanstack/react-start-server@1.167.46':
- resolution: {integrity: sha512-K7z8xBOEdp8u5CZCxWrbS0tFtk5XZGMdhssLeZlRZKlLDbX7BKLdMtJ7th5sR6QVt9MTUAg3LcoqvJMPSFF+lg==}
- engines: {node: '>=22.12.0'}
- peerDependencies:
- react: '>=18.0.0 || >=19.0.0'
- react-dom: '>=18.0.0 || >=19.0.0'
-
- '@tanstack/react-start@1.168.60':
- resolution: {integrity: sha512-WMOM0Xlh2lPbVlbjYM6uOxOpiaWRPvODm/dwkLsGKq5tjyHOHZmKckJgwlrZl7OQUqFlOZHYj8bKUTgoeg8cUQ==}
- engines: {node: '>=22.12.0'}
- peerDependencies:
- '@rsbuild/core': ^2.0.0
- '@vitejs/plugin-rsc': '*'
- react: '>=18.0.0 || >=19.0.0'
- react-dom: '>=18.0.0 || >=19.0.0'
- vite: '>=7.0.0'
- peerDependenciesMeta:
- '@rsbuild/core':
- optional: true
- '@vitejs/plugin-rsc':
- optional: true
- vite:
- optional: true
-
- '@tanstack/react-store@0.11.2':
- resolution: {integrity: sha512-oj5O5DmiMWE+ih+SioX2ayC1kbK7d3fpLx0B75fPJr9nY3zU+hoW010yr64qXsY/9fyiLVE2bn5mGNV3owm8RQ==}
- peerDependencies:
- react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
- react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
-
- '@tanstack/router-cli@1.167.40':
- resolution: {integrity: sha512-KKX9hedstsc0eEKfUAwrwy7CLNXdSxjiBBq0uojnjMnOnraRXP9Nf+x6/ZsAultxHp7NhWfYddO8VdT0zAtUDg==}
- engines: {node: '>=20.19'}
- hasBin: true
-
- '@tanstack/router-core@1.171.34':
- resolution: {integrity: sha512-X+19pGuuLVPvvAvPYw9v/+ktRk5cCll8AtfpBpOhDRmVgUMrfqze0467xtq8YRVVs/mmo5rVtWn/7Tp32RDBKw==}
- engines: {node: '>=20.19'}
-
- '@tanstack/router-devtools-core@1.168.2':
- resolution: {integrity: sha512-pCCdQ5M/NUeWdiAbPmjyfcNdls6G4vaVlIQbPf1IqZk1FLYFr00aQvi578yUuWFBNM2KNS2QcwM1uPucbtGf5Q==}
- engines: {node: '>=20.19'}
- peerDependencies:
- '@tanstack/router-core': ^1.171.30
- csstype: ^3.0.10
- peerDependenciesMeta:
- csstype:
- optional: true
-
- '@tanstack/router-generator@1.167.40':
- resolution: {integrity: sha512-WkEueqEvsBBudzO0fx1nWfOmRNW8OAvBoVABTGls9bAWzjdC+KDGHvjCNrvn88ofs1F6gqL8aWnzKCbxW3dCyQ==}
- engines: {node: '>=20.19'}
-
- '@tanstack/router-plugin@1.168.42':
- resolution: {integrity: sha512-vAR5WXJh/ErseEWQftDhsJcr2c++ucRQ6FbqN3ygMO44+ZxxRfW3sIpZmddHROVSmBk8jc6MrwjTPNjVhd62Vw==}
- engines: {node: '>=20.19'}
- peerDependencies:
- '@rsbuild/core': '>=1.0.2 || ^2.0.0'
- '@tanstack/react-router': ^1.170.41
- vite: '>=5.0.0 || >=6.0.0 || >=7.0.0 || >=8.0.0'
- vite-plugin-solid: ^2.11.10 || ^3.0.0-0
- webpack: '>=5.92.0'
- peerDependenciesMeta:
- '@rsbuild/core':
- optional: true
- '@tanstack/react-router':
- optional: true
- vite:
- optional: true
- vite-plugin-solid:
- optional: true
- webpack:
- optional: true
-
- '@tanstack/router-utils@1.162.3':
- resolution: {integrity: sha512-Icb0xGuG1+54IV0WMLRcc3ErTx2HeJWyPG661FkQ8UT6guoBq1FJjFRqlG/JS0xi4mFFkBhvwO7tbLa32f3yxA==}
- engines: {node: '>=20.19'}
-
- '@tanstack/start-client-core@1.170.34':
- resolution: {integrity: sha512-LfwZSbau2MLLZ/uPAoO+NC9fK3J66c0wLhnNQqIa+Goqw7bXPjkHwlsjY7evlUz1AnyhhQ1Qab95v+VmP0TZ9A==}
- engines: {node: '>=22.12.0'}
-
- '@tanstack/start-fn-stubs@1.162.0':
- resolution: {integrity: sha512-QWfUZ3Yo923tdQn38LyKMU8rcTw69zc+T4dAvgTWV4O56SqFRsGfS0lSWIMhJRwXIx/bvdi7nTUBDdZtTHtpTQ==}
- engines: {node: '>=22.12.0'}
-
- '@tanstack/start-plugin-core@1.171.49':
- resolution: {integrity: sha512-HPOb7LnMc71k38cd5uvMybPPUU/Q/56KvSqQzSWz7cps1ZDFXaxUM6EFaFHLCdgTWqGexNGDdRE+sUVPVBM4Xg==}
- engines: {node: '>=22.12.0'}
- peerDependencies:
- '@rsbuild/core': ^2.0.0
- vite: '>=7.0.0'
- peerDependenciesMeta:
- '@rsbuild/core':
- optional: true
- vite:
- optional: true
-
- '@tanstack/start-server-core@1.169.39':
- resolution: {integrity: sha512-pqqkxhXY46nuFSYt6TsMGyABiplUzHFHndKAlRRGC0fWDrJCH1koWxVMoxySa51ZETV79f/z73b5UZ1jfIkXwQ==}
- engines: {node: '>=22.12.0'}
-
- '@tanstack/start-storage-context@1.167.36':
- resolution: {integrity: sha512-x+xCXK2GtFzY6NbXqAg8YpU6cwAjDfMeYSNzxfGzntpjbwBRHHrXeC/kYUnBBQCV7wK4kJ8vBBQGP0OyYTasUg==}
- engines: {node: '>=22.12.0'}
-
- '@tanstack/store@0.11.2':
- resolution: {integrity: sha512-sJ4mjol8uQsHV0gOJzzjwXfh2Fwm+Sz0+8deqiTm4jGbMdjzNSW+xZCFm0kUa870uhd8yi+DpKnZb5Kc4apa0Q==}
-
- '@tanstack/virtual-file-routes@1.162.0':
- resolution: {integrity: sha512-uhOeFyxLcU41HzvrxsGpiWdcMbScY1EDgbZ5K7DVRMYInbLYWAC0EA/kx9wXAoSM8q82bUG2hRl8+EAjE6XAbA==}
- engines: {node: '>=20.19'}
-
- '@tybys/wasm-util@0.10.4':
- resolution: {integrity: sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==}
-
- '@types/d3-array@3.2.2':
- resolution: {integrity: sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==}
-
- '@types/d3-color@3.1.3':
- resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==}
-
- '@types/d3-ease@3.0.2':
- resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==}
-
- '@types/d3-interpolate@3.0.4':
- resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==}
-
- '@types/d3-path@3.1.1':
- resolution: {integrity: sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==}
-
- '@types/d3-scale@4.0.9':
- resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==}
-
- '@types/d3-shape@3.2.0':
- resolution: {integrity: sha512-kVd74ta9eof3eJOvbNd1vGKS/XERRyQbT26Og63hIsvDO84cjD5gEOhsXf26w3FSoNlPVz84DOFcKv/oou+fMw==}
-
- '@types/d3-time@3.0.4':
- resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==}
-
- '@types/d3-timer@3.0.2':
- resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==}
-
- '@types/node@22.20.5':
- resolution: {integrity: sha512-U2+DNr+wSjpsTS/wZGYHq7GcwfuSmKiKvoPvK22zwTlRhU91yOniN4qRR5KhIjvif7ysw/dz/hKmfDH0Ris4aA==}
-
- '@types/pg@8.23.1':
- resolution: {integrity: sha512-fKVHpikPdg4GKks3JuLEhvwSyvwzF23hnabPy6DD8ljVbC7+6J5dQzdv4arV6jqq57djnMgs1HKBxX4P8aBI3A==}
-
- '@types/react-dom@19.3.0':
- resolution: {integrity: sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q==}
- peerDependencies:
- '@types/react': ^19.3.0
-
- '@types/react@19.3.0':
- resolution: {integrity: sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==}
-
- '@types/trusted-types@2.0.7':
- resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
-
- '@types/use-sync-external-store@0.0.6':
- resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==}
-
- '@vitejs/plugin-react@6.1.1':
- resolution: {integrity: sha512-yxLaQV9gkhS8ezJqCM6+ndU7mDY6gqAg75NQ+0IjwEI8IYOmQCgkRwHKVSfWXW076DsqMo0Dk+0FK1U+M5RgFw==}
- engines: {node: ^20.19.0 || >=22.12.0}
- peerDependencies:
- '@rolldown/plugin-babel': ^0.1.7 || ^0.2.0
- babel-plugin-react-compiler: ^1.0.0
- oxc-transform-react: ^0.145.0
- vite: ^8.0.0
- peerDependenciesMeta:
- '@rolldown/plugin-babel':
- optional: true
- babel-plugin-react-compiler:
- optional: true
- oxc-transform-react:
- optional: true
-
- ansi-regex@5.0.1:
- resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
- engines: {node: '>=8'}
-
- ansi-styles@4.3.0:
- resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
- engines: {node: '>=8'}
-
- ansis@4.4.0:
- resolution: {integrity: sha512-9k3v7xcHwgdO/DruxGIg4HtjvlAZlcnsX/mzqUb1t3NkYnl9kK2UJ+Gq0io+vQf7iT//BD/HB/NBkUR1LWxoeA==}
- engines: {node: '>=14'}
-
- argparse@2.0.1:
- resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
-
- aria-hidden@1.2.6:
- resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==}
- engines: {node: '>=10'}
-
- babel-dead-code-elimination@1.0.12:
- resolution: {integrity: sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==}
-
- baseline-browser-mapping@2.11.27:
- resolution: {integrity: sha512-ElY12DaROGuan+lMmZ8Cvo/ZUbXPe7Enc/9VU/b1T3Kp4dwytRcNdR8DoSJN5SNJT/CuvcCA0DHDVmMOCePdRQ==}
- engines: {node: '>=6.0.0'}
- hasBin: true
-
- better-auth@1.7.7:
- resolution: {integrity: sha512-Zhgxi/c5ylmfB/sX+nwnBbsFf/j6k0L8DvL6CJXZSrXgxc5pPMC/e7j812zNd4L4B4ELmdURCPw3X8nAOUdcjw==}
- peerDependencies:
- '@lynx-js/react': '*'
- '@prisma/client': ^5.0.0 || ^6.0.0 || ^7.0.0
- '@sveltejs/kit': ^2.0.0
- '@tanstack/react-start': ^1.0.0
- '@tanstack/solid-start': ^1.0.0
- drizzle-kit: '>=0.31.4 || >=1.0.0-beta.1'
- drizzle-orm: ^0.45.2 || >=1.0.0-rc.1 <2.0.0
- mongodb: ^6.0.0 || ^7.0.0
- mysql2: ^3.0.0
- next: ^14.0.0 || ^15.0.0 || ^16.0.0
- pg: ^8.0.0
- prisma: ^5.0.0 || ^6.0.0 || ^7.0.0
- react: ^18.0.0 || ^19.0.0
- react-dom: ^18.0.0 || ^19.0.0
- solid-js: ^1.0.0
- svelte: ^4.0.0 || ^5.0.0
- vitest: ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0
- vue: ^3.0.0
- peerDependenciesMeta:
- '@lynx-js/react':
- optional: true
- '@prisma/client':
- optional: true
- '@sveltejs/kit':
- optional: true
- '@tanstack/react-start':
- optional: true
- '@tanstack/solid-start':
- optional: true
- drizzle-kit:
- optional: true
- drizzle-orm:
- optional: true
- mongodb:
- optional: true
- mysql2:
- optional: true
- next:
- optional: true
- pg:
- optional: true
- prisma:
- optional: true
- react:
- optional: true
- react-dom:
- optional: true
- solid-js:
- optional: true
- svelte:
- optional: true
- vitest:
- optional: true
- vue:
- optional: true
-
- better-call@1.4.0:
- resolution: {integrity: sha512-bBKOT4vv1kZLDgxVePdilk/Jwkn+dtRRsmi3DzHcDP+WnswyVl6dR59l2HEeP/0cB+bDoopASAesWDPIdd/zZA==}
- peerDependencies:
- zod: ^4.0.0
- peerDependenciesMeta:
- zod:
- optional: true
-
- browserslist@4.29.3:
- resolution: {integrity: sha512-1R4kiYKXGViqEN0CnoDrXc1StD9niAwu+j2dukWzrD4bJgsD4lDmEp0CRbc6E/vYJIfTHwPmwyaKtVSudICdPA==}
- engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
- hasBin: true
-
- buffer-from@1.1.2:
- resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
-
- caniuse-lite@1.0.30001814:
- resolution: {integrity: sha512-/Uaf1lAzr59XcMpW0o96WoEfr+VXK2OX4U9AgFoiSHsVJ4HppnIFUjtYzsyDH2+tgANaQb2/oxYGwCPapN1FpA==}
-
- chalk@5.6.2:
- resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==}
- engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
-
- chokidar@5.0.0:
- resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==}
- engines: {node: '>= 20.19.0'}
-
- class-variance-authority@0.7.1:
- resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==}
-
- cliui@8.0.1:
- resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
- engines: {node: '>=12'}
-
- clsx@2.1.1:
- resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
- engines: {node: '>=6'}
-
- cmdk@1.1.1:
- resolution: {integrity: sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg==}
- peerDependencies:
- react: ^18 || ^19 || ^19.0.0-rc
- react-dom: ^18 || ^19 || ^19.0.0-rc
-
- cn@0.4.0:
- resolution: {integrity: sha512-qOAeUhPwPzBxx6jaeQdo646XIKliKHc2j1ZF7Ngb1o0pJZKH5gq8FkA0aVdUdPFUDXNXyUCXpCtoJISo6dhizg==}
- engines: {node: '>=20'}
- hasBin: true
-
- color-convert@2.0.1:
- resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
- engines: {node: '>=7.0.0'}
-
- color-name@1.1.4:
- resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
-
- consola@3.4.2:
- resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==}
- engines: {node: ^14.18.0 || >=16.10.0}
-
- convert-source-map@2.0.0:
- resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
-
- cookie-es@3.1.1:
- resolution: {integrity: sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==}
-
- core-js@3.50.0:
- resolution: {integrity: sha512-BRWgOLKkFeCgRudR6zrs8p9XJZcE14grzKMMssoYrk6krtuEZ7MTKPIY5RzOnqsEKIR9kst7wNzphttraT+Yqw==}
-
- croner@10.0.1:
- resolution: {integrity: sha512-ixNtAJndqh173VQ4KodSdJEI6nuioBWI0V1ITNKhZZsO0pEMoDxz539T4FTTbSZ/xIOSuDnzxLVRqBVSvPNE2g==}
- engines: {node: '>=18.0'}
-
- cross-spawn@7.0.6:
- resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
- engines: {node: '>= 8'}
-
- crossws@0.4.12:
- resolution: {integrity: sha512-aypfsr6t0uNvkqaZc6zvBfXzC6pLI0/sIulpkV6RwCVtZqG5ebBzv4weImKK0VNCj91Wl9F5j7p5WU4MNrybng==}
- peerDependencies:
- srvx: '>=0.11.5'
- peerDependenciesMeta:
- srvx:
- optional: true
-
- cssesc@3.0.0:
- resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
- engines: {node: '>=4'}
- hasBin: true
-
- csstype@3.2.3:
- resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
-
- d3-array@3.2.4:
- resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==}
- engines: {node: '>=12'}
-
- d3-color@3.1.0:
- resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==}
- engines: {node: '>=12'}
-
- d3-ease@3.0.1:
- resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==}
- engines: {node: '>=12'}
-
- d3-format@3.1.2:
- resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==}
- engines: {node: '>=12'}
-
- d3-interpolate@3.0.1:
- resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==}
- engines: {node: '>=12'}
-
- d3-path@3.1.0:
- resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==}
- engines: {node: '>=12'}
-
- d3-scale@4.0.2:
- resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==}
- engines: {node: '>=12'}
-
- d3-shape@3.2.0:
- resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==}
- engines: {node: '>=12'}
-
- d3-time-format@4.1.0:
- resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==}
- engines: {node: '>=12'}
-
- d3-time@3.1.0:
- resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==}
- engines: {node: '>=12'}
-
- d3-timer@3.0.1:
- resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==}
- engines: {node: '>=12'}
-
- dayjs@1.11.23:
- resolution: {integrity: sha512-QDTCU0M0MxR3hQfnlDJfwekQiaanm1ubOD231u73WBckQ/fsamwRLiE2GBz6D3a/xF1NgfiDLJjXBa1hYOYTtQ==}
-
- db0@0.3.4:
- resolution: {integrity: sha512-RiXXi4WaNzPTHEOu8UPQKMooIbqOEyqA1t7Z6MsdxSCeb8iUC9ko3LcmsLmeUt2SM5bctfArZKkRQggKZz7JNw==}
- peerDependencies:
- '@electric-sql/pglite': '*'
- '@libsql/client': '*'
- better-sqlite3: '*'
- drizzle-orm: '*'
- mysql2: '*'
- sqlite3: '*'
- peerDependenciesMeta:
- '@electric-sql/pglite':
- optional: true
- '@libsql/client':
- optional: true
- better-sqlite3:
- optional: true
- drizzle-orm:
- optional: true
- mysql2:
- optional: true
- sqlite3:
- optional: true
-
- debug@4.4.3:
- resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
- engines: {node: '>=6.0'}
- peerDependencies:
- supports-color: '*'
- peerDependenciesMeta:
- supports-color:
- optional: true
-
- decimal.js-light@2.5.1:
- resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==}
-
- defu@6.1.7:
- resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==}
-
- detect-libc@2.1.2:
- resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
- engines: {node: '>=8'}
-
- detect-node-es@1.1.0:
- resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==}
-
- diff@8.0.4:
- resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==}
- engines: {node: '>=0.3.1'}
-
- dompurify@3.4.16:
- resolution: {integrity: sha512-sqo+pNp3qRhCIpbgRi1y8Tgk27Bo2Ry7w0dC1NBeNTdZChWjz9Xb/KOoZbRP/R6pQZ80Qw8YhXw13hWWBbMRnQ==}
-
- drizzle-kit@0.31.11:
- resolution: {integrity: sha512-YCYqxTLIB2OCqf6w9/Vef13baBVbwQIPcbT4Y56AfO6B9ajZhDhD8Jkveg/hJvT/iuMloKD/IYYkyMMNhr7Kqg==}
- hasBin: true
-
- drizzle-orm@0.45.3:
- resolution: {integrity: sha512-CAloER21cDdcgZ1OmjrZX82EeRNsdP+y0onX/eyoYDaYzki/adrAa91lzM5jWh7zZPK4qUbw/6LGv9J+A+uizA==}
- peerDependencies:
- '@aws-sdk/client-rds-data': '>=3'
- '@cloudflare/workers-types': '>=4'
- '@electric-sql/pglite': '>=0.2.0'
- '@libsql/client': '>=0.10.0'
- '@libsql/client-wasm': '>=0.10.0'
- '@neondatabase/serverless': '>=0.10.0'
- '@netlify/db': '>=0.4.0'
- '@op-engineering/op-sqlite': '>=2'
- '@opentelemetry/api': ^1.4.1
- '@planetscale/database': '>=1.13'
- '@prisma/client': '*'
- '@tidbcloud/serverless': '*'
- '@types/better-sqlite3': '*'
- '@types/pg': '*'
- '@types/sql.js': '*'
- '@upstash/redis': '>=1.34.7'
- '@vercel/postgres': '>=0.8.0'
- '@xata.io/client': '*'
- better-sqlite3: '>=7'
- bun-types: '*'
- expo-sqlite: '>=14.0.0'
- gel: '>=2'
- knex: '*'
- kysely: '*'
- mysql2: '>=2'
- pg: '>=8'
- postgres: '>=3'
- prisma: '*'
- sql.js: '>=1'
- sqlite3: '>=5'
- peerDependenciesMeta:
- '@aws-sdk/client-rds-data':
- optional: true
- '@cloudflare/workers-types':
- optional: true
- '@electric-sql/pglite':
- optional: true
- '@libsql/client':
- optional: true
- '@libsql/client-wasm':
- optional: true
- '@neondatabase/serverless':
- optional: true
- '@netlify/db':
- optional: true
- '@op-engineering/op-sqlite':
- optional: true
- '@opentelemetry/api':
- optional: true
- '@planetscale/database':
- optional: true
- '@prisma/client':
- optional: true
- '@tidbcloud/serverless':
- optional: true
- '@types/better-sqlite3':
- optional: true
- '@types/pg':
- optional: true
- '@types/sql.js':
- optional: true
- '@upstash/redis':
- optional: true
- '@vercel/postgres':
- optional: true
- '@xata.io/client':
- optional: true
- better-sqlite3:
- optional: true
- bun-types:
- optional: true
- expo-sqlite:
- optional: true
- gel:
- optional: true
- knex:
- optional: true
- kysely:
- optional: true
- mysql2:
- optional: true
- pg:
- optional: true
- postgres:
- optional: true
- prisma:
- optional: true
- sql.js:
- optional: true
- sqlite3:
- optional: true
-
- electron-to-chromium@1.5.444:
- resolution: {integrity: sha512-5ss/uJfoDYDHT0lfJzT6FbcskIzROIOPf0BbbFkGcvDzoJU7i//9GDrwwIHQVmIsrAGiF3ihpADBRIsrEFt1rQ==}
-
- emoji-regex@8.0.0:
- resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
-
- enhanced-resolve@5.26.0:
- resolution: {integrity: sha512-9vhedylFonb2YGogzUKX6+Ja72gOJbN1QHAqdrvqLwhdl/QWbKopzoUC9EbQNVsAns/bx/4uyqalrQAoy1IByw==}
- engines: {node: '>=10.13.0'}
-
- env-runner@0.1.16:
- resolution: {integrity: sha512-2LRJM4P2KLX6J83QZZrMqvgCDt/D5ea7wPcI3yYiy5cG/9rX5QwdwZFx0D7ktWnjdRyZxYjttGGorb5nFqb1CA==}
- hasBin: true
- peerDependencies:
- '@netlify/runtime': ^4.1.23
- '@vercel/queue': '>=0.2.0'
- miniflare: ^4.20260515.0
- wrangler: ^4.0.0
- peerDependenciesMeta:
- '@netlify/runtime':
- optional: true
- '@vercel/queue':
- optional: true
- miniflare:
- optional: true
- wrangler:
- optional: true
-
- es-toolkit@1.52.0:
- resolution: {integrity: sha512-XTNEJQh1tY1ZJVcf6ayP/2n4ZPyaHlW2FWs7xvw5ddPuhUVjLD3olQVQS7kf58JbAB48iL0uL/jerTrjtV3lDA==}
-
- esbuild@0.18.20:
- resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==}
- engines: {node: '>=12'}
- hasBin: true
-
- esbuild@0.25.12:
- resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==}
- engines: {node: '>=18'}
- hasBin: true
-
- esbuild@0.28.2:
- resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==}
- engines: {node: '>=18'}
- hasBin: true
-
- escalade@3.2.0:
- resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
- engines: {node: '>=6'}
-
- eventemitter3@5.0.4:
- resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==}
-
- eventsource-parser@3.1.1:
- resolution: {integrity: sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ==}
- engines: {node: '>=18.0.0'}
-
- eventsource@3.0.7:
- resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==}
- engines: {node: '>=18.0.0'}
-
- exsolve@1.1.3:
- resolution: {integrity: sha512-kuzL9zherLQoqDeQaS55AiiIg1kb4KYXaSusTtgZTPlvKP2gGCI82LNmBNh5RjDVUXIcmgx+/Mx7vPwRzBbhJA==}
-
- fdir@6.5.0:
- resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
- engines: {node: '>=12.0.0'}
- peerDependencies:
- picomatch: ^3 || ^4
- peerDependenciesMeta:
- picomatch:
- optional: true
-
- fetchdts@0.1.7:
- resolution: {integrity: sha512-YoZjBdafyLIop9lSxXVI33oLD5kN31q4Td+CasofLLYeLXRFeOsuOw0Uo+XNRi9PZlbfdlN2GmRtm4tCEQ9/KA==}
-
- fflate@0.4.9:
- resolution: {integrity: sha512-zdxgIEddhfsyCaWpJ2SdXEP8ZMrKJ6+5jl4OupODcywU0IhRk6gdXuVGcPICyfx2H97hVK7xmJtRLPjkxAX8Vw==}
-
- fsevents@2.3.3:
- resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
- engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
- os: [darwin]
-
- gensync@1.0.0-beta.2:
- resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
- engines: {node: '>=6.9.0'}
-
- get-caller-file@2.0.5:
- resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
- engines: {node: 6.* || 8.* || >= 10.*}
-
- get-nonce@1.0.1:
- resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==}
- engines: {node: '>=6'}
-
- get-tsconfig@4.14.3:
- resolution: {integrity: sha512-++QEw4DIY7WGoukz+/+A/8dGYPT9l9yIadnmSgZ8Rjr3YVSVDipQSO9CdnJo9ePqFqUUqh+wk9uIaoiAwsiPkA==}
-
- goober@2.1.19:
- resolution: {integrity: sha512-U7veizMqxyKlM58+Z5j2ngJBH/r9siDmxpvNxSw0PylF6WQvrASJEZrxh1hidRBJc2jqoBVSyOban5u8m+6Rxg==}
- peerDependencies:
- csstype: ^3.0.10
-
- graceful-fs@4.2.11:
- resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
-
- h3@2.0.1-rc.20:
- resolution: {integrity: sha512-28ljodXuUp0fZovdiSRq4G9OgrxCztrJe5VdYzXAB7ueRvI7pIUqLU14Xi3XqdYJ/khXjfpUOOD2EQa6CmBgsg==}
- engines: {node: '>=20.11.1'}
- hasBin: true
- peerDependencies:
- crossws: ^0.4.1
- peerDependenciesMeta:
- crossws:
- optional: true
-
- h3@2.0.1-rc.22:
- resolution: {integrity: sha512-Esv0DMIuPkCTSWCA0vO73vcTqwzH1wjSrAO1TXNu/K3up1sZHa9EKMapbmxCDYBeymC3fVTk4qxp7ogQWQ+KgA==}
- engines: {node: '>=20.11.1'}
- hasBin: true
- peerDependencies:
- crossws: ^0.4.1
- peerDependenciesMeta:
- crossws:
- optional: true
-
- hookable@6.1.2:
- resolution: {integrity: sha512-+abwxtiEA52GCVIsQqut3S/uKTbUwYIp4Pe/vv+6py5XiXBCqMZHg6pA6Y5qhgLSEys0/cYuPbO0z1QFj5ZCmg==}
-
- httpxy@0.5.5:
- resolution: {integrity: sha512-uDjmnPyp1q4Sgzf3w+J/Fc6UqcCEj0x4Wjp7OqK5dGhNeDgpyrAmnS6ey8QWrX3SWDon2DMKf9sBa5X9+CVyMA==}
-
- immer@10.2.0:
- resolution: {integrity: sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==}
-
- immer@11.1.21:
- resolution: {integrity: sha512-bZSadeCPGdaY5/qRLgr6mDSH1ra21rD3rqpiWk7+QTr4ayYPTE9qZYdLh/NdPhMe0wSrTvHD/Lk8q5EwhUs0aw==}
-
- internmap@2.0.3:
- resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==}
- engines: {node: '>=12'}
-
- is-fullwidth-code-point@3.0.0:
- resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
- engines: {node: '>=8'}
-
- isbot@5.2.2:
- resolution: {integrity: sha512-iQcBXcd+Rv/pkubRyGh2utW2j1oPG5hZY6TUhVPpqK4G+o3IbxpJNx04hgksjc/N7GK5pEorUxDeg31cFgEk/w==}
- engines: {node: '>=18'}
-
- isexe@2.0.0:
- resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
-
- jiti@2.7.0:
- resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==}
- hasBin: true
-
- jose@6.2.12:
- resolution: {integrity: sha512-9NiFmJEex0sy2Dk58j2UGBSHgUs2ypF9eZSu4L6vjOX3Dp96Sw1F3uL+H+D1sx02jZZdzUT0HgvCy59CuvXcWw==}
-
- js-tokens@4.0.0:
- resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
-
- js-yaml@4.3.2:
- resolution: {integrity: sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==}
- hasBin: true
-
- jsesc@3.1.0:
- resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
- engines: {node: '>=6'}
- hasBin: true
-
- json5@2.2.3:
- resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
- engines: {node: '>=6'}
- hasBin: true
-
- kysely@0.29.6:
- resolution: {integrity: sha512-hHaB8C/rfzDDtr/t8YZwxAuPJTT0zHyaPoVzcXwDYhYNAgH/4sIfVhi/XLLIY+bL/FqaIJnjATDbi8ObSELmxg==}
- engines: {node: '>=22.0.0'}
-
- launch-editor@2.14.1:
- resolution: {integrity: sha512-QWBrQsMpH7gPr965dsKD/3cKWiNoTjpATQf++Xq63N6sKRGMwlVXz41O1IZTMfZQgBctD/K5Zt06+/I6pP6+HA==}
-
- lightningcss-android-arm64@1.32.0:
- resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm64]
- os: [android]
-
- lightningcss-android-arm64@1.33.0:
- resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm64]
- os: [android]
-
- lightningcss-darwin-arm64@1.32.0:
- resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm64]
- os: [darwin]
-
- lightningcss-darwin-arm64@1.33.0:
- resolution: {integrity: sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm64]
- os: [darwin]
-
- lightningcss-darwin-x64@1.32.0:
- resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==}
- engines: {node: '>= 12.0.0'}
- cpu: [x64]
- os: [darwin]
-
- lightningcss-darwin-x64@1.33.0:
- resolution: {integrity: sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==}
- engines: {node: '>= 12.0.0'}
- cpu: [x64]
- os: [darwin]
-
- lightningcss-freebsd-x64@1.32.0:
- resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==}
- engines: {node: '>= 12.0.0'}
- cpu: [x64]
- os: [freebsd]
-
- lightningcss-freebsd-x64@1.33.0:
- resolution: {integrity: sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==}
- engines: {node: '>= 12.0.0'}
- cpu: [x64]
- os: [freebsd]
-
- lightningcss-linux-arm-gnueabihf@1.32.0:
- resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm]
- os: [linux]
-
- lightningcss-linux-arm-gnueabihf@1.33.0:
- resolution: {integrity: sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm]
- os: [linux]
-
- lightningcss-linux-arm64-gnu@1.32.0:
- resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm64]
- os: [linux]
- libc: [glibc]
-
- lightningcss-linux-arm64-gnu@1.33.0:
- resolution: {integrity: sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm64]
- os: [linux]
- libc: [glibc]
-
- lightningcss-linux-arm64-musl@1.32.0:
- resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm64]
- os: [linux]
- libc: [musl]
-
- lightningcss-linux-arm64-musl@1.33.0:
- resolution: {integrity: sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm64]
- os: [linux]
- libc: [musl]
-
- lightningcss-linux-x64-gnu@1.32.0:
- resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==}
- engines: {node: '>= 12.0.0'}
- cpu: [x64]
- os: [linux]
- libc: [glibc]
-
- lightningcss-linux-x64-gnu@1.33.0:
- resolution: {integrity: sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==}
- engines: {node: '>= 12.0.0'}
- cpu: [x64]
- os: [linux]
- libc: [glibc]
-
- lightningcss-linux-x64-musl@1.32.0:
- resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==}
- engines: {node: '>= 12.0.0'}
- cpu: [x64]
- os: [linux]
- libc: [musl]
-
- lightningcss-linux-x64-musl@1.33.0:
- resolution: {integrity: sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==}
- engines: {node: '>= 12.0.0'}
- cpu: [x64]
- os: [linux]
- libc: [musl]
-
- lightningcss-win32-arm64-msvc@1.32.0:
- resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm64]
- os: [win32]
-
- lightningcss-win32-arm64-msvc@1.33.0:
- resolution: {integrity: sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==}
- engines: {node: '>= 12.0.0'}
- cpu: [arm64]
- os: [win32]
-
- lightningcss-win32-x64-msvc@1.32.0:
- resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==}
- engines: {node: '>= 12.0.0'}
- cpu: [x64]
- os: [win32]
-
- lightningcss-win32-x64-msvc@1.33.0:
- resolution: {integrity: sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==}
- engines: {node: '>= 12.0.0'}
- cpu: [x64]
- os: [win32]
-
- lightningcss@1.32.0:
- resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==}
- engines: {node: '>= 12.0.0'}
-
- lightningcss@1.33.0:
- resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==}
- engines: {node: '>= 12.0.0'}
-
- lru-cache@5.1.1:
- resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
-
- lucide-react@0.577.0:
- resolution: {integrity: sha512-4LjoFv2eEPwYDPg/CUdBJQSDfPyzXCRrVW1X7jrx/trgxnxkHFjnVZINbzvzxjN70dxychOfg+FTYwBiS3pQ5A==}
- peerDependencies:
- react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
-
- magic-string@0.30.21:
- resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
-
- marked@18.0.14:
- resolution: {integrity: sha512-mBHK6FBHuBAlhgRe88w9F0O1AbwwXJUcQibUbC/QcdTbVGAD7aWza+xt3N6oT/jCZx3/OMeS+8rnuiHZcQ9s7A==}
- engines: {node: '>= 20'}
- hasBin: true
-
- ms@2.1.3:
- resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
-
- nanoid@3.3.19:
- resolution: {integrity: sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==}
- engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
- hasBin: true
-
- nanostores@1.5.4:
- resolution: {integrity: sha512-4UXY7OAJEK0Y6V3SudBU7cXjAzTDc189R78dDOh0Xbm19gpKYto6WizSg58LJf12lTsRxKSLGyE117OiLpM4DQ==}
- engines: {node: ^20.0.0 || >=22.0.0}
-
- nf3@0.3.24:
- resolution: {integrity: sha512-HxLK4bo+5jNsEETZp4w3tJblHOA9MCBY14IN9nZJJV8JDxt9yNIYxuBuLMjTAR5GFa3HL61+8VQDUrXv3/C8fw==}
-
- nitro@3.0.260610-beta:
- resolution: {integrity: sha512-KPb4L5yaF/Rx/xoGMpgHRJvZhbhGiqbRKOwwPLCH9jKTKTsEUHLjnJas85AeCzaswqa8Wi52eQBtRsODC4PS0Q==}
- engines: {node: ^20.19.0 || >=22.12.0}
- hasBin: true
- peerDependencies:
- '@vercel/queue': ^0.3.0
- dotenv: '*'
- giget: '*'
- jiti: ^2.7.0
- rollup: ^4.61.1
- vite: ^7 || ^8
- xml2js: ^0.6.2
- zephyr-agent: ^0.2.0
- peerDependenciesMeta:
- '@vercel/queue':
- optional: true
- dotenv:
- optional: true
- giget:
- optional: true
- jiti:
- optional: true
- rollup:
- optional: true
- vite:
- optional: true
- xml2js:
- optional: true
- zephyr-agent:
- optional: true
-
- node-releases@2.0.57:
- resolution: {integrity: sha512-kQK9LGGFiHtrWiNhZtA7Qbw17AQz+dmsEKODRIVTXA9+e5MS/2gZEBhYJt13GrAz5/IOZKddH/0Z3TP/Zgo+yw==}
- engines: {node: '>=18'}
-
- ocache@0.1.5:
- resolution: {integrity: sha512-kNNnkkVQup/QDvmTz8Q84wc2ntiyoVHDxa6eHWKt5qdGAmFRBIxy83rxgCYEjW0x06UJ9E3P6VgM2yY4rOBH4w==}
-
- ofetch@2.0.0-alpha.3:
- resolution: {integrity: sha512-zpYTCs2byOuft65vI3z43Dd6iSdFbOZZLb9/d21aCpx2rGastVU9dOCv0lu4ykc1Ur1anAYjDi3SUvR0vq50JA==}
-
- ohash@2.0.12:
- resolution: {integrity: sha512-65S/5gk9YSsaRjcyf7Nfa6h/d3E8/1gslpXfI4W7Dxn/oap8IKRuNT5VXkLQ1YFKIEg4apRY4Pj6aiwFzrDdmw==}
-
- oxc-parser@0.120.0:
- resolution: {integrity: sha512-WyPWZlcIm+Fkte63FGfgFB8mAAk33aH9h5N9lphXVOHSXEBFFsmYdOBedVKly363aWABjZdaj/m9lBfEY4wt+w==}
- engines: {node: ^20.19.0 || >=22.12.0}
-
- path-key@3.1.1:
- resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
- engines: {node: '>=8'}
-
- pathe@2.0.3:
- resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
-
- pg-cloudflare@1.4.1:
- resolution: {integrity: sha512-6PQbsFWZcp9EmJEwy5cGQ2La+AMWpP46lgbb8X+U/XsHIUweYDNCpeuKck5RxL2MdVFi7krbbEi5nX4Zh7JhrQ==}
-
- pg-connection-string@2.14.1:
- resolution: {integrity: sha512-qR3kGNPBLpCNtz0evbKA0Y/MRFXwSSdT+pTJvYp/bXTcReZbvX1kzF0IyTc1QnxqF7AZbOeBhNL8R5mYQZV/MA==}
-
- pg-int8@1.0.1:
- resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==}
- engines: {node: '>=4.0.0'}
-
- pg-pool@3.14.0:
- resolution: {integrity: sha512-gKtPkFdQPU3DksooVLi9LsjZxrsBUZIpa+7aVx+LV5pNh0KzP4Zleud2po+ConrxbuXGBJ6Hfer6hdgpIBpBaw==}
- peerDependencies:
- pg: '>=8.0'
-
- pg-protocol@1.16.1:
- resolution: {integrity: sha512-p9VOFMiHB/ZbJATetbg+99PxssTVSQRnyuPSQ67mN1+1KBOjZaZ83ZQzltnxPhJwSsC3nwVjJ10DVJlerbFzLg==}
-
- pg-types@2.2.0:
- resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==}
- engines: {node: '>=4'}
-
- pg@8.23.1:
- resolution: {integrity: sha512-aL96AHANtWjPLDOLqnhx+ngp9+UK7ETEU8VJrDCGvsSSi/mGLcWYsS6Herg7lmaBJe4uwrfqsa7gTEFaSizDoQ==}
- engines: {node: '>= 16.0.0'}
- peerDependencies:
- pg-native: '>=3.0.1'
- peerDependenciesMeta:
- pg-native:
- optional: true
-
- pgpass@1.0.5:
- resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==}
-
- picocolors@1.1.1:
- resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
-
- picomatch@4.0.7:
- resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==}
- engines: {node: '>=12'}
-
- pkce-challenge@5.0.1:
- resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==}
- engines: {node: '>=16.20.0'}
-
- postcss-selector-parser@6.0.10:
- resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==}
- engines: {node: '>=4'}
-
- postcss@8.5.28:
- resolution: {integrity: sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==}
- engines: {node: ^10 || ^12 || >=14}
-
- postgres-array@2.0.0:
- resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==}
- engines: {node: '>=4'}
-
- postgres-bytea@1.0.1:
- resolution: {integrity: sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==}
- engines: {node: '>=0.10.0'}
-
- postgres-date@1.0.7:
- resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==}
- engines: {node: '>=0.10.0'}
-
- postgres-interval@1.2.0:
- resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==}
- engines: {node: '>=0.10.0'}
-
- posthog-js@1.436.1:
- resolution: {integrity: sha512-+uPcck+hcaBbjtxBwOtiiZ9BcBXyJmewumUMVP5MrIZO36BHHZ+SzvHTxFsA5soNbPo2fuLppsWfpNnuSjbNeA==}
- peerDependencies:
- '@types/react': '>=16.8.0'
- react: '>=16.8.0'
- peerDependenciesMeta:
- '@types/react':
- optional: true
- react:
- optional: true
-
- posthog-node@5.55.0:
- resolution: {integrity: sha512-8dFtlDTqs0CKGZ8t4mUnk4NdShAgzru3B9D0MfM/NTBzlRyAjctivzWINLtMLRQxYjvgBohxy7RTwiQf4mPycQ==}
- engines: {node: ^20.20.0 || >=22.22.0}
- peerDependencies:
- rxjs: ^7.0.0
- peerDependenciesMeta:
- rxjs:
- optional: true
-
- preact@10.29.8:
- resolution: {integrity: sha512-ej2aVZ+vZ8WO7tvlQWRM9N63A0KzF9q4mWJfDUHgYaIofWY9hu74QdnQrjoPMmZi2/nZ5gN0bJCQF49xQqx09Q==}
- peerDependencies:
- preact-render-to-string: '>=5'
- peerDependenciesMeta:
- preact-render-to-string:
- optional: true
-
- prettier@3.9.9:
- resolution: {integrity: sha512-Z/CJHIkdujO/OtN7nXUii0Rf3VT5SRuhjBA82Xvu2XhBUgX3nhP67T0LHceBdQLex7OOFGTox+Q5Yg8Jk2Qivg==}
- engines: {node: '>=14'}
- hasBin: true
-
- query-selector-shadow-dom@1.0.1:
- resolution: {integrity: sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw==}
-
- react-dom@19.3.0:
- resolution: {integrity: sha512-JDk8dgif51OjFoDE70+OT9ICyYr+69HlmihNwp1+Nsfbna3t5sIiCa9ZJktDmQ4/1b/rn26hIAR2uYXDMr5r0Q==}
- peerDependencies:
- react: ^19.3.0
-
- react-is@19.3.0:
- resolution: {integrity: sha512-UpMYezM4v5/18F28aC66AEsjXIgE02kyEMH6yLdgLXu/UTfa1Ntwck/nNLrbqJsEXW7gPb0coNO9FQse9WTovA==}
-
- react-redux@9.3.0:
- resolution: {integrity: sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g==}
- peerDependencies:
- '@types/react': ^18.2.25 || ^19
- react: ^18.0 || ^19
- redux: ^5.0.0
- peerDependenciesMeta:
- '@types/react':
- optional: true
- redux:
- optional: true
-
- react-remove-scroll-bar@2.3.8:
- resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==}
- engines: {node: '>=10'}
- peerDependencies:
- '@types/react': '*'
- react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
- react-remove-scroll@2.7.2:
- resolution: {integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==}
- engines: {node: '>=10'}
- peerDependencies:
- '@types/react': '*'
- react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
- react-style-singleton@2.2.3:
- resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==}
- engines: {node: '>=10'}
- peerDependencies:
- '@types/react': '*'
- react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
- react@19.3.0:
- resolution: {integrity: sha512-E8LUcbtBWt20bbl2YoHfx4ZDBdxVTfOKtCZn9cDSJ4l6/nuoApcpIBcj47t2wZoVX8g2ZHuMHbiShgCR1T5Sog==}
- engines: {node: '>=0.10.0'}
-
- readdirp@5.1.1:
- resolution: {integrity: sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==}
- engines: {node: '>= 20.19.0'}
-
- recharts@3.8.0:
- resolution: {integrity: sha512-Z/m38DX3L73ExO4Tpc9/iZWHmHnlzWG4njQbxsF5aSjwqmHNDDIm0rdEBArkwsBvR8U6EirlEHiQNYWCVh9sGQ==}
- engines: {node: '>=18'}
- peerDependencies:
- react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
- react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
- react-is: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
-
- redux-thunk@3.1.0:
- resolution: {integrity: sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==}
- peerDependencies:
- redux: ^5.0.0
-
- redux@5.0.1:
- resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==}
-
- require-directory@2.1.1:
- resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
- engines: {node: '>=0.10.0'}
-
- reselect@5.1.1:
- resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==}
-
- reselect@5.3.0:
- resolution: {integrity: sha512-XGoLeRAVzUTcJ1qkxPQhDJyIZ5d6zzZD9nT7AEZOaaU9UbWclhycElmhO+VD5bFeLuzhPBaOV2oXC8uG35ZSpg==}
-
- resolve-pkg-maps@1.0.0:
- resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
-
- rolldown@1.2.12:
- resolution: {integrity: sha512-8wafseiaG80xmXSfqidUNqZcylTlhmPZZt+za2m+js2sFZ8dTNlhIOV2WcbIPx2hgwPBJpEUGFAMZ9bgBBLTSQ==}
- engines: {node: ^20.19.0 || >=22.12.0}
- hasBin: true
-
- rou3@0.8.1:
- resolution: {integrity: sha512-ePa+XGk00/3HuCqrEnK3LxJW7I0SdNg6EFzKUJG73hMAdDcOUC/i/aSz7LSDwLrGr33kal/rqOGydzwl6U7zBA==}
-
- rou3@0.9.2:
- resolution: {integrity: sha512-3SOzvaAg8rkHrXtRjpCvCvbyO5to9oOO27Z/XqHEYXfMRVSw/qMIVdmaOk9W2lcRLtR6dlqTjo9hDeJk70QBYQ==}
-
- scheduler@0.28.0:
- resolution: {integrity: sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==}
-
- semver@6.3.1:
- resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
- hasBin: true
-
- seroval-plugins@1.5.6:
- resolution: {integrity: sha512-HXuLAX2pu/UByPpaeo/TaMfvMIi+1QqIoPJYCcAtU8QkVNwgR6MPlGuCQTErV1JwraaMbYaWVIBX7mppzGLATQ==}
- engines: {node: '>=10'}
- peerDependencies:
- seroval: ^1.0
-
- seroval-plugins@1.6.8:
- resolution: {integrity: sha512-N7mWAMydj89EnYTHtRpS3LBrAz3J9O6oVrqpuXuvlAHfAUG8WEKqtbAd7SBiJNY5NfCAFhSdyAh7wI4Shjqy4g==}
- engines: {node: '>=10'}
- peerDependencies:
- seroval: ^1.0
-
- seroval@1.5.6:
- resolution: {integrity: sha512-rVQVWjjSvlINzaQPZH5JFqsqEsIWdTxY3iJZCnTL/5gQbXIRooVZKI60tVCkOVfzcRPejboxO2t0P89dg5mQaA==}
- engines: {node: '>=10'}
-
- seroval@1.6.8:
- resolution: {integrity: sha512-HlSgSAkTk4EqHcje1ptJjfZi1YDv5KbhVJ/d3P7T/nAXua2VmDu+AKDX5VTdFfZf48nDkWB2TKYt0DrCSa+3wg==}
- engines: {node: '>=10'}
-
- set-cookie-parser@3.1.2:
- resolution: {integrity: sha512-5/r/lTwbJ3zQ+qwdUFZYeRNqda7P5HD8zQKqlSjdGt1/S0cjLAphHusj4Y58ahDtWn/g32xrIS58/ikOvwl0Lw==}
-
- shebang-command@2.0.0:
- resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
- engines: {node: '>=8'}
-
- shebang-regex@3.0.0:
- resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
- engines: {node: '>=8'}
-
- shell-quote@1.12.0:
- resolution: {integrity: sha512-PcByqNyT/38F2kDNi006HAMRJaULuBzq/FOsw3qdZvX/GA9W/jamDaRskgHjubHiftXK5sIFxLNkvrXUwcof6Q==}
- engines: {node: '>= 0.4'}
-
- simple-icons@16.34.0:
- resolution: {integrity: sha512-UTxKn0PVspk84B2hHF3Dqiqht1yDjJmDc/t4cO7PyCQxCMk6OjEu95pnpGjhLaGeQ4qBrGASbefTIe/+czrX7g==}
- engines: {node: '>=0.12.18'}
-
- solid-js@1.9.15:
- resolution: {integrity: sha512-EeiY2xfpZJqPLjXspVEKjAII4yv8NyG//NxZ3IpOFHdUNnnTyL0uJOeS9LWGvA7cFCz5y94cjFwYlmw5Luncsg==}
-
- source-map-js@1.2.2:
- resolution: {integrity: sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==}
- engines: {node: '>=0.10.0'}
-
- source-map-support@0.5.21:
- resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
-
- source-map@0.6.1:
- resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
- engines: {node: '>=0.10.0'}
-
- source-map@0.7.6:
- resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==}
- engines: {node: '>= 12'}
-
- split2@4.2.0:
- resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
- engines: {node: '>= 10.x'}
-
- srvx@0.11.22:
- resolution: {integrity: sha512-LqZxxBDMKuMAZzFzJnDCkFOrs9MZQZr0LvHiO/SuSZVdQaXD7xQ5UWTUxheJrQPve1qk9MG2B/yttUvJxw8egQ==}
- engines: {node: '>=20.16.0'}
- hasBin: true
-
- string-width@4.2.3:
- resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
- engines: {node: '>=8'}
-
- strip-ansi@6.0.1:
- resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
- engines: {node: '>=8'}
-
- tailwindcss@4.3.3:
- resolution: {integrity: sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==}
-
- tapable@2.3.3:
- resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==}
- engines: {node: '>=6'}
-
- tiny-invariant@1.3.3:
- resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
-
- tinyglobby@0.2.17:
- resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==}
- engines: {node: '>=12.0.0'}
-
- tslib@2.8.1:
- resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
-
- tsx@4.23.15:
- resolution: {integrity: sha512-Yiex1Ovn8z2xPpOWckIiysV1SSyRMY9BkLF++q0yKiDxCqRhosKfMg3janKkiLBwZ5c/YryloKwGZcrEmtwxKw==}
- engines: {node: '>=18.0.0'}
- hasBin: true
-
- tw-animate-css@1.4.0:
- resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==}
-
- typescript@6.0.3:
- resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==}
- engines: {node: '>=14.17'}
- hasBin: true
-
- ufo@1.6.4:
- resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==}
-
- undici-types@6.21.0:
- resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
-
- unenv@2.0.0-rc.24:
- resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==}
-
- unplugin@3.4.0:
- resolution: {integrity: sha512-9skdIFlCsPdFV7wUfZxNsFInlW+7nJmGu2gkTu0OUhF56aXGsHab9x52/QhdJ4lC7ZDPWTxbiC4ANqVlsuaW3w==}
- engines: {node: ^20.19.0 || >=22.12.0}
- peerDependencies:
- '@farmfe/core': '*'
- '@rsbuild/core': '*'
- '@rspack/core': '*'
- bun-types-no-globals: '*'
- esbuild: '*'
- rolldown: '*'
- rollup: '*'
- unloader: '*'
- vite: '*'
- webpack: '*'
- peerDependenciesMeta:
- '@farmfe/core':
- optional: true
- '@rsbuild/core':
- optional: true
- '@rspack/core':
- optional: true
- bun-types-no-globals:
- optional: true
- esbuild:
- optional: true
- rolldown:
- optional: true
- rollup:
- optional: true
- unloader:
- optional: true
- vite:
- optional: true
- webpack:
- optional: true
-
- unstorage@2.0.0-alpha.7:
- resolution: {integrity: sha512-ELPztchk2zgFJnakyodVY3vJWGW9jy//keJ32IOJVGUMyaPydwcA1FtVvWqT0TNRch9H+cMNEGllfVFfScImog==}
- peerDependencies:
- '@azure/app-configuration': ^1.11.0
- '@azure/cosmos': ^4.9.1
- '@azure/data-tables': ^13.3.2
- '@azure/identity': ^4.13.0
- '@azure/keyvault-secrets': ^4.10.0
- '@azure/storage-blob': ^12.31.0
- '@capacitor/preferences': ^6 || ^7 || ^8
- '@deno/kv': '>=0.13.0'
- '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0
- '@planetscale/database': ^1.19.0
- '@upstash/redis': ^1.36.2
- '@vercel/blob': '>=0.27.3'
- '@vercel/functions': ^2.2.12 || ^3.0.0
- '@vercel/kv': ^1.0.1
- aws4fetch: ^1.0.20
- chokidar: ^4 || ^5
- db0: '>=0.3.4'
- idb-keyval: ^6.2.2
- ioredis: ^5.9.3
- lru-cache: ^11.2.6
- mongodb: ^6 || ^7
- ofetch: '*'
- uploadthing: ^7.7.4
- peerDependenciesMeta:
- '@azure/app-configuration':
- optional: true
- '@azure/cosmos':
- optional: true
- '@azure/data-tables':
- optional: true
- '@azure/identity':
- optional: true
- '@azure/keyvault-secrets':
- optional: true
- '@azure/storage-blob':
- optional: true
- '@capacitor/preferences':
- optional: true
- '@deno/kv':
- optional: true
- '@netlify/blobs':
- optional: true
- '@planetscale/database':
- optional: true
- '@upstash/redis':
- optional: true
- '@vercel/blob':
- optional: true
- '@vercel/functions':
- optional: true
- '@vercel/kv':
- optional: true
- aws4fetch:
- optional: true
- chokidar:
- optional: true
- db0:
- optional: true
- idb-keyval:
- optional: true
- ioredis:
- optional: true
- lru-cache:
- optional: true
- mongodb:
- optional: true
- ofetch:
- optional: true
- uploadthing:
- optional: true
-
- update-browserslist-db@1.3.3:
- resolution: {integrity: sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==}
- hasBin: true
- peerDependencies:
- browserslist: '>= 4.21.0'
-
- use-callback-ref@1.3.3:
- resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==}
- engines: {node: '>=10'}
- peerDependencies:
- '@types/react': '*'
- react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
- use-sidecar@1.1.3:
- resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==}
- engines: {node: '>=10'}
- peerDependencies:
- '@types/react': '*'
- react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
- peerDependenciesMeta:
- '@types/react':
- optional: true
-
- use-sync-external-store@1.7.0:
- resolution: {integrity: sha512-6L+EeigHMQhdaIPNIFUKwfWJSwWFQ8gJbJ2DLOs5sDIegTwR9fRxvnM3uciHKjIZhFz+KAv2emhWMRvDmMcY8A==}
- peerDependencies:
- react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
-
- util-deprecate@1.0.2:
- resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
-
- victory-vendor@37.3.6:
- resolution: {integrity: sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==}
-
- vite@8.3.2:
- resolution: {integrity: sha512-SQr1x6W5vVSbROg7vsyXIaxK9b0G7zsT68acdWWRmnBUsgDieLCRG+Rep9WdZgcposvv/GSnr4GUUBqB3vXq6w==}
- engines: {node: ^20.19.0 || >=22.12.0}
- hasBin: true
- peerDependencies:
- '@types/node': ^20.19.0 || >=22.12.0
- '@vitejs/devtools': ^0.7.1
- esbuild: ^0.27.0 || ^0.28.0
- jiti: '>=1.21.0'
- less: ^4.0.0
- sass: ^1.70.0
- sass-embedded: ^1.70.0
- stylus: '>=0.54.8'
- sugarss: ^5.0.0
- terser: ^5.16.0
- tsx: ^4.8.1
- yaml: ^2.4.2
- peerDependenciesMeta:
- '@types/node':
- optional: true
- '@vitejs/devtools':
- optional: true
- esbuild:
- optional: true
- jiti:
- optional: true
- less:
- optional: true
- sass:
- optional: true
- sass-embedded:
- optional: true
- stylus:
- optional: true
- sugarss:
- optional: true
- terser:
- optional: true
- tsx:
- optional: true
- yaml:
- optional: true
-
- vitefu@1.1.3:
- resolution: {integrity: sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==}
- peerDependencies:
- vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0
- peerDependenciesMeta:
- vite:
- optional: true
-
- web-vitals@6.2.1:
- resolution: {integrity: sha512-rLcLXA2sx6+9dE88NHFubwTtGxpK4yYBLj6qHPdFoCaLr0cXGb4efOqtKLlm4loGA4OEKHIQKMKzZkKyOh5ctw==}
-
- web-vitals@6.2.3:
- resolution: {integrity: sha512-Dmy+vdO1UPMqXiAtZSNayhl4f794Bxfd94W4HIj2HlYtczEQfEOon969memlcpcHrTuOKLa5baFjX7WbgmOq+A==}
-
- webpack-virtual-modules@0.6.2:
- resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==}
-
- which@2.0.2:
- resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
- engines: {node: '>= 8'}
- hasBin: true
-
- wrap-ansi@7.0.0:
- resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
- engines: {node: '>=10'}
-
- ws@8.22.0:
- resolution: {integrity: sha512-Ydggc987+RO0AnWtZ/7Wq9FtNvcrL1b/RO0ud9mWjUPgDrsAAwQSF51sm2hm1XofbU/4jkpGEsLFsZZxU+1DOg==}
- engines: {node: '>=10.0.0'}
- peerDependencies:
- bufferutil: ^4.0.1
- utf-8-validate: '>=5.0.2'
- peerDependenciesMeta:
- bufferutil:
- optional: true
- utf-8-validate:
- optional: true
-
- xmlbuilder2@4.0.3:
- resolution: {integrity: sha512-bx8Q1STctnNaaDymWnkfQLKofs0mGNN7rLLapJlGuV3VlvegD7Ls4ggMjE3aUSWItCCzU0PEv45lI87iSigiCA==}
- engines: {node: '>=20.0'}
-
- xtend@4.0.2:
- resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
- engines: {node: '>=0.4'}
-
- y18n@5.0.8:
- resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
- engines: {node: '>=10'}
-
- yallist@3.1.1:
- resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
-
- yargs-parser@21.1.1:
- resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
- engines: {node: '>=12'}
-
- yargs@17.7.3:
- resolution: {integrity: sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==}
- engines: {node: '>=12'}
-
- zod@4.6.5:
- resolution: {integrity: sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==}
-
-snapshots:
-
- '@babel/code-frame@7.29.7':
- dependencies:
- '@babel/helper-validator-identifier': 7.29.7
- js-tokens: 4.0.0
- picocolors: 1.1.1
-
- '@babel/compat-data@7.29.7': {}
-
- '@babel/core@7.29.7':
- dependencies:
- '@babel/code-frame': 7.29.7
- '@babel/generator': 7.29.8
- '@babel/helper-compilation-targets': 7.29.7
- '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7)
- '@babel/helpers': 7.29.7
- '@babel/parser': 7.29.9
- '@babel/template': 7.29.7
- '@babel/traverse': 7.29.8
- '@babel/types': 7.29.8
- '@jridgewell/remapping': 2.3.5
- convert-source-map: 2.0.0
- debug: 4.4.3
- gensync: 1.0.0-beta.2
- json5: 2.2.3
- semver: 6.3.1
- transitivePeerDependencies:
- - supports-color
-
- '@babel/generator@7.29.8':
- dependencies:
- '@babel/parser': 7.29.9
- '@babel/types': 7.29.8
- '@jridgewell/gen-mapping': 0.3.13
- '@jridgewell/trace-mapping': 0.3.31
- jsesc: 3.1.0
-
- '@babel/helper-compilation-targets@7.29.7':
- dependencies:
- '@babel/compat-data': 7.29.7
- '@babel/helper-validator-option': 7.29.7
- browserslist: 4.29.3
- lru-cache: 5.1.1
- semver: 6.3.1
-
- '@babel/helper-globals@7.29.7': {}
-
- '@babel/helper-module-imports@7.29.7':
- dependencies:
- '@babel/traverse': 7.29.8
- '@babel/types': 7.29.8
- transitivePeerDependencies:
- - supports-color
-
- '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)':
- dependencies:
- '@babel/core': 7.29.7
- '@babel/helper-module-imports': 7.29.7
- '@babel/helper-validator-identifier': 7.29.7
- '@babel/traverse': 7.29.8
- transitivePeerDependencies:
- - supports-color
-
- '@babel/helper-string-parser@7.29.7': {}
-
- '@babel/helper-validator-identifier@7.29.7': {}
-
- '@babel/helper-validator-option@7.29.7': {}
-
- '@babel/helpers@7.29.7':
- dependencies:
- '@babel/template': 7.29.7
- '@babel/types': 7.29.8
-
- '@babel/parser@7.29.9':
- dependencies:
- '@babel/types': 7.29.8
-
- '@babel/runtime@7.29.7': {}
-
- '@babel/template@7.29.7':
- dependencies:
- '@babel/code-frame': 7.29.7
- '@babel/parser': 7.29.9
- '@babel/types': 7.29.8
-
- '@babel/traverse@7.29.8':
- dependencies:
- '@babel/code-frame': 7.29.7
- '@babel/generator': 7.29.8
- '@babel/helper-globals': 7.29.7
- '@babel/parser': 7.29.9
- '@babel/template': 7.29.7
- '@babel/types': 7.29.8
- debug: 4.4.3
- transitivePeerDependencies:
- - supports-color
-
- '@babel/types@7.29.8':
- dependencies:
- '@babel/helper-string-parser': 7.29.7
- '@babel/helper-validator-identifier': 7.29.7
-
- '@base-ui/react@1.8.0(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)':
- dependencies:
- '@babel/runtime': 7.29.7
- '@base-ui/utils': 0.4.0(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
- '@floating-ui/react-dom': 2.1.9(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
- '@floating-ui/utils': 0.2.12
- react: 19.3.0
- react-dom: 19.3.0(react@19.3.0)
- use-sync-external-store: 1.7.0(react@19.3.0)
- optionalDependencies:
- '@types/react': 19.3.0
-
- '@base-ui/utils@0.4.0(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)':
- dependencies:
- '@babel/runtime': 7.29.7
- '@floating-ui/utils': 0.2.12
- react: 19.3.0
- react-dom: 19.3.0(react@19.3.0)
- reselect: 5.3.0
- use-sync-external-store: 1.7.0(react@19.3.0)
- optionalDependencies:
- '@types/react': 19.3.0
-
- '@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.4)':
- dependencies:
- '@better-auth/utils': 0.4.2
- '@better-fetch/fetch': 1.3.2
- '@opentelemetry/semantic-conventions': 1.43.0
- '@standard-schema/spec': 1.1.0
- better-call: 1.4.0(zod@4.6.5)
- jose: 6.2.12
- kysely: 0.29.6
- nanostores: 1.5.4
- zod: 4.6.5
- optionalDependencies:
- '@opentelemetry/api': 1.9.1
-
- '@better-auth/drizzle-adapter@1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.4))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.3(@electric-sql/pglite@0.5.8)(@opentelemetry/api@1.9.1)(@types/pg@8.23.1)(kysely@0.29.6)(pg@8.23.1))':
- dependencies:
- '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.4)
- '@better-auth/utils': 0.4.2
- optionalDependencies:
- drizzle-orm: 0.45.3(@electric-sql/pglite@0.5.8)(@opentelemetry/api@1.9.1)(@types/pg@8.23.1)(kysely@0.29.6)(pg@8.23.1)
-
- '@better-auth/kysely-adapter@1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.4))(@better-auth/utils@0.4.2)(kysely@0.29.6)':
- dependencies:
- '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.4)
- '@better-auth/utils': 0.4.2
- optionalDependencies:
- kysely: 0.29.6
-
- '@better-auth/memory-adapter@1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.4))(@better-auth/utils@0.4.2)':
- dependencies:
- '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.4)
- '@better-auth/utils': 0.4.2
-
- '@better-auth/mongo-adapter@1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.4))(@better-auth/utils@0.4.2)':
- dependencies:
- '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.4)
- '@better-auth/utils': 0.4.2
-
- '@better-auth/prisma-adapter@1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.4))(@better-auth/utils@0.4.2)':
- dependencies:
- '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.4)
- '@better-auth/utils': 0.4.2
-
- '@better-auth/telemetry@1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.4))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)':
- dependencies:
- '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.4)
- '@better-auth/utils': 0.4.2
- '@better-fetch/fetch': 1.3.2
-
- '@better-auth/utils@0.4.2':
- dependencies:
- '@noble/hashes': 2.4.0
-
- '@better-auth/utils@0.5.0':
- dependencies:
- '@noble/hashes': 2.4.0
-
- '@better-fetch/fetch@1.3.2': {}
-
- '@biomejs/biome@2.4.5':
- optionalDependencies:
- '@biomejs/cli-darwin-arm64': 2.4.5
- '@biomejs/cli-darwin-x64': 2.4.5
- '@biomejs/cli-linux-arm64': 2.4.5
- '@biomejs/cli-linux-arm64-musl': 2.4.5
- '@biomejs/cli-linux-x64': 2.4.5
- '@biomejs/cli-linux-x64-musl': 2.4.5
- '@biomejs/cli-win32-arm64': 2.4.5
- '@biomejs/cli-win32-x64': 2.4.5
-
- '@biomejs/cli-darwin-arm64@2.4.5':
- optional: true
-
- '@biomejs/cli-darwin-x64@2.4.5':
- optional: true
-
- '@biomejs/cli-linux-arm64-musl@2.4.5':
- optional: true
-
- '@biomejs/cli-linux-arm64@2.4.5':
- optional: true
-
- '@biomejs/cli-linux-x64-musl@2.4.5':
- optional: true
-
- '@biomejs/cli-linux-x64@2.4.5':
- optional: true
-
- '@biomejs/cli-win32-arm64@2.4.5':
- optional: true
-
- '@biomejs/cli-win32-x64@2.4.5':
- optional: true
-
- '@drizzle-team/brocli@0.10.2': {}
-
- '@electric-sql/pglite@0.5.8': {}
-
- '@emnapi/core@1.11.3':
- dependencies:
- '@emnapi/wasi-threads': 1.2.3
- tslib: 2.8.1
- optional: true
-
- '@emnapi/runtime@1.11.3':
- dependencies:
- tslib: 2.8.1
- optional: true
-
- '@emnapi/wasi-threads@1.2.3':
- dependencies:
- tslib: 2.8.1
- optional: true
-
- '@esbuild-kit/core-utils@3.3.2':
- dependencies:
- esbuild: 0.18.20
- source-map-support: 0.5.21
-
- '@esbuild-kit/esm-loader@2.6.5':
- dependencies:
- '@esbuild-kit/core-utils': 3.3.2
- get-tsconfig: 4.14.3
-
- '@esbuild/aix-ppc64@0.25.12':
- optional: true
-
- '@esbuild/aix-ppc64@0.28.2':
- optional: true
-
- '@esbuild/android-arm64@0.18.20':
- optional: true
-
- '@esbuild/android-arm64@0.25.12':
- optional: true
-
- '@esbuild/android-arm64@0.28.2':
- optional: true
-
- '@esbuild/android-arm@0.18.20':
- optional: true
-
- '@esbuild/android-arm@0.25.12':
- optional: true
-
- '@esbuild/android-arm@0.28.2':
- optional: true
-
- '@esbuild/android-x64@0.18.20':
- optional: true
-
- '@esbuild/android-x64@0.25.12':
- optional: true
-
- '@esbuild/android-x64@0.28.2':
- optional: true
-
- '@esbuild/darwin-arm64@0.18.20':
- optional: true
-
- '@esbuild/darwin-arm64@0.25.12':
- optional: true
-
- '@esbuild/darwin-arm64@0.28.2':
- optional: true
-
- '@esbuild/darwin-x64@0.18.20':
- optional: true
-
- '@esbuild/darwin-x64@0.25.12':
- optional: true
-
- '@esbuild/darwin-x64@0.28.2':
- optional: true
-
- '@esbuild/freebsd-arm64@0.18.20':
- optional: true
-
- '@esbuild/freebsd-arm64@0.25.12':
- optional: true
-
- '@esbuild/freebsd-arm64@0.28.2':
- optional: true
-
- '@esbuild/freebsd-x64@0.18.20':
- optional: true
-
- '@esbuild/freebsd-x64@0.25.12':
- optional: true
-
- '@esbuild/freebsd-x64@0.28.2':
- optional: true
-
- '@esbuild/linux-arm64@0.18.20':
- optional: true
-
- '@esbuild/linux-arm64@0.25.12':
- optional: true
-
- '@esbuild/linux-arm64@0.28.2':
- optional: true
-
- '@esbuild/linux-arm@0.18.20':
- optional: true
-
- '@esbuild/linux-arm@0.25.12':
- optional: true
-
- '@esbuild/linux-arm@0.28.2':
- optional: true
-
- '@esbuild/linux-ia32@0.18.20':
- optional: true
-
- '@esbuild/linux-ia32@0.25.12':
- optional: true
-
- '@esbuild/linux-ia32@0.28.2':
- optional: true
-
- '@esbuild/linux-loong64@0.18.20':
- optional: true
-
- '@esbuild/linux-loong64@0.25.12':
- optional: true
-
- '@esbuild/linux-loong64@0.28.2':
- optional: true
-
- '@esbuild/linux-mips64el@0.18.20':
- optional: true
-
- '@esbuild/linux-mips64el@0.25.12':
- optional: true
-
- '@esbuild/linux-mips64el@0.28.2':
- optional: true
-
- '@esbuild/linux-ppc64@0.18.20':
- optional: true
-
- '@esbuild/linux-ppc64@0.25.12':
- optional: true
-
- '@esbuild/linux-ppc64@0.28.2':
- optional: true
-
- '@esbuild/linux-riscv64@0.18.20':
- optional: true
-
- '@esbuild/linux-riscv64@0.25.12':
- optional: true
-
- '@esbuild/linux-riscv64@0.28.2':
- optional: true
-
- '@esbuild/linux-s390x@0.18.20':
- optional: true
-
- '@esbuild/linux-s390x@0.25.12':
- optional: true
-
- '@esbuild/linux-s390x@0.28.2':
- optional: true
-
- '@esbuild/linux-x64@0.18.20':
- optional: true
-
- '@esbuild/linux-x64@0.25.12':
- optional: true
-
- '@esbuild/linux-x64@0.28.2':
- optional: true
-
- '@esbuild/netbsd-arm64@0.25.12':
- optional: true
-
- '@esbuild/netbsd-arm64@0.28.2':
- optional: true
-
- '@esbuild/netbsd-x64@0.18.20':
- optional: true
-
- '@esbuild/netbsd-x64@0.25.12':
- optional: true
-
- '@esbuild/netbsd-x64@0.28.2':
- optional: true
-
- '@esbuild/openbsd-arm64@0.25.12':
- optional: true
-
- '@esbuild/openbsd-arm64@0.28.2':
- optional: true
-
- '@esbuild/openbsd-x64@0.18.20':
- optional: true
-
- '@esbuild/openbsd-x64@0.25.12':
- optional: true
-
- '@esbuild/openbsd-x64@0.28.2':
- optional: true
-
- '@esbuild/openharmony-arm64@0.25.12':
- optional: true
-
- '@esbuild/openharmony-arm64@0.28.2':
- optional: true
-
- '@esbuild/sunos-x64@0.18.20':
- optional: true
-
- '@esbuild/sunos-x64@0.25.12':
- optional: true
-
- '@esbuild/sunos-x64@0.28.2':
- optional: true
-
- '@esbuild/win32-arm64@0.18.20':
- optional: true
-
- '@esbuild/win32-arm64@0.25.12':
- optional: true
-
- '@esbuild/win32-arm64@0.28.2':
- optional: true
-
- '@esbuild/win32-ia32@0.18.20':
- optional: true
-
- '@esbuild/win32-ia32@0.25.12':
- optional: true
-
- '@esbuild/win32-ia32@0.28.2':
- optional: true
-
- '@esbuild/win32-x64@0.18.20':
- optional: true
-
- '@esbuild/win32-x64@0.25.12':
- optional: true
-
- '@esbuild/win32-x64@0.28.2':
- optional: true
-
- '@floating-ui/core@1.8.0':
- dependencies:
- '@floating-ui/utils': 0.2.12
-
- '@floating-ui/dom@1.8.0':
- dependencies:
- '@floating-ui/core': 1.8.0
- '@floating-ui/utils': 0.2.12
-
- '@floating-ui/react-dom@2.1.9(react-dom@19.3.0(react@19.3.0))(react@19.3.0)':
- dependencies:
- '@floating-ui/dom': 1.8.0
- react: 19.3.0
- react-dom: 19.3.0(react@19.3.0)
-
- '@floating-ui/utils@0.2.12': {}
-
- '@fontsource-variable/geist@5.3.0': {}
-
- '@jridgewell/gen-mapping@0.3.13':
- dependencies:
- '@jridgewell/sourcemap-codec': 1.6.0
- '@jridgewell/trace-mapping': 0.3.31
-
- '@jridgewell/remapping@2.3.5':
- dependencies:
- '@jridgewell/gen-mapping': 0.3.13
- '@jridgewell/trace-mapping': 0.3.31
-
- '@jridgewell/resolve-uri@3.1.2': {}
-
- '@jridgewell/sourcemap-codec@1.6.0': {}
-
- '@jridgewell/trace-mapping@0.3.31':
- dependencies:
- '@jridgewell/resolve-uri': 3.1.2
- '@jridgewell/sourcemap-codec': 1.6.0
-
- '@modelcontextprotocol/client@2.3.1':
- dependencies:
- '@modelcontextprotocol/core': 2.3.1
- cross-spawn: 7.0.6
- eventsource: 3.0.7
- eventsource-parser: 3.1.1
- jose: 6.2.12
- pkce-challenge: 5.0.1
- zod: 4.6.5
-
- '@modelcontextprotocol/core@2.3.1':
- dependencies:
- zod: 4.6.5
-
- '@modelcontextprotocol/server@2.3.1':
- dependencies:
- '@modelcontextprotocol/core': 2.3.1
- zod: 4.6.5
-
- '@napi-rs/wasm-runtime@1.2.4(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)':
- dependencies:
- '@emnapi/core': 1.11.3
- '@emnapi/runtime': 1.11.3
- '@tybys/wasm-util': 0.10.4
- optional: true
-
- '@neodrag/core@3.0.0-next.11': {}
-
- '@neodrag/solid@3.0.0-next.11(@neodrag/core@3.0.0-next.11)(solid-js@1.9.15)':
- dependencies:
- '@neodrag/core': 3.0.0-next.11
- solid-js: 1.9.15
-
- '@noble/ciphers@2.4.0': {}
-
- '@noble/hashes@2.4.0': {}
-
- '@oozcitak/dom@2.0.2':
- dependencies:
- '@oozcitak/infra': 2.0.2
- '@oozcitak/url': 3.0.0
- '@oozcitak/util': 10.0.0
-
- '@oozcitak/infra@2.0.2':
- dependencies:
- '@oozcitak/util': 10.0.0
-
- '@oozcitak/url@3.0.0':
- dependencies:
- '@oozcitak/infra': 2.0.2
- '@oozcitak/util': 10.0.0
-
- '@oozcitak/util@10.0.0': {}
-
- '@opentelemetry/api-logs@0.222.0':
- dependencies:
- '@opentelemetry/api': 1.9.1
-
- '@opentelemetry/api@1.9.1': {}
-
- '@opentelemetry/core@2.11.0(@opentelemetry/api@1.9.1)':
- dependencies:
- '@opentelemetry/api': 1.9.1
- '@opentelemetry/semantic-conventions': 1.43.0
-
- '@opentelemetry/exporter-logs-otlp-http@0.222.0(@opentelemetry/api@1.9.1)':
- dependencies:
- '@opentelemetry/api': 1.9.1
- '@opentelemetry/otlp-exporter-base': 0.222.0(@opentelemetry/api@1.9.1)
- '@opentelemetry/otlp-transformer': 0.222.0(@opentelemetry/api@1.9.1)
- '@opentelemetry/sdk-logs': 0.222.0(@opentelemetry/api@1.9.1)
-
- '@opentelemetry/exporter-trace-otlp-http@0.222.0(@opentelemetry/api@1.9.1)':
- dependencies:
- '@opentelemetry/api': 1.9.1
- '@opentelemetry/otlp-exporter-base': 0.222.0(@opentelemetry/api@1.9.1)
- '@opentelemetry/otlp-transformer': 0.222.0(@opentelemetry/api@1.9.1)
- '@opentelemetry/sdk-trace': 2.11.0(@opentelemetry/api@1.9.1)
-
- '@opentelemetry/otlp-exporter-base@0.222.0(@opentelemetry/api@1.9.1)':
- dependencies:
- '@opentelemetry/api': 1.9.1
- '@opentelemetry/core': 2.11.0(@opentelemetry/api@1.9.1)
- '@opentelemetry/otlp-transformer': 0.222.0(@opentelemetry/api@1.9.1)
-
- '@opentelemetry/otlp-transformer@0.222.0(@opentelemetry/api@1.9.1)':
- dependencies:
- '@opentelemetry/api': 1.9.1
- '@opentelemetry/api-logs': 0.222.0
- '@opentelemetry/core': 2.11.0(@opentelemetry/api@1.9.1)
- '@opentelemetry/resources': 2.11.0(@opentelemetry/api@1.9.1)
- '@opentelemetry/sdk-logs': 0.222.0(@opentelemetry/api@1.9.1)
- '@opentelemetry/sdk-metrics': 2.11.0(@opentelemetry/api@1.9.1)
- '@opentelemetry/sdk-trace': 2.11.0(@opentelemetry/api@1.9.1)
-
- '@opentelemetry/resources@2.11.0(@opentelemetry/api@1.9.1)':
- dependencies:
- '@opentelemetry/api': 1.9.1
- '@opentelemetry/core': 2.11.0(@opentelemetry/api@1.9.1)
- '@opentelemetry/semantic-conventions': 1.43.0
-
- '@opentelemetry/sdk-logs@0.222.0(@opentelemetry/api@1.9.1)':
- dependencies:
- '@opentelemetry/api': 1.9.1
- '@opentelemetry/api-logs': 0.222.0
- '@opentelemetry/core': 2.11.0(@opentelemetry/api@1.9.1)
- '@opentelemetry/resources': 2.11.0(@opentelemetry/api@1.9.1)
- '@opentelemetry/semantic-conventions': 1.43.0
-
- '@opentelemetry/sdk-metrics@2.11.0(@opentelemetry/api@1.9.1)':
- dependencies:
- '@opentelemetry/api': 1.9.1
- '@opentelemetry/core': 2.11.0(@opentelemetry/api@1.9.1)
- '@opentelemetry/resources': 2.11.0(@opentelemetry/api@1.9.1)
-
- '@opentelemetry/sdk-trace-base@2.11.0(@opentelemetry/api@1.9.1)':
- dependencies:
- '@opentelemetry/api': 1.9.1
- '@opentelemetry/core': 2.11.0(@opentelemetry/api@1.9.1)
- '@opentelemetry/resources': 2.11.0(@opentelemetry/api@1.9.1)
- '@opentelemetry/sdk-trace': 2.11.0(@opentelemetry/api@1.9.1)
- '@opentelemetry/semantic-conventions': 1.43.0
-
- '@opentelemetry/sdk-trace@2.11.0(@opentelemetry/api@1.9.1)':
- dependencies:
- '@opentelemetry/api': 1.9.1
- '@opentelemetry/core': 2.11.0(@opentelemetry/api@1.9.1)
- '@opentelemetry/resources': 2.11.0(@opentelemetry/api@1.9.1)
- '@opentelemetry/semantic-conventions': 1.43.0
-
- '@opentelemetry/semantic-conventions@1.43.0': {}
-
- '@oxc-parser/binding-android-arm-eabi@0.120.0':
- optional: true
-
- '@oxc-parser/binding-android-arm64@0.120.0':
- optional: true
-
- '@oxc-parser/binding-darwin-arm64@0.120.0':
- optional: true
-
- '@oxc-parser/binding-darwin-x64@0.120.0':
- optional: true
-
- '@oxc-parser/binding-freebsd-x64@0.120.0':
- optional: true
-
- '@oxc-parser/binding-linux-arm-gnueabihf@0.120.0':
- optional: true
-
- '@oxc-parser/binding-linux-arm-musleabihf@0.120.0':
- optional: true
-
- '@oxc-parser/binding-linux-arm64-gnu@0.120.0':
- optional: true
-
- '@oxc-parser/binding-linux-arm64-musl@0.120.0':
- optional: true
-
- '@oxc-parser/binding-linux-ppc64-gnu@0.120.0':
- optional: true
-
- '@oxc-parser/binding-linux-riscv64-gnu@0.120.0':
- optional: true
-
- '@oxc-parser/binding-linux-riscv64-musl@0.120.0':
- optional: true
-
- '@oxc-parser/binding-linux-s390x-gnu@0.120.0':
- optional: true
-
- '@oxc-parser/binding-linux-x64-gnu@0.120.0':
- optional: true
-
- '@oxc-parser/binding-linux-x64-musl@0.120.0':
- optional: true
-
- '@oxc-parser/binding-openharmony-arm64@0.120.0':
- optional: true
-
- '@oxc-parser/binding-wasm32-wasi@0.120.0(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)':
- dependencies:
- '@napi-rs/wasm-runtime': 1.2.4(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)
- transitivePeerDependencies:
- - '@emnapi/core'
- - '@emnapi/runtime'
- optional: true
-
- '@oxc-parser/binding-win32-arm64-msvc@0.120.0':
- optional: true
-
- '@oxc-parser/binding-win32-ia32-msvc@0.120.0':
- optional: true
-
- '@oxc-parser/binding-win32-x64-msvc@0.120.0':
- optional: true
-
- '@oxc-project/types@0.120.0': {}
-
- '@oxc-project/types@0.152.0': {}
-
- '@posthog/browser-common@0.9.1':
- dependencies:
- '@posthog/core': 1.56.0
- '@posthog/types': 1.413.0
-
- '@posthog/core@1.56.0':
- dependencies:
- '@posthog/types': 1.413.0
-
- '@posthog/types@1.413.0': {}
-
- '@radix-ui/primitive@1.1.7': {}
-
- '@radix-ui/react-compose-refs@1.1.5(@types/react@19.3.0)(react@19.3.0)':
- dependencies:
- react: 19.3.0
- optionalDependencies:
- '@types/react': 19.3.0
-
- '@radix-ui/react-context@1.2.2(@types/react@19.3.0)(react@19.3.0)':
- dependencies:
- react: 19.3.0
- optionalDependencies:
- '@types/react': 19.3.0
-
- '@radix-ui/react-dialog@1.2.0(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)':
- dependencies:
- '@radix-ui/primitive': 1.1.7
- '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0)
- '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0)
- '@radix-ui/react-dismissable-layer': 1.1.20(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
- '@radix-ui/react-focus-guards': 1.1.6(@types/react@19.3.0)(react@19.3.0)
- '@radix-ui/react-focus-scope': 1.2.0(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
- '@radix-ui/react-id': 1.1.4(@types/react@19.3.0)(react@19.3.0)
- '@radix-ui/react-portal': 1.1.18(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
- '@radix-ui/react-presence': 1.1.11(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
- '@radix-ui/react-primitive': 2.1.11(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
- '@radix-ui/react-slot': 1.4.0(@types/react@19.3.0)(react@19.3.0)
- '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.3.0)(react@19.3.0)
- '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0)
- aria-hidden: 1.2.6
- react: 19.3.0
- react-dom: 19.3.0(react@19.3.0)
- react-remove-scroll: 2.7.2(@types/react@19.3.0)(react@19.3.0)
- optionalDependencies:
- '@types/react': 19.3.0
- '@types/react-dom': 19.3.0(@types/react@19.3.0)
-
- '@radix-ui/react-dismissable-layer@1.1.20(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)':
- dependencies:
- '@radix-ui/primitive': 1.1.7
- '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0)
- '@radix-ui/react-primitive': 2.1.11(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
- '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.3.0)(react@19.3.0)
- '@radix-ui/react-use-effect-event': 0.0.5(@types/react@19.3.0)(react@19.3.0)
- react: 19.3.0
- react-dom: 19.3.0(react@19.3.0)
- optionalDependencies:
- '@types/react': 19.3.0
- '@types/react-dom': 19.3.0(@types/react@19.3.0)
-
- '@radix-ui/react-focus-guards@1.1.6(@types/react@19.3.0)(react@19.3.0)':
- dependencies:
- react: 19.3.0
- optionalDependencies:
- '@types/react': 19.3.0
-
- '@radix-ui/react-focus-scope@1.2.0(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)':
- dependencies:
- '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0)
- '@radix-ui/react-primitive': 2.1.11(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
- '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.3.0)(react@19.3.0)
- react: 19.3.0
- react-dom: 19.3.0(react@19.3.0)
- optionalDependencies:
- '@types/react': 19.3.0
- '@types/react-dom': 19.3.0(@types/react@19.3.0)
-
- '@radix-ui/react-id@1.1.4(@types/react@19.3.0)(react@19.3.0)':
- dependencies:
- '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0)
- react: 19.3.0
- optionalDependencies:
- '@types/react': 19.3.0
-
- '@radix-ui/react-portal@1.1.18(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)':
- dependencies:
- '@radix-ui/react-primitive': 2.1.11(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
- '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0)
- react: 19.3.0
- react-dom: 19.3.0(react@19.3.0)
- optionalDependencies:
- '@types/react': 19.3.0
- '@types/react-dom': 19.3.0(@types/react@19.3.0)
-
- '@radix-ui/react-presence@1.1.11(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)':
- dependencies:
- '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0)
- react: 19.3.0
- react-dom: 19.3.0(react@19.3.0)
- optionalDependencies:
- '@types/react': 19.3.0
- '@types/react-dom': 19.3.0(@types/react@19.3.0)
-
- '@radix-ui/react-primitive@2.1.11(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)':
- dependencies:
- '@radix-ui/react-slot': 1.4.0(@types/react@19.3.0)(react@19.3.0)
- react: 19.3.0
- react-dom: 19.3.0(react@19.3.0)
- optionalDependencies:
- '@types/react': 19.3.0
- '@types/react-dom': 19.3.0(@types/react@19.3.0)
-
- '@radix-ui/react-slot@1.4.0(@types/react@19.3.0)(react@19.3.0)':
- dependencies:
- '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0)
- react: 19.3.0
- optionalDependencies:
- '@types/react': 19.3.0
-
- '@radix-ui/react-use-callback-ref@1.1.4(@types/react@19.3.0)(react@19.3.0)':
- dependencies:
- react: 19.3.0
- optionalDependencies:
- '@types/react': 19.3.0
-
- '@radix-ui/react-use-controllable-state@1.2.6(@types/react@19.3.0)(react@19.3.0)':
- dependencies:
- '@radix-ui/primitive': 1.1.7
- '@radix-ui/react-use-effect-event': 0.0.5(@types/react@19.3.0)(react@19.3.0)
- '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0)
- react: 19.3.0
- optionalDependencies:
- '@types/react': 19.3.0
-
- '@radix-ui/react-use-effect-event@0.0.5(@types/react@19.3.0)(react@19.3.0)':
- dependencies:
- '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0)
- react: 19.3.0
- optionalDependencies:
- '@types/react': 19.3.0
-
- '@radix-ui/react-use-layout-effect@1.1.4(@types/react@19.3.0)(react@19.3.0)':
- dependencies:
- react: 19.3.0
- optionalDependencies:
- '@types/react': 19.3.0
-
- '@reduxjs/toolkit@2.13.0(react-redux@9.3.0(@types/react@19.3.0)(react@19.3.0)(redux@5.0.1))(react@19.3.0)':
- dependencies:
- '@standard-schema/spec': 1.1.0
- '@standard-schema/utils': 0.3.0
- immer: 11.1.21
- redux: 5.0.1
- redux-thunk: 3.1.0(redux@5.0.1)
- reselect: 5.3.0
- optionalDependencies:
- react: 19.3.0
- react-redux: 9.3.0(@types/react@19.3.0)(react@19.3.0)(redux@5.0.1)
-
- '@resvg/resvg-wasm@2.6.2': {}
-
- '@rolldown/binding-android-arm-eabi@1.2.12':
- optional: true
-
- '@rolldown/binding-android-arm64@1.2.12':
- optional: true
-
- '@rolldown/binding-darwin-arm64@1.2.12':
- optional: true
-
- '@rolldown/binding-darwin-x64@1.2.12':
- optional: true
-
- '@rolldown/binding-freebsd-x64@1.2.12':
- optional: true
-
- '@rolldown/binding-linux-arm-gnueabihf@1.2.12':
- optional: true
-
- '@rolldown/binding-linux-arm64-gnu@1.2.12':
- optional: true
-
- '@rolldown/binding-linux-arm64-musl@1.2.12':
- optional: true
-
- '@rolldown/binding-linux-ppc64-gnu@1.2.12':
- optional: true
-
- '@rolldown/binding-linux-s390x-gnu@1.2.12':
- optional: true
-
- '@rolldown/binding-linux-x64-gnu@1.2.12':
- optional: true
-
- '@rolldown/binding-linux-x64-musl@1.2.12':
- optional: true
-
- '@rolldown/binding-openharmony-arm64@1.2.12':
- optional: true
-
- '@rolldown/binding-win32-arm64-msvc@1.2.12':
- optional: true
-
- '@rolldown/binding-win32-x64-msvc@1.2.12':
- optional: true
-
- '@rolldown/pluginutils@1.0.1': {}
-
- '@solid-primitives/event-listener@2.4.6(solid-js@1.9.15)':
- dependencies:
- '@solid-primitives/utils': 6.4.1(solid-js@1.9.15)
- solid-js: 1.9.15
-
- '@solid-primitives/keyboard@1.3.7(solid-js@1.9.15)':
- dependencies:
- '@solid-primitives/event-listener': 2.4.6(solid-js@1.9.15)
- '@solid-primitives/rootless': 1.5.4(solid-js@1.9.15)
- '@solid-primitives/utils': 6.4.1(solid-js@1.9.15)
- solid-js: 1.9.15
-
- '@solid-primitives/resize-observer@2.2.0(solid-js@1.9.15)':
- dependencies:
- '@solid-primitives/event-listener': 2.4.6(solid-js@1.9.15)
- '@solid-primitives/rootless': 1.5.4(solid-js@1.9.15)
- '@solid-primitives/static-store': 0.1.4(solid-js@1.9.15)
- '@solid-primitives/utils': 6.4.1(solid-js@1.9.15)
- solid-js: 1.9.15
-
- '@solid-primitives/rootless@1.5.4(solid-js@1.9.15)':
- dependencies:
- '@solid-primitives/utils': 6.4.1(solid-js@1.9.15)
- solid-js: 1.9.15
-
- '@solid-primitives/static-store@0.1.4(solid-js@1.9.15)':
- dependencies:
- '@solid-primitives/utils': 6.4.1(solid-js@1.9.15)
- solid-js: 1.9.15
-
- '@solid-primitives/utils@6.4.1(solid-js@1.9.15)':
- dependencies:
- solid-js: 1.9.15
-
- '@standard-schema/spec@1.1.0': {}
-
- '@standard-schema/utils@0.3.0': {}
-
- '@tailwindcss/node@4.3.3':
- dependencies:
- '@jridgewell/remapping': 2.3.5
- enhanced-resolve: 5.26.0
- jiti: 2.7.0
- lightningcss: 1.32.0
- magic-string: 0.30.21
- source-map-js: 1.2.2
- tailwindcss: 4.3.3
-
- '@tailwindcss/oxide-android-arm64@4.3.3':
- optional: true
-
- '@tailwindcss/oxide-darwin-arm64@4.3.3':
- optional: true
-
- '@tailwindcss/oxide-darwin-x64@4.3.3':
- optional: true
-
- '@tailwindcss/oxide-freebsd-x64@4.3.3':
- optional: true
-
- '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3':
- optional: true
-
- '@tailwindcss/oxide-linux-arm64-gnu@4.3.3':
- optional: true
-
- '@tailwindcss/oxide-linux-arm64-musl@4.3.3':
- optional: true
-
- '@tailwindcss/oxide-linux-x64-gnu@4.3.3':
- optional: true
-
- '@tailwindcss/oxide-linux-x64-musl@4.3.3':
- optional: true
-
- '@tailwindcss/oxide-wasm32-wasi@4.3.3':
- optional: true
-
- '@tailwindcss/oxide-win32-arm64-msvc@4.3.3':
- optional: true
-
- '@tailwindcss/oxide-win32-x64-msvc@4.3.3':
- optional: true
-
- '@tailwindcss/oxide@4.3.3':
- optionalDependencies:
- '@tailwindcss/oxide-android-arm64': 4.3.3
- '@tailwindcss/oxide-darwin-arm64': 4.3.3
- '@tailwindcss/oxide-darwin-x64': 4.3.3
- '@tailwindcss/oxide-freebsd-x64': 4.3.3
- '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.3
- '@tailwindcss/oxide-linux-arm64-gnu': 4.3.3
- '@tailwindcss/oxide-linux-arm64-musl': 4.3.3
- '@tailwindcss/oxide-linux-x64-gnu': 4.3.3
- '@tailwindcss/oxide-linux-x64-musl': 4.3.3
- '@tailwindcss/oxide-wasm32-wasi': 4.3.3
- '@tailwindcss/oxide-win32-arm64-msvc': 4.3.3
- '@tailwindcss/oxide-win32-x64-msvc': 4.3.3
-
- '@tailwindcss/typography@0.5.20(tailwindcss@4.3.3)':
- dependencies:
- postcss-selector-parser: 6.0.10
- tailwindcss: 4.3.3
-
- '@tailwindcss/vite@4.3.3(vite@8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))':
- dependencies:
- '@tailwindcss/node': 4.3.3
- '@tailwindcss/oxide': 4.3.3
- tailwindcss: 4.3.3
- vite: 8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)
-
- '@tanstack/devtools-bundler-core@0.1.3(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)':
- dependencies:
- '@tanstack/devtools-client': 0.0.8
- '@tanstack/devtools-event-bus': 0.4.3
- chalk: 5.6.2
- launch-editor: 2.14.1
- magic-string: 0.30.21
- oxc-parser: 0.120.0(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)
- picomatch: 4.0.7
- transitivePeerDependencies:
- - '@emnapi/core'
- - '@emnapi/runtime'
- - bufferutil
- - utf-8-validate
-
- '@tanstack/devtools-client@0.0.8':
- dependencies:
- '@tanstack/devtools-event-client': 0.5.0
-
- '@tanstack/devtools-event-bus@0.4.3':
- dependencies:
- ws: 8.22.0
- transitivePeerDependencies:
- - bufferutil
- - utf-8-validate
-
- '@tanstack/devtools-event-client@0.5.0': {}
-
- '@tanstack/devtools-ui@0.7.1(csstype@3.2.3)(solid-js@1.9.15)':
- dependencies:
- clsx: 2.1.1
- dayjs: 1.11.23
- goober: 2.1.19(csstype@3.2.3)
- solid-js: 1.9.15
- transitivePeerDependencies:
- - csstype
-
- '@tanstack/devtools-vite@0.8.5(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(vite@8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))':
- dependencies:
- '@tanstack/devtools-bundler-core': 0.1.3(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)
- '@tanstack/devtools-client': 0.0.8
- '@tanstack/devtools-event-bus': 0.4.3
- chalk: 5.6.2
- vite: 8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)
- transitivePeerDependencies:
- - '@emnapi/core'
- - '@emnapi/runtime'
- - bufferutil
- - utf-8-validate
-
- '@tanstack/devtools@0.15.0(csstype@3.2.3)(solid-js@1.9.15)':
- dependencies:
- '@neodrag/core': 3.0.0-next.11
- '@neodrag/solid': 3.0.0-next.11(@neodrag/core@3.0.0-next.11)(solid-js@1.9.15)
- '@solid-primitives/event-listener': 2.4.6(solid-js@1.9.15)
- '@solid-primitives/keyboard': 1.3.7(solid-js@1.9.15)
- '@solid-primitives/resize-observer': 2.2.0(solid-js@1.9.15)
- '@tanstack/devtools-client': 0.0.8
- '@tanstack/devtools-event-bus': 0.4.3
- '@tanstack/devtools-ui': 0.7.1(csstype@3.2.3)(solid-js@1.9.15)
- clsx: 2.1.1
- goober: 2.1.19(csstype@3.2.3)
- solid-js: 1.9.15
- transitivePeerDependencies:
- - bufferutil
- - csstype
- - utf-8-validate
-
- '@tanstack/history@1.162.4': {}
-
- '@tanstack/intent@0.5.4': {}
-
- '@tanstack/react-devtools@0.10.13(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(csstype@3.2.3)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(solid-js@1.9.15)':
- dependencies:
- '@tanstack/devtools': 0.15.0(csstype@3.2.3)(solid-js@1.9.15)
- '@types/react': 19.3.0
- '@types/react-dom': 19.3.0(@types/react@19.3.0)
- react: 19.3.0
- react-dom: 19.3.0(react@19.3.0)
- transitivePeerDependencies:
- - bufferutil
- - csstype
- - solid-js
- - utf-8-validate
-
- '@tanstack/react-router-devtools@1.167.2(@tanstack/react-router@1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(@tanstack/router-core@1.171.34)(csstype@3.2.3)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)':
- dependencies:
- '@tanstack/react-router': 1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
- '@tanstack/router-devtools-core': 1.168.2(@tanstack/router-core@1.171.34)(csstype@3.2.3)
- react: 19.3.0
- react-dom: 19.3.0(react@19.3.0)
- optionalDependencies:
- '@tanstack/router-core': 1.171.34
- transitivePeerDependencies:
- - csstype
-
- '@tanstack/react-router@1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0)':
- dependencies:
- '@tanstack/history': 1.162.4
- '@tanstack/react-store': 0.11.2(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
- '@tanstack/router-core': 1.171.34
- isbot: 5.2.2
- react: 19.3.0
- react-dom: 19.3.0(react@19.3.0)
-
- '@tanstack/react-start-client@1.168.39(react-dom@19.3.0(react@19.3.0))(react@19.3.0)':
- dependencies:
- '@tanstack/react-router': 1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
- '@tanstack/router-core': 1.171.34
- '@tanstack/start-client-core': 1.170.34
- react: 19.3.0
- react-dom: 19.3.0(react@19.3.0)
-
- '@tanstack/react-start-rsc@0.1.59(crossws@0.4.12(srvx@0.11.22))(esbuild@0.28.2)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(rolldown@1.2.12)(vite@8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))':
- dependencies:
- '@tanstack/react-router': 1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
- '@tanstack/router-core': 1.171.34
- '@tanstack/router-utils': 1.162.3
- '@tanstack/start-client-core': 1.170.34
- '@tanstack/start-fn-stubs': 1.162.0
- '@tanstack/start-plugin-core': 1.171.49(@tanstack/react-router@1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(crossws@0.4.12(srvx@0.11.22))(esbuild@0.28.2)(rolldown@1.2.12)(vite@8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))
- '@tanstack/start-storage-context': 1.167.36
- pathe: 2.0.3
- react: 19.3.0
- react-dom: 19.3.0(react@19.3.0)
- transitivePeerDependencies:
- - '@farmfe/core'
- - '@rsbuild/core'
- - bun-types-no-globals
- - crossws
- - esbuild
- - rolldown
- - rollup
- - supports-color
- - unloader
- - vite
- - vite-plugin-solid
- - webpack
-
- '@tanstack/react-start-server@1.167.46(crossws@0.4.12(srvx@0.11.22))(react-dom@19.3.0(react@19.3.0))(react@19.3.0)':
- dependencies:
- '@tanstack/react-router': 1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
- '@tanstack/router-core': 1.171.34
- '@tanstack/start-server-core': 1.169.39(crossws@0.4.12(srvx@0.11.22))
- react: 19.3.0
- react-dom: 19.3.0(react@19.3.0)
- transitivePeerDependencies:
- - crossws
-
- '@tanstack/react-start@1.168.60(crossws@0.4.12(srvx@0.11.22))(esbuild@0.28.2)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(rolldown@1.2.12)(vite@8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))':
- dependencies:
- '@tanstack/react-router': 1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
- '@tanstack/react-start-client': 1.168.39(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
- '@tanstack/react-start-rsc': 0.1.59(crossws@0.4.12(srvx@0.11.22))(esbuild@0.28.2)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(rolldown@1.2.12)(vite@8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))
- '@tanstack/react-start-server': 1.167.46(crossws@0.4.12(srvx@0.11.22))(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
- '@tanstack/router-utils': 1.162.3
- '@tanstack/start-client-core': 1.170.34
- '@tanstack/start-plugin-core': 1.171.49(@tanstack/react-router@1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(crossws@0.4.12(srvx@0.11.22))(esbuild@0.28.2)(rolldown@1.2.12)(vite@8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))
- '@tanstack/start-server-core': 1.169.39(crossws@0.4.12(srvx@0.11.22))
- pathe: 2.0.3
- react: 19.3.0
- react-dom: 19.3.0(react@19.3.0)
- optionalDependencies:
- vite: 8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)
- transitivePeerDependencies:
- - '@farmfe/core'
- - '@rspack/core'
- - bun-types-no-globals
- - crossws
- - esbuild
- - react-server-dom-rspack
- - rolldown
- - rollup
- - supports-color
- - unloader
- - vite-plugin-solid
- - webpack
-
- '@tanstack/react-store@0.11.2(react-dom@19.3.0(react@19.3.0))(react@19.3.0)':
- dependencies:
- '@tanstack/store': 0.11.2
- react: 19.3.0
- react-dom: 19.3.0(react@19.3.0)
- use-sync-external-store: 1.7.0(react@19.3.0)
-
- '@tanstack/router-cli@1.167.40':
- dependencies:
- '@tanstack/router-generator': 1.167.40
- chokidar: 5.0.0
- yargs: 17.7.3
- transitivePeerDependencies:
- - supports-color
-
- '@tanstack/router-core@1.171.34':
- dependencies:
- '@tanstack/history': 1.162.4
- cookie-es: 3.1.1
- seroval: 1.6.8
- seroval-plugins: 1.6.8(seroval@1.6.8)
-
- '@tanstack/router-devtools-core@1.168.2(@tanstack/router-core@1.171.34)(csstype@3.2.3)':
- dependencies:
- '@tanstack/router-core': 1.171.34
- clsx: 2.1.1
- goober: 2.1.19(csstype@3.2.3)
- optionalDependencies:
- csstype: 3.2.3
-
- '@tanstack/router-generator@1.167.40':
- dependencies:
- '@babel/types': 7.29.8
- '@tanstack/router-core': 1.171.34
- '@tanstack/router-utils': 1.162.3
- '@tanstack/virtual-file-routes': 1.162.0
- jiti: 2.7.0
- magic-string: 0.30.21
- prettier: 3.9.9
- zod: 4.6.5
- transitivePeerDependencies:
- - supports-color
-
- '@tanstack/router-plugin@1.168.42(@tanstack/react-router@1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(esbuild@0.28.2)(rolldown@1.2.12)(vite@8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))':
- dependencies:
- '@babel/core': 7.29.7
- '@babel/template': 7.29.7
- '@babel/types': 7.29.8
- '@tanstack/router-core': 1.171.34
- '@tanstack/router-generator': 1.167.40
- '@tanstack/router-utils': 1.162.3
- chokidar: 5.0.0
- unplugin: 3.4.0(esbuild@0.28.2)(rolldown@1.2.12)(vite@8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))
- zod: 4.6.5
- optionalDependencies:
- '@tanstack/react-router': 1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
- vite: 8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)
- transitivePeerDependencies:
- - '@farmfe/core'
- - '@rspack/core'
- - bun-types-no-globals
- - esbuild
- - rolldown
- - rollup
- - supports-color
- - unloader
-
- '@tanstack/router-utils@1.162.3':
- dependencies:
- '@babel/generator': 7.29.8
- '@babel/parser': 7.29.9
- '@babel/types': 7.29.8
- ansis: 4.4.0
- babel-dead-code-elimination: 1.0.12
- diff: 8.0.4
- pathe: 2.0.3
- tinyglobby: 0.2.17
- transitivePeerDependencies:
- - supports-color
-
- '@tanstack/start-client-core@1.170.34':
- dependencies:
- '@tanstack/router-core': 1.171.34
- '@tanstack/start-fn-stubs': 1.162.0
- '@tanstack/start-storage-context': 1.167.36
- seroval: 1.6.8
-
- '@tanstack/start-fn-stubs@1.162.0': {}
-
- '@tanstack/start-plugin-core@1.171.49(@tanstack/react-router@1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(crossws@0.4.12(srvx@0.11.22))(esbuild@0.28.2)(rolldown@1.2.12)(vite@8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))':
- dependencies:
- '@babel/code-frame': 7.29.7
- '@babel/core': 7.29.7
- '@babel/types': 7.29.8
- '@jridgewell/remapping': 2.3.5
- '@tanstack/router-core': 1.171.34
- '@tanstack/router-generator': 1.167.40
- '@tanstack/router-plugin': 1.168.42(@tanstack/react-router@1.170.41(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(esbuild@0.28.2)(rolldown@1.2.12)(vite@8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))
- '@tanstack/router-utils': 1.162.3
- '@tanstack/start-server-core': 1.169.39(crossws@0.4.12(srvx@0.11.22))
- exsolve: 1.1.3
- lightningcss: 1.33.0
- pathe: 2.0.3
- picomatch: 4.0.7
- seroval: 1.6.8
- source-map: 0.7.6
- srvx: 0.11.22
- tinyglobby: 0.2.17
- ufo: 1.6.4
- vitefu: 1.1.3(vite@8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))
- xmlbuilder2: 4.0.3
- zod: 4.6.5
- optionalDependencies:
- vite: 8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)
- transitivePeerDependencies:
- - '@farmfe/core'
- - '@rspack/core'
- - '@tanstack/react-router'
- - bun-types-no-globals
- - crossws
- - esbuild
- - rolldown
- - rollup
- - supports-color
- - unloader
- - vite-plugin-solid
- - webpack
-
- '@tanstack/start-server-core@1.169.39(crossws@0.4.12(srvx@0.11.22))':
- dependencies:
- '@tanstack/history': 1.162.4
- '@tanstack/router-core': 1.171.34
- '@tanstack/start-client-core': 1.170.34
- '@tanstack/start-storage-context': 1.167.36
- fetchdts: 0.1.7
- h3-v2: h3@2.0.1-rc.20(crossws@0.4.12(srvx@0.11.22))
- seroval: 1.6.8
- transitivePeerDependencies:
- - crossws
-
- '@tanstack/start-storage-context@1.167.36':
- dependencies:
- '@tanstack/router-core': 1.171.34
-
- '@tanstack/store@0.11.2': {}
-
- '@tanstack/virtual-file-routes@1.162.0': {}
-
- '@tybys/wasm-util@0.10.4':
- dependencies:
- tslib: 2.8.1
- optional: true
-
- '@types/d3-array@3.2.2': {}
-
- '@types/d3-color@3.1.3': {}
-
- '@types/d3-ease@3.0.2': {}
-
- '@types/d3-interpolate@3.0.4':
- dependencies:
- '@types/d3-color': 3.1.3
-
- '@types/d3-path@3.1.1': {}
-
- '@types/d3-scale@4.0.9':
- dependencies:
- '@types/d3-time': 3.0.4
-
- '@types/d3-shape@3.2.0':
- dependencies:
- '@types/d3-path': 3.1.1
-
- '@types/d3-time@3.0.4': {}
-
- '@types/d3-timer@3.0.2': {}
-
- '@types/node@22.20.5':
- dependencies:
- undici-types: 6.21.0
-
- '@types/pg@8.23.1':
- dependencies:
- '@types/node': 22.20.5
- pg-protocol: 1.16.1
- pg-types: 2.2.0
-
- '@types/react-dom@19.3.0(@types/react@19.3.0)':
- dependencies:
- '@types/react': 19.3.0
-
- '@types/react@19.3.0':
- dependencies:
- csstype: 3.2.3
-
- '@types/trusted-types@2.0.7':
- optional: true
-
- '@types/use-sync-external-store@0.0.6': {}
-
- '@vitejs/plugin-react@6.1.1(vite@8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))':
- dependencies:
- '@rolldown/pluginutils': 1.0.1
- vite: 8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)
-
- ansi-regex@5.0.1: {}
-
- ansi-styles@4.3.0:
- dependencies:
- color-convert: 2.0.1
-
- ansis@4.4.0: {}
-
- argparse@2.0.1: {}
-
- aria-hidden@1.2.6:
- dependencies:
- tslib: 2.8.1
-
- babel-dead-code-elimination@1.0.12:
- dependencies:
- '@babel/core': 7.29.7
- '@babel/parser': 7.29.9
- '@babel/traverse': 7.29.8
- '@babel/types': 7.29.8
- transitivePeerDependencies:
- - supports-color
-
- baseline-browser-mapping@2.11.27: {}
-
- better-auth@1.7.7(@opentelemetry/api@1.9.1)(@tanstack/react-start@1.168.60(crossws@0.4.12(srvx@0.11.22))(esbuild@0.28.2)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(rolldown@1.2.12)(vite@8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)))(drizzle-kit@0.31.11)(drizzle-orm@0.45.3(@electric-sql/pglite@0.5.8)(@opentelemetry/api@1.9.1)(@types/pg@8.23.1)(kysely@0.29.6)(pg@8.23.1))(pg@8.23.1)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(solid-js@1.9.15):
- dependencies:
- '@better-auth/core': 1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.4)
- '@better-auth/drizzle-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.4))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.3(@electric-sql/pglite@0.5.8)(@opentelemetry/api@1.9.1)(@types/pg@8.23.1)(kysely@0.29.6)(pg@8.23.1))
- '@better-auth/kysely-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.4))(@better-auth/utils@0.4.2)(kysely@0.29.6)
- '@better-auth/memory-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.4))(@better-auth/utils@0.4.2)
- '@better-auth/mongo-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.4))(@better-auth/utils@0.4.2)
- '@better-auth/prisma-adapter': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.4))(@better-auth/utils@0.4.2)
- '@better-auth/telemetry': 1.7.7(@better-auth/core@1.7.7(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.4))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)
- '@better-auth/utils': 0.4.2
- '@better-fetch/fetch': 1.3.2
- '@noble/ciphers': 2.4.0
- '@noble/hashes': 2.4.0
- better-call: 1.4.0(zod@4.6.5)
- defu: 6.1.7
- jose: 6.2.12
- kysely: 0.29.6
- nanostores: 1.5.4
- zod: 4.6.5
- optionalDependencies:
- '@tanstack/react-start': 1.168.60(crossws@0.4.12(srvx@0.11.22))(esbuild@0.28.2)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(rolldown@1.2.12)(vite@8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15))
- drizzle-kit: 0.31.11
- drizzle-orm: 0.45.3(@electric-sql/pglite@0.5.8)(@opentelemetry/api@1.9.1)(@types/pg@8.23.1)(kysely@0.29.6)(pg@8.23.1)
- pg: 8.23.1
- react: 19.3.0
- react-dom: 19.3.0(react@19.3.0)
- solid-js: 1.9.15
- transitivePeerDependencies:
- - '@opentelemetry/api'
-
- better-call@1.4.0(zod@4.6.5):
- dependencies:
- '@better-auth/utils': 0.5.0
- '@better-fetch/fetch': 1.3.2
- rou3: 0.9.2
- set-cookie-parser: 3.1.2
- optionalDependencies:
- zod: 4.6.5
-
- browserslist@4.29.3:
- dependencies:
- baseline-browser-mapping: 2.11.27
- caniuse-lite: 1.0.30001814
- electron-to-chromium: 1.5.444
- node-releases: 2.0.57
- update-browserslist-db: 1.3.3(browserslist@4.29.3)
-
- buffer-from@1.1.2: {}
-
- caniuse-lite@1.0.30001814: {}
-
- chalk@5.6.2: {}
-
- chokidar@5.0.0:
- dependencies:
- readdirp: 5.1.1
-
- class-variance-authority@0.7.1:
- dependencies:
- clsx: 2.1.1
-
- cliui@8.0.1:
- dependencies:
- string-width: 4.2.3
- strip-ansi: 6.0.1
- wrap-ansi: 7.0.0
-
- clsx@2.1.1: {}
-
- cmdk@1.1.1(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0):
- dependencies:
- '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0)
- '@radix-ui/react-dialog': 1.2.0(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
- '@radix-ui/react-id': 1.1.4(@types/react@19.3.0)(react@19.3.0)
- '@radix-ui/react-primitive': 2.1.11(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)
- react: 19.3.0
- react-dom: 19.3.0(react@19.3.0)
- transitivePeerDependencies:
- - '@types/react'
- - '@types/react-dom'
-
- cn@0.4.0: {}
-
- color-convert@2.0.1:
- dependencies:
- color-name: 1.1.4
-
- color-name@1.1.4: {}
-
- consola@3.4.2: {}
-
- convert-source-map@2.0.0: {}
-
- cookie-es@3.1.1: {}
-
- core-js@3.50.0: {}
-
- croner@10.0.1: {}
-
- cross-spawn@7.0.6:
- dependencies:
- path-key: 3.1.1
- shebang-command: 2.0.0
- which: 2.0.2
-
- crossws@0.4.12(srvx@0.11.22):
- optionalDependencies:
- srvx: 0.11.22
-
- cssesc@3.0.0: {}
-
- csstype@3.2.3: {}
-
- d3-array@3.2.4:
- dependencies:
- internmap: 2.0.3
-
- d3-color@3.1.0: {}
-
- d3-ease@3.0.1: {}
-
- d3-format@3.1.2: {}
-
- d3-interpolate@3.0.1:
- dependencies:
- d3-color: 3.1.0
-
- d3-path@3.1.0: {}
-
- d3-scale@4.0.2:
- dependencies:
- d3-array: 3.2.4
- d3-format: 3.1.2
- d3-interpolate: 3.0.1
- d3-time: 3.1.0
- d3-time-format: 4.1.0
-
- d3-shape@3.2.0:
- dependencies:
- d3-path: 3.1.0
-
- d3-time-format@4.1.0:
- dependencies:
- d3-time: 3.1.0
-
- d3-time@3.1.0:
- dependencies:
- d3-array: 3.2.4
-
- d3-timer@3.0.1: {}
-
- dayjs@1.11.23: {}
-
- db0@0.3.4(@electric-sql/pglite@0.5.8)(drizzle-orm@0.45.3(@electric-sql/pglite@0.5.8)(@opentelemetry/api@1.9.1)(@types/pg@8.23.1)(kysely@0.29.6)(pg@8.23.1)):
- optionalDependencies:
- '@electric-sql/pglite': 0.5.8
- drizzle-orm: 0.45.3(@electric-sql/pglite@0.5.8)(@opentelemetry/api@1.9.1)(@types/pg@8.23.1)(kysely@0.29.6)(pg@8.23.1)
-
- debug@4.4.3:
- dependencies:
- ms: 2.1.3
-
- decimal.js-light@2.5.1: {}
-
- defu@6.1.7: {}
-
- detect-libc@2.1.2: {}
-
- detect-node-es@1.1.0: {}
-
- diff@8.0.4: {}
-
- dompurify@3.4.16:
- optionalDependencies:
- '@types/trusted-types': 2.0.7
-
- drizzle-kit@0.31.11:
- dependencies:
- '@drizzle-team/brocli': 0.10.2
- '@esbuild-kit/esm-loader': 2.6.5
- esbuild: 0.25.12
- tsx: 4.23.15
-
- drizzle-orm@0.45.3(@electric-sql/pglite@0.5.8)(@opentelemetry/api@1.9.1)(@types/pg@8.23.1)(kysely@0.29.6)(pg@8.23.1):
- optionalDependencies:
- '@electric-sql/pglite': 0.5.8
- '@opentelemetry/api': 1.9.1
- '@types/pg': 8.23.1
- kysely: 0.29.6
- pg: 8.23.1
-
- electron-to-chromium@1.5.444: {}
-
- emoji-regex@8.0.0: {}
-
- enhanced-resolve@5.26.0:
- dependencies:
- graceful-fs: 4.2.11
- tapable: 2.3.3
-
- env-runner@0.1.16:
- dependencies:
- crossws: 0.4.12(srvx@0.11.22)
- exsolve: 1.1.3
- httpxy: 0.5.5
- srvx: 0.11.22
-
- es-toolkit@1.52.0: {}
-
- esbuild@0.18.20:
- optionalDependencies:
- '@esbuild/android-arm': 0.18.20
- '@esbuild/android-arm64': 0.18.20
- '@esbuild/android-x64': 0.18.20
- '@esbuild/darwin-arm64': 0.18.20
- '@esbuild/darwin-x64': 0.18.20
- '@esbuild/freebsd-arm64': 0.18.20
- '@esbuild/freebsd-x64': 0.18.20
- '@esbuild/linux-arm': 0.18.20
- '@esbuild/linux-arm64': 0.18.20
- '@esbuild/linux-ia32': 0.18.20
- '@esbuild/linux-loong64': 0.18.20
- '@esbuild/linux-mips64el': 0.18.20
- '@esbuild/linux-ppc64': 0.18.20
- '@esbuild/linux-riscv64': 0.18.20
- '@esbuild/linux-s390x': 0.18.20
- '@esbuild/linux-x64': 0.18.20
- '@esbuild/netbsd-x64': 0.18.20
- '@esbuild/openbsd-x64': 0.18.20
- '@esbuild/sunos-x64': 0.18.20
- '@esbuild/win32-arm64': 0.18.20
- '@esbuild/win32-ia32': 0.18.20
- '@esbuild/win32-x64': 0.18.20
-
- esbuild@0.25.12:
- optionalDependencies:
- '@esbuild/aix-ppc64': 0.25.12
- '@esbuild/android-arm': 0.25.12
- '@esbuild/android-arm64': 0.25.12
- '@esbuild/android-x64': 0.25.12
- '@esbuild/darwin-arm64': 0.25.12
- '@esbuild/darwin-x64': 0.25.12
- '@esbuild/freebsd-arm64': 0.25.12
- '@esbuild/freebsd-x64': 0.25.12
- '@esbuild/linux-arm': 0.25.12
- '@esbuild/linux-arm64': 0.25.12
- '@esbuild/linux-ia32': 0.25.12
- '@esbuild/linux-loong64': 0.25.12
- '@esbuild/linux-mips64el': 0.25.12
- '@esbuild/linux-ppc64': 0.25.12
- '@esbuild/linux-riscv64': 0.25.12
- '@esbuild/linux-s390x': 0.25.12
- '@esbuild/linux-x64': 0.25.12
- '@esbuild/netbsd-arm64': 0.25.12
- '@esbuild/netbsd-x64': 0.25.12
- '@esbuild/openbsd-arm64': 0.25.12
- '@esbuild/openbsd-x64': 0.25.12
- '@esbuild/openharmony-arm64': 0.25.12
- '@esbuild/sunos-x64': 0.25.12
- '@esbuild/win32-arm64': 0.25.12
- '@esbuild/win32-ia32': 0.25.12
- '@esbuild/win32-x64': 0.25.12
-
- esbuild@0.28.2:
- optionalDependencies:
- '@esbuild/aix-ppc64': 0.28.2
- '@esbuild/android-arm': 0.28.2
- '@esbuild/android-arm64': 0.28.2
- '@esbuild/android-x64': 0.28.2
- '@esbuild/darwin-arm64': 0.28.2
- '@esbuild/darwin-x64': 0.28.2
- '@esbuild/freebsd-arm64': 0.28.2
- '@esbuild/freebsd-x64': 0.28.2
- '@esbuild/linux-arm': 0.28.2
- '@esbuild/linux-arm64': 0.28.2
- '@esbuild/linux-ia32': 0.28.2
- '@esbuild/linux-loong64': 0.28.2
- '@esbuild/linux-mips64el': 0.28.2
- '@esbuild/linux-ppc64': 0.28.2
- '@esbuild/linux-riscv64': 0.28.2
- '@esbuild/linux-s390x': 0.28.2
- '@esbuild/linux-x64': 0.28.2
- '@esbuild/netbsd-arm64': 0.28.2
- '@esbuild/netbsd-x64': 0.28.2
- '@esbuild/openbsd-arm64': 0.28.2
- '@esbuild/openbsd-x64': 0.28.2
- '@esbuild/openharmony-arm64': 0.28.2
- '@esbuild/sunos-x64': 0.28.2
- '@esbuild/win32-arm64': 0.28.2
- '@esbuild/win32-ia32': 0.28.2
- '@esbuild/win32-x64': 0.28.2
-
- escalade@3.2.0: {}
-
- eventemitter3@5.0.4: {}
-
- eventsource-parser@3.1.1: {}
-
- eventsource@3.0.7:
- dependencies:
- eventsource-parser: 3.1.1
-
- exsolve@1.1.3: {}
-
- fdir@6.5.0(picomatch@4.0.7):
- optionalDependencies:
- picomatch: 4.0.7
-
- fetchdts@0.1.7: {}
-
- fflate@0.4.9: {}
-
- fsevents@2.3.3:
- optional: true
-
- gensync@1.0.0-beta.2: {}
-
- get-caller-file@2.0.5: {}
-
- get-nonce@1.0.1: {}
-
- get-tsconfig@4.14.3:
- dependencies:
- resolve-pkg-maps: 1.0.0
-
- goober@2.1.19(csstype@3.2.3):
- dependencies:
- csstype: 3.2.3
-
- graceful-fs@4.2.11: {}
-
- h3@2.0.1-rc.20(crossws@0.4.12(srvx@0.11.22)):
- dependencies:
- rou3: 0.8.1
- srvx: 0.11.22
- optionalDependencies:
- crossws: 0.4.12(srvx@0.11.22)
-
- h3@2.0.1-rc.22(crossws@0.4.12(srvx@0.11.22)):
- dependencies:
- rou3: 0.8.1
- srvx: 0.11.22
- optionalDependencies:
- crossws: 0.4.12(srvx@0.11.22)
-
- hookable@6.1.2: {}
-
- httpxy@0.5.5: {}
-
- immer@10.2.0: {}
-
- immer@11.1.21: {}
-
- internmap@2.0.3: {}
-
- is-fullwidth-code-point@3.0.0: {}
-
- isbot@5.2.2: {}
-
- isexe@2.0.0: {}
-
- jiti@2.7.0: {}
-
- jose@6.2.12: {}
-
- js-tokens@4.0.0: {}
-
- js-yaml@4.3.2:
- dependencies:
- argparse: 2.0.1
-
- jsesc@3.1.0: {}
-
- json5@2.2.3: {}
-
- kysely@0.29.6: {}
-
- launch-editor@2.14.1:
- dependencies:
- picocolors: 1.1.1
- shell-quote: 1.12.0
-
- lightningcss-android-arm64@1.32.0:
- optional: true
-
- lightningcss-android-arm64@1.33.0:
- optional: true
-
- lightningcss-darwin-arm64@1.32.0:
- optional: true
-
- lightningcss-darwin-arm64@1.33.0:
- optional: true
-
- lightningcss-darwin-x64@1.32.0:
- optional: true
-
- lightningcss-darwin-x64@1.33.0:
- optional: true
-
- lightningcss-freebsd-x64@1.32.0:
- optional: true
-
- lightningcss-freebsd-x64@1.33.0:
- optional: true
-
- lightningcss-linux-arm-gnueabihf@1.32.0:
- optional: true
-
- lightningcss-linux-arm-gnueabihf@1.33.0:
- optional: true
-
- lightningcss-linux-arm64-gnu@1.32.0:
- optional: true
-
- lightningcss-linux-arm64-gnu@1.33.0:
- optional: true
-
- lightningcss-linux-arm64-musl@1.32.0:
- optional: true
-
- lightningcss-linux-arm64-musl@1.33.0:
- optional: true
-
- lightningcss-linux-x64-gnu@1.32.0:
- optional: true
-
- lightningcss-linux-x64-gnu@1.33.0:
- optional: true
-
- lightningcss-linux-x64-musl@1.32.0:
- optional: true
-
- lightningcss-linux-x64-musl@1.33.0:
- optional: true
-
- lightningcss-win32-arm64-msvc@1.32.0:
- optional: true
-
- lightningcss-win32-arm64-msvc@1.33.0:
- optional: true
-
- lightningcss-win32-x64-msvc@1.32.0:
- optional: true
-
- lightningcss-win32-x64-msvc@1.33.0:
- optional: true
-
- lightningcss@1.32.0:
- dependencies:
- detect-libc: 2.1.2
- optionalDependencies:
- lightningcss-android-arm64: 1.32.0
- lightningcss-darwin-arm64: 1.32.0
- lightningcss-darwin-x64: 1.32.0
- lightningcss-freebsd-x64: 1.32.0
- lightningcss-linux-arm-gnueabihf: 1.32.0
- lightningcss-linux-arm64-gnu: 1.32.0
- lightningcss-linux-arm64-musl: 1.32.0
- lightningcss-linux-x64-gnu: 1.32.0
- lightningcss-linux-x64-musl: 1.32.0
- lightningcss-win32-arm64-msvc: 1.32.0
- lightningcss-win32-x64-msvc: 1.32.0
-
- lightningcss@1.33.0:
- dependencies:
- detect-libc: 2.1.2
- optionalDependencies:
- lightningcss-android-arm64: 1.33.0
- lightningcss-darwin-arm64: 1.33.0
- lightningcss-darwin-x64: 1.33.0
- lightningcss-freebsd-x64: 1.33.0
- lightningcss-linux-arm-gnueabihf: 1.33.0
- lightningcss-linux-arm64-gnu: 1.33.0
- lightningcss-linux-arm64-musl: 1.33.0
- lightningcss-linux-x64-gnu: 1.33.0
- lightningcss-linux-x64-musl: 1.33.0
- lightningcss-win32-arm64-msvc: 1.33.0
- lightningcss-win32-x64-msvc: 1.33.0
-
- lru-cache@5.1.1:
- dependencies:
- yallist: 3.1.1
-
- lucide-react@0.577.0(react@19.3.0):
- dependencies:
- react: 19.3.0
-
- magic-string@0.30.21:
- dependencies:
- '@jridgewell/sourcemap-codec': 1.6.0
-
- marked@18.0.14: {}
-
- ms@2.1.3: {}
-
- nanoid@3.3.19: {}
-
- nanostores@1.5.4: {}
-
- nf3@0.3.24: {}
-
- nitro@3.0.260610-beta(@electric-sql/pglite@0.5.8)(chokidar@5.0.0)(drizzle-orm@0.45.3(@electric-sql/pglite@0.5.8)(@opentelemetry/api@1.9.1)(@types/pg@8.23.1)(kysely@0.29.6)(pg@8.23.1))(jiti@2.7.0)(vite@8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)):
- dependencies:
- consola: 3.4.2
- crossws: 0.4.12(srvx@0.11.22)
- db0: 0.3.4(@electric-sql/pglite@0.5.8)(drizzle-orm@0.45.3(@electric-sql/pglite@0.5.8)(@opentelemetry/api@1.9.1)(@types/pg@8.23.1)(kysely@0.29.6)(pg@8.23.1))
- env-runner: 0.1.16
- h3: 2.0.1-rc.22(crossws@0.4.12(srvx@0.11.22))
- hookable: 6.1.2
- nf3: 0.3.24
- ocache: 0.1.5
- ofetch: 2.0.0-alpha.3
- ohash: 2.0.12
- rolldown: 1.2.12
- srvx: 0.11.22
- unenv: 2.0.0-rc.24
- unstorage: 2.0.0-alpha.7(chokidar@5.0.0)(db0@0.3.4(@electric-sql/pglite@0.5.8)(drizzle-orm@0.45.3(@electric-sql/pglite@0.5.8)(@opentelemetry/api@1.9.1)(@types/pg@8.23.1)(kysely@0.29.6)(pg@8.23.1)))(ofetch@2.0.0-alpha.3)
- optionalDependencies:
- jiti: 2.7.0
- vite: 8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)
- transitivePeerDependencies:
- - '@azure/app-configuration'
- - '@azure/cosmos'
- - '@azure/data-tables'
- - '@azure/identity'
- - '@azure/keyvault-secrets'
- - '@azure/storage-blob'
- - '@capacitor/preferences'
- - '@deno/kv'
- - '@electric-sql/pglite'
- - '@libsql/client'
- - '@netlify/blobs'
- - '@netlify/runtime'
- - '@planetscale/database'
- - '@upstash/redis'
- - '@vercel/blob'
- - '@vercel/functions'
- - '@vercel/kv'
- - aws4fetch
- - better-sqlite3
- - chokidar
- - drizzle-orm
- - idb-keyval
- - ioredis
- - lru-cache
- - miniflare
- - mongodb
- - mysql2
- - sqlite3
- - uploadthing
- - wrangler
-
- node-releases@2.0.57: {}
-
- ocache@0.1.5:
- dependencies:
- ohash: 2.0.12
-
- ofetch@2.0.0-alpha.3: {}
-
- ohash@2.0.12: {}
-
- oxc-parser@0.120.0(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3):
- dependencies:
- '@oxc-project/types': 0.120.0
- optionalDependencies:
- '@oxc-parser/binding-android-arm-eabi': 0.120.0
- '@oxc-parser/binding-android-arm64': 0.120.0
- '@oxc-parser/binding-darwin-arm64': 0.120.0
- '@oxc-parser/binding-darwin-x64': 0.120.0
- '@oxc-parser/binding-freebsd-x64': 0.120.0
- '@oxc-parser/binding-linux-arm-gnueabihf': 0.120.0
- '@oxc-parser/binding-linux-arm-musleabihf': 0.120.0
- '@oxc-parser/binding-linux-arm64-gnu': 0.120.0
- '@oxc-parser/binding-linux-arm64-musl': 0.120.0
- '@oxc-parser/binding-linux-ppc64-gnu': 0.120.0
- '@oxc-parser/binding-linux-riscv64-gnu': 0.120.0
- '@oxc-parser/binding-linux-riscv64-musl': 0.120.0
- '@oxc-parser/binding-linux-s390x-gnu': 0.120.0
- '@oxc-parser/binding-linux-x64-gnu': 0.120.0
- '@oxc-parser/binding-linux-x64-musl': 0.120.0
- '@oxc-parser/binding-openharmony-arm64': 0.120.0
- '@oxc-parser/binding-wasm32-wasi': 0.120.0(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)
- '@oxc-parser/binding-win32-arm64-msvc': 0.120.0
- '@oxc-parser/binding-win32-ia32-msvc': 0.120.0
- '@oxc-parser/binding-win32-x64-msvc': 0.120.0
- transitivePeerDependencies:
- - '@emnapi/core'
- - '@emnapi/runtime'
-
- path-key@3.1.1: {}
-
- pathe@2.0.3: {}
-
- pg-cloudflare@1.4.1:
- optional: true
-
- pg-connection-string@2.14.1: {}
-
- pg-int8@1.0.1: {}
-
- pg-pool@3.14.0(pg@8.23.1):
- dependencies:
- pg: 8.23.1
-
- pg-protocol@1.16.1: {}
-
- pg-types@2.2.0:
- dependencies:
- pg-int8: 1.0.1
- postgres-array: 2.0.0
- postgres-bytea: 1.0.1
- postgres-date: 1.0.7
- postgres-interval: 1.2.0
-
- pg@8.23.1:
- dependencies:
- pg-connection-string: 2.14.1
- pg-pool: 3.14.0(pg@8.23.1)
- pg-protocol: 1.16.1
- pg-types: 2.2.0
- pgpass: 1.0.5
- optionalDependencies:
- pg-cloudflare: 1.4.1
-
- pgpass@1.0.5:
- dependencies:
- split2: 4.2.0
-
- picocolors@1.1.1: {}
-
- picomatch@4.0.7: {}
-
- pkce-challenge@5.0.1: {}
-
- postcss-selector-parser@6.0.10:
- dependencies:
- cssesc: 3.0.0
- util-deprecate: 1.0.2
-
- postcss@8.5.28:
- dependencies:
- nanoid: 3.3.19
- picocolors: 1.1.1
- source-map-js: 1.2.2
-
- postgres-array@2.0.0: {}
-
- postgres-bytea@1.0.1: {}
-
- postgres-date@1.0.7: {}
-
- postgres-interval@1.2.0:
- dependencies:
- xtend: 4.0.2
-
- posthog-js@1.436.1(@types/react@19.3.0)(react@19.3.0):
- dependencies:
- '@posthog/browser-common': 0.9.1
- '@posthog/core': 1.56.0
- '@posthog/types': 1.413.0
- core-js: 3.50.0
- dompurify: 3.4.16
- fflate: 0.4.9
- preact: 10.29.8
- query-selector-shadow-dom: 1.0.1
- web-vitals: 6.2.3
- web-vitals-soft-navs: web-vitals@6.2.1
- optionalDependencies:
- '@types/react': 19.3.0
- react: 19.3.0
- transitivePeerDependencies:
- - preact-render-to-string
-
- posthog-node@5.55.0:
- dependencies:
- '@posthog/core': 1.56.0
-
- preact@10.29.8: {}
-
- prettier@3.9.9: {}
-
- query-selector-shadow-dom@1.0.1: {}
-
- react-dom@19.3.0(react@19.3.0):
- dependencies:
- react: 19.3.0
- scheduler: 0.28.0
-
- react-is@19.3.0: {}
-
- react-redux@9.3.0(@types/react@19.3.0)(react@19.3.0)(redux@5.0.1):
- dependencies:
- '@types/use-sync-external-store': 0.0.6
- react: 19.3.0
- use-sync-external-store: 1.7.0(react@19.3.0)
- optionalDependencies:
- '@types/react': 19.3.0
- redux: 5.0.1
-
- react-remove-scroll-bar@2.3.8(@types/react@19.3.0)(react@19.3.0):
- dependencies:
- react: 19.3.0
- react-style-singleton: 2.2.3(@types/react@19.3.0)(react@19.3.0)
- tslib: 2.8.1
- optionalDependencies:
- '@types/react': 19.3.0
-
- react-remove-scroll@2.7.2(@types/react@19.3.0)(react@19.3.0):
- dependencies:
- react: 19.3.0
- react-remove-scroll-bar: 2.3.8(@types/react@19.3.0)(react@19.3.0)
- react-style-singleton: 2.2.3(@types/react@19.3.0)(react@19.3.0)
- tslib: 2.8.1
- use-callback-ref: 1.3.3(@types/react@19.3.0)(react@19.3.0)
- use-sidecar: 1.1.3(@types/react@19.3.0)(react@19.3.0)
- optionalDependencies:
- '@types/react': 19.3.0
-
- react-style-singleton@2.2.3(@types/react@19.3.0)(react@19.3.0):
- dependencies:
- get-nonce: 1.0.1
- react: 19.3.0
- tslib: 2.8.1
- optionalDependencies:
- '@types/react': 19.3.0
-
- react@19.3.0: {}
-
- readdirp@5.1.1: {}
-
- recharts@3.8.0(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react-is@19.3.0)(react@19.3.0)(redux@5.0.1):
- dependencies:
- '@reduxjs/toolkit': 2.13.0(react-redux@9.3.0(@types/react@19.3.0)(react@19.3.0)(redux@5.0.1))(react@19.3.0)
- clsx: 2.1.1
- decimal.js-light: 2.5.1
- es-toolkit: 1.52.0
- eventemitter3: 5.0.4
- immer: 10.2.0
- react: 19.3.0
- react-dom: 19.3.0(react@19.3.0)
- react-is: 19.3.0
- react-redux: 9.3.0(@types/react@19.3.0)(react@19.3.0)(redux@5.0.1)
- reselect: 5.1.1
- tiny-invariant: 1.3.3
- use-sync-external-store: 1.7.0(react@19.3.0)
- victory-vendor: 37.3.6
- transitivePeerDependencies:
- - '@types/react'
- - redux
-
- redux-thunk@3.1.0(redux@5.0.1):
- dependencies:
- redux: 5.0.1
-
- redux@5.0.1: {}
-
- require-directory@2.1.1: {}
-
- reselect@5.1.1: {}
-
- reselect@5.3.0: {}
-
- resolve-pkg-maps@1.0.0: {}
-
- rolldown@1.2.12:
- dependencies:
- '@oxc-project/types': 0.152.0
- '@rolldown/pluginutils': 1.0.1
- optionalDependencies:
- '@rolldown/binding-android-arm-eabi': 1.2.12
- '@rolldown/binding-android-arm64': 1.2.12
- '@rolldown/binding-darwin-arm64': 1.2.12
- '@rolldown/binding-darwin-x64': 1.2.12
- '@rolldown/binding-freebsd-x64': 1.2.12
- '@rolldown/binding-linux-arm-gnueabihf': 1.2.12
- '@rolldown/binding-linux-arm64-gnu': 1.2.12
- '@rolldown/binding-linux-arm64-musl': 1.2.12
- '@rolldown/binding-linux-ppc64-gnu': 1.2.12
- '@rolldown/binding-linux-s390x-gnu': 1.2.12
- '@rolldown/binding-linux-x64-gnu': 1.2.12
- '@rolldown/binding-linux-x64-musl': 1.2.12
- '@rolldown/binding-openharmony-arm64': 1.2.12
- '@rolldown/binding-win32-arm64-msvc': 1.2.12
- '@rolldown/binding-win32-x64-msvc': 1.2.12
-
- rou3@0.8.1: {}
-
- rou3@0.9.2: {}
-
- scheduler@0.28.0: {}
-
- semver@6.3.1: {}
-
- seroval-plugins@1.5.6(seroval@1.5.6):
- dependencies:
- seroval: 1.5.6
-
- seroval-plugins@1.6.8(seroval@1.6.8):
- dependencies:
- seroval: 1.6.8
-
- seroval@1.5.6: {}
-
- seroval@1.6.8: {}
-
- set-cookie-parser@3.1.2: {}
-
- shebang-command@2.0.0:
- dependencies:
- shebang-regex: 3.0.0
-
- shebang-regex@3.0.0: {}
-
- shell-quote@1.12.0: {}
-
- simple-icons@16.34.0: {}
-
- solid-js@1.9.15:
- dependencies:
- csstype: 3.2.3
- seroval: 1.5.6
- seroval-plugins: 1.5.6(seroval@1.5.6)
-
- source-map-js@1.2.2: {}
-
- source-map-support@0.5.21:
- dependencies:
- buffer-from: 1.1.2
- source-map: 0.6.1
-
- source-map@0.6.1: {}
-
- source-map@0.7.6: {}
-
- split2@4.2.0: {}
-
- srvx@0.11.22: {}
-
- string-width@4.2.3:
- dependencies:
- emoji-regex: 8.0.0
- is-fullwidth-code-point: 3.0.0
- strip-ansi: 6.0.1
-
- strip-ansi@6.0.1:
- dependencies:
- ansi-regex: 5.0.1
-
- tailwindcss@4.3.3: {}
-
- tapable@2.3.3: {}
-
- tiny-invariant@1.3.3: {}
-
- tinyglobby@0.2.17:
- dependencies:
- fdir: 6.5.0(picomatch@4.0.7)
- picomatch: 4.0.7
-
- tslib@2.8.1: {}
-
- tsx@4.23.15:
- dependencies:
- esbuild: 0.28.2
- optionalDependencies:
- fsevents: 2.3.3
-
- tw-animate-css@1.4.0: {}
-
- typescript@6.0.3: {}
-
- ufo@1.6.4: {}
-
- undici-types@6.21.0: {}
-
- unenv@2.0.0-rc.24:
- dependencies:
- pathe: 2.0.3
-
- unplugin@3.4.0(esbuild@0.28.2)(rolldown@1.2.12)(vite@8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)):
- dependencies:
- '@jridgewell/remapping': 2.3.5
- picomatch: 4.0.7
- webpack-virtual-modules: 0.6.2
- optionalDependencies:
- esbuild: 0.28.2
- rolldown: 1.2.12
- vite: 8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)
-
- unstorage@2.0.0-alpha.7(chokidar@5.0.0)(db0@0.3.4(@electric-sql/pglite@0.5.8)(drizzle-orm@0.45.3(@electric-sql/pglite@0.5.8)(@opentelemetry/api@1.9.1)(@types/pg@8.23.1)(kysely@0.29.6)(pg@8.23.1)))(ofetch@2.0.0-alpha.3):
- optionalDependencies:
- chokidar: 5.0.0
- db0: 0.3.4(@electric-sql/pglite@0.5.8)(drizzle-orm@0.45.3(@electric-sql/pglite@0.5.8)(@opentelemetry/api@1.9.1)(@types/pg@8.23.1)(kysely@0.29.6)(pg@8.23.1))
- ofetch: 2.0.0-alpha.3
-
- update-browserslist-db@1.3.3(browserslist@4.29.3):
- dependencies:
- browserslist: 4.29.3
- escalade: 3.2.0
- picocolors: 1.1.1
-
- use-callback-ref@1.3.3(@types/react@19.3.0)(react@19.3.0):
- dependencies:
- react: 19.3.0
- tslib: 2.8.1
- optionalDependencies:
- '@types/react': 19.3.0
-
- use-sidecar@1.1.3(@types/react@19.3.0)(react@19.3.0):
- dependencies:
- detect-node-es: 1.1.0
- react: 19.3.0
- tslib: 2.8.1
- optionalDependencies:
- '@types/react': 19.3.0
-
- use-sync-external-store@1.7.0(react@19.3.0):
- dependencies:
- react: 19.3.0
-
- util-deprecate@1.0.2: {}
-
- victory-vendor@37.3.6:
- dependencies:
- '@types/d3-array': 3.2.2
- '@types/d3-ease': 3.0.2
- '@types/d3-interpolate': 3.0.4
- '@types/d3-scale': 4.0.9
- '@types/d3-shape': 3.2.0
- '@types/d3-time': 3.0.4
- '@types/d3-timer': 3.0.2
- d3-array: 3.2.4
- d3-ease: 3.0.1
- d3-interpolate: 3.0.1
- d3-scale: 4.0.2
- d3-shape: 3.2.0
- d3-time: 3.1.0
- d3-timer: 3.0.1
-
- vite@8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15):
- dependencies:
- lightningcss: 1.33.0
- picomatch: 4.0.7
- postcss: 8.5.28
- rolldown: 1.2.12
- tinyglobby: 0.2.17
- optionalDependencies:
- '@types/node': 22.20.5
- esbuild: 0.28.2
- fsevents: 2.3.3
- jiti: 2.7.0
- tsx: 4.23.15
-
- vitefu@1.1.3(vite@8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)):
- optionalDependencies:
- vite: 8.3.2(@types/node@22.20.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)
-
- web-vitals@6.2.1: {}
-
- web-vitals@6.2.3: {}
-
- webpack-virtual-modules@0.6.2: {}
-
- which@2.0.2:
- dependencies:
- isexe: 2.0.0
-
- wrap-ansi@7.0.0:
- dependencies:
- ansi-styles: 4.3.0
- string-width: 4.2.3
- strip-ansi: 6.0.1
-
- ws@8.22.0: {}
-
- xmlbuilder2@4.0.3:
- dependencies:
- '@oozcitak/dom': 2.0.2
- '@oozcitak/infra': 2.0.2
- '@oozcitak/util': 10.0.0
- js-yaml: 4.3.2
-
- xtend@4.0.2: {}
-
- y18n@5.0.8: {}
-
- yallist@3.1.1: {}
-
- yargs-parser@21.1.1: {}
-
- yargs@17.7.3:
- dependencies:
- cliui: 8.0.1
- escalade: 3.2.0
- get-caller-file: 2.0.5
- require-directory: 2.1.1
- string-width: 4.2.3
- y18n: 5.0.8
- yargs-parser: 21.1.1
-
- zod@4.6.5: {}
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
deleted file mode 100644
index 79ae338..0000000
--- a/pnpm-workspace.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-packages:
- - packages/*
-allowBuilds:
- core-js: false
- esbuild: true
- lightningcss: true
diff --git a/public/logos/SOURCES.md b/public/logos/SOURCES.md
index 432d07e..06255fe 100644
--- a/public/logos/SOURCES.md
+++ b/public/logos/SOURCES.md
@@ -17,6 +17,7 @@ We changed only the `viewBox` of `stripe`, `revenuecat`, `openai`, `resend` and
| `revenuecat.svg` | RevenueCat press kit logomark, [revenuecat.com/press-kit](https://www.revenuecat.com/press-kit). SVGL has no RevenueCat logo. | [revenuecat.com/press-kit](https://www.revenuecat.com/press-kit) |
| `appstore.svg` | SVGL `appstore.svg` | |
| `googleplay.svg` | SVGL `googleplay.svg` | |
+| `google.svg` | [SVG Logos](https://github.com/gilbarbara/logos) `google-icon.svg` (CC0-1.0). SVGL's `google.svg` blurs at 14 px. The sign-in button uses it; Google isn't a connector. | |
| `openai.svg`, `openai-dark.svg` | SVGL `openai.svg`, `openai_dark.svg` | [openai.com/brand](https://openai.com/brand/) |
| `anthropic.svg`, `anthropic-dark.svg` | SVGL `anthropic_black.svg`, `anthropic_white.svg` | |
| `openrouter.svg`, `openrouter-dark.svg` | SVGL `openrouter_light.svg`, `openrouter_dark.svg` | |
diff --git a/public/logos/google.svg b/public/logos/google.svg
new file mode 100644
index 0000000..05d397a
--- /dev/null
+++ b/public/logos/google.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/scripts/benchmarks.ts b/scripts/benchmarks.ts
index 814e78d..19ea117 100644
--- a/scripts/benchmarks.ts
+++ b/scripts/benchmarks.ts
@@ -1,5 +1,5 @@
// Computes the benchmark percentiles for one month, by default the last
-// complete one: `pnpm benchmarks` or `pnpm benchmarks --month=2026-09`.
+// complete one: `bun run benchmarks` or `bun run benchmarks --month=2026-09`.
// With PGlite, stop the dev server first.
import assert from "node:assert/strict";
import { bandFor, percentile } from "#/lib/benchmarks";
diff --git a/scripts/check-books-close.ts b/scripts/check-books-close.ts
index 0d98ced..5177e05 100644
--- a/scripts/check-books-close.ts
+++ b/scripts/check-books-close.ts
@@ -1,5 +1,5 @@
// Checks month closing and adjustments in src/server/books.server.ts on a
-// scratch database. Run: DATABASE_URL=/tmp/books-check SYNC_SCHEDULER=off npx tsx scripts/check-books-close.ts
+// scratch database. Run: DATABASE_URL=/tmp/books-check SYNC_SCHEDULER=off bun scripts/check-books-close.ts
import assert from "node:assert/strict";
const { db, schema } = await import("../src/db/index.ts");
const { exportJournal } = await import("../src/server/books.server.ts");
@@ -28,5 +28,15 @@ assert(oct.some((e) => e.group === "earn:stripe"));
// Exporting November doesn't repeat the September adjustment.
const nov = await exportJournal(ws, "2026-11", { withBank: true });
assert(!nov.some((e) => e.group === "adjust:2026-09"));
+// A lost dispute (gross 0, net -6500 with a 1500 fee) leaves the Stripe
+// balance by its net, the part past the fee as a payment fee.
+await db.insert(schema.revenueLines).values({ workspaceId: ws.id, connectionId: stripe.id, date: "2026-06-10", currency: "USD", grossCents: 0, feesCents: 1500, netCents: -6500, netBaseCents: -6500, grossBaseCents: 0, feesBaseCents: 1500, refundsBaseCents: 0, externalId: "du_1" });
+const { booksInputs } = await import("../src/server/books.server.ts");
+const { journal } = await import("../src/lib/books.ts");
+const [june] = await booksInputs(ws, ["2026-06"]);
+const lines = journal(june).flatMap((e) => e.lines);
+const net = (a: string) => lines.filter((l) => l.account === a).reduce((x, l) => x + l.debit - l.credit, 0);
+assert.equal(net("balance:stripe"), -6500);
+assert.equal(net("payment_fees"), 6500);
console.log("close: ok");
process.exit(0);
diff --git a/scripts/check-books-export.ts b/scripts/check-books-export.ts
index 7c29da8..410d879 100644
--- a/scripts/check-books-export.ts
+++ b/scripts/check-books-export.ts
@@ -1,5 +1,5 @@
// Checks the journal files in src/server/books-export.server.ts on a scratch
-// database. Run: DATABASE_URL=/tmp/books-export-check SYNC_SCHEDULER=off npx tsx scripts/check-books-export.ts
+// database. Run: DATABASE_URL=/tmp/books-export-check SYNC_SCHEDULER=off bun scripts/check-books-export.ts
import assert from "node:assert/strict";
const { db, schema } = await import("../src/db/index.ts");
const { journalCsv } = await import("../src/server/books-export.server.ts");
diff --git a/scripts/check-books-tax.ts b/scripts/check-books-tax.ts
index 3ed7cf0..45bc761 100644
--- a/scripts/check-books-tax.ts
+++ b/scripts/check-books-tax.ts
@@ -1,5 +1,5 @@
// Checks the tax report (src/server/tax.server.ts, src/lib/tax.ts) on a scratch
-// database. Run: DATABASE_URL=/tmp/books-tax-check SYNC_SCHEDULER=off npx tsx scripts/check-books-tax.ts
+// database. Run: DATABASE_URL=/tmp/books-tax-check SYNC_SCHEDULER=off bun scripts/check-books-tax.ts
import assert from "node:assert/strict";
const { db, schema } = await import("../src/db/index.ts");
@@ -154,9 +154,10 @@ const fr = await check("FR", { country: "FR" });
assert.deepEqual(fr.rep.parts[0].forms.map((f) => f.name), ["Profit and loss"]);
assert.equal(fr.rep.parts[0].depreciation.length, 0);
-// No country: nothing to map.
+// No country: the same plain profit and loss.
const none = await seed({ country: "" as string });
-assert.equal((await taxReport({ ...none, country: null }, 2025)).parts.length, 0);
+const noneRep = await taxReport({ ...none, country: null }, 2025);
+assert.deepEqual(noneRep.parts[0].forms.map((f) => f.name), ["Profit and loss"]);
// The rules on their own: declining balance and the dates around them.
const one = (country: string, date: string, cost: number, y: number, inc: string | null = null) =>
diff --git a/scripts/check-books.ts b/scripts/check-books.ts
index 0a6f835..18efac7 100644
--- a/scripts/check-books.ts
+++ b/scripts/check-books.ts
@@ -1,5 +1,5 @@
// Checks the journal rules in src/lib/books.ts (docs/BOOKS.md).
-// Run: npx tsx scripts/check-books.ts
+// Run: bun scripts/check-books.ts
import assert from "node:assert/strict";
import {
adjustments,
@@ -95,6 +95,22 @@ assert(allBalanced(manual));
// The summary keeps every entry balanced.
assert(summarize([...dec, ...company], "2025-12").every(balanced));
+// A yearly cost's 12 months add up to it, rounding included.
+let yearly = 0;
+for (let m = 3; m <= 14; m++) {
+ const month = `${2026 + Math.floor((m - 1) / 12)}-${String(((m - 1) % 12) + 1).padStart(2, "0")}`;
+ const es = journal({ ...base, month, manual: [{ name: "Tool", productId: null, amount: 1000, interval: "year", startsOn: "2026-03-15", endsOn: null, category: "software", method: "personal", since: null }] });
+ yearly += sum(es, "software");
+}
+assert.equal(yearly, 1000);
+
+// A group's bank and other entries stay apart in the summary: two costs
+// with one name, one on the card and one from the company account.
+const twin = (method: "personal" | "company") => ({ name: "Domain", productId: null, amount: 1500, interval: "once" as const, startsOn: "2026-03-05", endsOn: null, category: "software" as const, method, since: null });
+const twins = summarize(journal({ ...base, month: "2026-03", incorporatedOn: "2026-02-01", manual: [twin("personal"), twin("company")] }), "2026-03");
+assert.equal(twins.length, 2);
+assert(twins.filter((e) => !e.bank).every((e) => !e.lines.some((l) => l.account === "company_bank")));
+
// A closed month that changed later goes out as one balanced adjustment,
// without the bank side for formats that leave it to the bank feed.
const before = totals(company);
diff --git a/scripts/rotate-secret-key.ts b/scripts/rotate-secret-key.ts
new file mode 100644
index 0000000..c7837be
--- /dev/null
+++ b/scripts/rotate-secret-key.ts
@@ -0,0 +1,80 @@
+// Re-encrypts every stored secret from OLD_SECRET_KEY to SECRET_KEY: connection
+// credentials and the alert channels' Slack and webhook values.
+//
+// OLD_SECRET_KEY= SECRET_KEY= SYNC_SCHEDULER=off \
+// DATABASE_URL= bun scripts/rotate-secret-key.ts [--dry-run]
+//
+// One transaction: a value that neither key opens aborts the whole run and
+// nothing is written. Values the new key already opens are left as they are,
+// so a second run is safe. Stop the app first (PGlite allows one process),
+// then start it with the new SECRET_KEY. Sessions and pending SMS codes are
+// signed with the key, so everyone signs in again.
+import { eq } from "drizzle-orm";
+import { db, schema } from "#/db";
+import { decrypt, encrypt, importSecret } from "#/lib/crypto";
+
+const dryRun = process.argv.includes("--dry-run");
+if (process.env.OLD_SECRET_KEY === process.env.SECRET_KEY)
+ throw new Error("OLD_SECRET_KEY and SECRET_KEY are the same");
+const oldKey = await importSecret(process.env.OLD_SECRET_KEY);
+const newKey = await importSecret(process.env.SECRET_KEY);
+
+// The value under the new key, or null when it already is.
+async function reencrypt(payload: string, where: string) {
+ if (await decrypt(payload, newKey).then(() => true, () => false)) return null;
+ const value = await decrypt(payload, oldKey).catch(() => {
+ throw new Error(`${where}: neither key decrypts it`);
+ });
+ return encrypt(value, newKey);
+}
+
+const counts = { connections: 0, channels: 0, current: 0 };
+
+await db.transaction(async (tx) => {
+ const conns = await tx
+ .select({
+ id: schema.connections.id,
+ credentials: schema.connections.credentials,
+ })
+ .from(schema.connections);
+ for (const c of conns) {
+ const credentials = await reencrypt(c.credentials, `connection ${c.id}`);
+ if (!credentials) {
+ counts.current++;
+ continue;
+ }
+ await tx
+ .update(schema.connections)
+ .set({ credentials })
+ .where(eq(schema.connections.id, c.id));
+ counts.connections++;
+ }
+
+ const channels = await tx.select().from(schema.alertChannels);
+ for (const ch of channels) {
+ const set: Partial = {};
+ for (const field of ["slackWebhook", "webhookUrl", "webhookSecret"] as const) {
+ const payload = ch[field];
+ if (!payload) continue;
+ const next = await reencrypt(payload, `${field} of workspace ${ch.workspaceId}`);
+ if (next) set[field] = next;
+ else counts.current++;
+ }
+ if (Object.keys(set).length === 0) continue;
+ await tx
+ .update(schema.alertChannels)
+ .set(set)
+ .where(eq(schema.alertChannels.workspaceId, ch.workspaceId));
+ counts.channels++;
+ }
+
+ if (dryRun) tx.rollback();
+}).catch((e) => {
+ // Drizzle's rollback() throws to end the transaction.
+ if (!(dryRun && e?.constructor?.name === "TransactionRollbackError")) throw e;
+});
+
+console.log(
+ `${dryRun ? "Dry run: would re-encrypt" : "Re-encrypted"} ${counts.connections} connections and ${counts.channels} alert channel rows; ${counts.current} values already used the new key.`,
+);
+process.exit(0);
diff --git a/scripts/seed.ts b/scripts/seed.ts
index fd9aa82..8527c55 100644
--- a/scripts/seed.ts
+++ b/scripts/seed.ts
@@ -1,4 +1,4 @@
-// Seeds one workspace with twelve months of numbers. Run with `pnpm db:seed`.
+// Seeds one workspace with twelve months of numbers. Run with `bun run db:seed`.
import { eq } from "drizzle-orm";
import { authSchema, db, schema } from "#/db";
import { seedWorkspace } from "#/server/seed.server";
diff --git a/src/components/books/export.tsx b/src/components/books/export.tsx
index 664c6d9..c663c22 100644
--- a/src/components/books/export.tsx
+++ b/src/components/books/export.tsx
@@ -124,7 +124,7 @@ export function BooksExport({ options }: { options: Options }) {
await save({ data: names });
setDirty(false);
}
- const res = await fetch(url);
+ const res = await fetch(url, { method: journal ? "POST" : "GET" });
if (!res.ok) return setError(await res.text());
const a = document.createElement("a");
a.href = URL.createObjectURL(await res.blob());
diff --git a/src/components/landing/footer.tsx b/src/components/landing/footer.tsx
index e37c366..a1c59e9 100644
--- a/src/components/landing/footer.tsx
+++ b/src/components/landing/footer.tsx
@@ -8,7 +8,8 @@ const COLUMNS: [string, [string, string][]][] = [
[
["Integrations", "/integrations"],
["Public pages", "/docs/public-pages"],
- ["Open profit", "/open"],
+ ["Profit database", "/open"],
+ ["Benchmarks", "/data"],
["Pricing", "/#pricing"],
["Changelog", "/changelog"],
["Blog", "/blog"],
@@ -17,7 +18,7 @@ const COLUMNS: [string, [string, string][]][] = [
[
"Developers",
[
- ["Docs", "/docs"],
+ ["Docs", "/docs/connectors"],
["Self-host", "/docs/self-host"],
["GitHub", GITHUB_URL],
],
@@ -55,7 +56,7 @@ export function Footer() {
{COLUMNS.map(([title, links]) => (
-
{title}
+
{title}
{links.map(([label, href]) => (
diff --git a/src/components/landing/nav.tsx b/src/components/landing/nav.tsx
index 9c5d982..bdc5f8e 100644
--- a/src/components/landing/nav.tsx
+++ b/src/components/landing/nav.tsx
@@ -9,7 +9,7 @@ const LINKS = [
["Product", "/#product"],
["Integrations", "/integrations"],
["Pricing", "/#pricing"],
- ["Docs", "/docs"],
+ ["Docs", "/docs/connectors"],
["Blog", "/blog"],
];
diff --git a/src/connectors/cloudflare.ts b/src/connectors/cloudflare.ts
index c5ddcca..7e362c0 100644
--- a/src/connectors/cloudflare.ts
+++ b/src/connectors/cloudflare.ts
@@ -40,6 +40,18 @@ type Usage = {
ZoneId?: string;
ZoneName?: string;
};
+type Info = { subscriptions?: { billing_cycle_anchor_timestamp: string }[] };
+
+// The latest day on or before `date` (YYYY-MM-DD) that falls on the anchor's
+// day of the month. 62 days back always reaches any day, the 31st included.
+function anchorOnOrBefore(date: string, anchor: string) {
+ const dom = new Date(anchor).getUTCDate();
+ let t = Date.parse(`${date}T00:00:00Z`);
+ for (let i = 0; i < 62 && new Date(t).getUTCDate() !== dom; i++)
+ t -= 86_400_000;
+ return new Date(t).toISOString().slice(0, 10);
+}
+
type Invoice = {
id: string;
amount: number;
@@ -79,13 +91,30 @@ export const cloudflare = register({
const id = await accountId(c);
const out: CostLine[] = [];
try {
+ // The range must include a subscription's billing cycle anchor day,
+ // or the API returns no usage, so it starts at the last anchor day
+ // on or before `from`; lines before `from` are dropped.
+ // https://developers.cloudflare.com/api/resources/billing/subresources/usage/methods/get_account_usage_v1/
+ const info = await getJson>(
+ `${BASE}/accounts/${id}/billable-usage/info`,
+ { headers: headers(c) },
+ );
+ let from = range.from;
+ for (const s of info.result?.subscriptions ?? []) {
+ const day = anchorOnOrBefore(
+ range.from,
+ s.billing_cycle_anchor_timestamp,
+ );
+ if (day < from) from = day;
+ }
const u = await getJson>(
- `${BASE}/accounts/${id}/billable-usage?from=${range.from}&to=${range.to}`,
+ `${BASE}/accounts/${id}/billable-usage?from=${from}&to=${range.to}`,
{ headers: headers(c) },
);
for (const r of u.result ?? []) {
if (!r.BilledCost) continue;
const date = r.ChargePeriodStart.slice(0, 10);
+ if (date < range.from) continue;
out.push({
externalId: `usage:${date}:${r.ServiceName}:${r.ChargeDescription ?? ""}:${r.ZoneId ?? ""}`,
date,
diff --git a/src/connectors/vercel.ts b/src/connectors/vercel.ts
index 40d0121..717487e 100644
--- a/src/connectors/vercel.ts
+++ b/src/connectors/vercel.ts
@@ -10,6 +10,9 @@ import {
const BASE = "https://api.vercel.com";
const headers = (c: Credentials) => ({ Authorization: `Bearer ${c.token}` });
+const DAY = 86_400_000;
+// 365 days fits the 1-year limit in leap years too.
+const YEAR = 365 * DAY;
type Charge = {
BilledCost: number;
@@ -64,22 +67,31 @@ export const vercel = register({
const team = await teamId(c);
return { label: `${u.user.username} · ${team}` };
},
- // FOCUS charges, one JSON object per line.
+ // FOCUS charges, one JSON object per line. One request covers at most a
+ // year, so a two-year backfill takes several, each [from, to) in UTC.
+ // https://vercel.com/docs/rest-api/reference/endpoints/billing/list-focus-billing-charges
async fetchCosts(c, range: SyncRange) {
const team = await teamId(c);
- const to = new Date(
- Date.parse(`${range.to}T00:00:00Z`) + 86_400_000,
- ).toISOString();
- const res = await fetch(
- `${BASE}/v1/billing/charges?teamId=${team}&from=${range.from}T00:00:00.000Z&to=${to}`,
- { headers: headers(c) },
- );
- if (!res.ok)
- throw new ConnectorError(
- `${res.status} ${await res.text().catch(() => "")}`.slice(0, 200),
- res.status,
+ const end = Date.parse(`${range.to}T00:00:00Z`) + DAY;
+ let text = "";
+ for (
+ let start = Date.parse(`${range.from}T00:00:00Z`);
+ start < end;
+ start += YEAR
+ ) {
+ const from = new Date(start).toISOString();
+ const to = new Date(Math.min(start + YEAR, end)).toISOString();
+ const res = await fetch(
+ `${BASE}/v1/billing/charges?teamId=${team}&from=${from}&to=${to}`,
+ { headers: headers(c) },
);
- const text = await res.text();
+ if (!res.ok)
+ throw new ConnectorError(
+ `${res.status} ${await res.text().catch(() => "")}`.slice(0, 200),
+ res.status,
+ );
+ text += `${await res.text()}\n`;
+ }
const out: CostLine[] = [];
for (const line of text.split("\n")) {
if (!line.trim()) continue;
diff --git a/src/content/blog/ai-token-cost-per-user.md b/src/content/blog/ai-token-cost-per-user.md
new file mode 100644
index 0000000..a12c982
--- /dev/null
+++ b/src/content/blog/ai-token-cost-per-user.md
@@ -0,0 +1,91 @@
+---
+title: AI token cost per user: how to work it out before you price
+description: What each user of your AI app costs in tokens, with October 2026 Claude and OpenAI prices, worked examples and five ways to keep heavy users profitable.
+date: 2026-10-19
+author: Raphael Morency
+---
+
+# AI token cost per user: how to work it out before you price
+
+On a $20 plan, a user who sends 20 chat messages a day to Claude Sonnet 5.5 costs you about $5 a month in tokens. A user who also runs five agent tasks a day costs about $62. Both pay $20, and your OpenAI or Anthropic bill shows one total for the two of them.
+
+You can work out the cost of each user before you set a price, with four numbers per feature and the model's price list.
+
+## The formula
+
+Each API call costs its input tokens at the input price plus its output tokens at the output price:
+
+```text
+Cost of one call = input tokens × input price + output tokens × output price
+Cost per user per month = calls per month × cost of one call
+```
+
+Prices are per million tokens, so divide by 1,000,000. If you use prompt caching, add a line for cached input, which the provider bills at a lower rate when you resend the same prompt prefix.
+
+## Claude and OpenAI API pricing in October 2026
+
+Standard prices per million tokens, from the [Claude pricing page](https://claude.com/pricing) and the [OpenAI pricing page](https://developers.openai.com/api/docs/pricing) on October 19, 2026:
+
+| Model | Input | Cached input | Output |
+|---|---|---|---|
+| Claude Opus 5.5 | $4.00 | $0.20 | $20.00 |
+| Claude Sonnet 5.5 | $2.00 | $0.10 | $10.00 |
+| Claude Haiku 5.5 | $0.10 | $0.01 | $0.50 |
+| GPT-6 Astra | $10.00 | $1.00 | $50.00 |
+| GPT-6.1 Sol | $2.00 | $0.10 | $10.00 |
+| GPT-6 Luna | $0.10 | $0.01 | $0.50 |
+
+Haiku 5.5's price applies to prompts up to 100,000 tokens, and Claude's cache reads assume the five-minute cache. Output costs five times the input on each model here, so a feature that writes long answers costs more than one that reads long documents.
+
+## Three features, priced
+
+Take three common features and an estimate of their tokens per call:
+
+| Feature | Input tokens | Output tokens | Sonnet 5.5 | Haiku 5.5 | Opus 5.5 |
+|---|---|---|---|---|---|
+| Chat reply | 2,000 | 500 | $0.009 | $0.0005 | $0.018 |
+| Summary of a 20-page document | 20,000 | 1,000 | $0.05 | $0.0025 | $0.10 |
+| Agent task, 10 steps | 150,000 | 8,000 | $0.38 | $0.019 | $0.76 |
+
+GPT-6.1 Sol costs the same as Sonnet 5.5 on these calls, and GPT-6 Luna the same as Haiku 5.5.
+
+The agent task costs about 40 times a chat reply because each step sends the conversation so far back to the model. Ten steps over a context that grows to 25,000 tokens add up to 150,000 input tokens. A long chat thread grows the same way, so measure your own average instead of using 2,000.
+
+## Light, typical and heavy users
+
+Put the three features on a $20 monthly plan built on Sonnet 5.5:
+
+| User | Usage per month | Token cost | Left from $20 after Stripe's fee |
+|---|---|---|---|
+| Light | 150 chat replies | $1.35 | $17.63 |
+| Typical | 600 chat replies and 10 summaries | $5.90 | $13.08 |
+| Heavy | 600 chat replies and 150 agent tasks | $62.40 | −$43.42 |
+
+Stripe's fee on a $20 subscription paid with a US card is 2.9% + 30¢ plus 0.7% for Stripe Billing, or $1.02.
+
+One heavy user wipes out the margin of more than three typical users. If a few users drive most of your token spend, your average cost per user looks fine while those few lose you money. Sort users by cost and check your top 10% before you look at the average.
+
+## Measure it in your own app
+
+Your provider's usage page shows spend by project, workspace or API key, by day. You won't find your users there. Each API response includes its token counts, so record them next to the user who made the call:
+
+- **OpenAI** returns `usage.input_tokens`, `usage.output_tokens` and `usage.input_tokens_details.cached_tokens` on the Responses API.
+- **Anthropic** returns `usage.input_tokens`, `usage.output_tokens`, `usage.cache_creation_input_tokens` and `usage.cache_read_input_tokens` on the Messages API.
+
+Store one row per call with the user, the feature, the model and those counts. Multiply by the price table once a day, and you have cost per user, per feature and per plan. Compare the total with your provider's usage page each month, and you'll catch calls your logging missed.
+
+## Keep heavy users profitable
+
+Once you know the cost per user, you can cut it or make heavy users pay for it in five ways:
+
+- **Route to a smaller model.** Haiku 5.5 costs a twentieth of Sonnet 5.5. Send classification, extraction and short replies to it, and keep the large model for the hard requests.
+- **Cache the repeated prefix.** On Sonnet 5.5, a cache read costs $0.10 per million tokens against $2.00 for fresh input. Cache system prompts, tool definitions and long documents a user asks about more than once.
+- **Batch what can wait.** Anthropic's [Message Batches API](https://platform.claude.com/docs/en/build-with-claude/batch-processing) and OpenAI's [Batch API](https://developers.openai.com/api/docs/guides/batch) charge 50% less for requests that can finish later. OpenAI gives batches up to 24 hours.
+- **Cap or meter the expensive feature.** Include a monthly number of agent tasks in each plan, then sell more as credits or charge per task above the quota.
+- **Price from the heavy user.** If a plan has no cap, set its price from what your 90th-percentile user costs.
+
+## Watch the total for each app
+
+Your per-user log shows who costs what. The provider's total is what you pay, and it includes retries, failed calls and test traffic your log may skip.
+
+OpenProfit reads that total from OpenAI, Anthropic, OpenRouter and xAI every day, split by project, workspace or API key, and puts it next to the app's revenue from Stripe or Polar. You see each app's margin after tokens, and OpenProfit alerts you by email, Slack or SMS when a provider's daily spend doubles against its average for the week before. [Claude API usage and costs by workspace](/integrations/anthropic) and [OpenAI usage dashboard by project](/integrations/openai) show what each connector reads.
diff --git a/src/content/blog/revenue-vs-profit-saas.md b/src/content/blog/revenue-vs-profit-saas.md
new file mode 100644
index 0000000..7e2b1e2
--- /dev/null
+++ b/src/content/blog/revenue-vs-profit-saas.md
@@ -0,0 +1,114 @@
+---
+title: Revenue vs profit: how to know if your SaaS makes money
+description: Revenue is what customers pay you. Profit is what's left after payment fees, refunds, AI tokens, hosting and your other bills. Work out both for your SaaS.
+date: 2026-10-19
+author: Raphael Morency
+---
+
+# Revenue vs profit: how to know if your SaaS makes money
+
+Revenue is what your customers pay you. Profit is what you keep after the costs of earning it: payment fees, refunds, AI tokens, hosting, email and the tools you pay for each month. Stripe can show $2,000 in MRR for an app that loses money, since Stripe sees the sales and none of your bills.
+
+## Revenue and profit, defined
+
+Four numbers sit between what customers pay and what you keep:
+
+| Number | How to get it | In a SaaS |
+|---|---|---|
+| Revenue | What customers paid, minus the sales tax or VAT you collected | Sales in Stripe, Polar, Paddle or Lemon Squeezy |
+| Net revenue | Revenue minus refunds and discounts | The sales you keep after refunds |
+| Gross profit | Net revenue minus the cost of revenue | The cost of revenue grows with each customer: payment fees, AI tokens, hosting, database, email and SMS |
+| Net profit | Gross profit minus your other costs | Tools, domains, contractors, ads, an accountant |
+
+You get two percentages from these:
+
+```text
+Gross margin = (net revenue − cost of revenue) ÷ net revenue × 100
+Net margin = net profit ÷ net revenue × 100
+```
+
+Use gross margin to judge whether each new customer makes you money, and net margin to judge the business as a whole.
+
+## One month of a $2,000 MRR AI app
+
+Take an app with 100 customers on a $20 monthly plan, billed through Stripe at its US card price of 2.9% + 30¢ plus 0.7% for Stripe Billing, with an OpenAI feature:
+
+| Line | Amount |
+|---|---|
+| Sales, 100 × $20 | $2,000 |
+| Refunds, 2 customers | −$40 |
+| **Net revenue** | **$1,960** |
+| Stripe fees, 100 charges | −$102 |
+| OpenAI tokens | −$610 |
+| Hosting on Vercel | −$45 |
+| Database on Supabase | −$25 |
+| Email on Resend | −$20 |
+| **Gross profit** | **$1,158** |
+| Gross margin | 59% |
+| Domain, error tracking, design tool | −$60 |
+| **Net profit** | **$1,098** |
+
+The Stripe dashboard shows $2,000. The founder keeps $1,098 of it, 55%, before income tax. Stripe keeps its fee when you refund a charge, so you pay the fee on both refunded charges.
+
+Watch the token line. If ten heavy users double next month's OpenAI bill to $1,220 with the same customers, gross profit falls to $548 and gross margin to 28%. MRR stays at $2,000 the whole time, and the Stripe dashboard looks the same as last month.
+
+A real product has smaller numbers. Over the last 30 days, [Lobbystack](https://openprofit.dev/p/lobbystack/lobbystack), the app my company sells, made $164 in revenue after Polar's fees. OpenAI cost $39, Twilio $15 and Railway $12, for $98 in profit and a 60% margin. OpenProfit read those amounts from the Polar, OpenAI, Twilio and Railway APIs.
+
+## The costs between your MRR and your profit
+
+You'll find each cost on a different page:
+
+- **Payment fees, refunds and disputes.** Your processor takes them out before the payout, so the deposit in your bank is smaller than your revenue. [How to get Stripe into QuickBooks or Xero](/blog/stripe-quickbooks-xero) shows the entries for one month.
+- **Sales tax and VAT.** You collect them for the government, so they don't count as revenue. Polar, Paddle and Lemon Squeezy act as the merchant of record: they collect and file the tax, then pay you the rest after their fee.
+- **AI APIs.** OpenAI, Anthropic, OpenRouter and xAI bill by token. Their usage pages split spend by project, workspace or API key, and the invoice comes after the month ends.
+- **Hosting and infrastructure.** Vercel, Railway, Cloudflare, DigitalOcean, Neon and MongoDB Atlas charge a plan price plus usage, and the usage part rises and falls with your traffic.
+- **Email, SMS and other APIs.** Resend, Twilio and Firecrawl charge per message or per request.
+- **Bills with no API.** A domain, a design tool or an accountant's fee shows up on your card statement and nowhere else.
+
+Unless you pay yourself a salary, your time stays out of the profit figure. Compare the profit with what your hours are worth before you decide the app pays.
+
+## Your costs sit on separate billing pages
+
+Each bill above sits on its own billing page, with its own date range and currency. Usage bills change by the day, and you learn the total when the provider charges your card. If one OpenAI account serves three apps, the bill gives you the account's total and leaves out which app spent it.
+
+Stripe has the revenue and each provider has its own costs, with no page that shows both. So you keep a monthly spreadsheet, or you guess.
+
+## Three ways to see all your costs in one place
+
+### A spreadsheet
+
+Make one row per month, with columns for sales, refunds, payment fees and each provider. On the first of each month, copy each total from its billing page and add the margin formulas. For one app with two flat bills, this works and costs nothing.
+
+It breaks once token or hosting usage becomes a real cost line, or once you run a second app on the same provider accounts. You spend an hour a month copying, and you see a cost spike a month after it happened. [OpenProfit vs a spreadsheet](/compare/spreadsheet) covers where each one fits.
+
+### Accounting software
+
+QuickBooks and Xero give you a profit and loss statement from your bank feed. A bookkeeper sorts the transactions, so you get the statement after the month closes. Bills you pay on your personal card don't reach the company's bank, so the books miss them. [My SaaS bills go on my personal card, so I built my own books](/blog/why-not-quickbooks) covers that gap.
+
+### OpenProfit
+
+OpenProfit reads revenue from Stripe, Polar, Paddle, Lemon Squeezy and RevenueCat, and costs from the billing APIs of 14 providers including OpenAI, Anthropic, Vercel and Railway. Paste an API key for each one, and OpenProfit loads up to two years of history. You get revenue, costs, profit and margin per app, by day, in one currency. You enter bills with no API once, at their monthly, yearly or one-time price.
+
+If a provider's daily spend doubles, OpenProfit alerts you by email, Slack or SMS before the invoice arrives. The code is open source under the MIT license, and the hosted version is free up to $2,500 in MRR.
+
+## Profit per app, when you run more than one
+
+If three apps share one OpenAI account, give each app its own OpenAI project and its own API key. OpenAI then reports spend per project, and so do Vercel per project, Anthropic per workspace, Railway per project and Cloudflare per zone.
+
+In OpenProfit, point each project at the app it serves. OpenProfit moves that project's costs to the app, history included, and keeps the projects you haven't assigned in an Unassigned bucket. You can then see which app pays for its tokens and which one lives off the others.
+
+## Margin benchmarks for SaaS and AI apps
+
+Benchmarkit's 2026 survey of 342 B2B SaaS and AI-native companies puts software gross margin at 80%, according to [Aleph's summary](https://www.getaleph.com/blog/2026-saas-benchmarks-takeaways). AI apps run lower. Bessemer's [State of AI 2025](https://www.bvp.com/atlas/the-state-of-ai-2025) reports about 60% gross margins for its steadier AI startups and about 25%, often negative, for the fastest-growing ones.
+
+For an app built on an AI API, 60% is normal. If your SaaS has no AI features and sits at 60%, look for the cost line that pulls it down.
+
+## Before you call your SaaS profitable
+
+- Count revenue after refunds, with sales tax and VAT taken out.
+- Put payment fees, AI tokens and hosting in the cost of revenue, and work out your gross margin.
+- Read usage bills by day instead of waiting for the invoice.
+- Split shared provider accounts by project, one per app.
+- Check the margin again after any bill jumps.
+
+To see your own numbers, [create an account on OpenProfit](https://openprofit.dev/login) and connect Stripe or Polar plus your largest bill. OpenProfit shows your profit per app within minutes.
diff --git a/src/content/blog/saas-running-costs.md b/src/content/blog/saas-running-costs.md
new file mode 100644
index 0000000..acc2de1
--- /dev/null
+++ b/src/content/blog/saas-running-costs.md
@@ -0,0 +1,114 @@
+---
+title: The monthly cost of running a SaaS, line by line
+description: A SaaS stack priced at three sizes, from a free side project to $20,000 MRR, with October 2026 prices for Vercel, Supabase, Resend, Sentry, PostHog and Stripe.
+date: 2026-10-19
+author: Raphael Morency
+---
+
+# The monthly cost of running a SaaS, line by line
+
+A side project can run on free tiers for the price of a domain, about $0.93 a month. At 100 paying customers the same stack costs $218 to $416 a month, and at 1,000 customers $1,883 to $3,167. Payment fees and product analytics make up most of it, and an AI feature can add more than both.
+
+I took the prices below from each provider's pricing page on October 19, 2026. The usage figures, such as emails sent and events tracked, are my estimates for a typical web app, so swap in your own.
+
+## The stack
+
+One common setup for a solo developer:
+
+| Job | Provider |
+|---|---|
+| Hosting | [Vercel](https://vercel.com/pricing) |
+| Database and sign-in | [Supabase](https://supabase.com/pricing) |
+| Email | [Resend](https://resend.com/pricing) |
+| Error tracking | [Sentry](https://sentry.io/pricing/) |
+| Product analytics | [PostHog](https://posthog.com/pricing) |
+| DNS | [Cloudflare](https://www.cloudflare.com/plans/) free plan |
+| Uptime checks | [UptimeRobot](https://uptimerobot.com/pricing/) free plan |
+| Domain | A .com at cost |
+| Payments | [Stripe](https://stripe.com/us/pricing) |
+
+A .com costs $11.17 a year at cost from November 1, 2026: Verisign's new [$10.97 wholesale price](https://www.sec.gov/Archives/edgar/data/0001014473/000101447326000028/vrsn-20260630.htm) plus ICANN's $0.20 fee. Cloudflare Registrar charges that price with no markup; Namecheap renews a .com at $18.48.
+
+## Side project: $0.93 a month
+
+Each line above fits a free plan for an app with a few dozen users and no revenue, so you pay for the domain alone.
+
+Two free plans stop fitting before you have many users:
+
+- **Vercel Hobby** is for "non-commercial, personal use only". The day you charge for the app, you need Pro at $20 a month, or a host such as Railway, whose Hobby plan starts at $5.
+- **Supabase Free** pauses a project after a week without activity, and lists no backups. Pausing suits a prototype; once customers pay, you'll want Pro's daily backups.
+
+## 100 customers, $2,000 MRR: $218 to $416
+
+Assume 1,000 monthly active users, 20,000 emails and 2 million analytics events a month:
+
+| Line | Plan | Per month |
+|---|---|---|
+| Hosting | Vercel Pro | $20 |
+| Database and sign-in | Supabase Pro | $25 |
+| Email | Resend Pro, 50,000 emails | $20 |
+| Error tracking | Sentry Developer, one user | $0 |
+| Product analytics | PostHog, 2 million events | $50 to $248 |
+| DNS, uptime checks | Free plans | $0 |
+| Domain | .com at cost | $0.93 |
+| Payment fees | Stripe, 100 charges of $20 | $102 |
+| **Total** | | **$218 to $416** |
+
+That's 11% to 21% of MRR. Hosting, database and email together cost $65.
+
+PostHog's range depends on one setting. The first million events each month cost nothing, and the next million cost $0.00005 each. PostHog adds $0.000198 for each event tied to a signed-in user's profile, which turns $50 into $248. PostHog says anonymous events cost up to four times less than identified ones.
+
+Stripe's line is 2.9% + 30¢ per card payment plus 0.7% for Stripe Billing, or $1.02 on each $20 charge. [Stripe vs Polar vs Paddle vs Lemon Squeezy](/blog/stripe-polar-paddle-lemon-squeezy-fees) compares what each processor leaves you.
+
+## 1,000 customers, $20,000 MRR: $1,883 to $3,167
+
+Assume 10,000 monthly active users, 200,000 emails and 20 million analytics events a month:
+
+| Line | Plan | Per month |
+|---|---|---|
+| Hosting | Vercel Pro plus the 10 million request CDN tier | $40 |
+| Database and sign-in | Supabase Pro | $25 |
+| Email | Resend Pro, 100,000 emails plus 100,000 at $0.90 per thousand | $125 |
+| Error tracking | Sentry Team | $29 |
+| Product analytics | PostHog, 20 million events | $643 to $1,928 |
+| DNS, uptime checks | Free plans | $0 |
+| Domain | .com at cost | $0.93 |
+| Payment fees | Stripe, 1,000 charges of $20 | $1,020 |
+| **Total** | | **$1,883 to $3,167** |
+
+That's 9% to 16% of MRR. Hosting, database, email and error tracking cost $219 together, about 1% of revenue.
+
+Stripe takes the largest fixed share, 5.1% of sales. Analytics comes second, and with identified events it passes Stripe. If you don't need a person profile on each event, turn profiles off for anonymous traffic, or capture fewer events.
+
+Sentry's Team plan costs $29 billed monthly, or $26 a month billed yearly. Resend's Scale plan with 200,000 emails costs $160, so paying overage on Pro saves $35.
+
+## AI tokens, if your app calls a model
+
+The totals above leave out AI APIs. If your app calls one, tokens can pass the other lines. On Claude Sonnet 5.5, a user who sends 600 chat messages and asks for 10 document summaries a month costs about $5.90 in tokens. At 1,000 customers that's $5,900 a month, more than the rest of the stack and Stripe combined. [AI token cost per user](/blog/ai-token-cost-per-user) shows how to work out your own number.
+
+## The limit that forces each upgrade
+
+- **Vercel:** Hobby forbids commercial use. Pro includes 1 million CDN requests and 1 TB of transfer, then moves you to a $20 tier with 10 million requests.
+- **Supabase:** Free caps the database at 500 MB and egress at 5 GB, and pauses inactive projects. Pro includes 8 GB of disk, 250 GB of egress and 100,000 monthly active users.
+- **Resend:** Free allows 3,000 emails a month and 100 a day. A busy day of password resets and receipts can pass that.
+- **PostHog:** Free drops events past 1 million a month.
+- **Sentry:** Developer allows one user and 5,000 errors a month.
+
+## Cheaper swaps
+
+| Swap | Cost at 100 customers |
+|---|---|
+| Render web service and Postgres for Vercel and Supabase | $13: $7 for the service, $6 for the database |
+| Railway Hobby for Vercel and Supabase | About $12 to $15 in usage, with a $5 minimum |
+| Neon Launch for the Supabase database | About $20 with compute always on, less with scale to zero |
+| Clerk for Supabase sign-in | $0 up to 50,000 monthly retained users |
+
+Sources: [Render](https://render.com/pricing), [Railway](https://railway.com/pricing), [Neon](https://neon.com/pricing) and [Clerk](https://clerk.com/pricing). The Railway and Neon figures are my estimates for a small app and database, at their published rates.
+
+You can go further and run the whole app on one server. A founder who runs several $10,000 MRR companies on a $20 a month stack [drew 517 comments on Hacker News](https://news.ycombinator.com/item?id=47736555) in April 2026. You then handle backups, updates and outages yourself.
+
+## Track the real number
+
+Your stack's cost moves with usage, and each line sits on its own billing page. OpenProfit reads Vercel, Railway, Cloudflare, Neon, Resend and nine other providers through their billing APIs, and Stripe, Polar, Paddle, Lemon Squeezy and RevenueCat for revenue. OpenProfit has no connector for Supabase, Sentry or PostHog, so you enter their plans once as flat costs.
+
+You then see each app's costs, revenue after fees and margin by day, with an alert when a provider's daily spend doubles. [Revenue vs profit](/blog/revenue-vs-profit-saas) shows how those costs turn into a margin.
diff --git a/src/content/blog/spend-limits-budget-alerts.md b/src/content/blog/spend-limits-budget-alerts.md
new file mode 100644
index 0000000..2780d12
--- /dev/null
+++ b/src/content/blog/spend-limits-budget-alerts.md
@@ -0,0 +1,83 @@
+---
+title: Spend limits vs budget alerts on Vercel, OpenAI and Firebase
+description: A budget alert emails you hours after the money is gone. Spend limits on Vercel, OpenAI, Anthropic, Firebase, AWS, Supabase, Neon and Railway, and what to set.
+date: 2026-10-19
+author: Raphael Morency
+---
+
+# Spend limits vs budget alerts on Vercel, OpenAI and Firebase
+
+In April 2026, a team found that someone had run up a [€54,000 Gemini bill](https://news.ycombinator.com/item?id=47791871) in 13 hours through their Firebase browser key. They had an €80 budget alert and a cost anomaly alert. Both fired a few hours late, and the charges had reached about €28,000 by the time the team reacted.
+
+A budget alert emails you about money you've spent, after the provider finishes counting it. A spend limit blocks new requests once you cross it, a few minutes late. You want both, set per project, and on most providers you have to turn the limit on yourself.
+
+## Budget alerts lag by hours
+
+A budget alert reads the provider's billing data, and providers process that data in batches:
+
+- **Google Cloud** says the first budget email can take several hours, and some costs take more than 24 hours to reach its [billing reports](https://docs.cloud.google.com/billing/docs/how-to/budgets-spend-caps).
+- **AWS Budgets** updates up to three times a day, 8 to 12 hours apart, according to the [AWS docs](https://docs.aws.amazon.com/cost-management/latest/userguide/budgets-managing-costs.html). Cost Anomaly Detection reads data up to 24 hours old.
+- **Cloudflare** processes usage once a day, so its [budget alert](https://developers.cloudflare.com/billing/manage/budget-alerts/) fires the day after you cross the threshold.
+
+Your services keep running while the email is on its way.
+
+## Spend limits lag by minutes
+
+A spend limit stops new usage once your spend crosses the cap. Vercel checks spend every few minutes. Gemini's project caps run about 10 minutes behind, and Firebase's spend caps several minutes. OpenAI says enforcement "is not instantaneous" and gives no number.
+
+You pay for whatever runs in that gap. One developer set a $62.50 hard limit on an OpenAI project and [paid about $20 more](https://www.reddit.com/r/OpenAI/comments/1vb4yty/api_spend_limit_delay_costs_me_money/), because their script kept running for close to two hours. Set each cap below the most you can afford to lose.
+
+## Provider by provider
+
+Checked against each provider's docs on October 19, 2026:
+
+| Provider | Hard limit | On by default | At the limit | Usage data |
+|---|---|---|---|---|
+| Vercel Pro | Pause Production Deployments | $200 budget with alerts; pausing off | Every project on the team returns a 503 | Checked every few minutes |
+| OpenAI | Hard spend limit, per organization or project | You turn it on | Requests return a 429 | No delay given |
+| Anthropic | Tier cap, plus your own organization and workspace limits | Tier cap: $500 on Start, $1,000 on Build | Requests fail until you raise the limit or the month resets | Within about 5 minutes |
+| Google Cloud | Spend cap budgets (Preview) for Gemini API, Cloud Run and a few others | No budget until you create one | That service pauses for the project | Hours, sometimes over 24 |
+| Firebase | Spend caps (Preview) for AI Logic, App Hosting, Functions and Extensions | You get a prompt for an alerts-only budget | That service pauses for the rest of the month | Several minutes for caps |
+| AWS | Budget actions can stop EC2 and RDS and deny new resources | Anomaly emails at $100 and 40% over expected | Email, plus the action if you set one | Up to 3 times a day |
+| Supabase Pro | Spend Cap on usage items | On | That usage item stops until the next cycle | Not documented |
+| Neon | None; alerts at 80% and 100% | Off | Projects keep running | Checked every 15 minutes |
+| Railway | Hard usage limit, $10 minimum | Not documented for compute | All workloads go offline | Not documented |
+| Cloudflare | None; a CPU limit per Worker | $10 alert on eligible accounts | One email | Once a day |
+
+### Settings to change at each provider
+
+- **[Vercel](https://vercel.com/docs/spend-management):** in **Settings › Billing › Spend Management**, turn on **Pause Production Deployments** if an outage costs you less than the bill would. Vercel then pauses production for every project on the team, and you resume each project by hand. Storage, AI Gateway and v0 keep billing while paused. A webhook at 50%, 75% and 100% lets you pause one project with your own code.
+- **[OpenAI](https://developers.openai.com/api/docs/guides/spend-limits):** in **Project settings › Limits**, set a monthly spend limit and turn on **Enforce a hard limit**. A limit per project stops one app from draining the budget of the others.
+- **[Anthropic](https://platform.claude.com/docs/en/api/rate-limits):** set an organization limit under **Billing › Spend limits**, then a limit per workspace with an email notification. Anthropic doesn't let you limit the default workspace, so give each app its own.
+- **[Google Cloud and Firebase](https://firebase.google.com/docs/projects/billing/spend-caps):** create a spend cap budget for each project and service that has one, such as the Gemini API or Cloud Run. Restrict each API key to the APIs it needs; the €54,000 bill came from a browser key with no API restrictions.
+- **[AWS](https://docs.aws.amazon.com/cost-management/latest/userguide/budgets-controls.html):** add a budget action that applies a deny policy or stops EC2 and RDS instances. Lambda, S3 and Bedrock keep running under it.
+- **[Supabase](https://supabase.com/docs/guides/platform/cost-control):** leave the Spend Cap on. It covers egress, storage, monthly active users and function invocations, and leaves out compute, read replicas, IPv4 and point-in-time recovery.
+- **[Neon](https://neon.com/docs/introduction/spending-notifications):** turn on spending notifications. To suspend computes at a limit, set per-project consumption quotas through the Neon API.
+- **[Railway](https://docs.railway.com/pricing/cost-control):** set a hard limit on the workspace's **Usage** page. Railway takes every workload offline at the limit and redeploys them when you raise it.
+
+## Close the holes a limit leaves open
+
+Three of the largest bills this year started with a key or an endpoint left open: the €54,000 Firebase browser key, an [$18,000 bill](https://news.ycombinator.com/item?id=47866293) from a public Cloud Run service with a $7 budget, and [$82,314 in 48 hours](https://www.reddit.com/r/googlecloud/comments/1reqtvi/) from a stolen Gemini key on an account that spent $180 a month. Restrict browser keys to their APIs and domains, keep server keys out of client code and published apps, and rotate any key you've pasted somewhere public.
+
+Give each app its own project, workspace or key at each provider. A per-project limit then stops one app without taking down the rest, and you can see which app ran up the bill.
+
+## Catch the slow creep
+
+A hard limit stops a spike. A bill that grows 10% a month stays under the cap you'd set. A developer on r/nextjs [described this](https://www.reddit.com/r/nextjs/comments/1vxqr53/how_do_you_keep_an_eye_on_your_vercel_neon_bill/): preview deployments of merged branches and leftover Neon branches pushed the Vercel and Neon bill up 10 to 15% a month.
+
+You catch creep by comparing each provider's spend week over week, and each app's margin month over month. OpenProfit reads daily costs from Vercel, Neon, OpenAI, Anthropic, Railway, Cloudflare and other providers, and runs two alert rules after each sync:
+
+- **Cost spike:** a provider's spend yesterday passed $5 and more than doubled its daily average over the seven days before.
+- **Margin floor:** an app's margin over the last seven days fell under 60%, or under the floor you set.
+
+Each alert goes out by email, Slack, webhook or SMS. OpenProfit reads the same billing data as the providers, so it reports a spike the day after at the earliest. For a 13-hour spike, the provider's hard limit is the protection that works.
+
+## Set these today
+
+- Turn on a hard limit at each provider that has one, per project where you can.
+- Set each cap below what you can afford to lose, since enforcement lags by minutes.
+- Restrict each API key to the APIs and domains it needs.
+- Give each app its own project, workspace or key.
+- Watch spend per provider by week and margin per app by month.
+
+[Get alerts in Slack, at your endpoint or by SMS](/docs/alerts) shows how to send OpenProfit's alerts to your channels.
diff --git a/src/content/blog/stripe-polar-paddle-lemon-squeezy-fees.md b/src/content/blog/stripe-polar-paddle-lemon-squeezy-fees.md
new file mode 100644
index 0000000..35fff41
--- /dev/null
+++ b/src/content/blog/stripe-polar-paddle-lemon-squeezy-fees.md
@@ -0,0 +1,77 @@
+---
+title: Stripe vs Polar vs Paddle vs Lemon Squeezy: what you keep
+description: Your share of a $20 subscription on Stripe, Polar, Paddle, Lemon Squeezy and Stripe Managed Payments, with each fee, the tax trade-off and payout terms.
+date: 2026-10-19
+author: Raphael Morency
+---
+
+# Stripe vs Polar vs Paddle vs Lemon Squeezy: what you keep
+
+On a $20 monthly subscription paid with a US card, Stripe leaves you $18.98. Polar and Paddle leave you $18.50, and Lemon Squeezy $18.40. You pay that difference for tax handling: Polar, Paddle and Lemon Squeezy collect and file sales tax in each country, and with Stripe you do it yourself.
+
+I took the fees below from each provider's pricing pages and docs on October 19, 2026, for a seller based in the US.
+
+## Merchant of record vs payment processor
+
+A merchant of record sells your product to the customer in its own name. Polar, Paddle and Lemon Squeezy work this way: they charge the customer, add the right sales tax or VAT, file the tax returns in each country, and pay you what's left after their fee. The customer's card statement shows their name, and the tax stays out of your revenue.
+
+Stripe is a payment processor. You are the seller, so you register for sales tax where you owe it. If your business is outside the EU, you may have to register for EU VAT from your first sale there. [Stripe Tax](https://docs.stripe.com/tax/filing) calculates and collects the tax, and you file and pay it.
+
+Stripe also sells a merchant of record service: [Stripe Managed Payments](https://stripe.com/managed-payments) adds 3.5% to the normal Stripe fees. It covers digital products sold by sellers in 37 countries, and Stripe reviews each seller before granting access.
+
+## The fees
+
+| | Stripe | Stripe Managed Payments | Polar | Lemon Squeezy | Paddle |
+|---|---|---|---|---|---|
+| US card | 2.9% + 30¢ | 2.9% + 30¢, plus 3.5% | 5% + 50¢ | 5% + 50¢ | 5% + 50¢ |
+| Card from outside the US | +1.5% | +1.5% | +1.5% | +1.5% | Included |
+| Subscriptions | +0.7% | +0.7% | Included | +0.5% | Included |
+| PayPal | Not listed | Not listed | Not supported | +1.5% | Included |
+| Sales tax and VAT | You file; Stripe Tax adds 0.5% where you're registered | Stripe files | Polar files | Lemon Squeezy files | Paddle files |
+| Dispute | $15 | $15 | $15 | $15 | $20 |
+
+Sources: [Stripe](https://stripe.com/us/pricing), [Polar](https://polar.sh/docs/merchant-of-record/fees), [Lemon Squeezy](https://docs.lemonsqueezy.com/help/getting-started/fees) and [Paddle](https://www.paddle.com/pricing).
+
+Stripe's subscription fee is Stripe Billing's 0.7% of billing volume. Polar's price applies to organizations created since May 27, 2026; older ones keep 4% + 40¢ plus 0.5% on subscriptions. Polar also sells plans from $20 a month that lower the rate, down to 3.4% + 30¢.
+
+All four merchants of record charge their percentage on the full amount the customer pays, tax included.
+
+## Your share of one sale
+
+| Sale | Stripe | Managed Payments | Polar | Lemon Squeezy | Paddle |
+|---|---|---|---|---|---|
+| $20 a month, US card | $18.98 | $18.28 | $18.50 | $18.40 | $18.50 |
+| €20 a month with VAT, German card | $17.31 | $16.64 | $16.91 | $16.80 | $16.80 to $17.25 |
+| $5 a month, US card | $4.52 | $4.34 | $4.25 | $4.22 | $4.25 |
+| $99 a year, US card | $95.14 | $91.67 | $93.55 | $93.05 | $93.55 |
+
+For the US rows, I assumed no sales tax on the sale. For the German row, I converted €20 at the European Central Bank's rate of October 19, 2026, to $22.45, of which $3.58 is the 19% VAT. The Stripe figure there includes Stripe Tax and leaves out the cost of filing the EU VAT return yourself. Paddle's range depends on whether it converts the whole sale to dollars at its 2% currency margin.
+
+On 100 customers paying $20, a merchant of record costs you $48 to $58 a month more than Stripe. In exchange, the merchant of record registers for VAT and files the sales tax returns for those sales.
+
+Fixed fees weigh most on small prices. At $5 a month, Polar and Paddle keep 15% of each sale, and Stripe keeps 9.6%. Lemon Squeezy and Paddle offer custom pricing for products under $10. With a yearly plan, you pay the fixed fee once instead of twelve times: $99 a year on Polar costs $5.45 in fees, against $10.95 for twelve monthly payments of $8.25.
+
+## Refunds, disputes and payouts
+
+Refunds, disputes and payouts also change the amount you receive:
+
+- **Refunds.** Stripe, Polar and Lemon Squeezy keep their original fee when you refund a sale. Paddle's terms let it recover its fees on a refund without stating the amount.
+- **Disputes.** Each one costs $15, or $20 on Paddle, and Paddle keeps the $20 whether it wins or loses. Stripe charges another $15 if you respond to the dispute, and returns that one when you win.
+- **Payouts.** Stripe pays out every business day for free. [Polar](https://polar.sh/docs/features/finance/payouts) pays when you request a withdrawal, seven days after the sale for organizations created since May 12, 2026, and passes on Stripe's payout fees: $2 for each month with a payout, plus 0.25% + 25¢ per payout. Lemon Squeezy pays twice a month above $50, and Paddle once a month above $100.
+
+## Lemon Squeezy since Stripe bought it
+
+Stripe bought Lemon Squeezy in 2024. In a [January 2026 update](https://www.lemonsqueezy.com/blog/2026-update), the Lemon Squeezy team wrote that it is building Stripe Managed Payments and plans to give Lemon Squeezy users a way to move there. As of October 19, 2026, Lemon Squeezy takes new stores, and Stripe hasn't announced a date for it to close. If you start today, expect to move to Managed Payments at some point.
+
+## Picking a provider
+
+- **Most of your customers are in the US, or you're already registered for sales tax:** Stripe leaves you the most of each sale.
+- **You sell to consumers in the EU or the UK and don't want to register for VAT:** a merchant of record. Paddle includes international cards and PayPal in its 5% + 50¢; Polar pays out faster and has cheaper plans once you sell more than about $1,400 a month.
+- **You already run on Stripe and want it to handle tax:** Stripe Managed Payments, if you pass the eligibility review. Of the five, it leaves you the least on a $20 or $99 sale.
+- **Your price is under $10:** the fixed fee takes a large share on all five. Sell yearly plans, or ask Paddle or Lemon Squeezy for custom pricing.
+
+## Track what you keep
+
+With any of the five, the payout in your bank is smaller than your sales. Record the sales, the fees and the refunds as separate lines in your books, and leave the tax a merchant of record collects out of your revenue. [How to get Stripe into QuickBooks or Xero](/blog/stripe-quickbooks-xero) shows the entries, and [Revenue vs profit](/blog/revenue-vs-profit-saas) shows where fees sit between your MRR and your profit.
+
+OpenProfit reads Stripe, Polar, Paddle and Lemon Squeezy through their APIs and shows your revenue after fees and refunds, with sales tax and VAT kept apart, next to the costs of each app. If you switch providers, connect both, and OpenProfit puts the revenue from each on the same product.
diff --git a/src/content/blog/stripe-quickbooks-xero.md b/src/content/blog/stripe-quickbooks-xero.md
index 6e42815..eab278d 100644
--- a/src/content/blog/stripe-quickbooks-xero.md
+++ b/src/content/blog/stripe-quickbooks-xero.md
@@ -1,13 +1,13 @@
---
-title: How to get Stripe into QuickBooks or Xero
-description: A Stripe payout is net of fees and refunds, so the deposit isn't your revenue. The entries your books need, and four ways to get Stripe into QuickBooks or Xero.
+title: Stripe QuickBooks and Xero integration: four ways compared
+description: A Stripe payout is net of fees and refunds. The entries your books need, and four ways in, from the Stripe Connector by QuickBooks to Xero's Stripe feed.
date: 2026-10-08
author: Raphael Morency
---
-# How to get Stripe into QuickBooks or Xero
+# Stripe QuickBooks and Xero integration: four ways compared
-Stripe pays you a payout net of its fees, refunds and disputes, so the deposit in your bank isn't your revenue. QuickBooks or Xero needs your gross sales, fees and refunds on separate lines, and the payout recorded as a transfer to your bank. This guide shows the entries, then compares four ways to make them: QuickBooks' own Stripe integration, Xero's Stripe feed, a sync app, and a monthly journal file from OpenProfit.
+Stripe pays you a payout net of its fees, refunds and disputes, so the deposit in your bank isn't your revenue. QuickBooks or Xero needs your gross sales, fees and refunds on separate lines, and the payout recorded as a transfer to your bank. This guide shows the entries, then compares four ways to make them: the Stripe Connector by QuickBooks, Xero's Stripe feed, a sync app, and a monthly journal file from OpenProfit.
## Why the deposit isn't your revenue
@@ -46,9 +46,9 @@ Three more things change the entries:
Each option below records the same entries. They differ in detail, price and which costs they cover.
-### QuickBooks' own Stripe integration
+### Stripe Connector by QuickBooks
-Intuit's [Stripe connection for QuickBooks Online](https://quickbooks.intuit.com/learn-support/en-us/help-article/manage-integrations/connect-manage-stripe-transactions-quickbooks/L10TzOVcN_US_en_US) imports sales, refunds, payouts and adjustments. Each sale shows its gross amount, fee and net, with the fee posted to a "Stripe Fees" expense account. Each payout becomes a deposit linked to the sales and fees inside it.
+Intuit's [Stripe Connector by QuickBooks](https://quickbooks.intuit.com/learn-support/en-us/help-article/manage-integrations/connect-manage-stripe-transactions-quickbooks/L10TzOVcN_US_en_US) imports sales, refunds, payouts and adjustments. Each sale shows its gross amount, fee and net, with the fee posted to a "Stripe Fees" expense account. Each payout becomes a deposit linked to the sales and fees inside it.
Its help article, updated September 21, 2026, lists these limits:
diff --git a/src/content/blog/tax-lines-for-software-costs.md b/src/content/blog/tax-lines-for-software-costs.md
index 2bc652f..dcc0f1c 100644
--- a/src/content/blog/tax-lines-for-software-costs.md
+++ b/src/content/blog/tax-lines-for-software-costs.md
@@ -1,11 +1,11 @@
---
-title: Which tax line do OpenAI, Vercel and Stripe fees go on?
+title: T2125 and Schedule C lines for OpenAI, Vercel and Stripe fees
description: The T2125, TP-80, GIFI, Schedule C and Form 1120 lines for AI APIs, hosting, payment fees, refunds, contractors and a laptop, checked against the 2025 forms.
date: 2026-10-08
author: Raphael Morency
---
-# Which tax line do OpenAI, Vercel and Stripe fees go on?
+# T2125 and Schedule C lines for OpenAI, Vercel and Stripe fees
No tax form has a line for AI APIs, hosting or email. In Canada they go under other expenses (T2125 line 9270, TP-80 line 246), or computer-related expenses (GIFI code 9150) for a corporation. In the US they go in Part V of Schedule C, or on line 26 of Form 1120. Payment fees, refunds, contractors and a laptop each have a better line, listed below.
diff --git a/src/content/blog/trustmrr-alternative.md b/src/content/blog/trustmrr-alternative.md
new file mode 100644
index 0000000..786c201
--- /dev/null
+++ b/src/content/blog/trustmrr-alternative.md
@@ -0,0 +1,92 @@
+---
+title: An open-source TrustMRR alternative with verified profit
+description: TrustMRR verifies revenue, and sellers type in their own profit margin. OpenProfit also reads costs from provider APIs, so profit is verified. MIT licensed.
+date: 2026-10-19
+author: Raphael Morency
+---
+
+# An open-source TrustMRR alternative with verified profit
+
+TrustMRR verifies what a startup earns. It reads revenue from Stripe, Polar or another payment provider through a read-only key, so a founder can't type in a bigger number. The profit margin on its listings comes from the seller, who types it into a form, and TrustMRR's tooltip calls it a "User-reported metric, not verified by TrustMRR."
+
+OpenProfit reads both sides. Revenue comes from the payment provider, costs come from the billing APIs of OpenAI, Vercel, Railway and 11 other providers, and the public page shows the profit between them. The code is open source under the MIT license.
+
+I checked each TrustMRR fact below against its own pages on October 19, 2026.
+
+## TrustMRR verifies revenue
+
+Marc Lou launched TrustMRR on October 30, 2025, and it has grown into a database of more than 10,000 startups and a marketplace for buying them. To list a startup, you connect Stripe, Lemon Squeezy, Polar, Paddle, Dodo Payments, RevenueCat, Superwall, the App Store, Creem, Whop or Shopify with a read-only key, according to its [FAQ](https://trustmrr.com/faq). For Stripe it accepts only restricted keys.
+
+TrustMRR then shows total revenue, MRR, revenue over the last 30 days, growth, customers and subscriptions, and refreshes them about every hour. According to its FAQ, these figures can differ from your provider's dashboard by up to 30%, depending on how the provider handles refunds, trials, prorations and currency conversion.
+
+## Profit on TrustMRR is self-reported
+
+You see a profit figure on startups listed for sale and nowhere else, as a profit margin for the last 30 days. The seller types it into the listing form as a percentage. TrustMRR shows it with the unverified label to signed-in visitors, and section 10.3 of its [terms](https://trustmrr.com/terms) says it doesn't verify the profit margins sellers provide.
+
+TrustMRR doesn't track costs. Its [API](https://trustmrr.com/docs/api/get-startup) has no expense field, and the listing's multiple divides the asking price by annualized revenue. One exception sits behind sign-in: an optional Meta Ads connection shows ad spend for the campaigns a founder picks.
+
+A buyer sees verified revenue next to a margin the seller chose, and can't tell a seller who earns 95% from one who typed 95%.
+
+## OpenProfit reads costs from the bills
+
+OpenProfit reads revenue from Stripe, Polar, Paddle, Lemon Squeezy and RevenueCat, after payment fees and refunds, with sales tax and VAT taken out. It reads costs from the billing and usage APIs of OpenAI, Anthropic, OpenRouter, xAI, Vercel, Cloudflare, Railway, DigitalOcean, Neon, MongoDB Atlas, GitHub, Twilio, Resend and Firecrawl. Profit is revenue minus those costs, for each product.
+
+Each public page names the providers behind its numbers. The page for [Lobbystack](https://openprofit.dev/p/lobbystack/lobbystack), the app my company sells, shows these numbers for the last 30 days:
+
+| Revenue | Costs | Profit | Margin |
+|---|---|---|---|
+| $164 | $66 | $98 | 60% |
+
+Below the numbers, the page says OpenProfit read them from the Polar, OpenAI, Railway and Twilio APIs, and lists each cost: OpenAI $39, Twilio $15, Railway $12. The founder can't edit those amounts.
+
+Costs you add by hand, such as a domain or a contractor, appear on the page with a "Self-reported" label. OpenProfit ranks products by profit on the leaderboard at [openprofit.dev/open](https://openprofit.dev/open) and leaves those costs out of the ranking.
+
+You choose how much a page shows. **Full** shows revenue, costs, profit and each cost source. **Revenue** shows revenue only. **Growth and margin** shows the margin and the cost sources without any amounts, for founders who want to prove they're profitable without saying how much they make.
+
+## TrustMRR and OpenProfit side by side
+
+| | TrustMRR | OpenProfit |
+|---|---|---|
+| Revenue | Verified, from 11 payment providers and app stores | Verified, from Stripe, Polar, Paddle, Lemon Squeezy and RevenueCat |
+| Costs | Not tracked, apart from optional Meta Ads spend | Verified, from 14 provider billing APIs |
+| Profit | A margin the seller types in, labeled unverified | Revenue minus verified costs, per product |
+| Public numbers | Startup page and revenue badge | Product page in three modes, and a badge |
+| Leaderboard | Revenue and MRR, more than 10,000 startups | Profit, revenue, margin and growth; one product so far |
+| Selling a startup | Marketplace: listings from $29, 3% closing fee | Not offered |
+| Source code | Closed | MIT, self-hosted in one Docker container |
+| Price | Free to list, paid add-ons | Free up to $2,500 MRR, then $19 or $49 a month |
+
+The OpenProfit leaderboard opened this month, and Lobbystack is the only product on it so far. TrustMRR claims about 200,000 visitors a month in its [llms.txt](https://trustmrr.com/llms.txt). If you want buyers to see your startup, weigh that audience above the rest of this table.
+
+## The limits of OpenProfit's verification
+
+OpenProfit vouches for the amounts it reads. It can't vouch for these:
+
+- **A provider the founder didn't connect.** Check the list of providers on the page against the product. An AI app with no AI provider on its page is leaving out its largest bill.
+- **Bills with no API**, such as a domain, a design tool or a contractor. They show as self-reported and stay out of the leaderboard.
+- **Costs the founder hasn't assigned to the product.** The page leaves them out, and in Full mode it says how much it left out.
+- **Self-hosted pages.** On a self-hosted instance, the person running the server controls the database, so those pages carry no Verified mark and stay off the leaderboard. For a Verified mark, use the hosted version at openprofit.dev.
+- **The founder's time**, which no billing API reports.
+
+## Other open-source TrustMRR alternatives
+
+Two other projects on page one of Google for "trustmrr alternative" call themselves open source, and neither reads costs. As of October 19, 2026:
+
+- **OpenRevenue** is MIT-licensed on [GitHub](https://github.com/openrevenueorg/openrevenueorg). Its README roadmap leaves the Stripe integration and the verification system unchecked, the last commit dates from December 13, 2025, and openrevenue.org doesn't load.
+- **Trust My MRR** launched in November 2025 as a Stripe-based alternative. trustmymrr.com returns a 404.
+
+## TrustMRR, OpenProfit or both
+
+- **To sell your startup**, list it on TrustMRR. Its buyers are the reason to be there, and OpenProfit doesn't sell startups.
+- **If your revenue comes through the App Store, Shopify, Whop or Creem**, TrustMRR reads them and OpenProfit doesn't.
+- **To show what you keep** when you build in public, publish an OpenProfit page.
+- **To buy a startup from a listing**, ask the seller for verified costs: an OpenProfit page in Full mode, or exports from each billing page.
+- **To do both**, connect the same Stripe or Polar account to each and put the two badges side by side. Both read your data and change nothing.
+
+## Publish your profit on OpenProfit
+
+1. [Create an account](https://openprofit.dev/login) and connect Stripe, Polar, Paddle, Lemon Squeezy or RevenueCat. OpenProfit loads up to two years of history.
+2. Connect the providers you pay, such as OpenAI, Vercel or Railway, and assign their projects to your product.
+3. Open **Products** and pick **Full**, **Revenue** or **Growth and margin** in the **Public** column. The page goes live at once, with a badge for your README or site.
+
+The product joins the leaderboard once its first revenue is 30 days old and it has at least one connected cost provider. [Share a product's numbers on a public page](/docs/public-pages) covers each mode and the badge.
diff --git a/src/content/changelog.md b/src/content/changelog.md
index 60e788a..1e1cef4 100644
--- a/src/content/changelog.md
+++ b/src/content/changelog.md
@@ -1,18 +1,22 @@
---
title: Changelog
-description: What's new in OpenProfit. Every release, newest first.
+description: Every OpenProfit release, newest first, from Books and the tax report to flat costs, alert emails and chart fixes.
---
# Changelog
-Every release, newest first. The full history is in the [commit log on GitHub](https://github.com/lobbystack/openprofit/commits/main).
+Every release, newest first. The full history is in the [commit log on GitHub](https://github.com/morencyr/openprofit/commits/main).
+
+## October 19, 2026
+
+- **Docker image on Bun.** The image runs on Bun instead of Node.js. If your setup overrides the container command or runs `node` inside the container, switch to `bun`.
## October 8, 2026
- **Books.** A new **Books** page exports a month of revenue and costs as a journal for QuickBooks, Xero or any accounting software, and lists the year's numbers on the lines of your tax form: T2125 and TP-80, the T2's GIFI schedules, Schedule C or Form 1120. Tell OpenProfit whether you have a company and who pays each provider, and it records costs on your personal card as money the business owes you. Exporting a month closes it; later changes come as an adjustment in the next export. See [Books](/docs/books).
- **One-time costs and equipment.** A flat cost can be **One time**, with a category. Equipment is depreciated on the tax report instead of deducted at once.
-- **Payouts and service periods.** Stripe payouts and the period each Stripe and Paddle payment covers now sync, so the books spread a yearly plan over its months. Polar revenue comes from orders, with refunds on the day they happen; reconnect Polar with the **Orders** and **Refunds** read scopes to get them.
-- **Bank of Canada rates.** Workspaces in Canadian dollars convert at the Bank of Canada's daily rate, as the CRA asks, from each connection's next full sync.
+- **Payouts and service periods.** Stripe payouts and the period each Stripe and Paddle payment covers now sync, so the books spread a yearly plan over its months. OpenProfit rereads the whole history of your Stripe and Paddle connections to fill them in. Polar revenue comes from orders, with refunds on the day they happen; reconnect Polar with the **Orders** and **Refunds** read scopes to get them.
+- **Bank of Canada rates.** Workspaces in Canadian dollars convert at the Bank of Canada's daily rate, as the CRA asks. OpenProfit rereads each connection's history to convert past lines at that rate.
## October 7, 2026
diff --git a/src/content/compare/baremetrics.md b/src/content/compare/baremetrics.md
index 1c92b19..3e717a4 100644
--- a/src/content/compare/baremetrics.md
+++ b/src/content/compare/baremetrics.md
@@ -1,10 +1,12 @@
---
title: OpenProfit vs Baremetrics
-description: Baremetrics is hosted subscription analytics priced by your ARR. OpenProfit reads your AI and hosting bills, shows profit per product, and gives you the numbers for your tax return.
+description: Baremetrics is subscription analytics priced by your ARR. OpenProfit adds your AI and hosting bills, profit per product, and your tax return numbers.
---
# OpenProfit vs Baremetrics
+Updated October 9, 2026.
+
Baremetrics is hosted subscription analytics with add-ons for failed-payment recovery, cancellation insights and forecasting. OpenProfit is an open-source app that pulls your revenue and your costs from the services you use, shows profit for every product you run, and gives you the numbers for your tax return.
Both show MRR. They part ways on costs. Baremetrics reads your expenses from QuickBooks or Xero on its top plan, once your books close. OpenProfit reads them from the providers that bill you, and writes the journal you import into QuickBooks or Xero.
diff --git a/src/content/compare/profitwell.md b/src/content/compare/profitwell.md
index d0d1aec..d274d1d 100644
--- a/src/content/compare/profitwell.md
+++ b/src/content/compare/profitwell.md
@@ -1,10 +1,12 @@
---
title: OpenProfit vs ProfitWell Metrics
-description: ProfitWell Metrics tracks subscription revenue for free. OpenProfit adds your costs, from AI providers to hosting, and shows profit per product. Here's how they differ.
+description: ProfitWell Metrics tracks subscription revenue for free. OpenProfit adds your costs, from AI providers to hosting, and shows profit per product.
---
# OpenProfit vs ProfitWell Metrics
+Updated October 6, 2026.
+
ProfitWell Metrics, now part of Paddle, is free subscription revenue reporting: MRR, churn, upgrades, lifetime value. OpenProfit answers a different question. It puts your revenue next to every bill you pay and shows what each product keeps.
If you only need revenue metrics, ProfitWell Metrics is free and mature. If you want to know whether a product is profitable after its OpenAI, Vercel and Railway bills, that's what OpenProfit is for.
diff --git a/src/content/compare/spreadsheet.md b/src/content/compare/spreadsheet.md
index 5d1cdc6..dbf9e17 100644
--- a/src/content/compare/spreadsheet.md
+++ b/src/content/compare/spreadsheet.md
@@ -5,6 +5,8 @@ description: What a profit spreadsheet costs you each month, what OpenProfit doe
# OpenProfit vs a spreadsheet
+Updated October 9, 2026.
+
Most people who run a few software products track profit the same way: a spreadsheet with a row per month, revenue copied from Stripe, costs copied from each billing page. It works the first month. By the third, it's out of date.
## What the spreadsheet costs you
diff --git a/src/content/data.md b/src/content/data.md
index aa4ad54..fecb00b 100644
--- a/src/content/data.md
+++ b/src/content/data.md
@@ -1,6 +1,6 @@
---
title: Benchmarks
-description: Monthly revenue, gross margin and cost shares of the products on OpenProfit, grouped by monthly recurring revenue (MRR). The numbers come from Stripe, OpenAI and the other providers' APIs.
+description: Monthly revenue, gross margin and cost shares of the products on OpenProfit, grouped by MRR, from Stripe, OpenAI and other provider APIs.
---
## Download
diff --git a/src/content/home.md b/src/content/home.md
index 45ba836..27ac553 100644
--- a/src/content/home.md
+++ b/src/content/home.md
@@ -3,7 +3,7 @@
OpenProfit is open-source finance for developers. Connect Stripe, OpenAI, Vercel and every other bill. See what each of your apps earns after costs, and get the numbers for your tax return.
- Website: https://openprofit.dev
-- Source: https://github.com/lobbystack/openprofit (MIT license)
+- Source: https://github.com/morencyr/openprofit (MIT license)
- Docs: https://openprofit.dev/docs/self-host
## What it does
diff --git a/src/content/integrations/anthropic.md b/src/content/integrations/anthropic.md
index f6607fd..c35c6c7 100644
--- a/src/content/integrations/anthropic.md
+++ b/src/content/integrations/anthropic.md
@@ -34,6 +34,8 @@ The key is stored encrypted and used only to read the cost report.
Workspaces are how Anthropic groups usage, so they're how OpenProfit maps it. Give each product its own workspace and its own API key, then assign the workspace to the product on the connection's page. Unassigned workspaces stay under Unassigned.
+[AI token cost per user](/blog/ai-token-cost-per-user) shows how to work out what each of your users costs in Claude tokens before you set a price.
+
## Common questions
**I use Claude through AWS Bedrock or Google Vertex.** Those charges appear on your AWS or Google Cloud bill, not in Anthropic's cost report. Add them as a flat monthly cost until a connector for those clouds exists.
diff --git a/src/content/integrations/cloudflare.md b/src/content/integrations/cloudflare.md
index af3abd2..e5d61a9 100644
--- a/src/content/integrations/cloudflare.md
+++ b/src/content/integrations/cloudflare.md
@@ -1,27 +1,45 @@
---
-title: Track Cloudflare costs
+title: Cloudflare usage and costs by zone
name: Cloudflare
kind: cost
summary: Billable usage, or invoices where usage isn't available.
-description: Bring your Cloudflare Workers, R2 and plan charges into the same view as your revenue. Connect with a read-only API token.
+description: Your Cloudflare Workers, R2 and other usage costs by day and zone, next to the revenue of each product. Connect with a read-only API token.
---
# Track Cloudflare costs
-Workers, R2, Images and the zone plans each bill separately on Cloudflare. OpenProfit reads them through the API and adds them to your costs, per day where Cloudflare reports usage, per invoice where it doesn't.
+Cloudflare shows usage costs under **Manage Account → Billing → Billable Usage**, by product, for the whole account. OpenProfit reads that usage through Cloudflare's API, splits it by zone, and sets each zone's costs against the revenue of the product it serves.
## What it reads
-OpenProfit first asks for billable usage, which gives daily amounts per product. Some accounts don't expose usage through the API; for those it reads billing history instead, one line per invoice item.
+OpenProfit first asks for billable usage. For each day it records:
+
+- the amount, in the currency Cloudflare bills you;
+- the Cloudflare service the usage belongs to;
+- the zone, when Cloudflare attributes the usage to one.
+
+Cloudflare updates this data once a day, and its total for a closed billing period matches the usage charges on that period's invoice.
+
+The API covers self-serve accounts. When Cloudflare refuses the request, OpenProfit reads the account's billing history instead: one line per entry, dated the day Cloudflare charged it, with no zone. The first sync asks for two years, or one year on the hosted Free plan.
## Connect it
-1. In the Cloudflare dashboard, open **My Profile → API Tokens** and create a custom token with two permissions: **Account · Billing · Read** and **Account · Account Settings · Read**.
-2. In OpenProfit, open **Connections → Cloudflare** and paste the token. Add the account id if the token can see more than one account.
-3. Press **Test**, then **Connect**.
+1. In the Cloudflare dashboard, open **My Profile → API Tokens**, click **Create Token** and start a custom token.
+2. Add two permissions: **Account · Billing · Read** and **Account · Account Settings · Read**.
+3. Under **Account Resources**, include only the account you want to read.
+4. In OpenProfit, open **Connections → Cloudflare** and paste the token. Skip the account id when the token covers one account.
+5. Press **Test**, then **Connect**. The test shows the account's name.
-The token can read billing and account names. It can't change anything.
+The token can read billing but can't change anything.
## Costs per product
-Where Cloudflare attributes usage to a zone, the zone appears on the connection's page and you assign it to a product. Account-wide charges stay under Unassigned.
+Each zone with usage this month appears on the connection's page with its spend. Assign a zone to a product and its costs follow, past days included. Usage outside any zone, and every line from billing history, sits in a **Not in a zone** row. That row follows the product you pick for it, or stays under Unassigned.
+
+The sample stack in [the monthly cost of running a SaaS](/blog/saas-running-costs) runs DNS on Cloudflare's free plan. [Connecting providers](/docs/connectors) covers sync timing and flat costs.
+
+## Common questions
+
+**Why don't my plan or domain show up?** Billable usage covers usage charges, and a zone plan or domain renewal isn't usage. Add it as a flat cost on the **Costs** page.
+
+**Can I use an account API token?** No. OpenProfit checks the token against Cloudflare's user token endpoint, so create it under **My Profile → API Tokens**.
diff --git a/src/content/integrations/digitalocean.md b/src/content/integrations/digitalocean.md
index bd91828..a24df02 100644
--- a/src/content/integrations/digitalocean.md
+++ b/src/content/integrations/digitalocean.md
@@ -15,21 +15,34 @@ DigitalOcean sends one invoice for the whole account. OpenProfit splits it by pr
OpenProfit reads your invoice items through DigitalOcean's billing API. For each month it records:
- the amount in US dollars, summed per project and product;
-- the product, such as Droplets, Kubernetes Clusters or Managed Databases;
+- the product, as the invoice names it, such as Kubernetes Clusters or Floating IPs;
- the DigitalOcean project the resources belong to.
-Past months come from the issued invoice. The current month comes from the invoice preview, which DigitalOcean updates daily, so this month's figure grows until the invoice closes.
+DigitalOcean invoices on the first day of each month for the month before. The current month comes from the invoice preview, which DigitalOcean generates daily, so this month's figure grows until the invoice arrives and replaces it.
+
+The first sync reads two years of invoices, or one year on the hosted Free plan. Later syncs reread the current month, and last month early in a new month, to pick up the issued invoice.
+
+In the last 30 days view, OpenProfit spreads each month's total across its days.
## Connect it
-1. In DigitalOcean, open **API → Tokens** and generate a personal access token. Under **Custom Scopes**, tick **billing:read** and **account:read**.
-2. In OpenProfit, open **Connections → DigitalOcean** and paste the token.
-3. Press **Test**, then **Connect**. The test shows your team name.
+1. In the DigitalOcean control panel, open **Account → API**. On the **Tokens** tab, click **Generate New Token**.
+2. Name the token and choose an expiration. Under **Scopes**, select **Custom Scopes** and tick `billing:read` and `account:read`, nothing else.
+3. In OpenProfit, open **Connections → DigitalOcean** and paste the token.
+4. Press **Test**, then **Connect**. The test shows your team name.
+
+Both scopes are read-only. One covers invoices, the other the account details the test shows.
## Costs per product
-Each DigitalOcean project appears on the connection's page. Assign it to a product and its costs follow, past months included. Invoice items without a project stay under Unassigned.
+Each DigitalOcean project with costs this month appears on the connection's page. Assign it to a product and its costs follow, past months included. Invoice items without a project sit in a **Not in a project** row, which follows the product you pick for it or stays under Unassigned.
+
+In the sample stack from [the monthly cost of running a SaaS](/blog/saas-running-costs), payment fees and analytics cost more than hosting and the database at 100 and 1,000 customers. [Connecting providers](/docs/connectors) covers sync timing and flat costs.
## Common questions
-**Why don't I see daily figures?** DigitalOcean itemizes costs per project only on invoices, and invoices cover a month.
+**Why don't I see daily figures?** OpenProfit reads invoices, and each DigitalOcean invoice covers one month. The current month's preview still updates every day.
+
+**Where do taxes go?** DigitalOcean's invoice data lists taxes as their own item with no project, so they land in the **Not in a project** row.
+
+**What if one project runs everything?** Its costs go to one product. Move each product's resources into its own DigitalOcean project to split them.
diff --git a/src/content/integrations/firecrawl.md b/src/content/integrations/firecrawl.md
index 16da2df..b10cdb3 100644
--- a/src/content/integrations/firecrawl.md
+++ b/src/content/integrations/firecrawl.md
@@ -3,7 +3,7 @@ title: Track Firecrawl costs per API key
name: Firecrawl
kind: cost
summary: Plan fee and extra credits per billing period, split by API key.
-description: See what each Firecrawl API key costs per billing period, estimated from credit usage and Firecrawl's published prices, next to the revenue of the product it serves.
+description: What each Firecrawl API key costs per billing period, estimated from credit usage and Firecrawl's prices, next to the revenue of the product it serves.
---
# Track Firecrawl costs per API key
diff --git a/src/content/integrations/lemonsqueezy.md b/src/content/integrations/lemonsqueezy.md
index 0e69638..8fffe5b 100644
--- a/src/content/integrations/lemonsqueezy.md
+++ b/src/content/integrations/lemonsqueezy.md
@@ -41,3 +41,5 @@ A test mode key reads your test mode data instead.
## Revenue per product
Each Lemon Squeezy product appears on the connection's page. Assign it to a product and its revenue follows, past sales included. Revenue that isn't tied to a Lemon Squeezy product gets its own row on the same page.
+
+[Lemon Squeezy vs Stripe](/blog/stripe-polar-paddle-lemon-squeezy-fees) compares Lemon Squeezy's fee, tax handling and payout terms with Stripe, Polar and Paddle.
diff --git a/src/content/integrations/mongodb.md b/src/content/integrations/mongodb.md
index 2fc5be5..a054317 100644
--- a/src/content/integrations/mongodb.md
+++ b/src/content/integrations/mongodb.md
@@ -3,7 +3,7 @@ title: Track MongoDB Atlas costs per project
name: MongoDB Atlas
kind: cost
summary: Daily invoice line items per project and SKU, including the current month.
-description: See what each MongoDB Atlas project costs per day, from your Atlas invoices, next to the revenue of the product it serves. Connect with a billing-only service account.
+description: What each MongoDB Atlas project costs per day, from your Atlas invoices, next to the revenue of its product. Connect with a billing-only service account.
---
# Track MongoDB Atlas costs per project
diff --git a/src/content/integrations/openai.md b/src/content/integrations/openai.md
index 77821d4..5956bb2 100644
--- a/src/content/integrations/openai.md
+++ b/src/content/integrations/openai.md
@@ -34,7 +34,7 @@ The key is stored encrypted and used only to read costs.
Each OpenAI project appears on the connection's page with this month's spend. Point a project at the product it serves, and its costs land on that product from then on, history included. Projects you leave unassigned stay under Unassigned until you decide. If you run one product, everything goes to it by default.
-Three products on one OpenAI account, one project each, and you see which one pays for its tokens.
+Three products on one OpenAI account, one project each, and you see which one pays for its tokens. To turn a project's spend into a price, see [AI token cost per user](/blog/ai-token-cost-per-user).
## Common questions
diff --git a/src/content/integrations/openrouter.md b/src/content/integrations/openrouter.md
index a014672..09b1437 100644
--- a/src/content/integrations/openrouter.md
+++ b/src/content/integrations/openrouter.md
@@ -37,3 +37,5 @@ OpenRouter serves activity only to management keys, and offers no read-only vari
## Costs per product
Each API key with spend appears on the connection's page under the hash OpenRouter's API uses to identify it. Assign a key to a product and its costs follow, past days included. Activity without a key stays under Unassigned.
+
+[AI token cost per user](/blog/ai-token-cost-per-user) shows how to turn a key's spend into a cost per user before you set a price.
diff --git a/src/content/integrations/paddle.md b/src/content/integrations/paddle.md
index 9788959..94d943b 100644
--- a/src/content/integrations/paddle.md
+++ b/src/content/integrations/paddle.md
@@ -33,3 +33,5 @@ A sandbox key (`pdl_sdbx_…`) reads your sandbox account instead.
## Revenue per product
Paddle revenue goes to the product you pick on the connection's page. If you run one Paddle account per product, connect each one and point it at its product.
+
+[Paddle vs Stripe](/blog/stripe-polar-paddle-lemon-squeezy-fees) compares Paddle's fee, tax handling and payout terms with Stripe, Polar and Lemon Squeezy.
diff --git a/src/content/integrations/polar.md b/src/content/integrations/polar.md
index 84e49c7..19fc9e6 100644
--- a/src/content/integrations/polar.md
+++ b/src/content/integrations/polar.md
@@ -33,3 +33,5 @@ A token with only `organizations:read` and `metrics:read` still syncs Polar's da
## Revenue per product
Polar revenue goes to the product you pick on the connection's page. One Polar organization per product keeps the split exact.
+
+[Polar vs Stripe](/blog/stripe-polar-paddle-lemon-squeezy-fees) compares Polar's fee, tax handling and payout terms with Stripe, Paddle and Lemon Squeezy.
diff --git a/src/content/integrations/railway.md b/src/content/integrations/railway.md
index 3a51f39..0498ce1 100644
--- a/src/content/integrations/railway.md
+++ b/src/content/integrations/railway.md
@@ -35,3 +35,5 @@ Credits, discounts and domains aren't in the usage data, so the total can still
## Costs per product
Each Railway project appears on the connection's page. Assign it to a product and its usage follows, past months included.
+
+Railway can take your workloads offline at a hard usage limit. [Spend limits vs budget alerts](/blog/spend-limits-budget-alerts) covers what to set it to.
diff --git a/src/content/integrations/stripe.md b/src/content/integrations/stripe.md
index dff300c..4a94a85 100644
--- a/src/content/integrations/stripe.md
+++ b/src/content/integrations/stripe.md
@@ -29,3 +29,5 @@ A restricted key can't move money or change your account.
## Revenue per product
Stripe revenue goes to the product you pick on the connection's page. If you run one Stripe account per product, connect each and point it at its product.
+
+A Stripe payout arrives net of fees and refunds. [Stripe to QuickBooks or Xero](/blog/stripe-quickbooks-xero) covers the entries your books need, and [Stripe vs Polar vs Paddle vs Lemon Squeezy](/blog/stripe-polar-paddle-lemon-squeezy-fees) compares what you keep from each sale.
diff --git a/src/content/integrations/twilio.md b/src/content/integrations/twilio.md
index 1a5d23a..e9f8eff 100644
--- a/src/content/integrations/twilio.md
+++ b/src/content/integrations/twilio.md
@@ -8,21 +8,35 @@ description: See what Twilio charges you per day for messages, calls and numbers
# Track Twilio costs per day
-Twilio charges per message, minute and phone number. OpenProfit reads the daily total and puts it next to the revenue of the product that sends those messages.
+Twilio charges per message, minute and phone number, and its usage records split that spend into dozens of categories. OpenProfit reads one daily total and puts it next to the revenue of the product that sends those messages.
## What it reads
-OpenProfit reads Twilio's daily usage records in the total price category. For each day it records the cost of all usage on the account and its subaccounts, in the currency Twilio bills you.
+OpenProfit reads Twilio's daily usage records in the `totalprice` category. Each day becomes one cost line, labeled **Usage**, with the price of all usage on the account and its subaccounts, in the currency Twilio bills you.
-Twilio's other usage categories overlap, so adding them up counts some costs twice. The total price category avoids that and includes costs that sit in no other category.
+The other categories overlap (`calls` contains `calls-inbound`), and some costs sit in no category. Adding categories up counts some charges twice and misses others.
+
+Twilio dates usage records by GMT day, and OpenProfit keeps those dates, so a California evening's usage can land on the next day.
+
+The first sync reads up to two years of records, or one year on the hosted Free plan. Every later sync rereads the last three days, so a revised day replaces the earlier figure.
## Connect it
-1. In the Twilio Console, open **Account settings → API keys & auth tokens** and create an API key. Pick **Restricted** as the key type.
-2. Under **Permissions**, grant `/twilio/billing/usage/read` and nothing else.
-3. In OpenProfit, open **Connections → Twilio** and paste your Account SID, the key's SID and its secret.
-4. Press **Test**, then **Connect**.
+1. In the Twilio Console, open **Settings → Account settings → API keys & auth tokens**.
+2. Select the **United States (US1)** region and click **Create API key**. A key works only in the region you created it in, and OpenProfit calls US1.
+3. Pick **Restricted** as the key type. Under **Permissions**, grant `/twilio/billing/usage/read` and nothing else.
+4. Copy the key's SID and secret before you click **Finish**.
+5. In OpenProfit, open **Connections → Twilio** and paste your Account SID, the key's SID and its secret.
+6. Press **Test**, then **Connect**. A usage-only key can't read the account's name, so the test shows a shortened Account SID.
## Costs per product
-Twilio reports one total per day. Pick the product it serves at the top of the connection's page and every day goes to it. If several products share the account, the total stays in the shared bucket.
+Twilio reports one total per day. Pick the product it serves at the top of the connection's page, and every day moves to that product, history included. If your workspace has one product, the connection starts on it.
+
+[The monthly cost of running a SaaS](/blog/saas-running-costs) prices the rest of a typical stack, from hosting to payment fees. [Connecting providers](/docs/connectors) covers sync timing and costs that have no API.
+
+## Common questions
+
+**Does it include subaccounts?** Yes. Twilio's usage records include every subaccount by default, and OpenProfit reads them through the main account.
+
+**Can I split one Twilio account between two products?** No. The daily total has no breakdown by app, so a connection goes to one product or stays Unassigned.
diff --git a/src/content/integrations/vercel.md b/src/content/integrations/vercel.md
index bb4504e..ee5c8c2 100644
--- a/src/content/integrations/vercel.md
+++ b/src/content/integrations/vercel.md
@@ -1,9 +1,9 @@
---
-title: Track Vercel costs per project
+title: Vercel usage and costs by project
name: Vercel
kind: cost
summary: Daily charges per project, read from Vercel's billing API.
-description: See what each Vercel project costs per day, from functions to bandwidth, next to the revenue of the product it hosts.
+description: Your Vercel usage and costs by day and project, from functions to bandwidth, next to the revenue of the product each project hosts.
---
# Track Vercel costs per project
@@ -12,24 +12,32 @@ A Vercel invoice is one number for the whole team. OpenProfit breaks it down by
## What it reads
-OpenProfit reads Vercel's billing charges, which Vercel publishes in the FOCUS format for cloud costs. For each charge it records:
+OpenProfit reads Vercel's billing charges API, which returns each day's charges in FOCUS, an open format for cloud cost data. For each charge it records:
-- the day and the amount billed;
-- the service, such as functions, edge requests or bandwidth;
-- the project, when Vercel attributes the charge to one.
+- the day and the amount billed, in US dollars;
+- the service Vercel names on the charge;
+- the project, from the project id and name Vercel tags the charge with.
-Charges that belong to the team as a whole, like the seat price of a Pro plan, have no project. They stay under Unassigned.
+Every charge with a nonzero amount counts, whatever its category: usage, purchases, taxes, credits or adjustments. Each sync after the first rereads the last three days, so a revised day replaces the earlier figure.
## Connect it
-1. In Vercel, open **Account Settings → Tokens** and create a token scoped to the team you want to read. Your role on that team needs billing access.
-2. In OpenProfit, open **Connections → Vercel** and paste the token. Add the team id if the token can see more than one team.
-3. Press **Test**, then **Connect**.
+1. In Vercel, open the **Account Tokens** page in your personal account's settings.
+2. Name the token. Under **Scope**, pick the team, then **All Projects**. A token scoped to one project can't read team-level data such as billing.
+3. Choose an expiration, click **Create** and copy the token.
+4. In OpenProfit, open **Connections → Vercel** and paste it. Leave the team id empty to read your default team, or paste the id from the team's settings.
+5. Press **Test**, then **Connect**. The test shows your username and the team id.
+
+Your team role must be one that can read billing: Owner, Member, Developer, Security, Billing or Enterprise Viewer.
## Costs per product
-Each project that has charges appears on the connection's page. Assign it to a product once and its costs follow from then on, including past days.
+Each project with charges this month appears on the connection's page. Assign it to a product and its costs follow, past days included. Charges without a project tag sit in a **Not in a project** row, which follows the product you pick for it or stays under Unassigned.
+
+In [the monthly cost of running a SaaS](/blog/saas-running-costs), Vercel Pro costs $20 a month at 100 customers and $40 at 1,000. [Connecting providers](/docs/connectors) covers sync timing and flat costs.
## Common questions
-**I'm on the Hobby plan.** Hobby has no charges to read. The connector is useful once a team is on a paid plan.
+**Does it work on the Hobby plan?** Hobby is free and has no billing cycle, so there are no charges to read. Connect the team once it moves to a paid plan.
+
+**Can OpenProfit stop a runaway Vercel bill?** No, it reads charges after Vercel records them. To cap spend, turn on **Pause Production Deployments** under **Settings → Billing → Spend Management**. [Spend limits vs budget alerts](/blog/spend-limits-budget-alerts) covers what to set.
diff --git a/src/db/index.ts b/src/db/index.ts
index 4e87467..1f1cbd8 100644
--- a/src/db/index.ts
+++ b/src/db/index.ts
@@ -40,7 +40,7 @@ export const db: NodePgDatabase =
pgDb ?? (pgliteDb as unknown as NodePgDatabase);
export type Db = typeof db;
-// Migrations in ./drizzle run once at start. `pnpm db:generate` writes a
+// Migrations in ./drizzle run once at start. `bun run db:generate` writes a
// new one after a schema change.
if (process.env.SKIP_MIGRATIONS !== "1") {
const opts = { migrationsFolder: "drizzle" };
diff --git a/src/docs/books.md b/src/docs/books.md
index c7eeab3..8cae117 100644
--- a/src/docs/books.md
+++ b/src/docs/books.md
@@ -28,6 +28,8 @@ Costs without an API go on the **Costs** page. Choose **One time** for a single
4. Leave **Product** on **All** for your books. A journal for one product leaves out shared costs, so import it only if that product is its own company.
5. Click **Download**.
+The QuickBooks and Xero files leave out what the bank feed already records. [Stripe to QuickBooks or Xero](/blog/stripe-quickbooks-xero) explains the entries behind a Stripe payout and how the Stripe Connector by QuickBooks compares.
+
Exporting a whole month closes it. The same month always exports the same file, and if a provider changes its numbers later, your next export adds an adjustment for the difference.
### Import into QuickBooks Online
@@ -66,7 +68,7 @@ Pick the year at the top of **Tax report**. The report lists each line of your f
| United States, no company or a single-member LLC | Schedule C |
| United States, company | Form 1120, with the 1120-S and 1065 equivalents |
-A line marked **Our choice** has no official home for that cost, such as AI usage or payment fees, and the note says why OpenProfit picked it. If you incorporated during the year, the report splits at that date.
+A line marked **Our choice** has no official home for that cost, such as AI usage or payment fees, and the note says why OpenProfit picked it. [T2125 and Schedule C lines for OpenAI, Vercel and Stripe fees](/blog/tax-lines-for-software-costs) explains each choice with its CRA, Revenu Québec or IRS source. If you incorporated during the year, the report splits at that date.
Equipment follows your country's rules. In Canada, a computer is class 50. In the United States, an item up to $2,500 is deducted in full under the de minimis safe harbor, and the report writes the election statement you attach to your return.
diff --git a/src/docs/connectors.md b/src/docs/connectors.md
index c3629f1..716db25 100644
--- a/src/docs/connectors.md
+++ b/src/docs/connectors.md
@@ -96,3 +96,5 @@ OpenProfit counts a monthly or yearly cost in every month from its start date to
Each workspace has one base currency, set during onboarding and editable in **Settings**. OpenProfit converts every line in another currency at the European Central Bank (ECB) rate for that line’s date. A workspace in Canadian dollars uses the Bank of Canada’s daily rate instead, as the Canada Revenue Agency (CRA) asks. Currencies the Bank doesn’t publish still use the ECB rate.
Flat costs have no date of their own, so they convert at the rate of the day you save them. When you change the base currency, every stored line converts again at its own date’s rate, and flat costs at that day’s rate.
+
+Changing the base currency also reopens every month you exported from [Books](/docs/books). The next export of a reopened month includes all its entries again, in the new currency. Delete the earlier import from your accounting software first, or it counts that month twice.
diff --git a/src/docs/environment.md b/src/docs/environment.md
index a485d93..27e4a1b 100644
--- a/src/docs/environment.md
+++ b/src/docs/environment.md
@@ -14,7 +14,7 @@ An instance doesn’t start correctly without these two:
| Variable | Default | Purpose |
| --- | --- | --- |
-| `SECRET_KEY` | None | 32 random bytes encoded as base64. Encrypts provider keys and signs sessions. Changing it makes stored provider keys unreadable |
+| `SECRET_KEY` | None | 32 random bytes encoded as base64. Encrypts provider keys and signs sessions. To change it, stop the app and run `OLD_SECRET_KEY= SECRET_KEY= bun scripts/rotate-secret-key.ts` against the database, or the app can't read the stored provider keys. Everyone signs in again |
| `APP_URL` | `http://localhost:3000` | Public address of the instance. Sign-in links point here |
## Database
@@ -32,6 +32,7 @@ Sign-in from the CLI and agent sign-up are rate-limited per IP address. Behind a
| Variable | Default | Purpose |
| --- | --- | --- |
| `TRUST_PROXY` | None | The number of proxies in front of the instance, usually `1`. OpenProfit then reads the client's address from `X-Forwarded-For`. Leave it unset when nothing sits in front, or clients can fake their address. Not needed on Railway |
+| `CLIENT_IP_HEADER` | None | A header your CDN sets to the client's address, such as `cf-connecting-ip` for Cloudflare. It takes precedence over `TRUST_PROXY`. Set it only when your firewall admits the CDN's addresses alone, or clients can fake their address |
## Email and sign-in
diff --git a/src/docs/public-pages.md b/src/docs/public-pages.md
index b0c1aa3..b43004e 100644
--- a/src/docs/public-pages.md
+++ b/src/docs/public-pages.md
@@ -56,3 +56,5 @@ The badge refreshes within five minutes of a sync. Links shared on social sites
- Its first revenue is at least 30 days old
Each tab lists only the products whose mode shows that number, so a Growth and margin page appears on the margin and growth tabs. Rankings count only costs read from provider APIs. Self-reported costs show on the product’s page but not on the leaderboard. Products on self-hosted instances don’t appear.
+
+For an example, see [OpenProfit's own page](https://openprofit.dev/p/lobbystack/openprofit). [An open-source TrustMRR alternative](/blog/trustmrr-alternative) compares OpenProfit's verified profit with TrustMRR's verified revenue.
diff --git a/src/docs/self-host.md b/src/docs/self-host.md
index a1c3b34..e20b8cb 100644
--- a/src/docs/self-host.md
+++ b/src/docs/self-host.md
@@ -25,7 +25,7 @@ docker run -d \
-v openprofit_data:/app/data \
-e SECRET_KEY=your_secret_here \
-e APP_URL=http://localhost:3000 \
- ghcr.io/lobbystack/openprofit:latest
+ ghcr.io/morencyr/openprofit:latest
```
The `-v` flag keeps your data in the `openprofit_data` volume when the container is replaced. Set `APP_URL` to the address people use to reach the instance, because sign-in links point there.
@@ -59,16 +59,27 @@ OpenProfit creates and updates its tables on start, so the database only needs t
Updating replaces the container and keeps the volume, so your data stays. Pull the new image and remove the old container:
```bash
-docker pull ghcr.io/lobbystack/openprofit:latest
+docker pull ghcr.io/morencyr/openprofit:latest
docker rm -f openprofit
```
Then run the `docker run` command from [Start the container](#start-the-container) again. Schema changes apply when the new container starts.
+## Deploy on Dokploy
+
+The hosted version at openprofit.dev runs this same image on Dokploy. To do the same:
+
+1. In a project, add a Postgres database and deploy it.
+2. Add an application with the Docker provider and the image `ghcr.io/morencyr/openprofit:latest`.
+3. Set `DATABASE_URL` to the database's internal connection string, and set `SECRET_KEY` and `APP_URL` as described above. Traefik sits in front, so set `TRUST_PROXY=1`.
+4. Add your domain with port `3000` and HTTPS, then deploy.
+
+To redeploy when a new image comes out, call the deploy webhook from the application's **Deployments** tab after each push.
+
## Deploy on Railway
-The hosted version at openprofit.dev runs this same image on Railway. To do the same:
+To run the image on Railway:
-1. Create a service from the image `ghcr.io/lobbystack/openprofit:latest`.
+1. Create a service from the image `ghcr.io/morencyr/openprofit:latest`.
2. Add a Postgres database to the project.
3. Set `DATABASE_URL` to the database’s connection string, and set `SECRET_KEY` and `APP_URL` as described above.
diff --git a/src/legal/privacy.md b/src/legal/privacy.md
index dd1d90b..7599b53 100644
--- a/src/legal/privacy.md
+++ b/src/legal/privacy.md
@@ -1,6 +1,6 @@
# Privacy Policy
-Last updated: October 9, 2026. Added the Bank of Canada to section 3.
+Last updated: October 22, 2026. Moved hosting from Railway to OVH and added Cloudflare to section 3.
This policy explains what personal information OpenProfit collects, why, and what you can do about it. OpenProfit is operated by Lobbystack Inc., Montreal, Quebec, Canada ("we", "us"). It covers the hosted service at openprofit.dev. If you run the open-source software on your own server, we receive nothing from it unless you switch on the usage ping described in section 5.
@@ -45,7 +45,8 @@ We do not sell personal information and we do not share it with advertisers. We
| Service | Purpose | Location |
| --- | --- | --- |
-| Railway | Hosting and database | United States |
+| OVH US LLC | Hosting and database | United States |
+| Cloudflare, Inc. | Network in front of the Service; it sees each request, including your IP address | United States, served from its global network |
| Polar Software Inc. | Payments, invoices, tax, as merchant of record | United States and EU |
| Resend | Sending sign-in links, alerts and the weekly email | United States |
| PostHog Inc. | Product analytics, web analytics without cookies, and session replay while Analytics is on; server logs and error reports | United States |
@@ -53,7 +54,7 @@ We do not sell personal information and we do not share it with advertisers. We
| Frankfurter (European Central Bank data) | Exchange rates; receives no personal data | EU |
| Bank of Canada | Exchange rates into Canadian dollars; receives no personal data | Canada |
-When we send browser analytics through PostHog's managed reverse proxy, the requests pass through Cloudflare, Inc., which PostHog lists as its subprocessor for that service.
+Browser analytics we send through PostHog's managed reverse proxy also pass through Cloudflare, Inc., which PostHog lists as its subprocessor for that service.
Each provider you connect receives API calls from us using your credential. Those calls contain nothing about you beyond the credential itself.
diff --git a/src/legal/security.md b/src/legal/security.md
index 085d36b..e7b8a59 100644
--- a/src/legal/security.md
+++ b/src/legal/security.md
@@ -61,7 +61,7 @@ OpenProfit uses these keys the same way as the others and only reads with them.
OpenProfit is open source under the MIT license, and the hosted version runs the same code. Self-host it and your keys stay on your server: one Docker container with Postgres inside, encrypting with a key you generate. The [self-host guide](/docs/self-host) walks through it.
-You can read every line that touches a key. Encryption is in [`src/lib/crypto.ts`](https://github.com/lobbystack/openprofit/blob/main/src/lib/crypto.ts), and each provider call is in [`src/connectors/`](https://github.com/lobbystack/openprofit/tree/main/src/connectors).
+You can read every line that touches a key. Encryption is in [`src/lib/crypto.ts`](https://github.com/morencyr/openprofit/blob/main/src/lib/crypto.ts), and each provider call is in [`src/connectors/`](https://github.com/morencyr/openprofit/tree/main/src/connectors).
A self-hosted copy sends us nothing unless you switch on its daily usage ping, which carries a version number and counts, never keys or amounts.
@@ -69,7 +69,7 @@ A self-hosted copy sends us nothing unless you switch on its daily usage ping, w
- You sign in with an email link, GitHub or Google. OpenProfit stores no passwords.
- Product analytics record what you do in the app, never amounts, keys or data from your providers. Switch them off in **Settings**.
-- The hosted version runs on Railway in the United States. The [Privacy Policy](/privacy) lists every company that handles your data, and the [Cookie Policy](/cookies) lists each cookie.
+- The hosted version runs on OVH servers in the United States, behind Cloudflare. The [Privacy Policy](/privacy) lists every company that handles your data, and the [Cookie Policy](/cookies) lists each cookie.
- To delete a workspace or your account, email hello@openprofit.dev.
## Report a vulnerability
diff --git a/src/legal/terms.md b/src/legal/terms.md
index 09c8a0d..e98bba6 100644
--- a/src/legal/terms.md
+++ b/src/legal/terms.md
@@ -4,7 +4,7 @@ Last updated: October 9, 2026
These terms are a contract between you and Lobbystack Inc. (Montreal, Quebec, Canada), which operates OpenProfit ("we", "us"). They cover the hosted service at openprofit.dev and its subdomains (the "Service"). By creating an account or using the Service you accept them. If you use the Service for a company, you confirm you can bind that company, and "you" means the company.
-The open-source code at github.com/lobbystack/openprofit is licensed under the MIT License. If you run your own copy, the MIT License governs the software and these terms do not apply, except section 11 on telemetry if you switch it on.
+The open-source code at github.com/morencyr/openprofit is licensed under the MIT License. If you run your own copy, the MIT License governs the software and these terms do not apply, except section 11 on telemetry if you switch it on.
## 1. The Service
diff --git a/src/lib/app.ts b/src/lib/app.ts
index 8eb2a78..33562bd 100644
--- a/src/lib/app.ts
+++ b/src/lib/app.ts
@@ -1,11 +1,36 @@
export const APP_NAME = "OpenProfit";
export const APP_TAGLINE = "Finance for developers";
export const APP_DOMAIN = "openprofit.dev";
-export const GITHUB_URL = "https://github.com/lobbystack/openprofit";
+export const GITHUB_URL = "https://github.com/morencyr/openprofit";
export const SITE_URL = "https://openprofit.dev";
export const SITE_DESCRIPTION =
"Open-source app that puts your revenue next to your OpenAI, Vercel and other bills, shows profit per app, and gives you the numbers for your tax return.";
+// Answers to onboarding's "Where did you hear about OpenProfit?", sent with
+// workspace_created so signups can be counted per channel.
+export const HEARD_FROM = [
+ "reddit",
+ "x",
+ "tiktok",
+ "google",
+ "ai",
+ "hacker_news",
+ "github",
+ "friend",
+ "other",
+] as const;
+export const HEARD_FROM_LABELS: Record<(typeof HEARD_FROM)[number], string> = {
+ reddit: "Reddit",
+ x: "X",
+ tiktok: "TikTok",
+ google: "Google search",
+ ai: "ChatGPT, Claude or another AI",
+ hacker_news: "Hacker News",
+ github: "GitHub",
+ friend: "A friend or colleague",
+ other: "Other",
+};
+
// Title, description, canonical and social tags for a public page. `image`
// replaces the root's 1200x630 social image.
export function seo({
@@ -40,6 +65,24 @@ export function seo({
};
}
+// A JSON-LD script for a route's head `scripts`.
+export const jsonLd = (data: object) => ({
+ type: "application/ld+json",
+ children: JSON.stringify({ "@context": "https://schema.org", ...data }),
+});
+
+// Breadcrumb trail shown in search results:
+// https://developers.google.com/search/docs/appearance/structured-data/breadcrumb
+export const breadcrumbs = (trail: [name: string, path: string][]) => ({
+ "@type": "BreadcrumbList",
+ itemListElement: trail.map(([name, path], i) => ({
+ "@type": "ListItem",
+ position: i + 1,
+ name,
+ item: `${SITE_URL}${path}`,
+ })),
+});
+
export const NOINDEX = { meta: [{ name: "robots", content: "noindex" }] };
// Where to go after signing in (`?redirect=`): a path on this site, never
diff --git a/src/lib/books.ts b/src/lib/books.ts
index a5f251b..e010ecc 100644
--- a/src/lib/books.ts
+++ b/src/lib/books.ts
@@ -69,12 +69,6 @@ const PROVIDER_ACCOUNT: Record = {
export const expenseAccount = (provider: string): ExpenseCategory =>
PROVIDER_ACCOUNT[provider] ?? "other";
-export function accountType(account: Account): AccountType {
- return account.startsWith("balance:")
- ? "asset"
- : ACCOUNTS[account as FixedAccount].type;
-}
-
// Default name, or the user's rename for their accounting software.
export function accountName(
account: Account,
@@ -182,7 +176,7 @@ export type BooksIn = {
const DAY = 86_400_000;
const days = (a: string, b: string) =>
Math.round((Date.parse(b) - Date.parse(a)) / DAY);
-const nextMonth = (m: string) => {
+export const nextMonth = (m: string) => {
const [y, mo] = m.split("-").map(Number);
return new Date(Date.UTC(y, mo, 1)).toISOString().slice(0, 7);
};
@@ -390,7 +384,16 @@ export function journal(input: BooksIn): Entry[] {
m.startsOn.slice(0, 7) <= month &&
(!m.endsOn || m.endsOn.slice(0, 7) >= month);
if (!active) continue;
- amount = m.interval === "year" ? Math.round(m.amount / 12) : m.amount;
+ // A yearly cost's k-th month of its year books the rounded share up
+ // to k minus the share before it, so its 12 months add up exactly.
+ const [y0, m0] = m.startsOn.split("-").map(Number);
+ const [y, mo] = month.split("-").map(Number);
+ const k = (((y - y0) * 12 + mo - m0) % 12) + 1;
+ amount =
+ m.interval === "year"
+ ? Math.round((m.amount * k) / 12) -
+ Math.round((m.amount * (k - 1)) / 12)
+ : m.amount;
}
if (!amount) continue;
const paidBy = payer(date, incorporatedOn, m.method, m.since);
@@ -435,11 +438,13 @@ export function journal(input: BooksIn): Entry[] {
}
// One entry per group, dated the end of the month: what the journal formats
-// export (one line per account and product).
+// export (one line per account and product). Bank and other entries of a
+// group stay apart, so the formats can still drop the bank ones.
export function summarize(entries: Entry[], month: string): Entry[] {
const groups = new Map();
for (const e of entries) {
- const g = groups.get(e.group) ?? {
+ const key = `${e.group}|${e.bank}`;
+ const g = groups.get(key) ?? {
date: monthEnd(month),
memo: e.memo,
group: e.group,
@@ -455,7 +460,7 @@ export function summarize(entries: Entry[], month: string): Entry[] {
same.credit += l.credit;
} else g.lines.push({ ...l });
}
- groups.set(e.group, g);
+ groups.set(key, g);
}
// A line's debit and credit net to one side.
return [...groups.values()].map((g) => ({
diff --git a/src/lib/content.ts b/src/lib/content.ts
index ae68acf..5b9d939 100644
--- a/src/lib/content.ts
+++ b/src/lib/content.ts
@@ -15,6 +15,13 @@ const marked = new Marked({
return `${this.parser.parseInline(tokens)} \n`;
},
},
+ // Wide tables scroll inside their own box on a phone instead of widening the page.
+ hooks: {
+ postprocess: (html) =>
+ html
+ .replaceAll(" "),
+ },
});
export function toHtml(md: string) {
@@ -50,6 +57,18 @@ export function parse(slug: string, raw: string): Page {
};
}
+// Question and answer pairs from a "## Common questions" section, written as
+// "**Question?** Answer" paragraphs, for FAQPage structured data. Markdown
+// links and emphasis become plain text.
+export function faqOf(body: string) {
+ const section =
+ body.split(/^## Common questions$/m)[1]?.split(/^## /m)[0] ?? "";
+ return [...section.matchAll(/^\*\*(.+?\?)\*\* (.+)$/gm)].map(([, q, a]) => ({
+ q,
+ a: a.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/[*`]/g, ""),
+ }));
+}
+
const load = (files: Record) =>
Object.entries(files).map(([path, raw]) =>
parse(path.split("/").pop()?.replace(/\.md$/, "") ?? path, raw),
diff --git a/src/lib/costs.ts b/src/lib/costs.ts
index b9367c4..7fb8bff 100644
--- a/src/lib/costs.ts
+++ b/src/lib/costs.ts
@@ -30,6 +30,9 @@ export const FlatCostInput = z
paidWith: z.enum(["personal", "company"]).optional(),
paidWithSince: Day.nullable().optional(),
})
+ .refine((f) => f.category !== "equipment" || f.interval === "once", {
+ message: "Equipment is a one-time cost.",
+ })
.refine((f) => !f.endsOn || f.endsOn >= f.startsOn, {
message: "The end date is before the start date.",
});
diff --git a/src/lib/crypto.ts b/src/lib/crypto.ts
index 87faeed..935b2da 100644
--- a/src/lib/crypto.ts
+++ b/src/lib/crypto.ts
@@ -8,16 +8,20 @@ const dec = new TextDecoder();
let cachedKey: CryptoKey | null = null;
-async function key() {
- if (cachedKey) return cachedKey;
- const raw = process.env.SECRET_KEY;
+// Imports a base64 SECRET_KEY. scripts/rotate-secret-key.ts passes the old
+// and new keys explicitly; everything else uses the one in the environment.
+export async function importSecret(raw: string | undefined) {
if (!raw) throw new Error("SECRET_KEY is not set");
const bytes = Uint8Array.from(atob(raw), (c) => c.charCodeAt(0));
if (bytes.length !== 32) throw new Error("SECRET_KEY must be 32 bytes");
- cachedKey = await crypto.subtle.importKey("raw", bytes, "AES-GCM", false, [
+ return crypto.subtle.importKey("raw", bytes, "AES-GCM", false, [
"encrypt",
"decrypt",
]);
+}
+
+async function key() {
+ cachedKey ??= await importSecret(process.env.SECRET_KEY);
return cachedKey;
}
@@ -25,23 +29,26 @@ const toB64 = (b: Uint8Array) => btoa(String.fromCharCode(...b));
const fromB64 = (s: string) => Uint8Array.from(atob(s), (c) => c.charCodeAt(0));
// Output: "v1.." with both parts base64.
-export async function encrypt(value: unknown) {
+export async function encrypt(value: unknown, k?: CryptoKey) {
const iv = crypto.getRandomValues(new Uint8Array(12));
const data = enc.encode(JSON.stringify(value));
const out = await crypto.subtle.encrypt(
{ name: "AES-GCM", iv },
- await key(),
+ k ?? (await key()),
data,
);
return `v1.${toB64(iv)}.${toB64(new Uint8Array(out))}`;
}
-export async function decrypt(payload: string): Promise {
+export async function decrypt(
+ payload: string,
+ k?: CryptoKey,
+): Promise {
const [version, iv, body] = payload.split(".");
if (version !== "v1" || !iv || !body) throw new Error("Bad ciphertext");
const out = await crypto.subtle.decrypt(
{ name: "AES-GCM", iv: fromB64(iv) },
- await key(),
+ k ?? (await key()),
fromB64(body),
);
return JSON.parse(dec.decode(out)) as T;
diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts
index 42c8f27..c04e2d5 100644
--- a/src/routeTree.gen.ts
+++ b/src/routeTree.gen.ts
@@ -16,6 +16,8 @@ import { Route as CliRouteImport } from './routes/cli'
import { Route as CookiesRouteImport } from './routes/cookies'
import { Route as DemoRouteImport } from './routes/demo'
import { Route as DocsRouteImport } from './routes/docs'
+import { Route as LlmsFullDottxtRouteImport } from './routes/llms-full[.]txt'
+import { Route as LlmsDottxtRouteImport } from './routes/llms[.]txt'
import { Route as LoginRouteImport } from './routes/login'
import { Route as McpRouteImport } from './routes/mcp'
import { Route as OnboardingRouteImport } from './routes/onboarding'
@@ -104,6 +106,16 @@ const DocsRoute = DocsRouteImport.update({
path: '/docs',
getParentRoute: () => rootRouteImport,
} as any)
+const LlmsFullDottxtRoute = LlmsFullDottxtRouteImport.update({
+ id: '/llms-full.txt',
+ path: '/llms-full.txt',
+ getParentRoute: () => rootRouteImport,
+} as any)
+const LlmsDottxtRoute = LlmsDottxtRouteImport.update({
+ id: '/llms.txt',
+ path: '/llms.txt',
+ getParentRoute: () => rootRouteImport,
+} as any)
const LoginRoute = LoginRouteImport.update({
id: '/login',
path: '/login',
@@ -375,6 +387,8 @@ export interface FileRoutesByFullPath {
'/cookies': typeof CookiesRoute
'/demo': typeof DemoRouteWithChildren
'/docs': typeof DocsRouteWithChildren
+ '/llms-full.txt': typeof LlmsFullDottxtRoute
+ '/llms.txt': typeof LlmsDottxtRoute
'/login': typeof LoginRoute
'/mcp': typeof McpRoute
'/onboarding': typeof OnboardingRoute
@@ -433,6 +447,8 @@ export interface FileRoutesByTo {
'/changelog': typeof ChangelogRoute
'/cli': typeof CliRoute
'/cookies': typeof CookiesRoute
+ '/llms-full.txt': typeof LlmsFullDottxtRoute
+ '/llms.txt': typeof LlmsDottxtRoute
'/login': typeof LoginRoute
'/mcp': typeof McpRoute
'/onboarding': typeof OnboardingRoute
@@ -495,6 +511,8 @@ export interface FileRoutesById {
'/cookies': typeof CookiesRoute
'/demo': typeof DemoRouteWithChildren
'/docs': typeof DocsRouteWithChildren
+ '/llms-full.txt': typeof LlmsFullDottxtRoute
+ '/llms.txt': typeof LlmsDottxtRoute
'/login': typeof LoginRoute
'/mcp': typeof McpRoute
'/onboarding': typeof OnboardingRoute
@@ -558,6 +576,8 @@ export interface FileRouteTypes {
| '/cookies'
| '/demo'
| '/docs'
+ | '/llms-full.txt'
+ | '/llms.txt'
| '/login'
| '/mcp'
| '/onboarding'
@@ -616,6 +636,8 @@ export interface FileRouteTypes {
| '/changelog'
| '/cli'
| '/cookies'
+ | '/llms-full.txt'
+ | '/llms.txt'
| '/login'
| '/mcp'
| '/onboarding'
@@ -677,6 +699,8 @@ export interface FileRouteTypes {
| '/cookies'
| '/demo'
| '/docs'
+ | '/llms-full.txt'
+ | '/llms.txt'
| '/login'
| '/mcp'
| '/onboarding'
@@ -739,6 +763,8 @@ export interface RootRouteChildren {
CookiesRoute: typeof CookiesRoute
DemoRoute: typeof DemoRouteWithChildren
DocsRoute: typeof DocsRouteWithChildren
+ LlmsFullDottxtRoute: typeof LlmsFullDottxtRoute
+ LlmsDottxtRoute: typeof LlmsDottxtRoute
LoginRoute: typeof LoginRoute
McpRoute: typeof McpRoute
OnboardingRoute: typeof OnboardingRoute
@@ -827,6 +853,20 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof DocsRouteImport
parentRoute: typeof rootRouteImport
}
+ '/llms-full.txt': {
+ id: '/llms-full.txt'
+ path: '/llms-full.txt'
+ fullPath: '/llms-full.txt'
+ preLoaderRoute: typeof LlmsFullDottxtRouteImport
+ parentRoute: typeof rootRouteImport
+ }
+ '/llms.txt': {
+ id: '/llms.txt'
+ path: '/llms.txt'
+ fullPath: '/llms.txt'
+ preLoaderRoute: typeof LlmsDottxtRouteImport
+ parentRoute: typeof rootRouteImport
+ }
'/login': {
id: '/login'
path: '/login'
@@ -1270,6 +1310,8 @@ const rootRouteChildren: RootRouteChildren = {
CookiesRoute: CookiesRoute,
DemoRoute: DemoRouteWithChildren,
DocsRoute: DocsRouteWithChildren,
+ LlmsFullDottxtRoute: LlmsFullDottxtRoute,
+ LlmsDottxtRoute: LlmsDottxtRoute,
LoginRoute: LoginRoute,
McpRoute: McpRoute,
OnboardingRoute: OnboardingRoute,
diff --git a/src/routes/api/journal[.]csv.ts b/src/routes/api/journal[.]csv.ts
index b9d7301..d1bdeca 100644
--- a/src/routes/api/journal[.]csv.ts
+++ b/src/routes/api/journal[.]csv.ts
@@ -3,7 +3,7 @@ import { createFileRoute } from "@tanstack/react-router";
export const Route = createFileRoute("/api/journal.csv")({
server: {
handlers: {
- GET: async ({ request }) => {
+ POST: async ({ request }) => {
// Imported here so pages that skip the database never open it.
const { journalDownload } = await import(
"#/server/books-export.server"
diff --git a/src/routes/app/costs.tsx b/src/routes/app/costs.tsx
index ecf4b9a..50e1859 100644
--- a/src/routes/app/costs.tsx
+++ b/src/routes/app/costs.tsx
@@ -194,6 +194,10 @@ function FlatCostForm({
setError("The end date is before the start date.");
return;
}
+ if (!once && v.category === "equipment") {
+ setError("Equipment is a one-time cost.");
+ return;
+ }
const data = {
name: v.name.trim(),
amountCents,
diff --git a/src/routes/blog.$slug.tsx b/src/routes/blog.$slug.tsx
index 42b6809..2eb42f8 100644
--- a/src/routes/blog.$slug.tsx
+++ b/src/routes/blog.$slug.tsx
@@ -1,6 +1,6 @@
import { createFileRoute } from "@tanstack/react-router";
import { ContentPage } from "#/components/content-page";
-import { SITE_URL, seo } from "#/lib/app";
+import { breadcrumbs, jsonLd, SITE_URL, seo } from "#/lib/app";
import { dayLabel } from "#/lib/format";
import { getPost } from "#/server/content.functions";
@@ -11,25 +11,33 @@ export const Route = createFileRoute("/blog/$slug")({
p
? {
...seo({
- title: `${p.title} · OpenProfit`,
+ // Post titles run near Google's 60-character cutoff, so no suffix.
+ title: p.title,
description: p.description,
path: `/blog/${p.slug}`,
}),
// schema.org BlogPosting: https://schema.org/BlogPosting
scripts: [
- {
- type: "application/ld+json",
- children: JSON.stringify({
- "@context": "https://schema.org",
- "@type": "BlogPosting",
- headline: p.title,
- description: p.description,
- datePublished: p.date,
- url: `${SITE_URL}/blog/${p.slug}`,
- author: { "@type": "Person", name: p.author },
- publisher: { "@type": "Organization", name: "Lobbystack Inc." },
- }),
- },
+ jsonLd({
+ "@graph": [
+ breadcrumbs([
+ ["Blog", "/blog"],
+ [p.title, `/blog/${p.slug}`],
+ ]),
+ {
+ "@type": "BlogPosting",
+ headline: p.title,
+ description: p.description,
+ datePublished: p.date,
+ url: `${SITE_URL}/blog/${p.slug}`,
+ author: { "@type": "Person", name: p.author },
+ publisher: {
+ "@type": "Organization",
+ name: "Lobbystack Inc.",
+ },
+ },
+ ],
+ }),
],
}
: {},
diff --git a/src/routes/compare.$slug.tsx b/src/routes/compare.$slug.tsx
index 2258071..48c5683 100644
--- a/src/routes/compare.$slug.tsx
+++ b/src/routes/compare.$slug.tsx
@@ -1,6 +1,6 @@
import { createFileRoute } from "@tanstack/react-router";
import { ContentPage } from "#/components/content-page";
-import { seo } from "#/lib/app";
+import { breadcrumbs, jsonLd, seo } from "#/lib/app";
import { getContentPage } from "#/server/content.functions";
export const Route = createFileRoute("/compare/$slug")({
@@ -9,11 +9,21 @@ export const Route = createFileRoute("/compare/$slug")({
// No loader data on a 404.
head: ({ loaderData: p }) =>
p
- ? seo({
- title: `${p.title} · OpenProfit`,
- description: p.description,
- path: `/compare/${p.slug}`,
- })
+ ? {
+ ...seo({
+ title: `${p.title} · OpenProfit`,
+ description: p.description,
+ path: `/compare/${p.slug}`,
+ }),
+ scripts: [
+ jsonLd(
+ breadcrumbs([
+ ["OpenProfit", "/"],
+ [p.title, `/compare/${p.slug}`],
+ ]),
+ ),
+ ],
+ }
: {},
component: () => ,
});
diff --git a/src/routes/docs.$slug.tsx b/src/routes/docs.$slug.tsx
index 8290d04..cc01168 100644
--- a/src/routes/docs.$slug.tsx
+++ b/src/routes/docs.$slug.tsx
@@ -1,5 +1,5 @@
import { createFileRoute } from "@tanstack/react-router";
-import { seo } from "#/lib/app";
+import { breadcrumbs, jsonLd, SITE_URL, seo } from "#/lib/app";
import { getContentPage } from "#/server/content.functions";
export const Route = createFileRoute("/docs/$slug")({
@@ -8,11 +8,29 @@ export const Route = createFileRoute("/docs/$slug")({
// No loader data on a 404.
head: ({ loaderData: p }) =>
p
- ? seo({
- title: `${p.title} · OpenProfit docs`,
- description: p.description,
- path: `/docs/${p.slug}`,
- })
+ ? {
+ ...seo({
+ title: `${p.title} · OpenProfit docs`,
+ description: p.description,
+ path: `/docs/${p.slug}`,
+ }),
+ scripts: [
+ jsonLd({
+ "@graph": [
+ breadcrumbs([
+ ["Docs", "/docs/connectors"],
+ [p.title, `/docs/${p.slug}`],
+ ]),
+ {
+ "@type": "TechArticle",
+ headline: p.title,
+ description: p.description,
+ url: `${SITE_URL}/docs/${p.slug}`,
+ },
+ ],
+ }),
+ ],
+ }
: {},
component: Page,
});
diff --git a/src/routes/index.tsx b/src/routes/index.tsx
index e3670fd..98c41b8 100644
--- a/src/routes/index.tsx
+++ b/src/routes/index.tsx
@@ -13,7 +13,7 @@ import { Hero } from "#/components/landing/hero";
import { Nav } from "#/components/landing/nav";
import { OpenSource } from "#/components/landing/open-source";
import { Pricing } from "#/components/landing/pricing";
-import { SITE_DESCRIPTION, SITE_URL, seo } from "#/lib/app";
+import { GITHUB_URL, SITE_DESCRIPTION, SITE_URL, seo } from "#/lib/app";
const LD = {
"@context": "https://schema.org",
@@ -25,6 +25,7 @@ const LD = {
operatingSystem: "Web",
url: SITE_URL,
description: SITE_DESCRIPTION,
+ sameAs: [GITHUB_URL, "https://www.npmjs.com/package/openprofit"],
offers: [
{ "@type": "Offer", name: "Free", price: "0", priceCurrency: "USD" },
{ "@type": "Offer", name: "Indie", price: "19", priceCurrency: "USD" },
@@ -36,7 +37,16 @@ const LD = {
name: "Lobbystack Inc.",
url: SITE_URL,
logo: `${SITE_URL}/apple-touch-icon.png`,
- sameAs: ["https://github.com/lobbystack/openprofit"],
+ sameAs: [GITHUB_URL],
+ },
+ // The name Google shows for the site in results, and the other names
+ // people search for it by:
+ // https://developers.google.com/search/docs/appearance/site-names
+ {
+ "@type": "WebSite",
+ name: "OpenProfit",
+ alternateName: ["Open Profit", "openprofit.dev"],
+ url: `${SITE_URL}/`,
},
],
};
@@ -44,7 +54,7 @@ const LD = {
export const Route = createFileRoute("/")({
head: () => ({
...seo({
- title: "OpenProfit: open-source finance for developers",
+ title: "OpenProfit: Open-source profit tracking for developers",
path: "/",
}),
scripts: [{ type: "application/ld+json", children: JSON.stringify(LD) }],
diff --git a/src/routes/integrations.$slug.tsx b/src/routes/integrations.$slug.tsx
index f6ce5ef..83ae12f 100644
--- a/src/routes/integrations.$slug.tsx
+++ b/src/routes/integrations.$slug.tsx
@@ -1,7 +1,7 @@
import { createFileRoute, Link } from "@tanstack/react-router";
import { ContentPage } from "#/components/content-page";
import { providerName } from "#/components/provider-logo";
-import { seo } from "#/lib/app";
+import { breadcrumbs, jsonLd, seo } from "#/lib/app";
import { getContentPage } from "#/server/content.functions";
export const Route = createFileRoute("/integrations/$slug")({
@@ -10,11 +10,37 @@ export const Route = createFileRoute("/integrations/$slug")({
// No loader data on a 404.
head: ({ loaderData: p }) =>
p
- ? seo({
- title: `${p.title} · OpenProfit`,
- description: p.description,
- path: `/integrations/${p.slug}`,
- })
+ ? {
+ ...seo({
+ title: `${p.title} · OpenProfit`,
+ description: p.description,
+ path: `/integrations/${p.slug}`,
+ }),
+ scripts: [
+ jsonLd({
+ "@graph": [
+ breadcrumbs([
+ ["Integrations", "/integrations"],
+ [providerName(p.slug), `/integrations/${p.slug}`],
+ ]),
+ // Read by AI answer engines; Google shows FAQ results
+ // only for government and health sites.
+ ...(p.faq.length
+ ? [
+ {
+ "@type": "FAQPage",
+ mainEntity: p.faq.map(({ q, a }) => ({
+ "@type": "Question",
+ name: q,
+ acceptedAnswer: { "@type": "Answer", text: a },
+ })),
+ },
+ ]
+ : []),
+ ],
+ }),
+ ],
+ }
: {},
component: Integration,
});
diff --git a/src/routes/llms-full[.]txt.ts b/src/routes/llms-full[.]txt.ts
new file mode 100644
index 0000000..29fa7d7
--- /dev/null
+++ b/src/routes/llms-full[.]txt.ts
@@ -0,0 +1,29 @@
+import { createFileRoute } from "@tanstack/react-router";
+import { COMPARISONS, INTEGRATIONS, POSTS } from "#/lib/content";
+import { DOCS } from "#/lib/docs";
+
+// Every page listed in /llms.txt, as one markdown file (llms-full.txt).
+const PATHS = [
+ "/",
+ "/security",
+ ...DOCS.map((d) => `/docs/${d.slug}`),
+ ...INTEGRATIONS.map((p) => `/integrations/${p.slug}`),
+ ...COMPARISONS.map((p) => `/compare/${p.slug}`),
+ ...POSTS.map((p) => `/blog/${p.slug}`),
+];
+
+export const Route = createFileRoute("/llms-full.txt")({
+ server: {
+ handlers: {
+ GET: async () => {
+ const { markdownFor } = await import("#/server/markdown.server");
+ const body = PATHS.flatMap((p) => markdownFor(p) ?? []).join(
+ "\n\n---\n\n",
+ );
+ return new Response(`${body}\n`, {
+ headers: { "Content-Type": "text/plain; charset=utf-8" },
+ });
+ },
+ },
+ },
+});
diff --git a/src/routes/llms[.]txt.ts b/src/routes/llms[.]txt.ts
new file mode 100644
index 0000000..b200d43
--- /dev/null
+++ b/src/routes/llms[.]txt.ts
@@ -0,0 +1,67 @@
+import { createFileRoute } from "@tanstack/react-router";
+import { SITE_DESCRIPTION, SITE_URL } from "#/lib/app";
+import { COMPARISONS, DATA, INTEGRATIONS, POSTS } from "#/lib/content";
+import { DOCS } from "#/lib/docs";
+
+const item = (title: string, path: string, about: string) =>
+ `- [${title}](${SITE_URL}${path})${about ? `: ${about}` : ""}`;
+
+// The site map for AI agents, in the llms.txt format (https://llmstxt.org).
+const BODY = [
+ "# OpenProfit",
+ "",
+ `> ${SITE_DESCRIPTION}`,
+ "",
+ `OpenProfit is open source under the MIT license and runs as one Docker image. Request any page below with \`Accept: text/markdown\` to get it as markdown, or read them all at ${SITE_URL}/llms-full.txt.`,
+ "",
+ "## Product",
+ "",
+ item("OpenProfit", "/", "What it does, the connectors, and pricing"),
+ item(
+ "Security",
+ "/security",
+ "The API key each provider needs and what OpenProfit does with it",
+ ),
+ item(
+ "Profit database",
+ "/open",
+ "Revenue, costs and profit from products that publish their numbers, read from Stripe, OpenAI, Vercel and other provider APIs",
+ ),
+ item(DATA.title, "/data", DATA.description),
+ "",
+ "## Docs",
+ "",
+ ...DOCS.map((d) => item(d.title, `/docs/${d.slug}`, d.description)),
+ "",
+ "## Integrations",
+ "",
+ ...INTEGRATIONS.map((p) =>
+ item(p.meta.name, `/integrations/${p.slug}`, p.meta.summary),
+ ),
+ "",
+ "## Comparisons",
+ "",
+ ...COMPARISONS.map((p) => item(p.title, `/compare/${p.slug}`, p.description)),
+ "",
+ "## Blog",
+ "",
+ ...POSTS.map((p) => item(p.title, `/blog/${p.slug}`, p.description)),
+ "",
+ "## Optional",
+ "",
+ item("Changelog", "/changelog", ""),
+ item("Privacy policy", "/privacy", ""),
+ item("Terms of service", "/terms", ""),
+ "",
+].join("\n");
+
+export const Route = createFileRoute("/llms.txt")({
+ server: {
+ handlers: {
+ GET: () =>
+ new Response(BODY, {
+ headers: { "Content-Type": "text/plain; charset=utf-8" },
+ }),
+ },
+ },
+});
diff --git a/src/routes/login.tsx b/src/routes/login.tsx
index fe718db..8a671f5 100644
--- a/src/routes/login.tsx
+++ b/src/routes/login.tsx
@@ -29,7 +29,7 @@ export const Route = createFileRoute("/login")({
});
function Login() {
- const { social, mailer } = Route.useLoaderData();
+ const { social, mailer, cloud } = Route.useLoaderData();
const back = Route.useSearch().redirect;
const next = back ?? "/app";
// A new account creates its workspace first, then continues to `back`.
@@ -92,7 +92,7 @@ function Login() {
})
}
>
- {p === "github" && (
+ {p === "github" ? (
+ ) : (
+
)}
{p === "github"
? "Continue with GitHub"
@@ -138,6 +146,19 @@ function Login() {
Could not send the link. Try again.
)}
+ {cloud && (
+
+ By continuing, you agree to the{" "}
+
+ Terms
+ {" "}
+ and{" "}
+
+ Privacy Policy
+
+ .
+
+ )}
)}
diff --git a/src/routes/onboarding.tsx b/src/routes/onboarding.tsx
index 71512ec..2b01ec3 100644
--- a/src/routes/onboarding.tsx
+++ b/src/routes/onboarding.tsx
@@ -5,12 +5,7 @@ import { z } from "zod";
import { Logo } from "#/components/logo";
import { Button } from "#/components/ui/button";
import { Checkbox } from "#/components/ui/checkbox";
-import {
- Field,
- FieldDescription,
- FieldGroup,
- FieldLabel,
-} from "#/components/ui/field";
+import { Field, FieldGroup, FieldLabel } from "#/components/ui/field";
import { Input } from "#/components/ui/input";
import { Label } from "#/components/ui/label";
import {
@@ -18,9 +13,10 @@ import {
NativeSelectOption,
} from "#/components/ui/native-select";
import { identify } from "#/lib/analytics";
-import { isLocalPath, NOINDEX } from "#/lib/app";
+import { HEARD_FROM, HEARD_FROM_LABELS, isLocalPath, NOINDEX } from "#/lib/app";
import { localDay } from "#/lib/books-settings";
import { CURRENCIES } from "#/lib/format";
+import { getAnalyticsConfig } from "#/server/analytics.functions";
import { getSession } from "#/server/auth.functions";
import { createWorkspaceFn } from "#/server/onboarding.functions";
@@ -34,15 +30,19 @@ export const Route = createFileRoute("/onboarding")({
redirect: z.string().refine(isLocalPath).optional().catch(undefined),
}),
loader: async () => {
- const user = await getSession();
+ const [user, analytics] = await Promise.all([
+ getSession(),
+ getAnalyticsConfig(),
+ ]);
if (!user) throw redirect({ to: "/login" });
- return user;
+ // The answer only goes to PostHog, so self-hosts without it don't ask.
+ return { user, askHeardFrom: analytics.key !== null };
},
component: Onboarding,
});
function Onboarding() {
- const user = Route.useLoaderData();
+ const { user, askHeardFrom } = Route.useLoaderData();
useEffect(() => identify(user.id, user.analytics), [user]);
const back = Route.useSearch().redirect;
const navigate = useNavigate();
@@ -50,6 +50,10 @@ function Onboarding() {
const [name, setName] = useState("");
const [currency, setCurrency] = useState<(typeof CURRENCIES)[number]>("USD");
const [incorporated, setIncorporated] = useState(false);
+ const [incorporatedOn, setIncorporatedOn] = useState("");
+ const [heardFrom, setHeardFrom] = useState<(typeof HEARD_FROM)[number] | "">(
+ "",
+ );
const [busy, setBusy] = useState(false);
async function submit(e: React.FormEvent) {
@@ -61,7 +65,8 @@ function Onboarding() {
name,
currency,
timezone,
- incorporatedOn: incorporated ? localDay() : null,
+ incorporatedOn: incorporated ? incorporatedOn : null,
+ heardFrom: heardFrom || undefined,
},
});
if (back) navigate({ href: back });
@@ -102,10 +107,6 @@ function Onboarding() {
))}
-
- Every amount converts to this currency at the European Central
- Bank rate for its day. You can change it in Settings.
-
@@ -115,11 +116,44 @@ function Onboarding() {
/>
This is an incorporated company
-
- Check this if your company files its own tax return. You can
- change it in Books.
-
+ {incorporated && (
+
+ Incorporated on
+ setIncorporatedOn(e.target.value)}
+ className="num"
+ />
+
+ )}
+ {askHeardFrom && (
+
+
+ Where did you hear about OpenProfit?
+
+
+ setHeardFrom(e.target.value as (typeof HEARD_FROM)[number])
+ }
+ >
+
+ Choose one (optional)
+
+ {HEARD_FROM.map((k) => (
+
+ {HEARD_FROM_LABELS[k]}
+
+ ))}
+
+
+ )}
Publish yours
+ , or see{" "}
+
+ how this compares with TrustMRR
+
.
diff --git a/src/routes/p.$workspace.$product_.badge[.]svg.ts b/src/routes/p.$workspace.$product_.badge[.]svg.ts
index 624051b..ddc7b58 100644
--- a/src/routes/p.$workspace.$product_.badge[.]svg.ts
+++ b/src/routes/p.$workspace.$product_.badge[.]svg.ts
@@ -1,6 +1,6 @@
import { createFileRoute } from "@tanstack/react-router";
-// Embeddable badge for a public product page. Under `pnpm dev`, Nitro treats
+// Embeddable badge for a public product page. Under `bun run dev`, Nitro treats
// image requests for .svg and .png paths as static files and answers 404
// (nitro/dist/_build/vite.dev.mjs); production serves them. To test in dev:
// curl -H "Sec-Fetch-Dest: document" .
diff --git a/src/routes/sitemap[.]xml.ts b/src/routes/sitemap[.]xml.ts
index 2c359b3..fb57c33 100644
--- a/src/routes/sitemap[.]xml.ts
+++ b/src/routes/sitemap[.]xml.ts
@@ -19,6 +19,13 @@ const STATIC = [
"/security",
];
+// Only pages with a real date get : the posts, and the blog index
+// at its newest post.
+const LASTMOD = new Map([
+ ["/blog", POSTS[0]?.meta.date],
+ ...POSTS.map((p) => [`/blog/${p.slug}`, p.meta.date] as const),
+]);
+
export const Route = createFileRoute("/sitemap.xml")({
server: {
handlers: {
@@ -44,7 +51,7 @@ export const Route = createFileRoute("/sitemap.xml")({
...pub.map((r) => `/p/${r.ws}/${r.p}`),
];
return new Response(
- `\n\n${paths.map((p) => ` ${SITE_URL}${p} `).join("\n")}\n \n`,
+ `\n\n${paths.map((p) => ` ${SITE_URL}${p} ${LASTMOD.get(p) ? `${LASTMOD.get(p)} ` : ""} `).join("\n")}\n \n`,
{
headers: {
"Content-Type": "application/xml; charset=utf-8",
diff --git a/src/server/auth.functions.ts b/src/server/auth.functions.ts
index f52a58d..dfba67a 100644
--- a/src/server/auth.functions.ts
+++ b/src/server/auth.functions.ts
@@ -1,6 +1,7 @@
import { createServerFn } from "@tanstack/react-start";
import { SOCIAL_PROVIDERS } from "#/lib/auth";
import { sessionUser } from "./auth.server";
+import { isCloud } from "./billing.server";
export type { SessionUser } from "./auth.server";
@@ -12,5 +13,7 @@ export const getAuthOptions = createServerFn({ method: "GET" }).handler(
async () => ({
social: SOCIAL_PROVIDERS,
mailer: Boolean(process.env.RESEND_API_KEY),
+ // The terms cover the hosted service only, not self-hosted installs.
+ cloud: isCloud,
}),
);
diff --git a/src/server/books-export.server.ts b/src/server/books-export.server.ts
index 9a8e7ed..2e109ca 100644
--- a/src/server/books-export.server.ts
+++ b/src/server/books-export.server.ts
@@ -155,12 +155,16 @@ export async function journalCsv(
month,
renames: ws.bookAccounts ?? {},
product: (id) => (id && names.get(id)) || null,
- dayFirst: Boolean(ws.country && ws.country !== "US"),
+ // With no country set, a USD workspace counts as being in the US.
+ dayFirst: ws.country ? ws.country !== "US" : ws.baseCurrency !== "USD",
});
return { csv: csvFile(rows) };
}
-// GET /api/journal.csv?month=YYYY-MM&format=quickbooks|xero|plain&product=id
+// POST /api/journal.csv?month=YYYY-MM&format=quickbooks|xero|plain&product=id
+// POST, because a whole-workspace export closes the month: the session
+// cookie (SameSite=Lax) doesn't go out on another site's POST, and link
+// prefetchers only GET.
export async function journalDownload(request: Request) {
const ws = await exportWorkspace(request);
if (!ws) return new Response("Sign in to export.", { status: 401 });
diff --git a/src/server/books.server.ts b/src/server/books.server.ts
index 1edff59..bc47885 100644
--- a/src/server/books.server.ts
+++ b/src/server/books.server.ts
@@ -8,6 +8,7 @@ import {
type Entry,
expenseAccount,
journal,
+ nextMonth,
summarize,
totals,
} from "#/lib/books";
@@ -18,24 +19,15 @@ import type { Workspace } from "./workspace.server";
// Loads the data for the books (docs/BOOKS.md) and runs the journal in
// src/lib/books.ts.
-const nextMonth = (m: string) => {
- const [y, mo] = m.split("-").map(Number);
- return new Date(Date.UTC(y, mo, 1)).toISOString().slice(0, 7);
-};
-
type RevenueRow = typeof schema.revenueLines.$inferSelect;
-// Gross, fees and refunds in base cents. Rows synced before the base
-// columns derive them from the net (or tax) rate.
+// Gross and refunds in base cents. Rows synced before the base columns
+// derive them from the net (or tax) rate. Fees are whatever net leaves out
+// of them, Stripe's own charges and lost disputes included, so a provider's
+// balance moves by net.
// ponytail: a fully refunded payment with no tax has no rate; it counts
// at 1:1 until the next full sync fills the base columns.
function baseAmounts(l: RevenueRow, baseCurrency: string) {
- if (l.grossBaseCents !== null)
- return {
- gross: l.grossBaseCents,
- fees: l.feesBaseCents ?? 0,
- refunds: l.refundsBaseCents ?? 0,
- };
const rate =
l.currency === baseCurrency
? 1
@@ -44,25 +36,26 @@ function baseAmounts(l: RevenueRow, baseCurrency: string) {
: l.taxCents
? l.taxBaseCents / l.taxCents
: 1;
- return {
- gross: Math.round(l.grossCents * rate),
- fees: Math.round(l.feesCents * rate),
- refunds: Math.round(l.refundsCents * rate),
- };
+ const gross = l.grossBaseCents ?? Math.round(l.grossCents * rate);
+ const refunds = l.refundsBaseCents ?? Math.round(l.refundsCents * rate);
+ return { gross, refunds, fees: gross - refunds - l.netBaseCents };
}
-export async function booksInput(
+// The books input for each month, from one read of the span they cover.
+export async function booksInputs(
ws: Workspace,
- month: string,
+ months: string[],
productId: string | null = null,
-): Promise {
- const first = `${month}-01`;
- const after = `${nextMonth(month)}-01`;
+): Promise {
+ if (!months.length) return [];
+ const sorted = [...months].sort();
+ const first = `${sorted[0]}-01`;
+ const after = `${nextMonth(sorted[sorted.length - 1])}-01`;
const only = (col: PgColumn) => (productId ? eq(col, productId) : undefined);
const r = schema.revenueLines;
const c = schema.costLines;
const [revenue, costs, payouts, flats, conns] = await Promise.all([
- // Paid in the month, or earning in it.
+ // Paid in the span, or earning in it.
db
.select({ line: r, provider: schema.connections.provider })
.from(r)
@@ -122,50 +115,65 @@ export async function booksInput(
.map((x) => x.id),
);
const conn = new Map(conns.map((x) => [x.id, x]));
- return {
- month,
- incorporatedOn: ws.incorporatedOn,
- providerName,
- revenue: revenue.map(({ line, provider }) => ({
- date: line.date,
- provider,
- productId: line.productId,
- ...baseAmounts(line, ws.baseCurrency),
- tax: line.taxBaseCents,
- remitsTax: remits.has(provider),
- serviceStart: line.serviceStart,
- serviceEnd: line.serviceEnd,
- })),
- costs: costs.map((x) => {
- const k = x.connectionId ? conn.get(x.connectionId) : undefined;
- return {
- date: x.date,
- provider: x.provider,
- productId: x.productId,
- amount: x.amountBaseCents,
- method: k?.paidWith ?? "personal",
- since: k?.paidWithSince ?? null,
- };
- }),
- payouts: payouts.map(({ p, provider }) => ({
- date: p.date,
- provider,
- amount: p.amountBaseCents,
- })),
- manual: flats.map((f) => ({
- name: f.name,
- productId: f.productId,
- amount: f.amountBaseCents ?? f.amountCents,
- interval: f.interval,
- startsOn: f.startsOn,
- endsOn: f.endsOn,
- category:
- f.category ??
- (f.provider === "manual" ? "other" : expenseAccount(f.provider)),
- method: f.paidWith,
- since: f.paidWithSince,
- })),
- };
+ const revenueIn = revenue.map(({ line, provider }) => ({
+ date: line.date,
+ provider,
+ productId: line.productId,
+ ...baseAmounts(line, ws.baseCurrency),
+ tax: line.taxBaseCents,
+ remitsTax: remits.has(provider),
+ serviceStart: line.serviceStart,
+ serviceEnd: line.serviceEnd,
+ }));
+ const costsIn = costs.map((x) => {
+ const k = x.connectionId ? conn.get(x.connectionId) : undefined;
+ return {
+ date: x.date,
+ provider: x.provider,
+ productId: x.productId,
+ amount: x.amountBaseCents,
+ method: k?.paidWith ?? "personal",
+ since: k?.paidWithSince ?? null,
+ };
+ });
+ const payoutsIn = payouts.map(({ p, provider }) => ({
+ date: p.date,
+ provider,
+ amount: p.amountBaseCents,
+ }));
+ const manual = flats.map((f) => ({
+ name: f.name,
+ productId: f.productId,
+ amount: f.amountBaseCents ?? f.amountCents,
+ interval: f.interval,
+ startsOn: f.startsOn,
+ endsOn: f.endsOn,
+ category: f.category ?? expenseAccount(f.provider),
+ method: f.paidWith,
+ since: f.paidWithSince,
+ }));
+ return months.map((month) => {
+ const from = `${month}-01`;
+ const to = `${nextMonth(month)}-01`;
+ const inMonth = (x: { date: string }) => x.date >= from && x.date < to;
+ return {
+ month,
+ incorporatedOn: ws.incorporatedOn,
+ providerName,
+ // Paid in the month, or earning in it.
+ revenue: revenueIn.filter(
+ (x) =>
+ inMonth(x) ||
+ (x.serviceStart !== null &&
+ x.serviceEnd !== null &&
+ x.serviceStart < to &&
+ x.serviceEnd > from),
+ ),
+ costs: costsIn.filter(inMonth),
+ payouts: payoutsIn.filter(inMonth),
+ manual,
+ };
+ });
}
// The year's depreciation under the workspace's tax rules (src/lib/tax.ts),
@@ -183,22 +191,12 @@ export const yearDepreciation = (ws: Workspace, input: BooksIn) =>
: undefined;
// The month's journal, summarized: one entry per source. December carries
-// the year's depreciation unless `depreciation` overrides it.
-export async function monthEntries(
- ws: Workspace,
- month: string,
- productId: string | null = null,
- depreciation?: number,
-) {
- const input = await booksInput(ws, month, productId);
- return summarize(
- journal({
- ...input,
- depreciation: depreciation ?? yearDepreciation(ws, input),
- }),
- month,
+// the year's depreciation.
+const entriesOf = (ws: Workspace, input: BooksIn) =>
+ summarize(
+ journal({ ...input, depreciation: yearDepreciation(ws, input) }),
+ input.month,
);
-}
// The journal for an export. A whole-workspace export closes the month:
// exporting it again gives the same entries, and later changes to a closed
@@ -208,14 +206,14 @@ export async function monthEntries(
export async function exportJournal(
ws: Workspace,
month: string,
- opts: { productId?: string | null; withBank: boolean; depreciation?: number },
+ opts: { productId?: string | null; withBank: boolean },
): Promise {
const keep = (es: Entry[]) =>
opts.withBank ? es : es.filter((e) => !e.bank);
- if (opts.productId)
- return keep(
- await monthEntries(ws, month, opts.productId, opts.depreciation),
- );
+ if (opts.productId) {
+ const [input] = await booksInputs(ws, [month], opts.productId);
+ return keep(entriesOf(ws, input));
+ }
const exported = await db.query.journalExports.findMany({
where: eq(schema.journalExports.workspaceId, ws.id),
@@ -223,27 +221,32 @@ export async function exportJournal(
const stored = exported.find((x) => x.month === month);
if (stored) return keep(stored.entries as Entry[]);
- const entries = await monthEntries(ws, month, null, opts.depreciation);
// Closed months before this one, as exported plus their adjustments so
// far, against what the data says now.
- for (const closed of exported
+ const closed = exported
.filter((x) => x.month < month)
- .sort((a, b) => a.month.localeCompare(b.month))) {
+ .sort((a, b) => a.month.localeCompare(b.month));
+ const [input, ...nows] = await booksInputs(ws, [
+ month,
+ ...closed.map((x) => x.month),
+ ]);
+ const entries = entriesOf(ws, input);
+ closed.forEach((c, i) => {
const sent = [
- ...(closed.entries as Entry[]).filter(
- (e) => !e.group.startsWith("adjust:"),
- ),
+ ...(c.entries as Entry[]).filter((e) => !e.group.startsWith("adjust:")),
...exported.flatMap((x) =>
- (x.entries as Entry[]).filter(
- (e) => e.group === `adjust:${closed.month}`,
- ),
+ (x.entries as Entry[]).filter((e) => e.group === `adjust:${c.month}`),
),
];
- const now = await monthEntries(ws, closed.month);
entries.push(
- ...adjustments(totals(sent), totals(now), `${month}-01`, closed.month),
+ ...adjustments(
+ totals(sent),
+ totals(entriesOf(ws, nows[i])),
+ `${month}-01`,
+ c.month,
+ ),
);
- }
+ });
await db
.insert(schema.journalExports)
.values({
@@ -258,10 +261,9 @@ export async function exportJournal(
// Twelve months of journal entries, for the tax report. Closes nothing.
export async function yearEntries(ws: Workspace, year: number) {
- const out: Entry[] = [];
- for (let m = 1; m <= 12; m++)
- out.push(
- ...(await monthEntries(ws, `${year}-${String(m).padStart(2, "0")}`)),
- );
- return out;
+ const months = Array.from(
+ { length: 12 },
+ (_, i) => `${year}-${String(i + 1).padStart(2, "0")}`,
+ );
+ return (await booksInputs(ws, months)).flatMap((i) => entriesOf(ws, i));
}
diff --git a/src/server/content.functions.ts b/src/server/content.functions.ts
index 5538625..e84f820 100644
--- a/src/server/content.functions.ts
+++ b/src/server/content.functions.ts
@@ -1,7 +1,13 @@
import { notFound } from "@tanstack/react-router";
import { createServerFn } from "@tanstack/react-start";
import { z } from "zod";
-import { CHANGELOG, COMPARISONS, INTEGRATIONS, POSTS } from "#/lib/content";
+import {
+ CHANGELOG,
+ COMPARISONS,
+ faqOf,
+ INTEGRATIONS,
+ POSTS,
+} from "#/lib/content";
import { DOCS } from "#/lib/docs";
import { LEGAL } from "#/lib/legal";
@@ -32,7 +38,7 @@ export const getContentPage = createServerFn({ method: "GET" })
: COMPARISONS;
const p = list.find((x) => x.slug === data.slug);
if (!p) throw notFound();
- return page(p);
+ return { ...page(p), faq: faqOf(p.body) };
});
export const getPost = createServerFn({ method: "GET" })
diff --git a/src/server/costs.functions.ts b/src/server/costs.functions.ts
index 52e58dd..5f1b7f9 100644
--- a/src/server/costs.functions.ts
+++ b/src/server/costs.functions.ts
@@ -64,9 +64,7 @@ export const getFlatCosts = createServerFn({ method: "GET" })
interval: f.interval,
startsOn: f.startsOn,
endsOn: f.endsOn,
- category:
- f.category ??
- (f.provider === "manual" ? "other" : expenseAccount(f.provider)),
+ category: f.category ?? expenseAccount(f.provider),
paidWith: f.paidWith,
paidWithSince: f.paidWithSince,
})),
diff --git a/src/server/discovery.server.ts b/src/server/discovery.server.ts
index 5c048bc..ef22ee1 100644
--- a/src/server/discovery.server.ts
+++ b/src/server/discovery.server.ts
@@ -27,7 +27,7 @@ const serverCard = (base: string) => ({
"Revenue, costs and profit per product, pulled from Stripe, OpenAI and other provider APIs.",
websiteUrl: base,
repository: {
- url: "https://github.com/lobbystack/openprofit",
+ url: "https://github.com/morencyr/openprofit",
source: "github",
},
icons: [{ src: `${base}/favicon.svg`, mimeType: "image/svg+xml" }],
diff --git a/src/server/edge.server.ts b/src/server/edge.server.ts
index b90f4d6..66740bb 100644
--- a/src/server/edge.server.ts
+++ b/src/server/edge.server.ts
@@ -7,7 +7,7 @@ import { markdownFor } from "./markdown.server";
// The build prerenders every page that has a markdown version. Nitro lists
// its static files before those pages are written, so they are served from
-// here, read and compressed once per process. `node .output/server/index.mjs`
+// here, read and compressed once per process. `bun .output/server/index.mjs`
// puts them in .output/public; anywhere else (dev, the prerender itself) the
// read fails and the page renders on the server.
const PUBLIC = join(dirname(process.argv[1] ?? ""), "../public");
diff --git a/src/server/fx.server.ts b/src/server/fx.server.ts
index 31f0272..dec8b7b 100644
--- a/src/server/fx.server.ts
+++ b/src/server/fx.server.ts
@@ -20,7 +20,7 @@ export async function convert(
return Math.round(cents * rate);
}
-async function rateFor(
+export async function rateFor(
date: string,
from: string,
to: string,
@@ -61,8 +61,13 @@ async function rateFor(
// requests. Today and later are cached only once quoted: the Bank publishes
// each afternoon, and the sync rereads the last days. Null when the Bank
// doesn't publish the currency (DKK, CZK...) or has no rate on or before the
-// date; Frankfurter covers those.
+// date; Frankfurter covers those. A day not yet quoted is held in memory for
+// an hour at the preceding rate, so a sync doesn't ask again for each line.
+const unquoted = new Map();
async function bankOfCanada(date: string, from: string) {
+ const key = `${from}:${date}`;
+ const held = unquoted.get(key);
+ if (held && held.until > Date.now()) return held.rate ?? null;
const series = `FX${from}CAD`;
const today = iso(Date.now());
const at = Date.parse(date);
@@ -94,5 +99,7 @@ async function bankOfCanada(date: string, from: string) {
}
if (rows.length)
await db.insert(schema.fxRates).values(rows).onConflictDoNothing();
+ if (!rows.some((r) => r.date === date))
+ unquoted.set(key, { rate, until: Date.now() + 3_600_000 });
return rate ?? null;
}
diff --git a/src/server/mcp.server.ts b/src/server/mcp.server.ts
index 16624ae..837433e 100644
--- a/src/server/mcp.server.ts
+++ b/src/server/mcp.server.ts
@@ -966,6 +966,7 @@ function build({ authInfo, requestInfo }: McpRequestContext) {
starts_on: f.startsOn,
ends_on: f.endsOn,
product_id: f.productId,
+ category: f.category,
...Object.fromEntries(
Object.entries(patch).filter(([, v]) => v !== undefined),
),
diff --git a/src/server/onboarding.functions.ts b/src/server/onboarding.functions.ts
index 20d803a..e277f81 100644
--- a/src/server/onboarding.functions.ts
+++ b/src/server/onboarding.functions.ts
@@ -1,5 +1,6 @@
import { createServerFn } from "@tanstack/react-start";
import { z } from "zod";
+import { HEARD_FROM } from "#/lib/app";
import { Day } from "#/lib/costs";
import { CURRENCIES, TimeZone } from "#/lib/format";
import { capture, identifyWorkspaces } from "./analytics.server";
@@ -15,6 +16,8 @@ const Input = z.object({
// The browser's today when "incorporated company" is checked; the Books
// page changes it.
incorporatedOn: Day.nullable().optional(),
+ // Only sent to analytics, not stored.
+ heardFrom: z.enum(HEARD_FROM).optional(),
});
export const createWorkspaceFn = createServerFn({ method: "POST" })
@@ -26,6 +29,7 @@ export const createWorkspaceFn = createServerFn({ method: "POST" })
await capture(user.id, ws.id, "workspace_created", {
currency: data.currency,
plan: ws.plan,
+ heard_from: data.heardFrom,
});
if (isCloud) await identifyWorkspaces(ws.id);
return { id: ws.id };
diff --git a/src/server/ratelimit.server.ts b/src/server/ratelimit.server.ts
index 52290c9..d9257fb 100644
--- a/src/server/ratelimit.server.ts
+++ b/src/server/ratelimit.server.ts
@@ -4,6 +4,9 @@ import { getRequestIP } from "@tanstack/react-start/server";
// - Railway's edge sets X-Real-IP to the client's address, overwriting what
// the client sent, and services behind it can't be reached directly:
// https://docs.railway.com/networking/public-networking/specs-and-limits
+// - CLIENT_IP_HEADER=name: a CDN in front sets this header to the client's
+// address (Cloudflare's CF-Connecting-IP). Only safe when the server
+// accepts traffic from that CDN alone, since anyone else could send it.
// - TRUST_PROXY=N: the instance sits behind N reverse proxies (nginx, Caddy,
// Traefik, a load balancer), each appending the address it saw to
// X-Forwarded-For. The Nth entry from the end is the client; entries
@@ -11,8 +14,13 @@ import { getRequestIP } from "@tanstack/react-start/server";
// - Otherwise the client could send either header, so the socket counts.
const raw = process.env.TRUST_PROXY;
const hops = raw === "true" ? 1 : Math.max(0, Math.floor(Number(raw)) || 0);
+const ipHeader = process.env.CLIENT_IP_HEADER?.trim().toLowerCase();
export function clientIp(request: Request) {
+ if (ipHeader) {
+ const ip = request.headers.get(ipHeader)?.trim();
+ if (ip) return ip;
+ }
if (process.env.RAILWAY_ENVIRONMENT_ID) {
const real = request.headers.get("x-real-ip");
if (real) return real;
diff --git a/src/server/scheduler.ts b/src/server/scheduler.ts
index 4071609..ce34caa 100644
--- a/src/server/scheduler.ts
+++ b/src/server/scheduler.ts
@@ -37,7 +37,7 @@ export function startScheduler() {
);
});
// Hosted, the 3rd of each month: last month's benchmarks, once its last
- // days have synced. `pnpm benchmarks` runs it by hand.
+ // days have synced. `bun run benchmarks` runs it by hand.
const benchmarks = new Cron(
"0 5 3 * *",
{
diff --git a/src/server/seed.server.ts b/src/server/seed.server.ts
index 989cff4..f9f1ce5 100644
--- a/src/server/seed.server.ts
+++ b/src/server/seed.server.ts
@@ -4,7 +4,7 @@ import { splitCents } from "#/connectors/types";
import { type db, schema } from "#/db";
import { encrypt } from "#/lib/crypto";
-// Sample numbers for `pnpm db:seed` and the public demo: two years ending
+// Sample numbers for `bun run db:seed` and the public demo: two years ending
// this month, so charts have a year-earlier line, three products, Stripe for
// revenue, seven cost providers and a few flat costs.
diff --git a/src/server/settings.functions.ts b/src/server/settings.functions.ts
index 248f2c4..e457ab3 100644
--- a/src/server/settings.functions.ts
+++ b/src/server/settings.functions.ts
@@ -7,7 +7,7 @@ import { PLANS } from "#/lib/plans";
import { requireUser } from "./auth.server";
import { isCloud } from "./billing.server";
import { convert } from "./fx.server";
-import { syncConnection } from "./sync.server";
+import { revenueBase, syncConnection } from "./sync.server";
import { currentWorkspace } from "./workspace.server";
export type Settings = {
@@ -117,20 +117,7 @@ export const updateSettings = createServerFn({ method: "POST" })
for (const l of rev) {
await db
.update(schema.revenueLines)
- .set({
- netBaseCents: await convert(
- l.netCents,
- l.currency,
- data.currency,
- l.date,
- ),
- taxBaseCents: await convert(
- l.taxCents,
- l.currency,
- data.currency,
- l.date,
- ),
- })
+ .set(await revenueBase(l, data.currency))
.where(eq(schema.revenueLines.id, l.id));
}
for (const l of cost) {
@@ -148,6 +135,28 @@ export const updateSettings = createServerFn({ method: "POST" })
}
// Flat costs have no date of their own; they convert at today's rate.
const today = new Date().toISOString().slice(0, 10);
+ // A payout still on its way converts at today's rate, as in the sync.
+ const payouts = await db.query.payouts.findMany({
+ where: eq(schema.payouts.workspaceId, ws.id),
+ });
+ for (const p of payouts) {
+ await db
+ .update(schema.payouts)
+ .set({
+ amountBaseCents: await convert(
+ p.amountCents,
+ p.currency,
+ data.currency,
+ p.date < today ? p.date : today,
+ ),
+ })
+ .where(eq(schema.payouts.id, p.id));
+ }
+ // Exported months hold entries in the old currency, so they reopen:
+ // adjustments against them would mix the two.
+ await db
+ .delete(schema.journalExports)
+ .where(eq(schema.journalExports.workspaceId, ws.id));
const flats = await db.query.flatCosts.findMany({
where: eq(schema.flatCosts.workspaceId, ws.id),
});
diff --git a/src/server/sync.server.ts b/src/server/sync.server.ts
index b063d84..8ba44e0 100644
--- a/src/server/sync.server.ts
+++ b/src/server/sync.server.ts
@@ -6,6 +6,7 @@ import {
inArray,
isNotNull,
like,
+ lt,
lte,
ne,
or,
@@ -15,6 +16,7 @@ import { connector, connectors } from "#/connectors";
import {
ConnectorError,
type Credentials,
+ type RevenueLine,
type Snapshot,
type SyncRange,
} from "#/connectors/types";
@@ -23,7 +25,7 @@ import { decrypt } from "#/lib/crypto";
import { evaluateAlerts } from "./alerts.server";
import { captureForWorkspace } from "./analytics.server";
import { isCloud } from "./billing.server";
-import { convert } from "./fx.server";
+import { convert, rateFor } from "./fx.server";
import { traced } from "./observability.server";
type Connection = typeof schema.connections.$inferSelect;
@@ -53,6 +55,32 @@ export function syncRange(
return { from: isoDay(from), to: isoDay(now) };
}
+// A revenue line's base-cents columns, at one rate for its day. The sync
+// and a base currency change both write them through here.
+export async function revenueBase(
+ l: Pick<
+ RevenueLine,
+ | "currency"
+ | "date"
+ | "grossCents"
+ | "feesCents"
+ | "refundsCents"
+ | "netCents"
+ | "taxCents"
+ >,
+ to: string,
+) {
+ const rate = l.currency === to ? 1 : await rateFor(l.date, l.currency, to);
+ const base = (cents = 0) => Math.round(cents * rate);
+ return {
+ netBaseCents: base(l.netCents),
+ grossBaseCents: base(l.grossCents),
+ feesBaseCents: base(l.feesCents),
+ refundsBaseCents: base(l.refundsCents),
+ taxBaseCents: base(l.taxCents),
+ };
+}
+
// Pull one connection. Lines are upserted by external id, so re-running a
// range is safe. `full` rereads the plan's whole history.
export async function syncConnection(
@@ -115,8 +143,6 @@ export async function syncConnection(
if (c.fetchRevenue) {
const lines = await c.fetchRevenue(creds, range);
for (const l of lines) {
- const base = (cents: number) =>
- convert(cents, l.currency, ws.baseCurrency, l.date);
const line = {
productId: productFor(l.subUnitId, l.subUnitLabel),
date: l.date,
@@ -125,12 +151,8 @@ export async function syncConnection(
feesCents: l.feesCents,
refundsCents: l.refundsCents,
netCents: l.netCents,
- netBaseCents: await base(l.netCents),
- grossBaseCents: await base(l.grossCents),
- feesBaseCents: await base(l.feesCents),
- refundsBaseCents: await base(l.refundsCents),
+ ...(await revenueBase(l, ws.baseCurrency)),
taxCents: l.taxCents ?? 0,
- taxBaseCents: await base(l.taxCents ?? 0),
serviceStart: l.serviceStart ?? null,
serviceEnd: l.serviceEnd ?? null,
kind: l.kind,
@@ -160,6 +182,30 @@ export async function syncConnection(
window,
new Set(lines.map((l) => l.externalId)),
);
+ // Lines under the current ids replace legacy ones as far back as the
+ // fetch read, which can start before the range (Polar rereads 21
+ // days of orders).
+ const prefix = c.legacyIds;
+ const oldest = lines.reduce(
+ (a, l) => (l.date < a ? l.date : a),
+ range.from,
+ );
+ if (
+ legacy &&
+ prefix !== undefined &&
+ oldest < range.from &&
+ !lines.some((l) => l.externalId.startsWith(prefix))
+ )
+ await db
+ .delete(schema.revenueLines)
+ .where(
+ and(
+ eq(schema.revenueLines.connectionId, conn.id),
+ like(schema.revenueLines.externalId, `${prefix}%`),
+ gte(schema.revenueLines.date, oldest),
+ lt(schema.revenueLines.date, range.from),
+ ),
+ );
}
if (c.fetchPayouts) {
diff --git a/src/server/tax.server.ts b/src/server/tax.server.ts
index 278faf5..8d61393 100644
--- a/src/server/tax.server.ts
+++ b/src/server/tax.server.ts
@@ -1,13 +1,12 @@
import { eq, min } from "drizzle-orm";
import { db, schema } from "#/db";
-import { type Entry, journal } from "#/lib/books";
+import { type Entry, journal, nextMonth } from "#/lib/books";
import { providerName } from "#/lib/providers";
import {
amounts,
balances,
deMinimisElection,
depreciation,
- type Equipment,
equipmentOf,
type Form,
form1120,
@@ -21,7 +20,7 @@ import {
total,
tp80,
} from "#/lib/tax";
-import { booksInput, yearDepreciation } from "./books.server";
+import { booksInputs, yearDepreciation } from "./books.server";
import type { Workspace } from "./workspace.server";
// The yearly tax report (docs/BOOKS.md "Tax report"): the journal's totals
@@ -63,10 +62,6 @@ const INVOICES: Record = {
supabase: "https://supabase.com/dashboard/org/_/billing#invoices",
};
-const nextMonth = (m: string) => {
- const [y, mo] = m.split("-").map(Number);
- return new Date(Date.UTC(y, mo, 1)).toISOString().slice(0, 7);
-};
const dayBefore = (d: string) =>
new Date(Date.parse(d) - 86_400_000).toISOString().slice(0, 10);
@@ -132,28 +127,29 @@ export async function taxReport(ws: Workspace, year: number) {
currency: ws.baseCurrency,
invoices,
};
- if (!ws.country) return { ...base, parts: [] };
-
const start = `${year}-01-01`;
const end = `${year}-12-31`;
const inc =
ws.incorporatedOn && ws.incorporatedOn <= end ? ws.incorporatedOn : null;
// A company's balance sheet adds up everything since the first month.
- const entries: Entry[] = [];
- let equipment: Equipment[] = [];
+ const months: string[] = [];
for (
let m = inc && first && first < `${year}-01` ? first : `${year}-01`;
m <= `${year}-12`;
m = nextMonth(m)
- ) {
- const input = await booksInput(ws, m);
- if (m === `${year}-12`) equipment = equipmentOf(input.manual);
- entries.push(
- ...journal({ ...input, depreciation: yearDepreciation(ws, input) }),
- );
- }
- const rows = depreciation(ws.country, ws.incorporatedOn, equipment, year);
+ )
+ months.push(m);
+ const inputs = await booksInputs(ws, months);
+ const entries: Entry[] = inputs.flatMap((input) =>
+ journal({ ...input, depreciation: yearDepreciation(ws, input) }),
+ );
+ const rows = depreciation(
+ ws.country,
+ ws.incorporatedOn,
+ equipmentOf(inputs[inputs.length - 1].manual),
+ year,
+ );
const between = (a: string, b: string) =>
entries.filter((e) => e.date >= a && e.date <= b);
diff --git a/src/styles.css b/src/styles.css
index faf6426..095c030 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -244,7 +244,8 @@
& code { font-family: var(--font-mono); font-size: 13px; background: var(--surface-2); padding: 1px 5px; border-radius: 4px; }
& pre { background: var(--surface-1); border: 1px solid var(--line); border-radius: 8px; padding: 14px 16px; overflow-x: auto; margin: 0 0 16px; }
& pre code { background: none; padding: 0; font-size: 13px; }
- & table { width: 100%; border-collapse: collapse; font-size: 13px; margin: 0 0 16px; }
+ & .table-scroll { overflow-x: auto; margin: 0 0 16px; }
+ & table { width: 100%; border-collapse: collapse; font-size: 13px; }
& th { text-align: left; font-weight: 500; color: var(--ink); border-bottom: 1px solid var(--line-strong); padding: 6px 8px 6px 0; }
& td { border-bottom: 1px solid var(--line); padding: 7px 8px 7px 0; vertical-align: top; }
/* Long identifiers in cells (API scopes, ids) wrap instead of widening the page on a phone. */
diff --git a/vite.config.ts b/vite.config.ts
index 44b3214..25b9f93 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -29,6 +29,8 @@ const config = defineConfig({
},
}),
nitro({
+ // TanStack Start hosting guide: the Bun preset serves with Bun.serve.
+ preset: "bun",
// PGlite and resvg (social images) ship wasm next to their JS;
// bundling drops it.
rollupConfig: {