diff --git a/.envrc b/.envrc deleted file mode 100644 index c4b17d79..00000000 --- a/.envrc +++ /dev/null @@ -1 +0,0 @@ -use_flake diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..4d77bf7b --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,3 @@ +* @tale + +/nix @tale @StealthBadger747 diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index e03834de..47610b51 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -28,20 +28,15 @@ jobs: - name: Check out the repo uses: actions/checkout@v4 - - name: Install node.js - uses: actions/setup-node@v4 - with: - node-version: 22 - - - uses: pnpm/action-setup@v4 - name: Install pnpm - with: - run_install: false + - name: Setup Mise + uses: jdx/mise-action@v2 - - name: Get pnpm store directory + - name: Set caching paths shell: bash run: | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + echo "GO_CACHE=$(go env GOCACHE)" >> $GITHUB_ENV + echo "GO_MODCACHE=$(go env GOMODCACHE)" >> $GITHUB_ENV - uses: actions/cache@v4 name: Setup pnpm cache @@ -51,11 +46,16 @@ jobs: restore-keys: | ${{ runner.os }}-pnpm-store- - - name: Install dependencies - run: pnpm install + - name: Setup Go cache + uses: actions/cache@v4 + with: + path: | + ${{ env.GO_CACHE }} + ${{ env.GO_MODCACHE }} + key: ${{ runner.os }}-go-${{ hashFiles('**/go.mod', '**/go.sum') }} - - name: Build - run: pnpm build + - name: CI pipeline + run: mise run ci nix: name: nix diff --git a/.github/workflows/next.yaml b/.github/workflows/next.yaml index f77a1f83..895c34fe 100644 --- a/.github/workflows/next.yaml +++ b/.github/workflows/next.yaml @@ -12,6 +12,8 @@ permissions: actions: write # Allow canceling in-progress runs contents: read # Read access to the repository packages: write # Write access to the container registry + id-token: write # For the attest action to push + attestations: write # For the attest action to push jobs: publish: @@ -19,6 +21,14 @@ jobs: if: ${{ github.event_name == 'workflow_dispatch' || (github.event.pull_request && github.event.pull_request.head.repo.full_name == github.repository && github.event.pull_request.head.ref == 'next') }} name: Docker Pre-release runs-on: ubuntu-latest + strategy: + matrix: + include: + - target: final + tag: 'next' + - target: debug-shell + tag: 'next-shell' + steps: - name: Check out the repo uses: actions/checkout@v4 @@ -29,7 +39,7 @@ jobs: with: images: ghcr.io/${{ github.repository }} tags: | - type=raw,value=next + type=raw,value=${{ matrix.tag }} - name: Set up QEMU uses: docker/setup-qemu-action@v3 @@ -44,12 +54,28 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Build and push Docker image - uses: docker/build-push-action@v5 + - name: Build and publish ghcr.io/${{ github.repository }}:${{ matrix.tag }} + uses: docker/build-push-action@v6 + id: push with: context: . file: ./Dockerfile + target: ${{ matrix.target }} push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} platforms: linux/amd64, linux/arm64 + cache-from: type=gha + cache-to: type=gha,mode=max + build-args: | + IMAGE_TAG=ghcr.io/${{ github.repository }}:${{ matrix.tag }} + secrets: | + gh_token=${{ secrets.GITHUB_TOKEN }} + + - name: Attestation Provenance for ghcr.io/${{ github.repository }}:${{ matrix.tag }} + uses: actions/attest-build-provenance@v2 + id: attest + with: + subject-name: ghcr.io/${{ github.repository }} + subject-digest: ${{ steps.push.outputs.digest }} + push-to-registry: true diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 04bff84e..f4612c8e 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -12,11 +12,21 @@ permissions: actions: write # Allow canceling in-progress runs contents: read # Read access to the repository packages: write # Write access to the container registry + id-token: write # For the attest action to push + attestations: write # For the attest action to push jobs: docker: name: Docker Release runs-on: ubuntu-latest + strategy: + matrix: + include: + - target: final + tag_suffix: '' + - target: debug-shell + tag_suffix: '-shell' + steps: - name: Check out the repo uses: actions/checkout@v4 @@ -28,6 +38,9 @@ jobs: images: ghcr.io/${{ github.repository }} tags: | type=semver,pattern={{version}} + flavor: | + latest=auto + suffix=${{ matrix.tag_suffix }},onlatest=true - name: Set up QEMU uses: docker/setup-qemu-action@v3 @@ -42,12 +55,25 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Build and push Docker image - uses: docker/build-push-action@v5 + - name: Build and push ${{ fromJSON(steps.meta.outputs.json).tags[0] }} + uses: docker/build-push-action@v6 + id: push with: context: . file: ./Dockerfile + target: ${{ matrix.target }} push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} platforms: linux/amd64, linux/arm64 + cache-from: type=gha + cache-to: type=gha,mode=max + build-args: | + IMAGE_TAG=ghcr.io/${{ github.repository }}:${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }} + - name: Attestation Provenance for ${{ fromJSON(steps.meta.outputs.json).tags[0] }} + uses: actions/attest-build-provenance@v2 + id: attest + with: + subject-name: ghcr.io/${{ github.repository }} + subject-digest: ${{ steps.push.outputs.digest }} + push-to-registry: true diff --git a/.gitignore b/.gitignore index 022a1769..f32916b2 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,9 @@ node_modules /build /test .env +app/hp_ssh.wasm +app/wasm_exec.js +/docs/.vitepress/dist/ +/docs/.vitepress/cache/ + +/.direnv diff --git a/.tool-versions b/.tool-versions index e3ec7800..a1e8ca83 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,4 @@ +# REMEMBER TO UPDATE mise.toml TOO pnpm 10.4.0 -node 22 +node 22.16 +go 1.25.1 diff --git a/.zed/settings.json b/.zed/settings.json index fc38e774..aad9e356 100644 --- a/.zed/settings.json +++ b/.zed/settings.json @@ -6,12 +6,20 @@ }, "code_actions_on_format": { "source.fixAll.biome": true, - "source.organizeImports.biome": true + "source.organizeImports.biome": true, + "source.organizeImports": true }, "languages": { "YAML": { "tab_size": 2, "hard_tabs": false + }, + "Go": { + "formatter": { + "language_server": { + "name": "gopls" + } + } } } } diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bd38be4..024ebc06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,32 @@ +### 0.6.1 (Next) +- **Headplane now supports connecting to machines via SSH in the web browser.** + - This is an experimental feature and requires the `integration.agent` section to be set up in the config file. + - This is built on top of a Go binary that runs in WebAssembly, using Xterm.js for the terminal interface. +- Begin using a new SQLite database file in `/var/lib/headplane/hp_persist.db`. + - The database is created automatically if it does not exist. + - It currently stores SSH connection details and HostInfo for the agent. + - User information is automatically migrated from the previous database. +- The docker container now runs in a distroless image (closes [#255](https://github.com/tale/headplane/issues/255)). + - A debug version of the container that runs as root and has a shell is available as `ghcr.io/tale/headplane:-shell`. +- Removing a Split DNS record will no longer make the split domain unresolvable by clients (closes [#231](https://github.com/tale/headplane/issues/231)). +- Reintroduce the toggle for overriding local DNS settings in the Headscale config (closes [#236](https://github.com/tale/headplane/issues/236)). +- Prefer cross-compiling in the Dockerfile to speed up builds while still supporting multiple architectures. +- Add a build attestation to validate SLSA provenance for the Docker image. +- Implement more accurate guessing on the PID with the `/proc` integration (via [#219](https://github.com/tale/headplane/pull/219)). +- Usernames will now correctly fall back to emails if not provided (via [#257](https://github.com/tale/headplane/pull/257)). +- Configuration loading via paths is now supported for sensitive values (via [#283](https://github.com/tale/headplane/pulls/283)) + - Options like `server.cookie_secret_path` can override `server.cookie_secret` + - Environment variables are interpolatable into these paths + - See the full reference in the [docs](https://github.com/tale/headplane/blob/main/docs/Configuration.md#sensitive-values) +- The nix overlay build is fixed for the SSH module (via [#282](https://github.com/tale/headplane/pull/282)) +- Switch our build processes to use TypeScript Go and Rolldown Vite for better build and type-check performance. +- Cookies are now encrypted JWTs, preserving API key secrets (*GHSA-wrqq-v7qw-r5w7*) +- OIDC profile pictures are now available from Gravatar by setting `oidc.profile_picture_source` to `gravatar` (closes [#232](https://github.com/tale/headplane/issues/232)). +- OIDC now allows passing many custom parameters: + - `oidc.authorization_endpoint`, `oidc.token_endpoint`, and `oidc.userinfo_endpoint` can be overridden to support non-standard providers or scenarios without discovery (closes [#117](https://github.com/tale/headplane/issues/117)). + - `oidc.scope` can be set to specify custom scopes (defaults to `openid email profile`). + - `oidc.extra_params` can be set to pass arbitrary query parameters to the authorization endpoint (closes [#197](https://github.com/tale/headplane/issues/197)). + ### 0.6.0 (May 25, 2025) - Headplane 0.6.0 now requires **Headscale 0.26.0** or newer. - Breaking API changes with routes and pre auth keys are now supported (closes [#204](https://github.com/tale/headplane/issues/204)). diff --git a/Caddyfile b/Caddyfile new file mode 100644 index 00000000..a036a72c --- /dev/null +++ b/Caddyfile @@ -0,0 +1,10 @@ +https://localhost { + reverse_proxy headscale:8080 + tls /certs/localhost.pem /certs/localhost-key.pem + + header { + Access-Control-Allow-Origin * + Access-Control-Allow-Headers * + Access-Control-Allow-Methods GET, POST, OPTIONS + } +} diff --git a/Dockerfile b/Dockerfile index 30b76a02..8bcfa666 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,35 +1,63 @@ -FROM golang:1.24 AS agent-build -WORKDIR /app +FROM --platform=$BUILDPLATFORM jdxcode/mise:latest AS mise-context +COPY mise.toml .tool-versions ./ +RUN --mount=type=secret,id=gh_token,env=MISE_GITHUB_TOKEN mise install + +FROM --platform=$BUILDPLATFORM mise-context AS go-build +WORKDIR /build/ COPY go.mod go.sum ./ RUN go mod download -COPY agent/ ./agent -RUN CGO_ENABLED=0 GOOS=linux go build \ - -trimpath \ - -ldflags "-s -w" \ - -o /app/hp_agent ./agent/cmd/hp_agent +COPY cmd/ ./cmd/ +COPY internal/ ./internal/ -FROM node:22-alpine AS build -WORKDIR /app +ARG TARGETOS +ARG TARGETARCH +ARG IMAGE_TAG +RUN mkdir -p /build/app/ && \ + GOOS=$TARGETOS GOARCH=$TARGETARCH CGO_ENABLED=0 IMAGE_TAG=$IMAGE_TAG \ + mise run wasm ::: agent ::: fake-shell -RUN npm install -g pnpm@10 -RUN apk add --no-cache git -COPY package.json pnpm-lock.yaml ./ +RUN chmod +x /build/build/hp_agent +RUN chmod +x /build/build/sh + +FROM --platform=$BUILDPLATFORM mise-context AS js-build +WORKDIR /build COPY patches ./patches +COPY package.json pnpm-lock.yaml ./ RUN pnpm install --frozen-lockfile COPY . . -RUN pnpm run build +RUN mise trust +COPY --from=go-build /build/app/hp_ssh.wasm /build/app/hp_ssh.wasm +COPY --from=go-build /build/app/wasm_exec.js /build/app/wasm_exec.js -FROM node:22-alpine -RUN apk add --no-cache ca-certificates -RUN mkdir -p /var/lib/headplane -RUN mkdir -p /usr/libexec/headplane +ARG IMAGE_TAG +RUN IMAGE_TAG=$IMAGE_TAG pnpm run build RUN mkdir -p /var/lib/headplane/agent +FROM gcr.io/distroless/nodejs22-debian12:latest AS final +COPY --from=js-build /build/build/ /app/build/ +COPY --from=js-build /build/drizzle /app/drizzle/ +COPY --from=js-build /var/lib/headplane /var/lib/headplane +COPY --from=js-build /build/node_modules/ /app/node_modules/ +COPY --from=go-build /build/build/hp_agent /usr/libexec/headplane/agent + +# Fake shell to inform the user that they should use the debug image +COPY --from=go-build /build/build/sh /bin/sh +COPY --from=go-build /build/build/sh /bin/bash + +WORKDIR /app +CMD [ "/app/build/server/index.js" ] + +FROM node:22-alpine AS debug-shell +RUN apk add --no-cache bash curl git + +COPY --from=js-build /build/build/ /app/build/ +COPY --from=js-build /build/drizzle /app/drizzle/ +COPY --from=js-build /var/lib/headplane /var/lib/headplane +COPY --from=js-build /build/node_modules/ /app/node_modules/ +COPY --from=go-build /build/build/hp_agent /usr/libexec/headplane/agent + WORKDIR /app -COPY --from=build /app/build /app/build -COPY --from=agent-build /app/hp_agent /usr/libexec/headplane/agent -RUN chmod +x /usr/libexec/headplane/agent -CMD [ "node", "./build/server/index.js" ] +CMD [ "node", "/app/build/server/index.js" ] diff --git a/README.md b/README.md index 28086f37..01e16c28 100644 --- a/README.md +++ b/README.md @@ -4,15 +4,15 @@ Preview @@ -44,12 +44,12 @@ There are 2 ways to deploy Headplane: Simple mode does not include the automatic management of DNS and Headplane settings, requiring manual editing and reloading when making changes. -### Versioning +## Versioning Headplane uses [semantic versioning](https://semver.org/) for its releases (since v0.6.0). Pre-release builds are available under the `next` tag and get updated when a new release PR is opened and actively in testing. -### Contributing +## Contributing Headplane is an open-source project and contributions are welcome! If you have any suggestions, bug reports, or feature requests, please open an issue. Also refer to the [contributor guidelines](./docs/CONTRIBUTING.md) for more info. @@ -59,30 +59,30 @@ refer to the [contributor guidelines](./docs/CONTRIBUTING.md) for more info. ACLs Machine Management diff --git a/agent/cmd/hp_agent/hp_agent.go b/agent/cmd/hp_agent/hp_agent.go deleted file mode 100644 index 82120595..00000000 --- a/agent/cmd/hp_agent/hp_agent.go +++ /dev/null @@ -1,35 +0,0 @@ -package main - -import ( - _ "github.com/joho/godotenv/autoload" - "github.com/tale/headplane/agent/internal/config" - "github.com/tale/headplane/agent/internal/hpagent" - "github.com/tale/headplane/agent/internal/tsnet" - "github.com/tale/headplane/agent/internal/util" -) - -type Register struct { - Type string - ID string -} - -func main() { - log := util.GetLogger() - cfg, err := config.Load() - if err != nil { - log.Fatal("Failed to load config: %s", err) - } - - log.SetDebug(cfg.Debug) - agent := tsnet.NewAgent(cfg) - - agent.Connect() - defer agent.Shutdown() - - log.Msg(&Register{ - Type: "register", - ID: agent.ID, - }) - - hpagent.FollowMaster(agent) -} diff --git a/agent/internal/hpagent/handler.go b/agent/internal/hpagent/handler.go deleted file mode 100644 index 1228194c..00000000 --- a/agent/internal/hpagent/handler.go +++ /dev/null @@ -1,87 +0,0 @@ -package hpagent - -import ( - "bufio" - "encoding/json" - "os" - "sync" - - "github.com/tale/headplane/agent/internal/tsnet" - "github.com/tale/headplane/agent/internal/util" - "tailscale.com/tailcfg" -) - -// Represents messages from the Headplane master -type RecvMessage struct { - NodeIDs []string -} - -type SendMessage struct { - Type string - Data any -} - -// Starts listening for messages from stdin -func FollowMaster(agent *tsnet.TSAgent) { - log := util.GetLogger() - scanner := bufio.NewScanner(os.Stdin) - - for scanner.Scan() { - line := scanner.Bytes() - - var msg RecvMessage - err := json.Unmarshal(line, &msg) - if err != nil { - log.Error("Unable to unmarshal message: %s", err) - log.Debug("Full Error: %v", err) - continue - } - - log.Debug("Recieved message from master: %v", line) - - if len(msg.NodeIDs) == 0 { - log.Debug("Message recieved had no node IDs") - log.Debug("Full message: %s", line) - continue - } - - // Accumulate the results since we invoke via gofunc - results := make(map[string]*tailcfg.HostinfoView) - mu := sync.Mutex{} - wg := sync.WaitGroup{} - - for _, nodeID := range msg.NodeIDs { - wg.Add(1) - go func(nodeID string) { - defer wg.Done() - result, err := agent.GetStatusForPeer(nodeID) - if err != nil { - log.Error("Unable to get status for node %s: %s", nodeID, err) - return - } - - if result == nil { - log.Debug("No status for node %s", nodeID) - return - } - - mu.Lock() - results[nodeID] = result - mu.Unlock() - }(nodeID) - } - - wg.Wait() - - // Send the results back to the Headplane master - log.Debug("Sending status back to master: %v", results) - log.Msg(&SendMessage{ - Type: "status", - Data: results, - }) - } - - if err := scanner.Err(); err != nil { - log.Fatal("Error reading from stdin: %s", err) - } -} diff --git a/agent/internal/tsnet/peers.go b/agent/internal/tsnet/peers.go deleted file mode 100644 index 9628dca1..00000000 --- a/agent/internal/tsnet/peers.go +++ /dev/null @@ -1,66 +0,0 @@ -package tsnet - -import ( - "context" - "encoding/hex" - "fmt" - "strings" - - "github.com/tale/headplane/agent/internal/util" - "tailscale.com/tailcfg" - "tailscale.com/types/key" - - "go4.org/mem" -) - -// Returns the raw hostinfo for a peer based on node ID. -func (s *TSAgent) GetStatusForPeer(id string) (*tailcfg.HostinfoView, error) { - log := util.GetLogger() - - if !strings.HasPrefix(id, "nodekey:") { - log.Debug("Node ID with missing prefix: %s", id) - return nil, fmt.Errorf("invalid node ID: %s", id) - } - - log.Debug("Querying status of peer: %s", id) - status, err := s.Lc.Status(context.Background()) - if err != nil { - log.Debug("Failed to get status: %s", err) - return nil, fmt.Errorf("failed to get status: %w", err) - } - - // We need to convert from 64 char hex to 32 byte raw. - bytes, err := hex.DecodeString(id[8:]) - if err != nil { - log.Debug("Failed to decode hex: %s", err) - return nil, fmt.Errorf("failed to decode hex: %w", err) - } - - raw := mem.B(bytes) - if raw.Len() != 32 { - log.Debug("Invalid node ID length: %d", raw.Len()) - return nil, fmt.Errorf("invalid node ID length: %d", raw.Len()) - } - - nodeKey := key.NodePublicFromRaw32(raw) - peer := status.Peer[nodeKey] - if peer == nil { - // Check if we are on Self. - if status.Self.PublicKey == nodeKey { - peer = status.Self - } else { - log.Debug("Peer not found in status: %s", id) - return nil, nil - } - } - - ip := peer.TailscaleIPs[0].String() - whois, err := s.Lc.WhoIs(context.Background(), ip) - if err != nil { - log.Debug("Failed to get whois: %s", err) - return nil, fmt.Errorf("failed to get whois: %w", err) - } - - log.Debug("Got whois for peer %s: %v", id, whois) - return &whois.Node.Hostinfo, nil -} diff --git a/app/components/Code.tsx b/app/components/Code.tsx index f9735542..17e8676a 100644 --- a/app/components/Code.tsx +++ b/app/components/Code.tsx @@ -21,7 +21,6 @@ export default function Code({ isCopyable, children, className }: CodeProps) { {children} {isCopyable && ( {oidc ? ( - diff --git a/app/routes/auth/logout.ts b/app/routes/auth/logout.ts index 07130522..e46e7a21 100644 --- a/app/routes/auth/logout.ts +++ b/app/routes/auth/logout.ts @@ -9,9 +9,10 @@ export async function action({ request, context, }: ActionFunctionArgs) { - const session = await context.sessions.auth(request); - if (!session.has('api_key')) { - return redirect('/login'); + try { + await context.sessions.auth(request); + } catch { + redirect('/login'); } // When API key is disabled, we need to explicitly redirect @@ -22,7 +23,7 @@ export async function action({ return redirect(url, { headers: { - 'Set-Cookie': await context.sessions.destroy(session), + 'Set-Cookie': await context.sessions.destroySession(), }, }); } diff --git a/app/routes/auth/oidc-callback.ts b/app/routes/auth/oidc-callback.ts index 342beca6..08c1eed3 100644 --- a/app/routes/auth/oidc-callback.ts +++ b/app/routes/auth/oidc-callback.ts @@ -1,9 +1,21 @@ -import { type LoaderFunctionArgs, Session, redirect } from 'react-router'; +import { createHash } from 'node:crypto'; +import { count, eq } from 'drizzle-orm'; +import { createCookie, type LoaderFunctionArgs, redirect } from 'react-router'; +import { ulid } from 'ulidx'; import type { LoadContext } from '~/server'; -import type { AuthSession, OidcFlowSession } from '~/server/web/sessions'; -import { finishAuthFlow, formatError } from '~/utils/oidc'; +import { HeadplaneConfig } from '~/server/config/schema'; +import { users } from '~/server/db/schema'; +import { Roles } from '~/server/web/roles'; +import { FlowUser, finishAuthFlow, formatError } from '~/utils/oidc'; import { send } from '~/utils/res'; +interface OidcFlowSession { + state: string; + nonce: string; + code_verifier: string; + redirect_uri: string; +} + export async function loader({ request, context, @@ -18,13 +30,21 @@ export async function loader({ return redirect('/login'); } - const session = await context.sessions.getOrCreate(request); - if (session.get('state') !== 'flow') { - return redirect('/login'); // Haven't started an OIDC flow + const cookie = createCookie('__oidc_auth_flow', { + httpOnly: true, + maxAge: 300, // 5 minutes + }); + + const data: OidcFlowSession | null = await cookie.parse( + request.headers.get('Cookie'), + ); + + if (data === null) { + console.warn('OIDC flow session not found'); + return redirect('/login'); } - const payload = session.get('oidc')!; - const { code_verifier, state, nonce, redirect_uri } = payload; + const { code_verifier, state, nonce, redirect_uri } = data; if (!code_verifier || !state || !nonce || !redirect_uri) { return send({ error: 'Missing OIDC state' }, { status: 400 }); } @@ -42,20 +62,39 @@ export async function loader({ }; try { - const user = await finishAuthFlow(context.oidc, flowOptions); - session.unset('oidc'); - const userSession = session as Session; - - // TODO: This is breaking, to stop the "over-generation" of API - // keys because they are currently non-deletable in the headscale - // database. Look at this in the future once we have a solution - // or we have permissioned API keys. - userSession.set('user', user); - userSession.set('api_key', context.config.oidc?.headscale_api_key!); - userSession.set('state', 'auth'); + let user = await finishAuthFlow(context.oidc, flowOptions); + user = { + ...user, + picture: setOidcPictureForSource( + user, + context.config.oidc?.profile_picture_source ?? 'oidc', + ), + }; + + const [{ count: userCount }] = await context.db + .select({ count: count() }) + .from(users) + .where(eq(users.caps, Roles.owner)); + + await context.db + .insert(users) + .values({ + id: ulid(), + sub: user.subject, + caps: userCount === 0 ? Roles.owner : Roles.member, + }) + .onConflictDoNothing(); + return redirect('/machines', { headers: { - 'Set-Cookie': await context.sessions.commit(userSession), + 'Set-Cookie': await context.sessions.createSession({ + // TODO: This is breaking, to stop the "over-generation" of API + // keys because they are currently non-deletable in the headscale + // database. Look at this in the future once we have a solution + // or we have permissioned API keys. + api_key: context.config.oidc?.headscale_api_key!, + user, + }), }, }); } catch (error) { @@ -67,3 +106,26 @@ export async function loader({ }); } } + +type PictureSource = NonNullable< + HeadplaneConfig['oidc'] +>['profile_picture_source']; + +function setOidcPictureForSource(user: FlowUser, source: PictureSource) { + // Already set by default in the callback, so we can just return it + if (source === 'oidc') { + return user.picture; + } + + if (source === 'gravatar') { + if (!user.email) { + return undefined; + } + + const emailHash = user.email.trim().toLowerCase(); + const hash = createHash('sha256').update(emailHash).digest('hex'); + return `https://www.gravatar.com/avatar/${hash}?s=200&d=identicon&r=x`; + } + + return undefined; +} diff --git a/app/routes/auth/oidc-start.ts b/app/routes/auth/oidc-start.ts index 89c6dfbe..0a19fe02 100644 --- a/app/routes/auth/oidc-start.ts +++ b/app/routes/auth/oidc-start.ts @@ -1,42 +1,43 @@ -import { type LoaderFunctionArgs, Session, redirect } from 'react-router'; +import { createCookie, type LoaderFunctionArgs, redirect } from 'react-router'; import type { LoadContext } from '~/server'; -import { AuthSession, OidcFlowSession } from '~/server/web/sessions'; import { beginAuthFlow, getRedirectUri } from '~/utils/oidc'; export async function loader({ request, context, }: LoaderFunctionArgs) { - const session = await context.sessions.getOrCreate(request); - if ((session as Session).has('api_key')) { + try { + await context.sessions.auth(request); return redirect('/machines'); - } + } catch {} - if (!context.oidc) { + if (!context.oidc || !context.config.oidc) { throw new Error('OIDC is not enabled'); } + const cookie = createCookie('__oidc_auth_flow', { + httpOnly: true, + maxAge: 300, // 5 minutes + }); + const redirectUri = context.config.oidc?.redirect_uri ?? getRedirectUri(request); const data = await beginAuthFlow( context.oidc, redirectUri, - // We can't get here without the OIDC config being defined - context.config.oidc!.token_endpoint_auth_method, + context.config.oidc.scope, + context.config.oidc.extra_params, ); - session.set('state', 'flow'); - session.set('oidc', { - state: data.state, - nonce: data.nonce, - code_verifier: data.codeVerifier, - redirect_uri: redirectUri, - }); - return redirect(data.url, { status: 302, headers: { - 'Set-Cookie': await context.sessions.commit(session), + 'Set-Cookie': await cookie.serialize({ + state: data.state, + nonce: data.nonce, + code_verifier: data.codeVerifier, + redirect_uri: redirectUri, + }), }, }); } diff --git a/app/routes/dns/components/manage-ns.tsx b/app/routes/dns/components/manage-ns.tsx index 74a39489..285277f2 100644 --- a/app/routes/dns/components/manage-ns.tsx +++ b/app/routes/dns/components/manage-ns.tsx @@ -1,16 +1,24 @@ -import { Form } from 'react-router'; +import { Info } from 'lucide-react'; +import { Form, useSubmit } from 'react-router'; import Button from '~/components/Button'; import Link from '~/components/Link'; +import Switch from '~/components/Switch'; import TableList from '~/components/TableList'; +import Tooltip from '~/components/Tooltip'; import cn from '~/utils/cn'; import AddNS from '../dialogs/add-ns'; interface Props { nameservers: Record; + overrideLocalDns: boolean; isDisabled: boolean; } -export default function ManageNS({ nameservers, isDisabled }: Props) { +export default function ManageNS({ + nameservers, + isDisabled, + overrideLocalDns, +}: Props) { return (

Nameservers

@@ -31,6 +39,7 @@ export default function ManageNS({ nameservers, isDisabled }: Props) { isGlobal={key === 'global'} isDisabled={isDisabled} nameservers={nameservers} + overrideLocalDns={overrideLocalDns} name={key} /> ))} @@ -45,6 +54,7 @@ interface ListProps { isGlobal: boolean; isDisabled: boolean; nameservers: Record; + overrideLocalDns: boolean; name: string; } @@ -52,6 +62,7 @@ function NameserverList({ isGlobal, isDisabled, nameservers, + overrideLocalDns, name, }: ListProps) { const list = isGlobal ? nameservers.global : nameservers[name]; @@ -59,12 +70,54 @@ function NameserverList({ return null; } + const submit = useSubmit(); return (
-

- {isGlobal ? 'Global Nameservers' : name} -

+ {isGlobal ? ( +
+

+ Global Nameservers +

+
+ + + + When enabled, use the DNS servers listed below to resolve + names outside the tailnet. When disabled (default), devices + will prefer their local DNS configuration. + + Learn More + + + +

Override DNS servers

+ { + submit( + { + action_id: 'override_dns', + override_dns: v ? 'true' : 'false', + }, + { + method: 'POST', + }, + ); + }} + /> +
+
+ ) : ( +

{name}

+ )}
{list.length > 0 diff --git a/app/routes/dns/dialogs/add-ns.tsx b/app/routes/dns/dialogs/add-ns.tsx index 823c4215..65ea3d98 100644 --- a/app/routes/dns/dialogs/add-ns.tsx +++ b/app/routes/dns/dialogs/add-ns.tsx @@ -1,4 +1,4 @@ -import { RepoForkedIcon } from '@primer/octicons-react'; +import { Split } from 'lucide-react'; import { useMemo, useState } from 'react'; import Chip from '~/components/Chip'; import Dialog from '~/components/Dialog'; @@ -35,15 +35,15 @@ export default function AddNameserver({ nameservers }: Props) { Add nameserver Add nameserver - +
@@ -53,9 +53,9 @@ export default function AddNameserver({ nameservers }: Props) { } className={cn('inline-flex items-center')} + leftIcon={} + text="Split DNS" /> Only clients that support split DNS (Tailscale v1.8 or later @@ -76,9 +76,9 @@ export default function AddNameserver({ nameservers }: Props) { Only single-label or fully-qualified queries matching this suffix @@ -86,7 +86,7 @@ export default function AddNameserver({ nameservers }: Props) { ) : ( - + )} diff --git a/app/routes/dns/dns-actions.ts b/app/routes/dns/dns-actions.ts index 654b8ffa..4d0e60e6 100644 --- a/app/routes/dns/dns-actions.ts +++ b/app/routes/dns/dns-actions.ts @@ -42,6 +42,8 @@ export async function dnsAction({ return removeRecord(formData, context); case 'add_record': return addRecord(formData, context); + case 'override_dns': + return overrideDns(formData, context); default: return data({ success: false }, 400); } @@ -104,7 +106,7 @@ async function removeNs(formData: FormData, context: LoadContext) { await context.hs.patch([ { path: `dns.nameservers.split."${splitName}"`, - value: servers, + value: servers.length > 0 ? servers : null, }, ]); } @@ -230,3 +232,20 @@ async function addRecord(formData: FormData, context: LoadContext) { await context.integration?.onConfigChange(context.client); } + +async function overrideDns(formData: FormData, context: LoadContext) { + const override = formData.get('override_dns')?.toString(); + if (!override) { + return data({ success: false }, 400); + } + + const overrideValue = override === 'true'; + await context.hs.patch([ + { + path: 'dns.override_local_dns', + value: overrideValue, + }, + ]); + + await context.integration?.onConfigChange(context.client); +} diff --git a/app/routes/dns/overview.tsx b/app/routes/dns/overview.tsx index a5794e29..5c4c42a3 100644 --- a/app/routes/dns/overview.tsx +++ b/app/routes/dns/overview.tsx @@ -44,6 +44,7 @@ export async function loader({ nameservers: config.dns.nameservers.global, splitDns: config.dns.nameservers.split, searchDomains: config.dns.search_domains, + overrideDns: config.dns.override_local_dns, extraRecords: context.hs.d, }; @@ -84,7 +85,11 @@ export default function Page() { )} - +

- + { @@ -97,7 +97,7 @@ export default function MachineRow({ )} > {ip} - +

))} @@ -131,8 +131,8 @@ export default function MachineRow({ )} >

{node.online && !node.expired @@ -143,10 +143,10 @@ export default function MachineRow({ @@ -177,6 +177,10 @@ export function uiTagsForNode(node: PopulatedNode, isAgent?: boolean) { uiTags.push('subnet-approved'); } + if (node.hostInfo?.sshHostKeys && node.hostInfo?.sshHostKeys.length > 0) { + uiTags.push('tailscale-ssh'); + } + if (isAgent === true) { uiTags.push('headplane-agent'); } @@ -189,27 +193,30 @@ export function mapTagsToComponents(node: PopulatedNode, uiTags: string[]) { switch (tag) { case 'exit-approved': case 'exit-waiting': - return ; + return ; case 'subnet-approved': case 'subnet-waiting': - return ; + return ; case 'expired': case 'no-expiry': return ( ); + case 'tailscale-ssh': + return ; + case 'headplane-agent': - return ; + return ; default: - return; + return null; } }); } diff --git a/app/routes/machines/components/menu.tsx b/app/routes/machines/components/menu.tsx index 167f92d3..4c7a9cef 100644 --- a/app/routes/machines/components/menu.tsx +++ b/app/routes/machines/components/menu.tsx @@ -1,5 +1,6 @@ -import { Cog, Ellipsis } from 'lucide-react'; +import { Cog, Ellipsis, SquareTerminal } from 'lucide-react'; import { useState } from 'react'; +import Button from '~/components/Button'; import Menu from '~/components/Menu'; import type { User } from '~/types'; import cn from '~/utils/cn'; @@ -10,7 +11,6 @@ import Move from '../dialogs/move'; import Rename from '../dialogs/rename'; import Routes from '../dialogs/routes'; import Tags from '../dialogs/tags'; - interface MenuProps { node: PopulatedNode; users: User[]; @@ -29,8 +29,11 @@ export default function MachineMenu({ isDisabled, }: MenuProps) { const [modal, setModal] = useState(null); + const supportsTailscaleSSH = + node.hostInfo?.sshHostKeys && node.hostInfo?.sshHostKeys.length > 0; + return ( - <> +

{modal === 'remove' && ( )} + {supportsTailscaleSSH ? ( + isFullButton ? ( + + ) : ( + + ) + ) : undefined} {isFullButton ? ( @@ -126,6 +172,6 @@ export default function MachineMenu({ - +
); } diff --git a/app/routes/machines/dialogs/expire.tsx b/app/routes/machines/dialogs/expire.tsx index 12f78b79..5c0863b3 100644 --- a/app/routes/machines/dialogs/expire.tsx +++ b/app/routes/machines/dialogs/expire.tsx @@ -16,8 +16,8 @@ export default function Expire({ machine, isOpen, setIsOpen }: ExpireProps) { This will disconnect the machine from your Tailnet. In order to reconnect, you will need to re-authenticate from the device. - - + + ); diff --git a/app/routes/machines/machine-actions.ts b/app/routes/machines/machine-actions.ts index d613cfb1..791cb68c 100644 --- a/app/routes/machines/machine-actions.ts +++ b/app/routes/machines/machine-actions.ts @@ -14,7 +14,7 @@ export async function machineAction({ ); const formData = await request.formData(); - const apiKey = session.get('api_key')!; + const apiKey = session.api_key; const action = formData.get('action_id')?.toString(); if (!action) { @@ -55,7 +55,7 @@ export async function machineAction({ } if ( - node.user.providerId?.split('/').pop() !== session.get('user')!.subject && + node.user.providerId?.split('/').pop() !== session.user.subject && !check ) { throw data('You do not have permission to act on this machine', { diff --git a/app/routes/machines/machine.tsx b/app/routes/machines/machine.tsx index 051794f2..2a8dc7d5 100644 --- a/app/routes/machines/machine.tsx +++ b/app/routes/machines/machine.tsx @@ -2,7 +2,6 @@ import { CheckCircle, CircleSlash, Info, UserCircle } from 'lucide-react'; import { useMemo, useState } from 'react'; import type { ActionFunctionArgs, LoaderFunctionArgs } from 'react-router'; import { Link as RemixLink, useLoaderData } from 'react-router'; -import { mapTag } from 'yaml/util'; import Attribute from '~/components/Attribute'; import Button from '~/components/Button'; import Card from '~/components/Card'; @@ -40,9 +39,9 @@ export async function loader({ const [machine, { users }] = await Promise.all([ context.client.get<{ node: Machine }>( `v1/node/${params.id}`, - session.get('api_key')!, + session.api_key, ), - context.client.get<{ users: User[] }>('v1/user', session.get('api_key')!), + context.client.get<{ users: User[] }>('v1/user', session.api_key), ]); const lookup = await context.agents?.lookup([machine.node.nodeKey]); @@ -78,7 +77,7 @@ export default function Page() { return (

- + All Machines / @@ -92,9 +91,9 @@ export default function Page() { >

{node.givenName}

- + - +
@@ -109,7 +108,10 @@ export default function Page() {
- {node.user.name || node.user.displayName || node.user.email || node.user.id} + {node.user.name || + node.user.displayName || + node.user.email || + node.user.id}
@@ -124,14 +126,14 @@ export default function Page() {
- +

Subnets & Routing

Subnets let you expose physical network routes onto Tailscale.{' '} Learn More @@ -139,11 +141,11 @@ export default function Page() {

@@ -167,11 +169,11 @@ export default function Page() { )}
@@ -199,11 +201,11 @@ export default function Page() { )}
@@ -234,11 +236,11 @@ export default function Page() { )}
@@ -250,15 +252,23 @@ export default function Page() { issues.

- + {stats ? ( @@ -268,14 +278,14 @@ export default function Page() { ) : undefined} {magic ? ( ) : undefined} @@ -342,13 +352,13 @@ export default function Page() { Client Connectivity

) { const session = await context.sessions.auth(request); - const user = session.get('user'); + const user = session.user; if (!user) { throw new Error('Missing user session. Please log in again.'); } @@ -41,11 +41,8 @@ export async function loader({ ); const [{ nodes }, { users }] = await Promise.all([ - context.client.get<{ nodes: Machine[] }>( - 'v1/node', - session.get('api_key')!, - ), - context.client.get<{ users: User[] }>('v1/user', session.get('api_key')!), + context.client.get<{ nodes: Machine[] }>('v1/node', session.api_key), + context.client.get<{ users: User[] }>('v1/user', session.api_key), ]); let magic: string | undefined; @@ -90,18 +87,18 @@ export default function Page() {

Manage the devices connected to your Tailnet.{' '} Learn more

@@ -113,7 +110,7 @@ export default function Page() {

Addresses

{data.magic ? ( - + Since MagicDNS is enabled, you can access devices based on their name and also at{' '} @@ -141,16 +138,16 @@ export default function Page() { > {data.populatedNodes.map((machine) => ( ))} diff --git a/app/routes/settings/auth-keys/actions.ts b/app/routes/settings/auth-keys/actions.ts index cdb4517f..e503bc62 100644 --- a/app/routes/settings/auth-keys/actions.ts +++ b/app/routes/settings/auth-keys/actions.ts @@ -20,7 +20,7 @@ export async function authKeysAction({ } const formData = await request.formData(); - const apiKey = session.get('api_key')!; + const apiKey = session.api_key; const action = formData.get('action_id')?.toString(); if (!action) { throw data('Missing `action_id` in the form data.', { diff --git a/app/routes/settings/auth-keys/auth-key-row.tsx b/app/routes/settings/auth-keys/auth-key-row.tsx index 76f422d3..ce4d7d40 100644 --- a/app/routes/settings/auth-keys/auth-key-row.tsx +++ b/app/routes/settings/auth-keys/auth-key-row.tsx @@ -17,8 +17,12 @@ export default function AuthKeyRow({ authKey, user, url }: Props) { return (
- - + + @@ -30,13 +34,12 @@ export default function AuthKeyRow({ authKey, user, url }: Props) { tailscale up --login-server={url} --authkey {authKey.key} -
+
{(authKey.used && !authKey.reusable) || new Date(authKey.expiration) < new Date() ? undefined : ( )} diff --git a/app/routes/settings/auth-keys/overview.tsx b/app/routes/settings/auth-keys/overview.tsx index 3658147c..408b246d 100644 --- a/app/routes/settings/auth-keys/overview.tsx +++ b/app/routes/settings/auth-keys/overview.tsx @@ -1,8 +1,7 @@ import { FileKey2 } from 'lucide-react'; import { useMemo, useState } from 'react'; import type { ActionFunctionArgs, LoaderFunctionArgs } from 'react-router'; -import { useLoaderData } from 'react-router'; -import { Link as RemixLink } from 'react-router'; +import { Link as RemixLink, useLoaderData } from 'react-router'; import Code from '~/components/Code'; import Link from '~/components/Link'; import Notice from '~/components/Notice'; @@ -23,7 +22,7 @@ export async function loader({ const session = await context.sessions.auth(request); const { users } = await context.client.get<{ users: User[] }>( 'v1/user', - session.get('api_key')!, + session.api_key, ); const preAuthKeys = await Promise.all( @@ -36,7 +35,7 @@ export async function loader({ try { const { preAuthKeys } = await context.client.get<{ preAuthKeys: PreAuthKey[]; - }>(`v1/preauthkey?${qp.toString()}`, session.get('api_key')!); + }>(`v1/preauthkey?${qp.toString()}`, session.api_key); return { success: true, user, @@ -139,13 +138,15 @@ export default function Page() { return key.reusable; } + + return false; }); }, [keys, selectedUser, status]); return (

- + Settings / Pre-Auth Keys @@ -176,8 +177,8 @@ export default function Page() { devices to your Tailnet. To learn more about using pre-authentication keys, visit the{' '} Tailscale documentation @@ -185,14 +186,14 @@ export default function Page() {

+ + +
+ ); +} diff --git a/app/routes/ssh/wasm_exec.d.ts b/app/routes/ssh/wasm_exec.d.ts new file mode 100644 index 00000000..25b56fd5 --- /dev/null +++ b/app/routes/ssh/wasm_exec.d.ts @@ -0,0 +1,7 @@ +declare class Go { + importObject: WebAssembly.Imports; + run(instance: WebAssembly.Instance): Promise; + argv?: string[]; + env?: Record; + exit?: (code: number) => void; +} diff --git a/app/routes/ssh/xterm.client.tsx b/app/routes/ssh/xterm.client.tsx new file mode 100644 index 00000000..9e570617 --- /dev/null +++ b/app/routes/ssh/xterm.client.tsx @@ -0,0 +1,226 @@ +import { ClipboardAddon } from '@xterm/addon-clipboard'; +import { FitAddon } from '@xterm/addon-fit'; +import { Unicode11Addon } from '@xterm/addon-unicode11'; +import { WebLinksAddon } from '@xterm/addon-web-links'; +import * as xterm from '@xterm/xterm'; +import { Loader2 } from 'lucide-react'; +import { useEffect, useRef, useState } from 'react'; +import cn from '~/utils/cn'; +import { useLiveData } from '~/utils/live-data'; +import toast from '~/utils/toast'; + +import '@xterm/xterm/css/xterm.css'; + +interface XTermProps { + ipn: TsWasmNet; + username: string; + hostname: string; +} + +// Go's WASM -> JS crosses realms so we might have to normalize the data under +// certain conditions. This also enforces bytes instead of strings being sent. +function normU8(data: unknown) { + if (data instanceof Uint8Array) { + return data; + } + + if (data && typeof data === 'object') { + const any = data as { + buffer?: ArrayBufferLike; + byteOffset?: number; + byteLength?: number; + }; + + if ( + any.buffer instanceof ArrayBuffer && + typeof any.byteLength === 'number' + ) { + return new Uint8Array( + any.buffer.slice( + any.byteOffset ?? 0, + (any.byteOffset ?? 0) + any.byteLength, + ), + ); + } + } + + throw new Error('Data is not a Uint8Array or ArrayBuffer-like object'); +} + +export default function XTerm({ ipn, username, hostname }: XTermProps) { + const { pause } = useLiveData(); + + const genRef = useRef(0); + const termRef = useRef(null); + const roRef = useRef(null); + const inputRef = useRef<(input: Uint8Array) => void>(null); + const sshRef = useRef(null); + const divRef = useRef(null); + + const [isResizing, setIsResizing] = useState(false); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + pause(); + }); + + useEffect(() => { + if (!divRef.current) { + return; + } + + const currentGen = ++genRef.current; + const term = new xterm.Terminal({ + allowProposedApi: true, + cursorBlink: true, + convertEol: true, + fontSize: 14, + }); + + const fit = new FitAddon(); + term.loadAddon(fit); + + term.loadAddon(new Unicode11Addon()); + term.loadAddon(new ClipboardAddon()); + term.loadAddon( + new WebLinksAddon((event, uri) => { + event.view?.open(uri, '_blank', 'noopener noreferrer'); + }), + ); + + term.unicode.activeVersion = '11'; + termRef.current = term; + term.open(divRef.current!); + fit.fit(); + term.focus(); + + const session = ipn.OpenSSH(hostname, username, { + rows: term.rows, + cols: term.cols, + onStdout: (data) => { + if (currentGen !== genRef.current || term !== termRef.current) { + console.warn('Stale terminal instance, ignoring stdout'); + return; + } + + const text = normU8(data); + term.write(text); + }, + onStderr: (data) => { + if (currentGen !== genRef.current || term !== termRef.current) { + console.warn('Stale terminal instance, ignoring stderr'); + return; + } + + const text = normU8(data); + term.write(text); + const str = new TextDecoder().decode(text); + setError(str); + }, + onStdin: (func) => { + inputRef.current = func; + }, + onConnect: () => { + if (currentGen !== genRef.current) { + console.warn('Stale terminal instance, ignoring onConnect'); + return; + } + + setIsLoading(false); + }, + onDisconnect: () => { + if (currentGen !== genRef.current) { + console.warn('Stale terminal instance, ignoring onDisconnect'); + return; + } + + roRef.current?.disconnect(); + term.dispose(); + termRef.current = null; + inputRef.current = null; + sshRef.current = null; + + setIsLoading(false); + }, + }); + + sshRef.current = session; + const enc = new TextEncoder(); + term.onData((data) => { + if (currentGen !== genRef.current) { + console.warn('Stale terminal instance, ignoring onData'); + return; + } + + const bytes = enc.encode(data); + inputRef.current?.(bytes); + }); + + const ro = new ResizeObserver(() => { + if (currentGen !== genRef.current || term !== termRef.current) { + console.warn('Stale terminal instance, ignoring resize'); + return; + } + + setIsResizing(true); + fit.fit(); + sshRef.current?.Resize(term.cols, term.rows); + setTimeout(() => setIsResizing(false), 100); + }); + + roRef.current = ro; + ro.observe(divRef.current!); + + return () => { + ++genRef.current; + roRef.current?.disconnect(); + roRef.current = null; + + sshRef.current?.Close(); + sshRef.current = null; + + term.dispose(); + if (termRef.current === term) { + termRef.current = null; + } + + inputRef.current = null; + }; + }, [ipn, username, hostname]); + + return ( + <> + {isLoading ? ( +
+ +
+ ) : undefined} +
+ {termRef.current && isResizing ? ( +
+ {termRef.current.cols}x{termRef.current.rows} +
+ ) : undefined} + {error !== null ? ( +
+ Failed to connect to SSH session + {error} +
+ ) : undefined} + + ); +} diff --git a/app/routes/users/onboarding-skip.tsx b/app/routes/users/onboarding-skip.tsx index 06a98379..faf72a49 100644 --- a/app/routes/users/onboarding-skip.tsx +++ b/app/routes/users/onboarding-skip.tsx @@ -1,16 +1,23 @@ +import { eq } from 'drizzle-orm'; import { LoaderFunctionArgs, redirect } from 'react-router'; import { LoadContext } from '~/server'; +import { users } from '~/server/db/schema'; export async function loader({ request, context, }: LoaderFunctionArgs) { - const session = await context.sessions.auth(request); - const user = session.get('user'); - if (!user) { + try { + const { user } = await context.sessions.auth(request); + await context.db + .update(users) + .set({ + onboarded: true, + }) + .where(eq(users.sub, user.subject)); + + return redirect('/machines'); + } catch { return redirect('/login'); } - - context.sessions.overrideOnboarding(user.subject, true); - return redirect('/machines'); } diff --git a/app/routes/users/onboarding.tsx b/app/routes/users/onboarding.tsx index 52e4ceed..5f92dfba 100644 --- a/app/routes/users/onboarding.tsx +++ b/app/routes/users/onboarding.tsx @@ -4,12 +4,7 @@ import { GrApple } from 'react-icons/gr'; import { ImFinder } from 'react-icons/im'; import { MdAndroid } from 'react-icons/md'; import { PiTerminalFill, PiWindowsLogoFill } from 'react-icons/pi'; -import { - LoaderFunctionArgs, - NavLink, - redirect, - useLoaderData, -} from 'react-router'; +import { LoaderFunctionArgs, NavLink, useLoaderData } from 'react-router'; import Button from '~/components/Button'; import Card from '~/components/Card'; import Link from '~/components/Link'; @@ -27,10 +22,6 @@ export async function loader({ context, }: LoaderFunctionArgs) { const session = await context.sessions.auth(request); - const user = session.get('user'); - if (!user) { - return redirect('/login'); - } // Try to determine the OS split between Linux, Windows, macOS, iOS, and Android // We need to convert this to a known value to return it to the client so we can @@ -60,11 +51,11 @@ export async function loader({ break; } - let firstMachine: Machine | undefined = undefined; + let firstMachine: Machine | undefined; try { const { nodes } = await context.client.get<{ nodes: Machine[] }>( 'v1/node', - session.get('api_key')!, + session.api_key, ); const node = nodes.find((n) => { @@ -79,12 +70,7 @@ export async function loader({ return false; } - const sessionUser = session.get('user'); - if (!sessionUser) { - return false; - } - - if (subject !== sessionUser.subject) { + if (subject !== session.user.subject) { return false; } @@ -98,7 +84,7 @@ export async function loader({ } return { - user, + user: session.user, osValue, firstMachine, }; @@ -126,7 +112,7 @@ export default function Page() { return (
- + Welcome!
@@ -138,9 +124,9 @@ export default function Page() { - @@ -206,12 +192,12 @@ export default function Page() { } > - @@ -238,12 +224,12 @@ export default function Page() { } > - @@ -261,12 +247,12 @@ export default function Page() { } > - @@ -287,8 +273,8 @@ export default function Page() {

@@ -300,7 +286,7 @@ export default function Page() {

IP Addresses

{firstMachine.ipAddresses.map((ip) => ( -

+

{ip}

))} @@ -308,8 +294,8 @@ export default function Page() {
- - @@ -335,7 +321,7 @@ export default function Page() {
)}
- +
@@ -129,8 +127,8 @@ export default function Page() { .map((user) => ( ))} diff --git a/app/routes/users/user-actions.ts b/app/routes/users/user-actions.ts index 821d1217..1e94a128 100644 --- a/app/routes/users/user-actions.ts +++ b/app/routes/users/user-actions.ts @@ -1,7 +1,6 @@ -import { ActionFunctionArgs, Session, data } from 'react-router'; +import { ActionFunctionArgs, data } from 'react-router'; import type { LoadContext } from '~/server'; import { Capabilities, Roles } from '~/server/web/roles'; -import { AuthSession } from '~/server/web/sessions'; import { User } from '~/types'; import { data400, data403 } from '~/utils/res'; @@ -15,7 +14,7 @@ export async function userAction({ throw data403('You do not have permission to update users'); } - const apiKey = session.get('api_key')!; + const apiKey = session.api_key; const formData = await request.formData(); const action = formData.get('action_id')?.toString(); if (!action) { diff --git a/app/server/README.md b/app/server/README.md index 76d5b9be..ef23e178 100644 --- a/app/server/README.md +++ b/app/server/README.md @@ -7,6 +7,10 @@ many side-effects (in this case, importing a module may run code). ``` server ├── index.ts: Loads everything and starts the web server. +├── agent/ +│ ├── dispatcher.ts: Serializes commands for the agent control fd (stdin). +│ ├── ssh.ts: Manages & multiplexes the active web SSH connections +│ ├── env.ts: Checks the environment variables for custom overrides. ├── config/ │ ├── integration/ │ │ ├── abstract.ts: Defines the abstract class for integrations. diff --git a/app/server/config/integration/proc.ts b/app/server/config/integration/proc.ts index d6ca9b8a..b6772598 100644 --- a/app/server/config/integration/proc.ts +++ b/app/server/config/integration/proc.ts @@ -46,7 +46,7 @@ export default class ProcIntegration extends Integration { return pid; } catch (error) { - log.error('config', 'Failed to read %s: %s', path, error); + log.debug('config', 'Failed to read %s: %s', path, error); } }); diff --git a/app/server/config/loader.ts b/app/server/config/loader.ts index 699479a7..f3deea86 100644 --- a/app/server/config/loader.ts +++ b/app/server/config/loader.ts @@ -1,5 +1,5 @@ -import { constants, access, readFile } from 'node:fs/promises'; -import { env, exit } from 'node:process'; +import { access, constants, readFile } from 'node:fs/promises'; +import { env } from 'node:process'; import { type } from 'arktype'; import { configDotenv } from 'dotenv'; import { parseDocument } from 'yaml'; @@ -11,6 +11,28 @@ import { partialHeadplaneConfig, } from './schema'; +// Custom error for config issues +export class ConfigError extends Error { + constructor(message: string) { + super(message); + this.name = 'ConfigError'; + } +} + +/** + * Interpolate environment variables in a string + * Replaces ${VAR_NAME} patterns with the actual environment variable values + */ +export function interpolateEnvVars(str: string): string { + return str.replace(/\$\{([^}]+)\}/g, (_, varName) => { + const value = env[varName]; + if (value === undefined) { + throw new ConfigError(`Environment variable "${varName}" not found`); + } + return value; + }); +} + // loadConfig is a has a lifetime of the entire application and is // used to load the configuration for Headplane. It is called once. // @@ -18,54 +40,108 @@ import { // But this may not be necessary as a use-case anyways export async function loadConfig({ loadEnv, path }: EnvOverrides) { log.debug('config', 'Loading configuration file: %s', path); - const valid = await validateConfigPath(path); - if (!valid) { - exit(1); - } + await validateConfigPath(path); const data = await loadConfigFile(path); if (!data) { - exit(1); + throw new ConfigError('Failed to load configuration file'); } let config = validateConfig({ ...data, debug: log.debugEnabled }); - if (!config) { - exit(1); - } if (!loadEnv) { log.debug('config', 'Environment variable overrides are disabled'); log.debug('config', 'This also disables the loading of a .env file'); - return config; + const moddedConfig = await loadSecretsFromFiles(config); + log.debug('config', 'Loaded file-based secrets'); + return moddedConfig; } log.info('config', 'Loading a .env file (if available)'); - configDotenv({ override: true }); - config = coalesceEnv(config); - if (!config) { - exit(1); + configDotenv({ override: true, quiet: true }); + const merged = coalesceEnv(config); + if (merged) config = merged; + if (config.headscale && typeof config.headscale.config_path === 'string') { + config.headscale.config_path = interpolateEnvVars( + config.headscale.config_path, + ); } - return config; + const moddedConfig = await loadSecretsFromFiles(config); + log.debug('config', 'Loaded file-based secrets'); + + return moddedConfig; } -export async function hp_loadConfig() { - // // OIDC Related Checks - // if (config.oidc) { - // if (!config.oidc.client_secret && !config.oidc.client_secret_path) { - // log.error('CFGX', 'OIDC configuration is missing a secret, disabling'); - // log.error( - // 'CFGX', - // 'Please specify either `oidc.client_secret` or `oidc.client_secret_path`', - // ); - // } - // if (config.oidc?.strict_validation) { - // const result = await testOidc(config.oidc); - // if (!result) { - // log.error('CFGX', 'OIDC configuration failed validation, disabling'); - // } - // } - // } +/** + * Recursively walks the config object; for any key in the whitelist of secret path keys, + * reads that file and assigns its contents to the corresponding key + * without the suffix, then removes the "_path" property. + */ +const SECRET_PATH_KEYS = [ + 'pre_authkey_path', + 'client_secret_path', + 'headscale_api_key_path', + 'cookie_secret_path', +] as const; + +// For fast set hashing lookups, but we still need the array for typings +const SECRET_PATH_KEY_SET = new Set(SECRET_PATH_KEYS); + +type SecretPathKey = (typeof SECRET_PATH_KEYS)[number]; +type StripPath = S extends `${infer T}_path` ? T : never; +type KeysToPromote = Extract; +type MappedKeys = StripPath>; + +type NonNullablized = Omit | MappedKeys> & { + [K in MappedKeys]-?: string; +}; + +type NestedNonNullablized = T extends readonly (infer U)[] + ? readonly NestedNonNullablized[] + : T extends (infer U)[] + ? NestedNonNullablized[] + : T extends object + ? { + [K in keyof NonNullablized]: NestedNonNullablized< + NonNullablized[K] + >; + } + : T; + +async function loadSecretsFromFiles( + obj: T, +): Promise> { + // Work with a Record so we can mutate/delete properties + const record = obj as Record; + + for (const key of Object.keys(record)) { + const val = record[key]; + + if (val && typeof val === 'object') { + // recurse into nested objects + record[key] = await loadSecretsFromFiles(val); + continue; + } + + if (SECRET_PATH_KEY_SET.has(key) && typeof val === 'string') { + try { + const path = interpolateEnvVars(val); + const content = await readFile(path, 'utf8'); + const secretKey = key.slice(0, -5); // drop '_path' + record[secretKey] = content.trim(); + delete record[key]; + log.debug('config', 'Loaded secret from %s → %s', val, secretKey); + } catch (err) { + if (err instanceof ConfigError) throw err; + log.error('config', 'Failed to read secret file %s: %s', val, err); + throw new ConfigError(`Failed to read secret file ${val}: ${err}`); + } + } + } + + // Cast back to the original T so callers keep their precise type + return record as NestedNonNullablized; } async function validateConfigPath(path: string) { @@ -76,7 +152,9 @@ async function validateConfigPath(path: string) { } catch (error) { log.error('config', 'Unable to read a configuration file at %s', path); log.error('config', '%s', error); - return false; + throw new ConfigError( + `Unable to read configuration file at ${path}: ${error}`, + ); } } @@ -91,7 +169,7 @@ async function loadConfigFile(path: string): Promise { log.error('config', ` - ${error.toString()}`); } - return false; + throw new ConfigError(`Cannot parse configuration file at ${path}`); } if (configYaml.warnings.length > 0) { @@ -109,7 +187,7 @@ async function loadConfigFile(path: string): Promise { } catch (e) { log.error('config', 'Error reading configuration file at %s', path); log.error('config', '%s', e); - return false; + throw new ConfigError(`Error reading configuration file at ${path}: ${e}`); } } @@ -117,14 +195,14 @@ export function validateConfig(config: unknown) { log.debug('config', 'Validating Headplane configuration'); const result = headplaneConfig(config); if (result instanceof type.errors) { - log.error('config', 'Error validating Headplane configuration:'); + const errorMessages = []; for (const [number, error] of result.entries()) { - log.error('config', ` - (${number}): ${error.toString()}`); + const errorMsg = error.toString(); + log.error('config', ` - (${number}): ${errorMsg}`); + errorMessages.push(errorMsg); } - - return; + throw new ConfigError(errorMessages.join('\n')); } - return result; } diff --git a/app/server/config/schema.ts b/app/server/config/schema.ts index ccb17438..7c086296 100644 --- a/app/server/config/schema.ts +++ b/app/server/config/schema.ts @@ -19,8 +19,36 @@ const stringToBool = type('string | boolean').pipe((v) => { const serverConfig = type({ host: 'string.ip', port: type('string | number.integer').pipe((v) => Number(v)), - cookie_secret: '32 <= string <= 32', + data_path: 'string = "/var/lib/headplane/"', + cookie_secret: '(32 <= string <= 32)?', + cookie_secret_path: 'string?', cookie_secure: stringToBool, +}) + .narrow((obj: Record, ctx: any) => { + const hasVal = obj.cookie_secret != null && `${obj.cookie_secret}` !== ''; + const hasPath = + obj.cookie_secret_path != null && obj.cookie_secret_path !== ''; + if (hasVal && hasPath) + return ctx.reject( + `Only one of "cookie_secret" or "cookie_secret_path" may be set.`, + ); + if (!hasVal && !hasPath) + return ctx.reject( + `Either "cookie_secret" or "cookie_secret_path" must be provided for cookie_secret.`, + ); + return true; + }) + .onDeepUndeclaredKey('reject'); + +const partialServerConfig = type({ + host: 'string.ip?', + port: type('string | number.integer') + .pipe((v) => Number(v)) + .optional(), + data_path: 'string = "/var/lib/headplane/"', + cookie_secret: '32 <= string <= 32?', + cookie_secret_path: 'string?', + cookie_secure: stringToBool.optional(), }); const oidcConfig = type({ @@ -33,9 +61,53 @@ const oidcConfig = type({ redirect_uri: 'string.url?', user_storage_file: 'string = "/var/lib/headplane/users.json"', disable_api_key_login: stringToBool, - headscale_api_key: 'string', + headscale_api_key: 'string?', + headscale_api_key_path: 'string?', + profile_picture_source: '"oidc" | "gravatar" = "oidc"', strict_validation: stringToBool.default(true), -}).onDeepUndeclaredKey('reject'); + scope: 'string = "openid email profile"', + extra_params: 'Record?', + authorization_endpoint: 'string.url?', + token_endpoint: 'string.url?', + userinfo_endpoint: 'string.url?', +}) + .narrow((obj: Record, ctx: any) => { + const hasVal = + obj.headscale_api_key != null && `${obj.headscale_api_key}` !== ''; + const hasPath = + obj.headscale_api_key_path != null && obj.headscale_api_key_path !== ''; + if (hasVal && hasPath) + return ctx.reject( + `Only one of "headscale_api_key" or "headscale_api_key_path" may be set.`, + ); + if (!hasVal && !hasPath) + return ctx.reject( + `Either "headscale_api_key" or "headscale_api_key_path" must be provided.`, + ); + return true; + }) + .onDeepUndeclaredKey('reject'); + +const partialOidcConfig = type({ + issuer: 'string.url?', + client_id: 'string?', + client_secret: 'string?', + client_secret_path: 'string?', + token_endpoint_auth_method: + '"client_secret_basic" | "client_secret_post" | "client_secret_jwt"?', + redirect_uri: 'string.url?', + user_storage_file: 'string?', + disable_api_key_login: stringToBool.optional(), + headscale_api_key: 'string?', + headscale_api_key_path: 'string?', + profile_picture_source: '("oidc" | "gravatar")?', + strict_validation: stringToBool.default(true), + scope: 'string?', + extra_params: 'Record?', + authorization_endpoint: 'string.url?', + token_endpoint: 'string.url?', + userinfo_endpoint: 'string.url?', +}); const headscaleConfig = type({ url: type('string.url').pipe((v) => (v.endsWith('/') ? v.slice(0, -1) : v)), @@ -46,25 +118,52 @@ const headscaleConfig = type({ dns_records_path: 'string?', }).onDeepUndeclaredKey('reject'); +const partialHeadscaleConfig = type({ + url: type('string.url') + .pipe((v) => (v.endsWith('/') ? v.slice(0, -1) : v)) + .optional(), + tls_cert_path: 'string?', + public_url: 'string.url?', + config_path: 'string?', + config_strict: stringToBool.optional(), + dns_records_path: 'string?', +}); + const agentConfig = type({ enabled: stringToBool.default(false), host_name: 'string = "headplane-agent"', - pre_authkey: 'string = ""', + pre_authkey: 'string?', + pre_authkey_path: 'string?', cache_ttl: 'number.integer = 180000', cache_path: 'string = "/var/lib/headplane/agent_cache.json"', executable_path: 'string = "/usr/libexec/headplane/agent"', work_dir: 'string = "/var/lib/headplane/agent"', -}); +}) + .narrow((obj: Record, ctx: any) => { + const hasVal = obj.pre_authkey != null && `${obj.pre_authkey}` !== ''; + const hasPath = obj.pre_authkey_path != null && obj.pre_authkey_path !== ''; + if (hasVal && hasPath) + return ctx.reject( + `Only one of "pre_authkey" or "pre_authkey_path" may be set.`, + ); + if (!hasVal && !hasPath) + return ctx.reject( + `Either "pre_authkey" or "pre_authkey_path" must be provided.`, + ); + return true; + }) + .onDeepUndeclaredKey('reject'); const partialAgentConfig = type({ - enabled: stringToBool, - host_name: 'string | undefined', - pre_authkey: 'string | undefined', - cache_ttl: 'number.integer | undefined', - cache_path: 'string | undefined', - executable_path: 'string | undefined', - work_dir: 'string | undefined', -}).partial(); + enabled: stringToBool.default(false), + host_name: 'string = "headplane-agent"', + pre_authkey: 'string?', + pre_authkey_path: 'string?', + cache_ttl: 'number.integer = 180000', + cache_path: 'string = "/var/lib/headplane/agent_cache.json"', + executable_path: 'string = "/usr/libexec/headplane/agent"', + work_dir: 'string = "/var/lib/headplane/agent"', +}); const dockerConfig = type({ enabled: stringToBool, @@ -114,10 +213,10 @@ export const headplaneConfig = type({ export const partialHeadplaneConfig = type({ debug: stringToBool, - server: serverConfig.partial(), - 'oidc?': oidcConfig.partial(), + server: partialServerConfig, + 'oidc?': partialOidcConfig, 'integration?': partialIntegrationConfig, - headscale: headscaleConfig.partial(), + headscale: partialHeadscaleConfig, }).partial(); export type HeadplaneConfig = typeof headplaneConfig.infer; diff --git a/app/server/db/client.server.ts b/app/server/db/client.server.ts new file mode 100644 index 00000000..c364b1d4 --- /dev/null +++ b/app/server/db/client.server.ts @@ -0,0 +1,28 @@ +import { mkdir } from 'node:fs/promises'; +import { dirname, resolve } from 'node:path'; +import { migrate } from 'drizzle-orm/libsql/migrator'; +import { drizzle } from 'drizzle-orm/libsql/sqlite3'; +import log from '~/utils/log'; + +export async function createDbClient(path: string) { + const realPath = resolve(path); + try { + await mkdir(dirname(realPath), { recursive: true }); + } catch (error) { + log.error( + 'server', + 'Failed to create directory for database at %s: %s', + realPath, + error instanceof Error ? error.message : String(error), + ); + throw new Error(`Could not create directory for database at ${realPath}`); + } + + // Turn the path into a URL with the file protocol + const db = drizzle(`file://${realPath}`); + migrate(db, { + migrationsFolder: './drizzle', + }); + + return db; +} diff --git a/app/server/db/pruner.ts b/app/server/db/pruner.ts new file mode 100644 index 00000000..94919577 --- /dev/null +++ b/app/server/db/pruner.ts @@ -0,0 +1,55 @@ +import { eq, isNotNull } from 'drizzle-orm'; +import { LoaderFunctionArgs } from 'react-router'; +import { Machine } from '~/types'; +import log from '~/utils/log'; +import { LoadContext } from '..'; +import { ephemeralNodes } from './schema'; + +export async function pruneEphemeralNodes({ + context, + request, +}: LoaderFunctionArgs) { + const session = await context.sessions.auth(request); + const ephemerals = await context.db + .select() + .from(ephemeralNodes) + .where(isNotNull(ephemeralNodes.node_key)); + + if (ephemerals.length === 0) { + log.debug('api', 'No ephemeral nodes to prune'); + return; + } + + const { nodes } = await context.client.get<{ nodes: Machine[] }>( + 'v1/node', + session.api_key, + ); + + const toPrune = nodes.filter((node) => { + if (node.online) { + return false; + } + + return ephemerals.some((ephemeral) => node.nodeKey === ephemeral.node_key); + }); + + if (toPrune.length === 0) { + log.debug('api', 'No SSH nodes to prune'); + return; + } + + // Delete from the Headscale nodes list and then from the database + const promises = toPrune.map((node) => { + return async () => { + log.debug('api', `Pruning node ${node.name}`); + await context.client.delete(`v1/node/${node.id}`, session.api_key); + + await context.db + .delete(ephemeralNodes) + .where(eq(ephemeralNodes.node_key, node.nodeKey)); + log.debug('api', `Node ${node.name} pruned successfully`); + }; + }); + + await Promise.all(promises.map((p) => p())); +} diff --git a/app/server/db/schema.ts b/app/server/db/schema.ts new file mode 100644 index 00000000..1f24d1f2 --- /dev/null +++ b/app/server/db/schema.ts @@ -0,0 +1,31 @@ +import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'; +import { HostInfo } from '~/types'; + +export const ephemeralNodes = sqliteTable('ephemeral_nodes', { + auth_key: text('auth_key').primaryKey(), + node_key: text('node_key'), +}); + +export type EphemeralNode = typeof ephemeralNodes.$inferSelect; +export type EphemeralNodeInsert = typeof ephemeralNodes.$inferInsert; + +export const hostInfo = sqliteTable('host_info', { + host_id: text('host_id').primaryKey(), + payload: text('payload', { mode: 'json' }).$type(), + updated_at: integer('updated_at', { mode: 'timestamp' }).$default( + () => new Date(), + ), +}); + +export type HostInfoRecord = typeof hostInfo.$inferSelect; +export type HostInfoInsert = typeof hostInfo.$inferInsert; + +export const users = sqliteTable('users', { + id: text('id').primaryKey(), + sub: text('sub').notNull().unique(), + caps: integer('caps').notNull().default(0), + onboarded: integer('onboarded', { mode: 'boolean' }).notNull().default(false), +}); + +export type User = typeof users.$inferSelect; +export type UserInsert = typeof users.$inferInsert; diff --git a/app/server/headscale/config-schema.ts b/app/server/headscale/config-schema.ts index 68b5be2d..1873a13a 100644 --- a/app/server/headscale/config-schema.ts +++ b/app/server/headscale/config-schema.ts @@ -103,6 +103,7 @@ export const headscaleConfig = type({ dns: { magic_dns: goBool.default(true), base_domain: 'string = "headscale.net"', + override_local_dns: goBool.default(false), nameservers: type({ global: type('string[]').default(() => []), split: type('Record').default(() => ({})), diff --git a/app/server/hp-agent.ts b/app/server/hp-agent.ts new file mode 100644 index 00000000..fe9b0591 --- /dev/null +++ b/app/server/hp-agent.ts @@ -0,0 +1,420 @@ +import { ChildProcessWithoutNullStreams, spawn } from 'node:child_process'; +import EventEmitter from 'node:events'; +import { access, constants, mkdir, open } from 'node:fs/promises'; +import { getegid, geteuid } from 'node:process'; +import { createInterface, Interface } from 'node:readline'; +import { inArray } from 'drizzle-orm'; +import { LibSQLDatabase } from 'drizzle-orm/libsql/driver-core'; +import { HostInfo } from '~/types'; +import log from '~/utils/log'; +import { HeadplaneConfig } from './config/schema'; +import { hostInfo } from './db/schema'; + +export async function createHeadplaneAgent( + config: NonNullable['agent'] | undefined, + headscaleUrl: string, + db: LibSQLDatabase, +) { + if (!config?.enabled) { + return; + } + + if (!config.pre_authkey) { + log.error('agent', 'Agent `pre_authkey` is not set'); + log.warn('agent', 'The agent will not run until resolved'); + return; + } + + try { + await access(config.work_dir, constants.R_OK | constants.W_OK); + log.debug('config', 'Using agent work dir at %s', config.work_dir); + } catch (error) { + // Try to create the directory just in case + try { + await mkdir(config.work_dir, { recursive: true }); + log.debug('config', 'Created agent work dir at %s', config.work_dir); + log.info( + 'config', + 'Created missing agent work dir at %s', + config.work_dir, + ); + + return; + } catch (innerError) { + log.error( + 'config', + 'Failed to create agent work dir at %s', + config.work_dir, + ); + log.info( + 'config', + 'Agent work dir not accessible at %s', + config.work_dir, + ); + log.debug('config', 'Error details: %s', error); + log.debug('config', 'Create error details: %s', innerError); + return; + } + } + + try { + const handle = await open(config.cache_path, 'a+'); + log.info('agent', 'Using agent cache file at %s', config.cache_path); + await handle.close(); + } catch (error) { + log.info( + 'agent', + 'Agent cache file not accessible at %s', + config.cache_path, + ); + log.debug('agent', 'Error details: %s', error); + return; + } + + const agent = new HeadplaneAgent({ + ...config, + headscaleUrl, + }); + + agent.on('spawn', () => { + log.info('agent', 'Headplane agent started'); + }); + + agent.on('ready', () => { + log.info('agent', 'Headplane agent is ready and serving queries'); + }); + + agent.on('error', (err) => { + log.warn('agent', 'Headplane agent experienced an error: %s', err.message); + log.debug('agent', 'Error details: %o', err); + }); + + agent.on('exit', ({ code, signal }) => { + log.warn( + 'agent', + 'Headplane agent exited with code %s and signal %s', + code, + signal, + ); + }); + + agent.on('restart', ({ delay, attempt }) => { + log.warn( + 'agent', + 'Headplane agent will restart in %f seconds (attempt %d)', + delay / 1000, + attempt, + ); + }); + + agent.on('stderr', (data) => { + log.error('agent', 'Headplane agent stderr:', data); + }); + + agent.on('info', async ({ id, info }) => { + log.debug('agent', 'Received HostInfo for %s', id); + try { + const parsedInfo = JSON.parse(info) as HostInfo; + await db + .insert(hostInfo) + .values({ + host_id: id, + payload: parsedInfo, + updated_at: new Date(), + }) + .onConflictDoUpdate({ + target: hostInfo.host_id, + set: { + payload: parsedInfo, + updated_at: new Date(), + }, + }); + } catch (error) { + log.error( + 'agent', + 'Failed to parse HostInfo for %s: %s', + id, + error instanceof Error ? error.message : String(error), + ); + return; + } + }); + + agent.start(); + + process.on('SIGTERM', () => agent.shutdown()); + process.on('SIGINT', () => agent.shutdown()); + + return { + agentID: () => agent.agentID(), + lookup: async (nodes: string[]) => { + const results = await db + .select() + .from(hostInfo) + .where(inArray(hostInfo.host_id, nodes)); + + return Object.fromEntries( + results.filter((r) => r.payload).map((r) => [r.host_id, r.payload]), + ) as Record; + }, + }; +} + +type AgentOptions = NonNullable< + NonNullable['agent'] +> & { + headscaleUrl: string; +}; + +interface AgentEvents { + ready: []; + spawn: []; + error: [Error]; + exit: [{ code?: number; signal?: NodeJS.Signals }]; + restart: [{ delay: number; attempt: number }]; + stderr: [string]; + info: [{ id: string; info: string }]; +} + +/** + * A custom class that turns the lifecycle of the agent into an event emitter. + * It has many different responsibilities ensuring that: + * - The agent is spawned with the correct configuration + * - The agent is ready and still running (ping/heartbeat) + * - The agent is restarted on a backoff strategy + */ +class HeadplaneAgent extends EventEmitter { + private child?: ChildProcessWithoutNullStreams; + private readline?: Interface; + + private options: AgentOptions; + + private hbInterval?: NodeJS.Timeout; + private hbDeadline?: NodeJS.Timeout; + private restartTimer?: NodeJS.Timeout; + private isWaitingForAck = false; + private isShuttingDown = false; + private backoffAttempt = 0; + private agentId?: string; + + private BASE_BACKOFF_MS = 1.5 * 1000; // 1.5 seconds + private MAX_BACKOFF_MS = 30 * 1000; // 30 seconds + private PROBE_COOLDOWN_MS = 5 * 60_000; // 5 minutes + private PROBE_ATTEMPT_INTERVAL = 10; // Every 10th attempt + + private HEARTBEAT_INTERVAL_MS = 5 * 1000; // 5 seconds + private HEARTBEAT_TIMEOUT_MS = 3 * 1000; // 3 seconds + + constructor(options: AgentOptions) { + super(); + this.options = options; + } + + agentID() { + return this.agentId; + } + + start() { + this.isShuttingDown = false; + this.spawnInternalChild(); + } + + shutdown() { + this.isShuttingDown = true; + this.agentId = undefined; + + clearTimeout(this.restartTimer); + clearInterval(this.hbInterval); + clearTimeout(this.hbDeadline); + this.isWaitingForAck = false; + + this.send('SHUTDOWN'); + this.child?.kill('SIGTERM'); + this.readline?.close(); + } + + private spawnInternalChild() { + this.child = spawn(this.options.executable_path, { + stdio: ['pipe', 'pipe', 'pipe'], + uid: geteuid?.() ?? undefined, + gid: getegid?.() ?? undefined, + env: { + HOME: process.env.HOME, + HEADPLANE_AGENT_WORK_DIR: this.options.work_dir, + HEADPLANE_AGENT_DEBUG: log.debugEnabled ? 'true' : 'false', + HEADPLANE_AGENT_HOSTNAME: this.options.host_name, + HEADPLANE_AGENT_TS_SERVER: this.options.headscaleUrl, + HEADPLANE_AGENT_TS_AUTHKEY: this.options.pre_authkey, + }, + }); + + this.emit('spawn'); + this.child.on('error', (err) => this.emit('error', err)); + this.child.stderr.on('data', (data) => + this.emit('stderr', data.toString()), + ); + + this.child.on('exit', (code, signal) => { + this.agentId = undefined; + this.emit('exit', { + code: code ?? undefined, + signal: signal ?? undefined, + }); + + this.readline?.close(); + clearInterval(this.hbInterval); + clearTimeout(this.hbDeadline); + this.isWaitingForAck = false; + + if (this.isShuttingDown) { + log.info('agent', 'Child process exited gracefully'); + return; + } + + this.backoffAttempt++; + const delay = this.calculateBackoff(); + this.emit('restart', { delay, attempt: this.backoffAttempt }); + this.restartTimer = setTimeout(() => this.spawnInternalChild(), delay); + }); + + this.readline = createInterface({ input: this.child.stdout }); + this.readline.on('line', (line) => this.readlineHandler(line)); + this.send('START'); + + // Start the heartbeat loop with our custom interval + this.hbInterval = setInterval(() => { + if (!this.child || this.child.killed) return; + + // If we get here, we missed the last PONG response and can die + if (this.isWaitingForAck) { + this.agentId = undefined; + this.emit('error', new Error('Agent heartbeat missed')); + this.child.kill('SIGTERM'); + return; + } + + this.isWaitingForAck = true; + this.send('PING'); + + clearTimeout(this.hbDeadline); + this.hbDeadline = setTimeout(() => { + if (this.isWaitingForAck) { + this.agentId = undefined; + this.emit('error', new Error('Agent heartbeat timeout')); + this.child?.kill('SIGTERM'); + } + }, this.HEARTBEAT_TIMEOUT_MS); + }, this.HEARTBEAT_INTERVAL_MS); + } + + private send(s: string) { + if (!this.child || this.child.killed) return; + const ok = this.child.stdin.write(`${s}\n`); + if (!ok) this.child.stdin.once('drain', () => {}); + } + + /** + * Calculates a backoff time based on the current attempt. + * Supports a randomized jitter to avoid thundering herd problems. + * + * @param min The minimum backoff time in milliseconds. + * @param max The maximum backoff time in milliseconds. + * @returns The calculated backoff time in milliseconds. + */ + private calculateBackoff() { + const attempt = this.backoffAttempt; + if (attempt > 0 && attempt % this.PROBE_ATTEMPT_INTERVAL === 0) { + const jitter = Math.floor(Math.random() * (this.MAX_BACKOFF_MS + 1)); + const sign = Math.random() < 0.5 ? -1 : 1; + + return Math.max(0, this.PROBE_COOLDOWN_MS + jitter * sign); + } + + const cap = Math.min( + this.MAX_BACKOFF_MS, + this.BASE_BACKOFF_MS * 2 ** attempt, + ); + + return Math.floor(Math.random() * (cap + 1)); + } + + /** + * Processes and dispatches the appropriate response based on the message. + * @param line The message to process (piped straight from readline) + */ + private readlineHandler(line: string) { + // When we are ready we force a refresh so that the UI has the most + // up-to-date information and will gracefully handle new info being sent + if (line.startsWith('READY')) { + this.backoffAttempt = 0; + this.send('REFRESH'); + this.emit('ready'); + + const agentId = line.slice(5).trim(); + if (this.agentId && this.agentId !== agentId) { + log.warn( + 'agent', + 'Agent ID changed from %s to %s', + this.agentId, + agentId, + ); + } + + this.agentId = agentId; + return; + } + + if (line.startsWith('PONG')) { + this.isWaitingForAck = false; + clearTimeout(this.hbDeadline); + + const agentId = line.slice(5).trim(); + if (this.agentId && this.agentId !== agentId) { + log.warn( + 'agent', + 'Agent ID changed from %s to %s', + this.agentId, + agentId, + ); + } + + this.agentId = agentId; + return; + } + + if (line.startsWith('HOSTINFO')) { + const data = line.slice(9).trim(); + const [id, ...infoParts] = data.split(' '); + const info = infoParts.join(' '); + this.emit('info', { id, info }); + return; + } + + if (line.startsWith('ERROR')) { + const error = line.slice(6).trim(); + this.emit('error', new Error(error)); + return; + } + + if (line.startsWith('LOG')) { + const logSnippet = line.slice(4).trim(); + const [level, ...messageParts] = logSnippet.split(' '); + const message = messageParts.join(' '); + switch (level) { + case 'INFO': + log.info('agent', message); + break; + case 'WARN': + log.warn('agent', message); + break; + case 'ERROR': + log.error('agent', message); + break; + default: + log.debug('agent', message); + } + + return; + } + } +} diff --git a/app/server/index.ts b/app/server/index.ts index fc3b8b59..257d36de 100644 --- a/app/server/index.ts +++ b/app/server/index.ts @@ -1,14 +1,15 @@ +import { join } from 'node:path'; import { env, versions } from 'node:process'; import { createHonoServer } from 'react-router-hono-server/node'; - import log from '~/utils/log'; import { configureConfig, configureLogger, envVariables } from './config/env'; import { loadIntegration } from './config/integration'; import { loadConfig } from './config/loader'; +import { createDbClient } from './db/client.server'; import { createApiClient } from './headscale/api-client'; import { loadHeadscaleConfig } from './headscale/config-loader'; -import { loadAgentSocket } from './web/agent'; -import { createOidcClient } from './web/oidc'; +import { createHeadplaneAgent } from './hp-agent'; +import { configureOidcAuth } from './web/oidc'; import { createSessionStorage } from './web/sessions'; declare global { @@ -28,6 +29,13 @@ const config = await loadConfig( }), ); +const db = await createDbClient(join(config.server.data_path, 'hp_persist.db')); +const agents = await createHeadplaneAgent( + config.integration?.agent, + config.headscale.url, + db, +); + // We also use this file to load anything needed by the react router code. // These are usually per-request things that we need access to, like the // helper that can issue and revoke cookies. @@ -41,27 +49,27 @@ const appLoadContext = { ), // TODO: Better cookie options in config - sessions: await createSessionStorage( - { - name: '_hp_session', - maxAge: 60 * 60 * 24, // 24 hours + sessions: await createSessionStorage({ + secret: config.server.cookie_secret, + db, + oidcUsersFile: config.oidc?.user_storage_file, + cookie: { + name: '_hp_auth', secure: config.server.cookie_secure, - secrets: [config.server.cookie_secret], + maxAge: 60 * 60 * 24, // 24 hours + // domain: config.server.cookie_domain, }, - config.oidc?.user_storage_file, - ), + }), client: await createApiClient( config.headscale.url, config.headscale.tls_cert_path, ), - agents: await loadAgentSocket( - config.integration?.agent, - config.headscale.url, - ), + agents, integration: await loadIntegration(config.integration), - oidc: config.oidc ? await createOidcClient(config.oidc) : undefined, + oidc: config.oidc ? await configureOidcAuth(config.oidc) : undefined, + db, }; declare module 'react-router' { @@ -72,6 +80,18 @@ export default createHonoServer({ overrideGlobalObjects: true, port: config.server.port, hostname: config.server.host, + beforeAll: async (app) => { + app.use(__PREFIX__, async (c) => { + return c.redirect(`${__PREFIX__}/`); + }); + }, + serveStaticOptions: { + clientAssets: { + // This is part of our monkey-patch for react-router-hono-server + // To see the first part, go to the patches/ directory. + rewriteRequestPath: (path) => path.replace(`${__PREFIX__}`, ''), + }, + }, // Only log in development mode defaultLogger: import.meta.env.DEV, diff --git a/app/server/web/agent.ts b/app/server/web/agent.ts deleted file mode 100644 index 4d446d45..00000000 --- a/app/server/web/agent.ts +++ /dev/null @@ -1,441 +0,0 @@ -import { ChildProcess, spawn } from 'node:child_process'; -import { createHash } from 'node:crypto'; -import { - constants, - access, - mkdir, - open, - readFile, - writeFile, -} from 'node:fs/promises'; -import { exit } from 'node:process'; -import { createInterface } from 'node:readline'; -import { setTimeout } from 'node:timers/promises'; -import { type } from 'arktype'; -import { HostInfo } from '~/types'; -import log from '~/utils/log'; -import type { HeadplaneConfig } from '../config/schema'; - -interface LogResponse { - Level: 'info' | 'debug' | 'error' | 'fatal'; - Message: string; -} - -interface RegisterMessage { - Type: 'register'; - ID: string; -} - -interface StatusMessage { - Type: 'status'; - Data: Record; -} - -interface MessageResponse { - Level: 'msg'; - Message: RegisterMessage | StatusMessage; -} - -type AgentResponse = LogResponse | MessageResponse; - -export async function loadAgentSocket( - config: NonNullable['agent'] | undefined, - headscaleUrl: string, -) { - if (!config?.enabled) { - return; - } - - if (config.pre_authkey.trim().length === 0) { - log.error('agent', 'Agent `pre_authkey` is not set'); - log.warn('agent', 'The agent will not run until resolved'); - return; - } - - try { - await access(config.work_dir, constants.R_OK | constants.W_OK); - log.debug('config', 'Using agent work dir at %s', config.work_dir); - } catch (error) { - // Try to create the directory just in case - try { - await mkdir(config.work_dir, { recursive: true }); - log.debug('config', 'Created agent work dir at %s', config.work_dir); - log.info( - 'config', - 'Created missing agent work dir at %s', - config.work_dir, - ); - - return; - } catch (innerError) { - log.error( - 'config', - 'Failed to create agent work dir at %s', - config.work_dir, - ); - log.info( - 'config', - 'Agent work dir not accessible at %s', - config.work_dir, - ); - log.debug('config', 'Error details: %s', error); - log.debug('config', 'Create error details: %s', innerError); - return; - } - } - - try { - const handle = await open(config.cache_path, 'a+'); - log.info('agent', 'Using agent cache file at %s', config.cache_path); - await handle.close(); - } catch (error) { - log.info( - 'agent', - 'Agent cache file not accessible at %s', - config.cache_path, - ); - log.debug('agent', 'Error details: %s', error); - return; - } - - const cache = new TimedCache(config.cache_ttl, config.cache_path); - return new AgentManager(cache, config, headscaleUrl); -} - -class AgentManager { - private static readonly MAX_RESTARTS = 5; - private restartCounter = 0; - - private cache: TimedCache; - private headscaleUrl: string; - private config: NonNullable< - NonNullable['agent'] - >; - - private spawnProcess: ChildProcess | null; - private agentId: string | null; - - constructor( - cache: TimedCache, - config: NonNullable['agent']>, - headscaleUrl: string, - ) { - this.cache = cache; - this.config = config; - this.headscaleUrl = headscaleUrl; - this.spawnProcess = null; - this.agentId = null; - this.startAgent(); - - process.on('SIGINT', () => { - this.spawnProcess?.kill(); - exit(0); - }); - - process.on('SIGTERM', () => { - this.spawnProcess?.kill(); - exit(0); - }); - } - - /** - * Used by the UI to indicate why the agent is not running. - * Exhaustion requires a manual restart of the agent. - * (Which can be invoked via the UI) - * @returns true if the agent is exhausted - */ - exhausted() { - return this.restartCounter >= AgentManager.MAX_RESTARTS; - } - - /* - * Called by the UI to manually force a restart of the agent. - */ - deExhaust() { - this.restartCounter = 0; - this.startAgent(); - } - - /* - * Stored agent ID for the current process. This is caught by the agent - * when parsing the stdout on agent startup. - */ - agentID() { - return this.agentId; - } - - private startAgent() { - if (this.spawnProcess) { - log.debug('agent', 'Agent already running'); - return; - } - - if (this.exhausted()) { - log.error('agent', 'Agent is exhausted, cannot start'); - return; - } - - // Cannot be detached since we want to follow our process lifecycle - // We also need to be able to send data to the process by using stdin - log.info( - 'agent', - 'Starting agent process (attempt %d)', - this.restartCounter, - ); - this.spawnProcess = spawn(this.config.executable_path, [], { - detached: false, - stdio: ['pipe', 'pipe', 'pipe'], - env: { - HOME: process.env.HOME, - HEADPLANE_EMBEDDED: 'true', - HEADPLANE_AGENT_WORK_DIR: this.config.work_dir, - HEADPLANE_AGENT_DEBUG: log.debugEnabled ? 'true' : 'false', - HEADPLANE_AGENT_HOSTNAME: this.config.host_name, - HEADPLANE_AGENT_TS_SERVER: this.headscaleUrl, - HEADPLANE_AGENT_TS_AUTHKEY: this.config.pre_authkey, - }, - }); - - if (!this.spawnProcess?.pid) { - log.error('agent', 'Failed to start agent process'); - this.restartCounter++; - global.setTimeout(() => this.startAgent(), 1000); - return; - } - - if (this.spawnProcess.stdin === null || this.spawnProcess.stdout === null) { - log.error('agent', 'Failed to connect to agent process'); - this.restartCounter++; - global.setTimeout(() => this.startAgent(), 1000); - return; - } - - const rlStdout = createInterface({ - input: this.spawnProcess.stdout, - crlfDelay: Number.POSITIVE_INFINITY, - }); - - rlStdout.on('line', (line) => { - try { - const parsed = JSON.parse(line) as AgentResponse; - if (parsed.Level === 'msg') { - switch (parsed.Message.Type) { - case 'register': - this.agentId = parsed.Message.ID; - break; - case 'status': - for (const [key, value] of Object.entries(parsed.Message.Data)) { - // Mark the agent as the one that is running - // We store it in the cache so that it shows - // itself later - if (key === this.agentId) { - value.HeadplaneAgent = true; - } - - this.cache.set(key, value); - } - - break; - } - - return; - } - - switch (parsed.Level) { - case 'info': - case 'debug': - case 'error': - log[parsed.Level]('agent', parsed.Message); - break; - case 'fatal': - log.error('agent', parsed.Message); - break; - default: - log.debug('agent', 'Unknown agent response: %s', line); - break; - } - } catch (error) { - log.debug('agent', 'Failed to parse agent response: %s', error); - log.debug('agent', 'Raw data: %s', line); - } - }); - - this.spawnProcess.on('error', (error) => { - log.error('agent', 'Failed to start agent process: %s', error); - this.restartCounter++; - this.spawnProcess = null; - global.setTimeout(() => this.startAgent(), 1000); - }); - - this.spawnProcess.on('exit', (code) => { - log.error('agent', 'Agent process exited with code %d', code ?? -1); - this.restartCounter++; - this.spawnProcess = null; - global.setTimeout(() => this.startAgent(), 1000); - }); - } - - async lookup(nodeIds: string[]) { - const entries = this.cache.toJSON(); - const missing = nodeIds.filter((nodeId) => !entries[nodeId]); - if (missing.length > 0) { - await this.requestData(missing); - } - - return Object.entries(entries).reduce>( - (acc, [key, value]) => { - if (nodeIds.includes(key)) { - acc[key] = value; - } - - return acc; - }, - {}, - ); - } - - // Request data from the internal agent by sending a message to the process - // via stdin. This is a blocking call, so it will wait for the agent to - // respond before returning. - private async requestData(nodeList: string[]) { - if (this.exhausted()) { - return; - } - - // Wait for the process to be spawned, busy waiting is gross - while (this.spawnProcess === null) { - await setTimeout(100); - } - - // Send the request to the agent, without waiting for a response. - // The live data invalidator will re-request the data if it is not - // available in the cache anyways. - const data = JSON.stringify({ NodeIDs: nodeList }); - this.spawnProcess.stdin?.write(`${data}\n`); - } -} - -const diskSchema = type({ - key: 'string', - value: 'unknown', - expires: 'number?', -}).array(); - -// A persistent HashMap with a TTL for each key -class TimedCache { - private _cache = new Map(); - private _timings = new Map(); - - // Default TTL is 1 minute - private defaultTTL: number; - private filePath: string; - private writeLock = false; - - // Last flush ID is essentially a hash of the flush contents - // Prevents unnecessary flushing if nothing has changed - private lastFlushId = ''; - - constructor(defaultTTL: number, filePath: string) { - this.defaultTTL = defaultTTL; - this.filePath = filePath; - - // Load the cache from disk and then queue flushes every 10 seconds - this.load().then(() => { - setInterval(() => this.flush(), 10000); - }); - } - - set(key: string, value: V, ttl: number = this.defaultTTL) { - this._cache.set(key, value); - this._timings.set(key, Date.now() + ttl); - } - - get(key: string) { - const value = this._cache.get(key); - if (!value) { - return; - } - - const expires = this._timings.get(key); - if (!expires || expires < Date.now()) { - this._cache.delete(key); - this._timings.delete(key); - return; - } - - return value; - } - - // Map into a Record without any TTLs - toJSON() { - const result: Record = {}; - for (const [key, value] of this._cache.entries()) { - result[key] = value; - } - - return result; - } - - // WARNING: This function expects that this.filePath is NOT ENOENT - private async load() { - const data = await readFile(this.filePath, 'utf-8'); - const cache = () => { - try { - return JSON.parse(data); - } catch (e) { - return undefined; - } - }; - - const diskData = cache(); - if (diskData === undefined) { - log.error('agent', 'Failed to load cache at %s', this.filePath); - return; - } - - const cacheData = diskSchema(diskData); - if (cacheData instanceof type.errors) { - log.debug('agent', 'Failed to load cache at %s', this.filePath); - log.debug('agent', 'Error details: %s', cacheData.toString()); - - // Skip loading the cache (it should be overwritten soon) - return; - } - - for (const { key, value, expires } of diskData) { - this._cache.set(key, value); - this._timings.set(key, expires); - } - - log.info('agent', 'Loaded cache from %s', this.filePath); - } - - private async flush() { - const data = Array.from(this._cache.entries()).map(([key, value]) => { - return { key, value, expires: this._timings.get(key) }; - }); - - if (data.length === 0) { - return; - } - - // Calculate the hash of the data - const dumpData = JSON.stringify(data); - const sha = createHash('sha256').update(dumpData).digest('hex'); - if (sha === this.lastFlushId) { - return; - } - - // We need to lock the writeLock so that we don't try to write - // to the file while we're already writing to it - while (this.writeLock) { - await setTimeout(100); - } - - this.writeLock = true; - await writeFile(this.filePath, dumpData, 'utf-8'); - log.debug('agent', 'Flushed cache to %s', this.filePath); - this.lastFlushId = sha; - this.writeLock = false; - } -} diff --git a/app/server/web/oidc.ts b/app/server/web/oidc.ts index 7d566bd9..d3b5424f 100644 --- a/app/server/web/oidc.ts +++ b/app/server/web/oidc.ts @@ -1,90 +1,37 @@ -import { readFile } from 'node:fs/promises'; -import * as client from 'openid-client'; +import * as oidc from 'openid-client'; import log from '~/utils/log'; -import type { HeadplaneConfig } from '../config/schema'; +import { HeadplaneConfig } from '../config/schema'; -async function loadClientSecret(path: string) { - // We need to interpolate environment variables into the path - // Path formatting can be like ${ENV_NAME}/path/to/secret - const matches = path.match(/\${(.*?)}/g); - let resolvedPath = path; +export type OidcConfig = NonNullable; - if (matches) { - for (const match of matches) { - const env = match.slice(2, -1); - const value = process.env[env]; - if (!value) { - log.error('config', 'Environment variable %s is not set', env); - return; - } - - log.debug('config', 'Interpolating %s with %s', match, value); - resolvedPath = resolvedPath.replace(match, value); - } - } - - try { - log.debug('config', 'Reading client secret from %s', resolvedPath); - const secret = await readFile(resolvedPath, 'utf-8'); - if (secret.trim().length === 0) { - log.error('config', 'Empty OIDC client secret'); - return; - } - - return secret.trim(); - } catch (error) { - log.error('config', 'Failed to read client secret from %s', path); - log.error('config', 'Error: %s', error); - log.debug('config', 'Error details: %o', error); - } -} - -function clientAuthMethod( - method: string, -): (secret: string) => client.ClientAuth { - switch (method) { - case 'client_secret_post': - return client.ClientSecretPost; +export async function configureOidcAuth(config: OidcConfig) { + log.debug('config', 'Running OIDC discovery for %s', config.issuer); + let clientAuthMethod: oidc.ClientAuth; + switch (config.token_endpoint_auth_method) { case 'client_secret_basic': - return client.ClientSecretBasic; + clientAuthMethod = oidc.ClientSecretBasic(config.client_secret!); + break; + case 'client_secret_post': + clientAuthMethod = oidc.ClientSecretPost(config.client_secret!); + break; case 'client_secret_jwt': - return client.ClientSecretJwt; + clientAuthMethod = oidc.ClientSecretJwt(config.client_secret!); + break; default: throw new Error('Invalid client authentication method'); } -} - -// Loads and configures an OIDC client to support OIDC authentication. -// This runs under the assumption the OIDC configuration exists and is valid. -// If it is invalid, Headplane automatically disables it. -// -// TODO: Support custom endpoints instead of relying on OIDC discovery. -// This will enable us to support servers like GitHub that do not support -// nor advertise a .well-known endpoint. -export async function createOidcClient( - config: NonNullable, -) { - // const secret = await loadClientSecret(oidc); - const secret = config.client_secret_path - ? await loadClientSecret(config.client_secret_path) - : config.client_secret; - if (!secret) { - log.error('config', 'Missing an OIDC client secret'); - return; - } - - log.debug('config', 'Running OIDC discovery for %s', config.issuer); + let oidcClient: oidc.Configuration; try { - const oidc = await client.discovery( + const discovery = await oidc.discovery( new URL(config.issuer), config.client_id, - secret, - clientAuthMethod(config.token_endpoint_auth_method)(secret), + config.client_secret!, // TODO: Fix this config schema + clientAuthMethod, ); - const metadata = oidc.serverMetadata(); - if (!metadata.authorization_endpoint) { + const meta = discovery.serverMetadata(); + if (!meta.authorization_endpoint) { log.error( 'config', 'Issuer discovery did not return `authorization_endpoint`', @@ -93,70 +40,118 @@ export async function createOidcClient( 'config', 'OIDC server does not support authorization code flow', ); + log.error('config', 'You may need to set this manually in the config'); return; } - if (!metadata.token_endpoint) { + if (!meta.token_endpoint) { log.error('config', 'Issuer discovery did not return `token_endpoint`'); - log.error('config', 'OIDC server does not support token exchange'); + log.error( + 'config', + 'OIDC server does not support authorization code flow', + ); + log.error('config', 'You may need to set this manually in the config'); return; } - // If this field is missing, assume the server supports all response types - // and that we can continue safely. - if (metadata.response_types_supported) { - if (!metadata.response_types_supported.includes('code')) { - log.error( - 'config', - 'Issuer discovery `response_types_supported` does not include `code`', - ); - log.error('config', 'OIDC server does not support code flow'); - return; - } + if (!meta.userinfo_endpoint) { + log.error( + 'config', + 'Issuer discovery did not return `userinfo_endpoint`', + ); + log.error('config', 'OIDC server does not support user info endpoint'); + log.error('config', 'You may need to set this manually in the config'); + return; } - if (metadata.token_endpoint_auth_methods_supported) { + if (meta.token_endpoint_auth_methods_supported) { if ( - !metadata.token_endpoint_auth_methods_supported.includes( + !meta.token_endpoint_auth_methods_supported.includes( config.token_endpoint_auth_method, ) ) { log.error( 'config', - 'Issuer discovery `token_endpoint_auth_methods_supported` does not include `%s`', + 'OIDC server does not support client authentication method %s', config.token_endpoint_auth_method, ); log.error( 'config', - 'OIDC server does not support %s', - config.token_endpoint_auth_method, + 'Supported methods: %s', + meta.token_endpoint_auth_methods_supported.join(', '), ); return; } } - if (!metadata.userinfo_endpoint) { + log.debug('config', 'OIDC discovery successful'); + log.debug( + 'config', + 'Authorization endpoint: %s', + meta.authorization_endpoint, + ); + log.debug('config', 'Token endpoint: %s', meta.token_endpoint); + log.debug('config', 'Userinfo endpoint: %s', meta.userinfo_endpoint); + + // Manually construct the endpoints to coalesce with config if needed + oidcClient = new oidc.Configuration( + { + issuer: config.issuer, + authorization_endpoint: + config.authorization_endpoint || meta.authorization_endpoint, + token_endpoint: config.token_endpoint || meta.token_endpoint, + userinfo_endpoint: config.userinfo_endpoint || meta.userinfo_endpoint, + }, + config.client_id, + config.client_secret!, + clientAuthMethod, + ); + } catch (err) { + log.error('config', 'OIDC discovery failed: %s', err); + log.debug('config', 'Error details: %o', err); + log.error( + 'config', + 'This may be an error, or the server may not support discovery', + ); + + if ( + !config.authorization_endpoint || + !config.token_endpoint || + !config.userinfo_endpoint + ) { log.error( 'config', - 'Issuer discovery did not return `userinfo_endpoint`', + 'Endpoints are not fully configured, cannot continue', + ); + log.error( + 'config', + 'You must set authorization_endpoint, token_endpoint and userinfo_endpoint manually in the config or fix the discovery issue', ); - log.error('config', 'OIDC server does not support userinfo endpoint'); return; } - log.debug('config', 'OIDC client created successfully'); - log.info('config', 'Using %s as the OIDC issuer', config.issuer); + oidcClient = new oidc.Configuration( + { + issuer: config.issuer, + authorization_endpoint: config.authorization_endpoint, + token_endpoint: config.token_endpoint, + userinfo_endpoint: config.userinfo_endpoint, + }, + config.client_id, + config.client_secret!, + clientAuthMethod, + ); + + log.debug('config', 'Using manually configured endpoints'); log.debug( 'config', 'Authorization endpoint: %s', - metadata.authorization_endpoint, + config.authorization_endpoint, ); - log.debug('config', 'Token endpoint: %s', metadata.token_endpoint); - log.debug('config', 'Userinfo endpoint: %s', metadata.userinfo_endpoint); - return oidc; - } catch (error) { - log.error('config', 'Failed to discover OIDC issuer'); - log.error('config', 'Error: %s', error); - log.debug('config', 'Error details: %o', error); + log.debug('config', 'Token endpoint: %s', config.token_endpoint); + log.debug('config', 'Userinfo endpoint: %s', config.userinfo_endpoint); } + + log.info('config', 'Successfully configured OIDC authentication'); + return oidcClient; } diff --git a/app/server/web/sessions.ts b/app/server/web/sessions.ts index 164dc338..231b0eb5 100644 --- a/app/server/web/sessions.ts +++ b/app/server/web/sessions.ts @@ -1,13 +1,13 @@ -import { open, readFile } from 'node:fs/promises'; +import { createHash } from 'node:crypto'; +import { open, readFile, rm } from 'node:fs/promises'; import { resolve } from 'node:path'; -import { exit } from 'node:process'; -import { - CookieSerializeOptions, - Session, - SessionStorage, - createCookieSessionStorage, -} from 'react-router'; +import { eq } from 'drizzle-orm'; +import { LibSQLDatabase } from 'drizzle-orm/libsql/driver'; +import { EncryptJWT, jwtDecrypt } from 'jose'; +import { createCookie } from 'react-router'; +import { ulid } from 'ulidx'; import log from '~/utils/log'; +import { users } from '../db/schema'; import { Capabilities, Roles } from './roles'; export interface AuthSession { @@ -22,6 +22,17 @@ export interface AuthSession { }; } +interface JWTSession { + api_key: string; + user: { + subject: string; + name: string; + email?: string; + username?: string; + picture?: string; + }; +} + export interface OidcFlowSession { state: 'flow'; oidc: { @@ -32,264 +43,243 @@ export interface OidcFlowSession { }; } -type JoinedSession = AuthSession | OidcFlowSession; -interface Error { - error: string; -} - -interface CookieOptions { - name: string; - secure: boolean; - maxAge: number; - secrets: string[]; - domain?: string; +interface AuthSessionOptions { + secret: string; + db: LibSQLDatabase; + oidcUsersFile?: string; + cookie: { + name: string; + secure: boolean; + maxAge: number; + domain?: string; + }; } class Sessionizer { - private storage: SessionStorage; - private caps: Record; - private capsPath?: string; - - constructor( - options: CookieOptions, - caps: Record, - capsPath?: string, - ) { - this.caps = caps; - this.capsPath = capsPath; - this.storage = createCookieSessionStorage({ - cookie: { - ...options, - httpOnly: true, - path: __PREFIX__, // Only match on the prefix - sameSite: 'lax', // TODO: Strictify with Domain, - }, - }); + private options: AuthSessionOptions; + + constructor(options: AuthSessionOptions) { + this.options = options; } // This throws on the assumption that auth is already checked correctly // on something that wraps the route calling auth. The top-level routes // that call this are wrapped with try/catch to handle the error. async auth(request: Request) { - const cookie = request.headers.get('cookie'); - const session = await this.storage.getSession(cookie); - const type = session.get('state'); - if (!type) { - throw new Error('Session state not found'); - } + return decodeSession(request, this.options); + } - if (type !== 'auth') { - throw new Error('Session is not authenticated'); - } + async createSession( + payload: JWTSession, + maxAge = this.options.cookie.maxAge, + ) { + // TODO: What the hell is this garbage + return createSession(payload, { + ...this.options, + cookie: { + ...this.options.cookie, + maxAge, + }, + }); + } - return session as Session; + async destroySession() { + return destroySession(this.options); } - roleForSubject(subject: string): keyof typeof Roles | undefined { - const role = this.caps[subject]?.c; - if (!role) { + async roleForSubject( + subject: string, + ): Promise { + const [user] = await this.options.db + .select() + .from(users) + .where(eq(users.sub, subject)) + .limit(1); + + if (!user) { return; } // We need this in string form based on Object.keys of the roles for (const [key, value] of Object.entries(Roles)) { - if (value === role) { + if (value === user.caps) { return key as keyof typeof Roles; } } } - onboardForSubject(subject: string) { - return this.caps[subject]?.oo ?? false; - } - // Given an OR of capabilities, check if the session has the required // capabilities. If not, return false. Can throw since it calls auth() async check(request: Request, capabilities: Capabilities) { const session = await this.auth(request); - const { subject } = session.get('user') ?? {}; - if (!subject) { - return false; - } // This is the subject we set on API key based sessions. API keys // inherently imply admin access so we return true for all checks. - if (subject === 'unknown-non-oauth') { + if (session.user.subject === 'unknown-non-oauth') { return true; } - // If the role does not exist, then this is a new subject that we have - // not seen before. Since this is new, we set access to the lowest - // level by default which is the member role. - // - // This also allows us to avoid configuring preventing sign ups with - // OIDC, since the default sign up logic gives member which does not - // have access to the UI whatsoever. - const role = this.caps[subject]; - if (!role) { - const memberRole = await this.registerSubject(subject); - return (capabilities & memberRole.c) === capabilities; - } + const [user] = await this.options.db + .select() + .from(users) + .where(eq(users.sub, session.user.subject)) + .limit(1); - return (capabilities & role.c) === capabilities; - } - - async checkSubject(subject: string, capabilities: Capabilities) { - // This is the subject we set on API key based sessions. API keys - // inherently imply admin access so we return true for all checks. - if (subject === 'unknown-non-oauth') { - return true; - } - - // If the role does not exist, then this is a new subject that we have - // not seen before. Since this is new, we set access to the lowest - // level by default which is the member role. - // - // This also allows us to avoid configuring preventing sign ups with - // OIDC, since the default sign up logic gives member which does not - // have access to the UI whatsoever. - const role = this.caps[subject]; - if (!role) { - const memberRole = await this.registerSubject(subject); - return (capabilities & memberRole.c) === capabilities; - } - - return (capabilities & role.c) === capabilities; - } - - // This code is very simple, if the user does not exist in the database - // file then we register it with the lowest level of access. If the user - // database is empty, the first user to sign in will be given the owner - // role. - private async registerSubject(subject: string) { - if (this.caps[subject]) { - return this.caps[subject]; - } - - if (Object.keys(this.caps).length === 0) { - log.debug('auth', 'First user registered as owner: %s', subject); - this.caps[subject] = { c: Roles.owner }; - await this.flushUserDatabase(); - return this.caps[subject]; - } - - log.debug('auth', 'New user registered as member: %s', subject); - this.caps[subject] = { c: Roles.member }; - await this.flushUserDatabase(); - return this.caps[subject]; - } - - private async flushUserDatabase() { - if (!this.capsPath) { - return; + if (!user) { + return false; } - const data = Object.entries(this.caps).map(([u, { c, oo }]) => ({ - u, - c, - oo, - })); - try { - const handle = await open(this.capsPath, 'w'); - await handle.write(JSON.stringify(data)); - await handle.close(); - } catch (error) { - log.error('config', 'Error writing user database file: %s', error); - } + return (capabilities & user.caps) === capabilities; } // Updates the capabilities and roles of a subject async reassignSubject(subject: string, role: keyof typeof Roles) { // Check if we are owner - if (this.roleForSubject(subject) === 'owner') { + const subjectRole = await this.roleForSubject(subject); + if (subjectRole === 'owner') { return false; } - this.caps[subject] = { - ...this.caps[subject], // Preserve the existing capabilities if any - c: Roles[role], - }; + await this.options.db + .update(users) + .set({ + caps: Roles[role], + }) + .where(eq(users.sub, subject)); - await this.flushUserDatabase(); return true; } +} - // Overrides the onboarding status for a subject - async overrideOnboarding(subject: string, onboarding: boolean) { - this.caps[subject] = { - ...this.caps[subject], // Preserve the existing capabilities if any - oo: onboarding, - }; - await this.flushUserDatabase(); - } +async function createSession(payload: JWTSession, options: AuthSessionOptions) { + const secret = createHash('sha256').update(options.secret, 'utf8').digest(); + const jwt = await new EncryptJWT({ + ...payload, + }) + .setProtectedHeader({ alg: 'dir', enc: 'A256GCM', typ: 'JWT' }) + .setIssuedAt() + .setExpirationTime('1d') + .setIssuer('urn:tale:headplane') + .setAudience('urn:tale:headplane') + .setJti(ulid()) + .encrypt(secret); + + const cookie = createCookie(options.cookie.name, { + ...options.cookie, + path: __PREFIX__, + }); + + return cookie.serialize(jwt); +} - getOrCreate(request: Request) { - return this.storage.getSession(request.headers.get('cookie')) as Promise< - Session - >; +async function decodeSession(request: Request, options: AuthSessionOptions) { + const cookieHeader = request.headers.get('cookie'); + if (cookieHeader === null) { + throw new Error('No session cookie found'); } - destroy(session: Session) { - return this.storage.destroySession(session); - } + const cookie = createCookie(options.cookie.name, { + ...options.cookie, + path: __PREFIX__, + }); - commit(session: Session, options?: CookieSerializeOptions) { - return this.storage.commitSession(session, options); + const cookieValue = (await cookie.parse(cookieHeader)) as string | null; + if (cookieValue === null) { + throw new Error('Session cookie is empty'); } + + const secret = createHash('sha256').update(options.secret, 'utf8').digest(); + const { payload } = await jwtDecrypt(cookieValue, secret, { + issuer: 'urn:tale:headplane', + audience: 'urn:tale:headplane', + }); + + // Safe since we encode the session directly into the JWT + return payload as unknown as JWTSession; } -export async function createSessionStorage( - options: CookieOptions, - usersPath?: string, -) { - const map: Record< - string, - { - c: number; - oo?: boolean; - } - > = {}; - if (usersPath) { - // We need to load our users from the file (default to empty map) - // We then translate each user into a capability object using the helper - // method defined in the roles.ts file - const data = await loadUserFile(usersPath); - log.debug('config', 'Loaded %d users from database', data.length); - - for (const user of data) { - map[user.u] = { - c: user.c, - oo: user.oo, - }; - } +async function destroySession(options: AuthSessionOptions) { + const cookie = createCookie(options.cookie.name, { + ...options.cookie, + path: __PREFIX__, + }); + + return cookie.serialize('', { + expires: new Date(0), + }); +} + +export async function createSessionStorage(options: AuthSessionOptions) { + if (options.oidcUsersFile) { + await migrateUserDatabase(options.oidcUsersFile, options.db); } - return new Sessionizer(options, map, usersPath); + return new Sessionizer(options); } -async function loadUserFile(path: string) { +async function migrateUserDatabase(path: string, db: LibSQLDatabase) { + log.info('config', 'Migrating old user database from %s', path); const realPath = resolve(path); + log.warn( + 'config', + 'oidc.user_storage_file is deprecated and will be removed in Headplane 0.7.0', + ); + log.warn( + 'config', + 'You can ignore this warning if you do not use OIDC authentication.', + ); + log.warn( + 'config', + 'Data will be automatically migrated to the new SQL database.', + ); + log.warn( + 'config', + 'Refer to server.data_path to ensure this path is mounted correctly is using Docker.', + ); + try { const handle = await open(realPath, 'a+'); - log.info('config', 'Using user database file at %s', realPath); await handle.close(); } catch (error) { - log.info('config', 'User database file not accessible at %s', realPath); + log.warn('config', 'Failed to migrate old user database at %s', realPath); + log.warn( + 'config', + 'This is not an error, but existing users will not be migrated', + ); + log.warn('config', 'Unable to open user database file: %s', error); log.debug('config', 'Error details: %s', error); - exit(1); + return; } + log.info('config', 'Found old user database file at %s', realPath); + log.info('config', 'Migrating user database to the new SQL database'); + + let migratableUsers: { + u: string; + c: number; + oo?: boolean; + }[]; + try { const data = await readFile(realPath, 'utf8'); + if (data.trim().length === 0) { + log.info('config', 'Old user database file is empty, nothing to migrate'); + log.info( + 'config', + 'You SHOULD remove oidc.user_storage_file from your config!', + ); + await rm(realPath, { force: true }); + return; + } + const users = JSON.parse(data.trim()) as { u?: string; c?: number; oo?: boolean; }[]; - // Never trust user input - return users.filter( + migratableUsers = users.filter( (user) => user.u !== undefined && user.c !== undefined, ) as { u: string; @@ -297,8 +287,38 @@ async function loadUserFile(path: string) { oo?: boolean; }[]; } catch (error) { - log.debug('config', 'Error reading user database file: %s', error); - log.debug('config', 'Using empty user database'); - return []; + log.warn('config', 'Error reading old user database file: %s', error); + log.warn('config', 'Not migrating any users'); + return; + } + + if (migratableUsers.length === 0) { + log.info('config', 'No users found in the old database to migrate'); + return; } + + log.info( + 'config', + 'Migrating %d users from the old database', + migratableUsers.length, + ); + + const updated = await db + .insert(users) + .values( + migratableUsers.map((user) => ({ + id: ulid(), + sub: user.u, + caps: user.c, + onboarded: user.oo ?? false, + })), + ) + .onConflictDoNothing({ + target: users.sub, + }) + .returning(); + + log.info('config', 'Migrated %d users successfully', updated.length); + log.info('config', 'Removed old user database file %s', realPath); + await rm(realPath, { force: true }); } diff --git a/app/types/Machine.ts b/app/types/Machine.ts index de9b929c..5d3e27d9 100644 --- a/app/types/Machine.ts +++ b/app/types/Machine.ts @@ -1,3 +1,4 @@ +import type { PreAuthKey } from './PreAuthKey'; import type { User } from './User'; export interface Machine { @@ -12,7 +13,7 @@ export interface Machine { lastSeen: string; expiry: string | null; - preAuthKey?: unknown; // TODO + preAuthKey?: PreAuthKey; createdAt: string; registerMethod: diff --git a/app/utils/oidc.ts b/app/utils/oidc.ts index 788029c7..70e772e2 100644 --- a/app/utils/oidc.ts +++ b/app/utils/oidc.ts @@ -33,22 +33,21 @@ export function getRedirectUri(req: Request) { export async function beginAuthFlow( config: Configuration, redirect_uri: string, - token_endpoint_auth_method: string, + scope: string, + extra_params: Record = {}, ) { const codeVerifier = client.randomPKCECodeVerifier(); const codeChallenge = await client.calculatePKCECodeChallenge(codeVerifier); const params: Record = { + ...extra_params, + scope, redirect_uri, - scope: 'openid profile email', code_challenge: codeChallenge, code_challenge_method: 'S256', - token_endpoint_auth_method, state: client.randomState(), }; - // PKCE is backwards compatible with non-PKCE servers - // so if we don't support it, just set our nonce if (!config.serverMetadata().supportsPKCE()) { params.nonce = client.randomNonce(); } @@ -69,10 +68,18 @@ interface FlowOptions { nonce?: string; } +export interface FlowUser { + subject: string; + name: string; + email: string | undefined; + username: string | undefined; + picture: string | undefined; +} + export async function finishAuthFlow( config: Configuration, options: FlowOptions, -) { +): Promise { const tokens = await client.authorizationCodeGrant( config, new URL(options.redirect_uri), diff --git a/biome.json b/biome.json index 2092cedb..eb8e0d23 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", + "$schema": "https://biomejs.dev/schemas/2.2.0/schema.json", "vcs": { "enabled": false, "clientKind": "git", @@ -7,7 +7,7 @@ }, "files": { "ignoreUnknown": false, - "ignore": [] + "includes": ["**", "!app/wasm_exec.js"] }, "formatter": { "enabled": true, @@ -15,8 +15,13 @@ "lineWidth": 80, "lineEnding": "lf" }, - "organizeImports": { - "enabled": true + "assist": { + "actions": { + "source": { + "organizeImports": "on", + "useSortedAttributes": "on" + } + } }, "linter": { "enabled": true, @@ -28,6 +33,9 @@ }, "correctness": { "useExhaustiveDependencies": "off" + }, + "suspicious": { + "noExplicitAny": "warn" } } }, diff --git a/cmd/fake_sh/fake_sh.go b/cmd/fake_sh/fake_sh.go new file mode 100644 index 00000000..8057a33b --- /dev/null +++ b/cmd/fake_sh/fake_sh.go @@ -0,0 +1,19 @@ +package main + +import ( + "fmt" + "os" +) + +var imageTag string + +func main() { + if imageTag == "" { + os.Exit(1) + } + + fmt.Fprintln(os.Stderr, "Headplane containers do not contain a shell by default.") + fmt.Fprintln(os.Stderr, "If you need a non-production container with a shell and root access use:") + fmt.Fprintf(os.Stderr, "\n%s-shell\n\n", imageTag) + os.Exit(127) +} diff --git a/cmd/hp_agent/hp_agent.go b/cmd/hp_agent/hp_agent.go new file mode 100644 index 00000000..65c6506a --- /dev/null +++ b/cmd/hp_agent/hp_agent.go @@ -0,0 +1,61 @@ +package main + +import ( + "bufio" + "context" + "fmt" + "os" + "strings" + + "github.com/tale/headplane/internal/config" + "github.com/tale/headplane/internal/tsnet" + "github.com/tale/headplane/internal/util" +) + +type Register struct { + Type string + ID string +} + +func main() { + log := util.GetLogger() + cfg, err := config.Load() + if err != nil { + log.Fatal("Failed to load config: %s", err) + } + + log.SetDebug(cfg.Debug) + agent := tsnet.NewAgent(cfg) + defer agent.Shutdown() + + scanner := bufio.NewScanner(os.Stdin) + for scanner.Scan() { + line := scanner.Bytes() + directive := strings.TrimSpace(string(line)) + log.Debug("Received directive: %s", directive) + + switch directive { + case "START": + agent.Connect() + fmt.Printf("READY %s\n", agent.ID) + + case "SHUTDOWN": + agent.Shutdown() + os.Exit(0) + + case "PING": + fmt.Printf("PONG %s\n", agent.ID) + + case "REFRESH": + err := agent.DispatchHostInfo(context.Background()) + if err != nil { + fmt.Printf("ERROR %s\n", err) + } + } + } + + if err := scanner.Err(); err != nil { + fmt.Printf("ERROR %s\n", err) + os.Exit(1) + } +} diff --git a/cmd/hp_ssh/hp_ssh.go b/cmd/hp_ssh/hp_ssh.go new file mode 100644 index 00000000..bee7ce11 --- /dev/null +++ b/cmd/hp_ssh/hp_ssh.go @@ -0,0 +1,108 @@ +//go:build js && wasm + +package main + +import ( + "context" + "log" + "syscall/js" + + "github.com/tale/headplane/internal/hp_ipn" +) + +func main() { + log.Printf("Loading WASM Headplane SSH module") + js.Global().Set("TsWasmNet", js.FuncOf(func(this js.Value, args []js.Value) any { + if len(args) != 2 { + log.Fatal("Usage: TsWasmNet(config, callbacks)") + return nil + } + + options, err := hp_ipn.ParseTsWasmNetOptions(args[0]) + if err != nil { + log.Fatal("Error parsing options:", err) + return nil + } + + callbacks, err := hp_ipn.ParseTsWasmNetCallbacks(args[1]) + if err != nil { + log.Fatal("Error parsing callbacks:", err) + return nil + } + + ipn, err := hp_ipn.NewTsWasmIpn(options, callbacks) + if err != nil { + log.Fatal("Error creating TsWasmIpn:", err) + return nil + } + + return map[string]any{ + "Start": js.FuncOf(func(this js.Value, args []js.Value) any { + ipn.Start(context.Background()) + return nil + }), + "OpenSSH": js.FuncOf(func(this js.Value, args []js.Value) any { + if len(args) != 3 { + log.Fatal("Usage: OpenSSH(host, user, options)") + return nil + } + + hostname := args[0] + if hostname.IsNull() || hostname.IsUndefined() { + log.Fatal("Hostname must be a non-null, non-undefined string") + return nil + } + + if hostname.Type() != js.TypeString { + log.Fatal("Hostname must be a string") + return nil + } + + username := args[1] + if username.IsNull() || username.IsUndefined() { + log.Fatal("Username must be a non-null, non-undefined string") + return nil + } + + if username.Type() != js.TypeString { + log.Fatal("Username must be a string") + return nil + } + + sshOptions, err := hp_ipn.ParseSSHXtermConfig(args[2]) + if err != nil { + log.Fatal("Error parsing SSH options:", err) + return nil + } + + session := ipn.NewSSHSession(hostname.String(), username.String(), sshOptions) + go session.ConnectAndRun() + + return map[string]any{ + "Close": js.FuncOf(func(this js.Value, args []js.Value) any { + return session.Close() != nil + }), + + "Resize": js.FuncOf(func(this js.Value, args []js.Value) any { + if len(args) != 2 { + log.Fatal("Usage: Resize(cols, rows)") + return nil + } + + rows := args[0].Int() + cols := args[1].Int() + if cols <= 0 || rows <= 0 { + log.Fatal("Columns and rows must be positive integers") + return nil + } + + return session.Resize(cols, rows) == nil + }), + } + }), + } + })) + + log.Printf("WASM Headplane SSH module loaded successfully") + <-make(chan bool) +} diff --git a/compose.yaml b/compose.yaml index 439515b2..b20d969c 100644 --- a/compose.yaml +++ b/compose.yaml @@ -7,6 +7,22 @@ networks: name: "headplane-dev" driver: "bridge" services: + caddy: + image: "caddy:2" + container_name: "headplane-caddy" + restart: "unless-stopped" + depends_on: + - "headscale" + networks: + - "headplane-dev" + ports: + - "80:80" + - "443:443" + volumes: + - "./Caddyfile:/etc/caddy/Caddyfile" + - "./test/caddy/data:/data" + - "./test/caddy/config:/config" + - "./test/caddy/certs:/certs" headscale: image: "headscale/headscale:0.26.0-debug" container_name: "headscale" diff --git a/config.example.yaml b/config.example.yaml index 09897b98..9d4b1e60 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -12,6 +12,14 @@ server: # (I recommend this is true in production) cookie_secure: true + # The path to persist Headplane specific data. All data going forward + # is stored in this directory, including the internal database and + # any cache related files. + # + # Data formats prior to 0.6.1 will automatically be migrated. + # PLEASE ensure this directory is mounted if running in Docker. + data_path: "/var/lib/headplane" + # Headscale specific settings to allow Headplane to talk # to Headscale and access deep integration features headscale: @@ -129,6 +137,17 @@ integration: oidc: issuer: "https://accounts.google.com" + # If your OIDC provider does not support discovery (does not have the URL at + # `/.well-known/openid-configuration`), you need to manually set endpoints. + # This also works to override endpoints if you so desire or if your OIDC + # discovery is missing certain endpoints (ie GitHub). + # For some typical providers, see the documentation. + + # authorization_endpoint: "" + # token_endpoint: "" + # userinfo_endpoint: "" + + # The client ID for the OIDC client # For the best experience please ensure this is *identical* to the client_id # you are using for Headscale. A lot of OIDC providers will use different # subjects per user based on the client_id and for this to work correctly @@ -143,6 +162,9 @@ oidc: # with systemd's `LoadCredential` straightforward: # client_secret_path: "${CREDENTIALS_DIRECTORY}/oidc_client_secret" + # Defaults to 'openid email profile' + # scope: "openid email profile" + disable_api_key_login: false token_endpoint_auth_method: "client_secret_post" @@ -159,6 +181,13 @@ oidc: # for your Headplane instance with /admin/oidc/callback redirect_uri: "http://localhost:3000/admin/oidc/callback" - # Stores the users and their permissions for Headplane - # This is a path to a JSON file, default is specified below. - user_storage_file: "/var/lib/headplane/users.json" + # By default profile pictures are pulled from the OIDC provider when + # we go to fetch the userinfo endpoint. Optionally, this can be set to + # "oidc" or "gravatar" as of 0.6.1. + # profile_picture_source: "gravatar" + + # Extra query parameters can be passed to the authorization endpoint + # by setting them here. This is useful for providers that require any kind + # of custom hinting. + # extra_params: + # prompt: "select_account" # Example: force account selection on Google diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts new file mode 100644 index 00000000..15c7bbea --- /dev/null +++ b/docs/.vitepress/config.ts @@ -0,0 +1,43 @@ +import { defineConfig } from 'vitepress'; + +export default defineConfig({ + title: 'Headplane', + description: 'The missing dashboard for Headscale', + ignoreDeadLinks: ['/docs/Integrated-Mode', '/docs/Simple-Mode'], + cleanUrls: true, + themeConfig: { + nav: [ + { text: 'Home', link: '/' }, + { text: 'Sponsor Headplane', link: 'https://github.com/sponsors/tale' }, + ], + sidebar: [ + { + text: 'Chapters', + items: [ + { text: 'Getting Started', link: '/README' }, + { text: 'Configuration', link: '/Configuration' }, + { text: 'Bare-Metal Mode', link: '/Bare-Metal' }, + { text: 'Integrated Mode', link: '/Integrated-Mode' }, + { text: 'Simple Mode', link: '/Simple-Mode' }, + { text: 'Nix', link: '/Nix' }, + { text: 'NixOS', link: '/NixOS-options' }, + { text: 'Security', link: '/SECURITY' }, + { text: 'Contributing', link: '/CONTRIBUTING' }, + { text: 'Changelog', link: '/CHANGELOG' }, + ], + }, + ], + + socialLinks: [ + { icon: 'github', link: 'https://github.com/tale/headplane' }, + ], + + lastUpdated: { + text: 'Updated at', + formatOptions: { + dateStyle: 'full', + timeStyle: 'medium', + }, + }, + }, +}); diff --git a/docs/Bare-Metal.md b/docs/Bare-Metal.md index 4b83bcca..e8a17252 100644 --- a/docs/Bare-Metal.md +++ b/docs/Bare-Metal.md @@ -12,7 +12,7 @@ different needs. Requirements: - Headscale 0.26 or newer (already deployed) -- Node.js 22 LTS or newer +- Node.js **22.16** LTS or newer - [PNPM](https://pnpm.io/installation) 10.x - A finished configuration file (config.yaml) @@ -42,7 +42,7 @@ The structure of this folder is very important and should not be tampered with. ### Integrated Mode Since you are running Headplane in Bare-Metal, you most likely also are running -Headscale in Bare-Metal. Refer to the [**Integrated Mode**](/docs/Integrated-Mode.md) +Headscale in Bare-Metal. Refer to the [**Integrated Mode**](./Integrated-Mode.md) guide for instructions on setting up the integrated mode in Native Linux (/proc). ### Changing the Admin Path @@ -58,7 +58,7 @@ Just keep in mind that the admin path is not configurable at runtime, so you will need to rebuild the project if you want to change it. Also, anything aside from `/admin` is not officially supported and could break in future versions. -> Refer to the [**Configuration**](/docs/Configuration.md) guide for help with +> Refer to the [**Configuration**](./Configuration.md) guide for help with > setting up your `config.yaml` file to the appropriate values. ### Systemd Unit diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md new file mode 120000 index 00000000..81dc0a0d --- /dev/null +++ b/docs/CHANGELOG.md @@ -0,0 +1 @@ +./../CHANGELOG.md \ No newline at end of file diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 539b8d43..947a1a5a 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -45,3 +45,9 @@ before commit to make these changes automatically. > All of these guidelines are fairly simple to follow and are flexible if needed. > I won't automatically close PRs or issues if they don't follow these rules, > but instead we can discuss them and see if we can come to a compromise. + +### Contribution Tooling +If you plan to work with the WASM SSH agent, you will need to install +`mkcert` or an equivalent to create certificates in `./test/caddy/certs`. +It expects a `localhost.pem` and `localhost-key.pem` file to be present in that +directory. PNPM has a script to do it with `pnpm mkcert` already already. diff --git a/docs/Configuration.md b/docs/Configuration.md index 0c3770b1..7d07ac08 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -3,7 +3,7 @@ > Since 0.5, you will need to manually migrate your configuration to the new format. Headplane uses a configuration file to manage its settings -([**config.example.yaml**](../config.example.yaml)). By default, Headplane looks +([**config.example.yaml**](https://github.com/tale/headplane/blob/main/config.example.yaml)). By default, Headplane looks for a the file at `/etc/headplane/config.yaml`. This can be changed using the **`HEADPLANE_CONFIG_PATH`** environment variable to point to a different location. @@ -30,6 +30,53 @@ Setting this also tells Headplane to load the relative `.env` file into the envi > environment variables meaning you cannot specify variables such as > `HEADPLANE_DEBUG_LOG=true` or `HEADPLANE_CONFIG_PATH=/etc/headplane/config.yaml`. +## Sensitive Values +Headplane supports a dual-mode pattern for providing certain sensitive configuration values, such as secrets, keys, and private certificates. For each such field, you can either: + +1. Set the value directly in the configuration file (e.g., `cookie_secret: "your-32-character-long-secret"`) +2. Provide a path to a file containing the value using the `_path` suffixed key (e.g., `cookie_secret_path: "/path/to/your/cookie_secret_file"`) + +When using a `_path` option, the content of the specified file will be read and used as the value for the setting. These paths can include environment variable interpolation (e.g., `${CREDENTIALS_DIRECTORY}/my_secret_file`), which is useful for integration with tools like systemd's `LoadCredential`. + +**Important Rules for Dual-Mode Fields:** +- You **cannot** set both the direct value (e.g., `cookie_secret`) and its corresponding `_path` (e.g., `cookie_secret_path`) simultaneously. Doing so will result in a configuration error. +- If a `_path` is provided, the corresponding direct value field (if also present and not null) will usually be ignored or may cause validation errors depending on the specific field and loader logic. It's best to provide only one. +- The same dual-mode pattern works with environment variables. You can set `HEADPLANE_OIDC__CLIENT_SECRET` for a direct value or `HEADPLANE_OIDC__CLIENT_SECRET_PATH` to specify a path to a file containing the secret. + +**Note on Path Processing:** +Headplane uses a whitelist approach to determine which `_path` fields should have their content loaded as secrets. Only the explicitly whitelisted paths below will have their file content read and used as configuration values. All other paths with a `_path` suffix will have environment variables interpolated but will not have their content loaded. + +The following configuration options in Headplane are treated as secret paths: + +- **Server Settings (`server.*`):** + - `cookie_secret_path` (for web session encoding) + - *Note:* Either `cookie_secret` or `cookie_secret_path` must be provided for web session security. + +- **Headscale Connection Settings (`headscale.*`):** + - `tls_cert_path` (custom TLS certificate for connecting to Headscale) + - *Note:* This is treated as a regular path, not a secret path, so it will not have its content loaded. + +- **Integration Agent Settings (`integration.agent.*`):** + - `pre_authkey_path` (pre-auth key for the Headplane agent to connect to the Tailnet) + - *Note:* Either `pre_authkey` or `pre_authkey_path` must be provided when the agent is enabled. + +- **OIDC Settings (`oidc.*`):** + - `client_secret_path` (OIDC client secret) + - *Note:* Either `client_secret` or `client_secret_path` must be provided for OIDC authentication. + - `headscale_api_key_path` (Headscale API key used by Headplane during the OIDC authentication flow) + - *Note:* Either `headscale_api_key` or `headscale_api_key_path` must be provided for OIDC integration. + +**Distinction for Non-Secret Paths:** +Other configuration fields that end with `_path` are treated as regular paths and will not have their content loaded. For example: +- `server.agent.cache_path` (default: `/var/lib/headplane/agent_cache.json`): This is a direct file path where Headplane will *store* its agent cache data. +- `headscale.config_path`: This is an optional path to Headscale's `config.yaml` file, which Headplane might read or use for validation. + +All path fields (both secret and non-secret) support environment variable interpolation using the `${VAR_NAME}` syntax. + +The path-based secret loading mechanism also works with environment variables. For instance: +- `HEADPLANE_OIDC__CLIENT_SECRET_PATH=/path/to/secret/file` will load the OIDC client secret from the specified file +- `HEADPLANE_SERVER__COOKIE_SECRET_PATH=${CREDENTIALS_DIRECTORY}/cookie_secret` will use environment variable interpolation in the path + ## Debugging To enable debug logging, set the **`HEADPLANE_DEBUG_LOG=true`** environment variable. This will enable all debug logs for Headplane, which could fill up log space very quickly. diff --git a/docs/Integrated-Mode.md b/docs/Integrated-Mode.md index ad7e1ffb..85e57091 100644 --- a/docs/Integrated-Mode.md +++ b/docs/Integrated-Mode.md @@ -3,15 +3,15 @@ Integration Preview @@ -21,7 +21,7 @@ deployment method for most users, as it provides a more feature-complete experience. ## Deployment -> If you are not looking to deploy with Docker, follow the [**Bare-Metal**](/docs/Bare-Metal.md) deployment guide. +> If you are not looking to deploy with Docker, follow the [**Bare-Metal**](./Bare-Metal.md) deployment guide. > Refer to the `Integrated Mode` section at the bottom for caveats. Requirements: @@ -73,7 +73,7 @@ This will result in the Headplane UI being available at the `/admin` path of the server you deployed it on. The `/admin` path is currently not configurable unless you build the container yourself or run Headplane in Bare-Metal mode. -> Refer to the [**Configuration**](/docs/Configuration.md) guide for help with +> Refer to the [**Configuration**](./Configuration.md) guide for help with > setting up your `config.yaml` file to the appropriate values. ## Docker Integration diff --git a/docs/Nix.md b/docs/Nix.md index 12f3c186..12678ad7 100644 --- a/docs/Nix.md +++ b/docs/Nix.md @@ -1,40 +1,56 @@ # Nix -[flake.nix](../flake.nix) provided: -``` -$ nix flake show . --all-systems -git+file:///home/igor/personal/headplane?ref=refs/heads/nix&rev=2d78a95a0648a3778e114fb246ea436e96475d62 -├───devShell -│ ├───aarch64-darwin: development environment 'headplane' -│ ├───x86_64-darwin: development environment 'headplane' -│ └───x86_64-linux: development environment 'headplane' +[flake.nix](https://github.com/tale/headplane/blob/main/flake.nix) provided: +```sh +$ nix flake show github:tale/headplane --all-systems +github:tale/headplane/ec6d455461955242393b60d9ce60c5123fa9784f?narHash=sha256-CM/vXzUiOed7i1Pp15KyV4FuIvumRlXnpF33dSWZZH4%3D +├───checks +│ ├───aarch64-darwin +│ │ └───default: derivation 'headplane-with-agent' +│ ├───x86_64-darwin +│ │ └───default: derivation 'headplane-with-agent' +│ └───x86_64-linux +│ └───default: derivation 'headplane-with-agent' +├───devShells +│ ├───aarch64-darwin +│ │ └───default: development environment 'headplane' +│ ├───x86_64-darwin +│ │ └───default: development environment 'headplane' +│ └───x86_64-linux +│ └───default: development environment 'headplane' ├───formatter -│ ├───aarch64-darwin: package 'alejandra-3.1.0' -│ ├───x86_64-darwin: package 'alejandra-3.1.0' -│ └───x86_64-linux: package 'alejandra-3.1.0' +│ ├───aarch64-darwin: package 'alejandra-4.0.0' +│ ├───x86_64-darwin: package 'alejandra-4.0.0' +│ └───x86_64-linux: package 'alejandra-4.0.0' ├───nixosModules │ └───headplane: NixOS module ├───overlays │ └───default: Nixpkgs overlay └───packages ├───aarch64-darwin - │ ├───headplane: package 'headplane-0.5.3-SNAPSHOT' - │ └───headplane-agent: package 'hp_agent-0.5.3-SNAPSHOT' + │ ├───headplane: package 'headplane-0.6.1' + │ ├───headplane-agent: package 'hp_agent-0.6.1' + │ ├───headplane-nixos-docs: package 'headplane-nixos-docs.md' + │ └───headplane-ssh-wasm: package 'headplane-ssh-wasm-0.6.1' ├───x86_64-darwin - │ ├───headplane: package 'headplane-0.5.3-SNAPSHOT' - │ └───headplane-agent: package 'hp_agent-0.5.3-SNAPSHOT' + │ ├───headplane: package 'headplane-0.6.1' + │ ├───headplane-agent: package 'hp_agent-0.6.1' + │ ├───headplane-nixos-docs: package 'headplane-nixos-docs.md' + │ └───headplane-ssh-wasm: package 'headplane-ssh-wasm-0.6.1' └───x86_64-linux - ├───headplane: package 'headplane-0.5.3-SNAPSHOT' - └───headplane-agent: package 'hp_agent-0.5.3-SNAPSHOT' + ├───headplane: package 'headplane-0.6.1' + ├───headplane-agent: package 'hp_agent-0.6.1' + ├───headplane-nixos-docs: package 'headplane-nixos-docs.md' + └───headplane-ssh-wasm: package 'headplane-ssh-wasm-0.6.1' ``` ## NixOS module options -Defined as `services.headplane.*`, check the `./nix/` directory for details. +Defined as `services.headplane.*`, check the `./nix/` directory for details.\ +The full (generated by `mise run nixos-docs`) list of `services.headplane.settings.*` options: [./NixOS-options.md](./NixOS-options.md) ## Usage - 1. Add the `github:tale/headplane` flake input. -2. Import a default overlay to add `pkgs.headplane` and `pkgs.headplane-agent`. +2. Import a default overlay to add `pkgs.headplane`. 3. Import NixOS module for `services.headplane.*`. ```nix @@ -43,7 +59,7 @@ Defined as `services.headplane.*`, check the `./nix/` directory for details. inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; headplane = { - url = "github:igor-ramazanov/headplane/nix"; + url = "github:tale/headplane"; inputs.nixpkgs.follows = "nixpkgs"; }; }; @@ -59,7 +75,7 @@ Defined as `services.headplane.*`, check the `./nix/` directory for details. # provides `services.headplane.*` NixOS options. headplane.nixosModules.headplane { - # provides `pkgs.headplane` and `pkgs.headplane-agent`. + # provides `pkgs.headplane` nixpkgs.overlays = [ headplane.overlays.default ]; } { @@ -69,51 +85,41 @@ Defined as `services.headplane.*`, check the `./nix/` directory for details. # A workaround generate a valid Headscale config accepted by Headplane when `config_strict == true`. settings = lib.recursiveUpdate config.services.headscale.settings { - acme_email = "/dev/null"; tls_cert_path = "/dev/null"; tls_key_path = "/dev/null"; policy.path = "/dev/null"; - oidc.client_secret_path = "/dev/null"; }; headscaleConfig = format.generate "headscale.yml" settings; in { services.headplane = { enable = true; - agent = { - # As an example only. - # Headplane Agent hasn't yet been ready at the moment of writing the doc. - enable = true; - settings = { - HEADPLANE_AGENT_DEBUG = true; - HEADPLANE_AGENT_HOSTNAME = "localhost"; - HEADPLANE_AGENT_TS_SERVER = "https://example.com"; - HEADPLANE_AGENT_TS_AUTHKEY = "xxxxxxxxxxxxxx"; - HEADPLANE_AGENT_HP_SERVER = "https://example.com/admin/dns"; - HEADPLANE_AGENT_HP_AUTHKEY = "xxxxxxxxxxxxxx"; - }; - }; settings = { server = { host = "127.0.0.1"; port = 3000; - cookie_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; - cookie_secure = true; + # Using `sops-nix` as an example, can be a path to any file with a secret. + cookie_secret_path = config.sops.secrets."headplane/serverCookieSecret".path; }; headscale = { url = "https://example.com"; config_path = "${headscaleConfig}"; - config_strict = true; }; - integration.proc.enabled = true; + integration.agent = { + enabled = true; + # Using `sops-nix` as an example, can be a path to any file with a secret. + pre_authkey_path = config.sops.secrets."headplane/integrationAgentPreAuthkeyPath".path; + }; oidc = { issuer = "https://oidc.example.com"; client_id = "headplane"; - client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; + # Using `sops-nix` as an example, can be a path to any file with a secret. + client_secret_path = config.sops.secrets."headplane/oidcClientSecret".path; disable_api_key_login = true; # Might needed when integrating with Authelia. token_endpoint_auth_method = "client_secret_basic"; - headscale_api_key = "xxxxxxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; + # Using `sops-nix` as an example, can be a path to any file with a secret. + headscale_api_key_path = config.sops.secrets."headplane/oidcHeadscaleApiKey".path; redirect_uri = "https://oidc.example.com/admin/oidc/callback"; }; }; @@ -125,3 +131,4 @@ Defined as `services.headplane.*`, check the `./nix/` directory for details. }; } ``` + diff --git a/docs/NixOS-options.md b/docs/NixOS-options.md new file mode 100644 index 00000000..275b8ba7 --- /dev/null +++ b/docs/NixOS-options.md @@ -0,0 +1,378 @@ +# NixOS module options + +All options must be under `services.headplane`. + +For example: `settings.headscale.config_path` becomes `services.headplane.settings.headscale.config_path`. + +## debug +*Description:* Enable debug logging + +*Type:* boolean + +*Default:* `false` + + +## enable +*Description:* Whether to enable headplane. + +*Type:* boolean + +*Default:* `false` + +*Example:* `true` + + +## package +*Description:* The headplane package to use. + +*Type:* package + +*Default:* `pkgs.headplane` + + +## settings +*Description:* Headplane configuration options. Generates a YAML config file. +See: https://github.com/tale/headplane/blob/main/config.example.yaml + + +*Type:* submodule + +*Default:* `{ }` + + +## settings.headscale +*Description:* Headscale specific settings for Headplane integration. + +*Type:* submodule + +*Default:* `{ }` + + +## settings.headscale.config_path +*Description:* Path to the Headscale configuration file. +This is optional, but HIGHLY recommended for the best experience. +If this is read only, Headplane will show your configuration settings +in the Web UI, but they cannot be changed. + + +*Type:* null or absolute path + +*Default:* `null` + +*Example:* `"/etc/headscale/config.yaml"` + + +## settings.headscale.config_strict +*Description:* Headplane internally validates the Headscale configuration +to ensure that it changes the configuration in a safe way. +If you want to disable this validation, set this to false. + + +*Type:* boolean + +*Default:* `true` + + +## settings.headscale.dns_records_path +*Description:* If you are using `dns.extra_records_path` in your Headscale configuration, you need to set this to the path for Headplane to be able to read the DNS records. +Ensure that the file is both readable and writable by the Headplane process. +When using this, Headplane will no longer need to automatically restart Headscale for DNS record changes. + + +*Type:* null or absolute path + +*Default:* `null` + +*Example:* `"/var/lib/headplane/extra_records.json"` + + +## settings.headscale.public_url +*Description:* Public URL if differrent. This affects certain parts of the web UI. + +*Type:* null or string + +*Default:* `null` + +*Example:* `"https://headscale.example.com"` + + +## settings.headscale.tls_cert_path +*Description:* Path to a file containing the TLS certificate. + + +*Type:* null or absolute path + +*Default:* `null` + +*Example:* `"config.sops.secrets.tls_cert.path"` + + +## settings.headscale.url +*Description:* The URL to your Headscale instance. +All API requests are routed through this URL. +THIS IS NOT the gRPC endpoint, but the HTTP endpoint. +IMPORTANT: If you are using TLS this MUST be set to `https://`. + + +*Type:* string + +*Default:* `"http://127.0.0.1:8080"` + +*Example:* `"https://headscale.example.com"` + + +## settings.integration +*Description:* Integration configurations for Headplane to interact with Headscale. + +*Type:* submodule + +*Default:* `{ }` + + +## settings.integration.agent +*Description:* Agent configuration for the Headplane agent. + +*Type:* submodule + +*Default:* `{ }` + + +## settings.integration.agent.cache_path +*Description:* Where to store the agent cache. + +*Type:* absolute path + +*Default:* `"/var/lib/headplane/agent_cache.json"` + + +## settings.integration.agent.cache_ttl +*Description:* How long to cache agent information (in milliseconds). +If you want data to update faster, reduce the TTL, but this will increase the frequency of requests to Headscale. + + +*Type:* signed integer + +*Default:* `180000` + + +## settings.integration.agent.enabled +*Description:* The Headplane agent allows retrieving information about nodes. +This allows the UI to display version, OS, and connectivity data. +You will see the Headplane agent in your Tailnet as a node when it connects. + + +*Type:* boolean + +*Default:* `false` + + +## settings.integration.agent.host_name +*Description:* Optionally change the name of the agent in the Tailnet + +*Type:* string + +*Default:* `"headplane-agent"` + + +## settings.integration.agent.package +*Description:* The headplane-agent package to use. + +*Type:* package + +*Default:* `pkgs.headplane-agent` + + +## settings.integration.agent.pre_authkey_path +*Description:* Path to a file containing the agent preauth key. +To connect to your Tailnet, you need to generate a pre-auth key. +This can be done via the web UI or through the `headscale` CLI. + + +*Type:* null or absolute path + +*Default:* `null` + +*Example:* `"config.sops.secrets.agent_pre_authkey.path"` + + +## settings.integration.agent.work_dir +*Description:* Do not change this unless you are running a custom deployment. +The work_dir represents where the agent will store its data to be able to automatically reauthenticate with your Tailnet. +It needs to be writable by the user running the Headplane process. + + +*Type:* absolute path + +*Default:* `"/var/lib/headplane/agent"` + + +## settings.integration.proc +*Description:* Native process integration settings. + +*Type:* submodule + +*Default:* `{ }` + + +## settings.integration.proc.enabled +*Description:* Enable "Native" integration that works when Headscale and +Headplane are running outside of a container. There is no additional +configuration, but you need to ensure that the Headplane process +can terminate the Headscale process. + + +*Type:* boolean + +*Default:* `true` + + +## settings.oidc +*Description:* OIDC Configuration for authentication. + +*Type:* submodule + +*Default:* `{ }` + + +## settings.oidc.client_id +*Description:* The client ID for the OIDC client. + +*Type:* string + +*Default:* `""` + +*Example:* `"your-client-id"` + + +## settings.oidc.client_secret_path +*Description:* Path to a file containing the OIDC client secret. + + +*Type:* null or absolute path + +*Default:* `null` + +*Example:* `"config.sops.secrets.oidc_client_secret.path"` + + +## settings.oidc.disable_api_key_login +*Description:* Whether to disable API key login. + +*Type:* boolean + +*Default:* `false` + + +## settings.oidc.headscale_api_key_path +*Description:* Path to a file containing the Headscale API key. + + +*Type:* null or absolute path + +*Default:* `null` + +*Example:* `"config.sops.secrets.headscale_api_key.path"` + + +## settings.oidc.issuer +*Description:* URL to OpenID issuer. + +*Type:* string + +*Default:* `""` + +*Example:* `"https://provider.example.com/issuer-url"` + + +## settings.oidc.redirect_uri +*Description:* This should point to your publicly accessible URL +for your Headplane instance with /admin/oidc/callback. + + +*Type:* string + +*Default:* `""` + +*Example:* `"https://headscale.example.com/admin/oidc/callback"` + + +## settings.oidc.token_endpoint_auth_method +*Description:* The token endpoint authentication method. + +*Type:* one of "client_secret_post", "client_secret_basic", "client_secret_jwt" + +*Default:* `"client_secret_post"` + + +## settings.oidc.user_storage_file +*Description:* Path to a file containing the users and their permissions for Headplane. + + +*Type:* absolute path + +*Default:* `"/var/lib/headplane/users.json"` + +*Example:* `"/var/lib/headplane/users.json"` + + +## settings.server +*Description:* Server configuration for Headplane web application. + +*Type:* submodule + +*Default:* `{ }` + + +## settings.server.cookie_secret_path +*Description:* Path to a file containing the cookie secret. +The secret must be exactly 32 characters long. + + +*Type:* null or absolute path + +*Default:* `null` + +*Example:* `"config.sops.secrets.headplane_cookie.path"` + + +## settings.server.cookie_secure +*Description:* Should the cookies only work over HTTPS? +Set to false if running via HTTP without a proxy. +Recommended to be true in production. + + +*Type:* boolean + +*Default:* `true` + + +## settings.server.data_path +*Description:* The path to persist Headplane specific data. +All data going forward is stored in this directory, including the internal database and any cache related files. +Data formats prior to 0.6.1 will automatically be migrated. + + +*Type:* absolute path + +*Default:* `"/var/lib/headplane"` + +*Example:* `"/var/lib/headplane"` + + +## settings.server.host +*Description:* The host address to bind to. + +*Type:* string + +*Default:* `"127.0.0.1"` + +*Example:* `"0.0.0.0"` + + +## settings.server.port +*Description:* The port to listen on. + +*Type:* 16 bit unsigned integer; between 0 and 65535 (both inclusive) + +*Default:* `3000` + diff --git a/docs/README.md b/docs/README.md new file mode 120000 index 00000000..3dfb7d79 --- /dev/null +++ b/docs/README.md @@ -0,0 +1 @@ +./../README.md \ No newline at end of file diff --git a/docs/Simple-Mode.md b/docs/Simple-Mode.md index b6ba6d07..2660a449 100644 --- a/docs/Simple-Mode.md +++ b/docs/Simple-Mode.md @@ -4,10 +4,10 @@ Simple mode enables you to quickly deploy Headplane and is recommended for any testing or simple environments. It does not include the automatic management of DNS and Headplane settings, requiring manual editing and reloading when making changes. If you're looking for a more feature-complete deployment method, check -out [**Integrated Mode**](/docs/Integrated-Mode.md). +out [**Integrated Mode**](./Integrated-Mode.md). ## Deployment -> If you are not looking to deploy with Docker, follow the [**Bare-Metal**](/docs/Bare-Metal.md) deployment guide. +> If you are not looking to deploy with Docker, follow the [**Bare-Metal**](./Bare-Metal.md) deployment guide. Requirements: - Docker and Docker Compose @@ -33,5 +33,5 @@ This will result in the Headplane UI being available at the `/admin` path of the server you deployed it on. The `/admin` path is currently not configurable unless you build the container yourself or run Headplane in Bare-Metal mode. -> Refer to the [**Configuration**](/docs/Configuration.md) guide for help with +> Refer to the [**Configuration**](./Configuration.md) guide for help with > setting up your `config.yaml` file to the appropriate values. diff --git a/assets/acls-dark.png b/docs/assets/acls-dark.png similarity index 100% rename from assets/acls-dark.png rename to docs/assets/acls-dark.png diff --git a/assets/acls-light.png b/docs/assets/acls-light.png similarity index 100% rename from assets/acls-light.png rename to docs/assets/acls-light.png diff --git a/assets/dns-dark.png b/docs/assets/dns-dark.png similarity index 100% rename from assets/dns-dark.png rename to docs/assets/dns-dark.png diff --git a/assets/dns-light.png b/docs/assets/dns-light.png similarity index 100% rename from assets/dns-light.png rename to docs/assets/dns-light.png diff --git a/assets/machine-dark.png b/docs/assets/machine-dark.png similarity index 100% rename from assets/machine-dark.png rename to docs/assets/machine-dark.png diff --git a/assets/machine-light.png b/docs/assets/machine-light.png similarity index 100% rename from assets/machine-light.png rename to docs/assets/machine-light.png diff --git a/assets/preview-dark.png b/docs/assets/preview-dark.png similarity index 100% rename from assets/preview-dark.png rename to docs/assets/preview-dark.png diff --git a/assets/preview-light.png b/docs/assets/preview-light.png similarity index 100% rename from assets/preview-light.png rename to docs/assets/preview-light.png diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..98e8701f --- /dev/null +++ b/docs/index.md @@ -0,0 +1,22 @@ +--- +# https://vitepress.dev/reference/default-theme-home-page +layout: home + +hero: + name: "A feature-complete Web UI for Headscale" + text: "Documentation" + tagline: "A feature-complete Web UI for Headscale" + actions: + - theme: brand + text: Getting Started + link: /README + +features: + - title: Web SSH + details: Connect to machines directly from your browser + - title: OIDC + details: Login through your favourite SSO provider + - title: And many more + details: Setup ACLs, DNS, pre-auth keys, etc. +--- + diff --git a/drizzle.config.ts b/drizzle.config.ts new file mode 100644 index 00000000..4b0e848f --- /dev/null +++ b/drizzle.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'drizzle-kit'; +export default defineConfig({ + dialect: 'sqlite', + schema: './app/server/db/schema.ts', + dbCredentials: { + url: 'file:test/hp_persist.db', + }, +}); diff --git a/drizzle/0000_spicy_bloodscream.sql b/drizzle/0000_spicy_bloodscream.sql new file mode 100644 index 00000000..7876f33b --- /dev/null +++ b/drizzle/0000_spicy_bloodscream.sql @@ -0,0 +1,4 @@ +CREATE TABLE `ephemeral_nodes` ( + `auth_key` text PRIMARY KEY NOT NULL, + `node_key` text +); diff --git a/drizzle/0001_naive_lilith.sql b/drizzle/0001_naive_lilith.sql new file mode 100644 index 00000000..aaa61db9 --- /dev/null +++ b/drizzle/0001_naive_lilith.sql @@ -0,0 +1,5 @@ +CREATE TABLE `host_info` ( + `host_id` text PRIMARY KEY NOT NULL, + `payload` text, + `updated_at` integer +); diff --git a/drizzle/0002_square_bloodstorm.sql b/drizzle/0002_square_bloodstorm.sql new file mode 100644 index 00000000..2c22affc --- /dev/null +++ b/drizzle/0002_square_bloodstorm.sql @@ -0,0 +1,8 @@ +CREATE TABLE `users` ( + `id` text PRIMARY KEY NOT NULL, + `sub` text NOT NULL, + `caps` integer DEFAULT 0 NOT NULL, + `onboarded` integer DEFAULT false NOT NULL +); +--> statement-breakpoint +CREATE UNIQUE INDEX `users_sub_unique` ON `users` (`sub`); diff --git a/drizzle/meta/0000_snapshot.json b/drizzle/meta/0000_snapshot.json new file mode 100644 index 00000000..034f5630 --- /dev/null +++ b/drizzle/meta/0000_snapshot.json @@ -0,0 +1,42 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "ab03ffcd-9aa5-4b4b-9f38-322acc6899a3", + "prevId": "00000000-0000-0000-0000-000000000000", + "tables": { + "ephemeral_nodes": { + "name": "ephemeral_nodes", + "columns": { + "auth_key": { + "name": "auth_key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "node_key": { + "name": "node_key", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} diff --git a/drizzle/meta/0001_snapshot.json b/drizzle/meta/0001_snapshot.json new file mode 100644 index 00000000..4980bd6c --- /dev/null +++ b/drizzle/meta/0001_snapshot.json @@ -0,0 +1,73 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "16f780a3-a6e7-4810-94bb-fad5c6446ab4", + "prevId": "ab03ffcd-9aa5-4b4b-9f38-322acc6899a3", + "tables": { + "ephemeral_nodes": { + "name": "ephemeral_nodes", + "columns": { + "auth_key": { + "name": "auth_key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "node_key": { + "name": "node_key", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "host_info": { + "name": "host_info", + "columns": { + "host_id": { + "name": "host_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "payload": { + "name": "payload", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} diff --git a/drizzle/meta/0002_snapshot.json b/drizzle/meta/0002_snapshot.json new file mode 100644 index 00000000..9b09baf6 --- /dev/null +++ b/drizzle/meta/0002_snapshot.json @@ -0,0 +1,119 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "2c18fbcb-d5f5-47c0-962d-54121cbb2e71", + "prevId": "16f780a3-a6e7-4810-94bb-fad5c6446ab4", + "tables": { + "ephemeral_nodes": { + "name": "ephemeral_nodes", + "columns": { + "auth_key": { + "name": "auth_key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "node_key": { + "name": "node_key", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "host_info": { + "name": "host_info", + "columns": { + "host_id": { + "name": "host_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "payload": { + "name": "payload", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "sub": { + "name": "sub", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "caps": { + "name": "caps", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "onboarded": { + "name": "onboarded", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": { + "users_sub_unique": { + "name": "users_sub_unique", + "columns": ["sub"], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json new file mode 100644 index 00000000..78491b64 --- /dev/null +++ b/drizzle/meta/_journal.json @@ -0,0 +1,27 @@ +{ + "version": "7", + "dialect": "sqlite", + "entries": [ + { + "idx": 0, + "version": "6", + "when": 1750355487927, + "tag": "0000_spicy_bloodscream", + "breakpoints": true + }, + { + "idx": 1, + "version": "6", + "when": 1755554742267, + "tag": "0001_naive_lilith", + "breakpoints": true + }, + { + "idx": 2, + "version": "6", + "when": 1755617607599, + "tag": "0002_square_bloodstorm", + "breakpoints": true + } + ] +} diff --git a/flake.nix b/flake.nix index 92295326..1591c12d 100644 --- a/flake.nix +++ b/flake.nix @@ -24,13 +24,15 @@ rec { (system: let pkgs = import nixpkgs { inherit system; - overlays = [devshell.overlays.default]; + overlays = [ devshell.overlays.default ]; }; in rec { formatter = pkgs.alejandra; packages = { - headplane = pkgs.callPackage ./nix/package.nix {}; + headplane = pkgs.callPackage ./nix/package.nix {headplane-ssh-wasm = packages.headplane-ssh-wasm;}; headplane-agent = pkgs.callPackage ./nix/agent.nix {}; + headplane-nixos-docs = pkgs.callPackage ./nix/docs.nix {}; + headplane-ssh-wasm = pkgs.callPackage ./nix/ssh-wasm.nix {}; }; checks.default = pkgs.symlinkJoin { name = "headplane-with-agent"; @@ -55,14 +57,18 @@ rec { pkgs.nodejs-slim_22 pkgs.pnpm_10 pkgs.typescript-language-server + pkgs.mise + pkgs.mkcert ]; env = []; }; }) // { overlays.default = final: prev: { - headplane = final.callPackage ./nix/package.nix {}; + headplane = final.callPackage ./nix/package.nix {headplane-ssh-wasm = final.headplane-ssh-wasm;}; headplane-agent = final.callPackage ./nix/agent.nix {}; + headplane-nixos-docs = final.callPackage ./nix/docs.nix {}; + headplane-ssh-wasm = final.callPackage ./nix/ssh-wasm.nix {}; }; nixosModules.headplane = import ./nix/module.nix; }; diff --git a/go.mod b/go.mod index 6e32cbd0..f46a9bb9 100644 --- a/go.mod +++ b/go.mod @@ -1,41 +1,38 @@ module github.com/tale/headplane -go 1.23.1 - -toolchain go1.23.4 +go 1.25.1 require ( - github.com/joho/godotenv v1.5.1 - go4.org/mem v0.0.0-20220726221520-4f986261bf13 - tailscale.com v1.78.3 + go4.org/mem v0.0.0-20240501181205-ae6ca9944745 + golang.org/x/crypto v0.41.0 + tailscale.com v1.88.2 ) require ( filippo.io/edwards25519 v1.1.0 // indirect github.com/akutz/memconn v0.1.0 // indirect github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect - github.com/aws/aws-sdk-go-v2 v1.24.1 // indirect - github.com/aws/aws-sdk-go-v2/config v1.26.5 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.16.16 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 // indirect + github.com/aws/aws-sdk-go-v2 v1.36.0 // indirect + github.com/aws/aws-sdk-go-v2/config v1.29.5 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.58 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.27 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.31 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.31 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.12 // indirect github.com/aws/aws-sdk-go-v2/service/ssm v1.44.7 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 // indirect - github.com/aws/smithy-go v1.19.0 // indirect - github.com/bits-and-blooms/bitset v1.13.0 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.24.14 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.13 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.33.13 // indirect + github.com/aws/smithy-go v1.22.2 // indirect github.com/coder/websocket v1.8.12 // indirect github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 // indirect github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa // indirect github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e // indirect - github.com/fxamacker/cbor/v2 v2.6.0 // indirect - github.com/gaissmai/bart v0.11.1 // indirect - github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 // indirect + github.com/fxamacker/cbor/v2 v2.8.0 // indirect + github.com/gaissmai/bart v0.18.0 // indirect + github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect @@ -43,50 +40,40 @@ require ( github.com/google/go-cmp v0.6.0 // indirect github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/gorilla/csrf v1.7.2 // indirect - github.com/gorilla/securecookie v1.1.2 // indirect github.com/hdevalence/ed25519consensus v0.2.0 // indirect - github.com/illarion/gonotify/v2 v2.0.3 // indirect - github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 // indirect + github.com/illarion/gonotify/v3 v3.0.2 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86 // indirect github.com/jsimonetti/rtnetlink v1.4.0 // indirect github.com/klauspost/compress v1.17.11 // indirect - github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a // indirect github.com/mdlayher/genetlink v1.3.2 // indirect - github.com/mdlayher/netlink v1.7.2 // indirect + github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 // indirect github.com/mdlayher/sdnotify v1.0.0 // indirect github.com/mdlayher/socket v0.5.0 // indirect github.com/miekg/dns v1.1.58 // indirect github.com/mitchellh/go-ps v1.0.0 // indirect - github.com/pierrec/lz4/v4 v4.1.21 // indirect github.com/prometheus-community/pro-bing v0.4.0 // indirect github.com/safchain/ethtool v0.3.0 // indirect github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e // indirect github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 // indirect - github.com/tailscale/golang-x-crypto v0.0.0-20240604161659-3fde5e568aa4 // indirect github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 // indirect github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a // indirect github.com/tailscale/netlink v1.1.1-0.20240822203006-4d49adab4de7 // indirect - github.com/tailscale/peercred v0.0.0-20240214030740-b535050b2aa4 // indirect - github.com/tailscale/web-client-prebuilt v0.0.0-20240226180453-5db17b287bf1 // indirect - github.com/tailscale/wireguard-go v0.0.0-20241113014420-4e883d38c8d3 // indirect - github.com/tcnksm/go-httpstat v0.2.0 // indirect - github.com/u-root/uio v0.0.0-20240118234441-a3c409a6018e // indirect - github.com/vishvananda/netns v0.0.4 // indirect + github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc // indirect + github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976 // indirect + github.com/tailscale/wireguard-go v0.0.0-20250716170648-1d0488a3d7da // indirect + github.com/vishvananda/netns v0.0.5 // indirect github.com/x448/float16 v0.8.4 // indirect go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect - golang.org/x/crypto v0.25.0 // indirect - golang.org/x/exp v0.0.0-20240119083558-1b970713d09a // indirect - golang.org/x/mod v0.19.0 // indirect - golang.org/x/net v0.27.0 // indirect - golang.org/x/sync v0.9.0 // indirect - golang.org/x/sys v0.27.0 // indirect - golang.org/x/term v0.22.0 // indirect - golang.org/x/text v0.16.0 // indirect - golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.23.0 // indirect + golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac // indirect + golang.org/x/mod v0.26.0 // indirect + golang.org/x/net v0.42.0 // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/sys v0.35.0 // indirect + golang.org/x/term v0.34.0 // indirect + golang.org/x/text v0.28.0 // indirect + golang.org/x/time v0.11.0 // indirect + golang.org/x/tools v0.35.0 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect golang.zx2c4.com/wireguard/windows v0.5.3 // indirect - gvisor.dev/gvisor v0.0.0-20240722211153-64c016c92987 // indirect + gvisor.dev/gvisor v0.0.0-20250205023644-9414b50a5633 // indirect ) diff --git a/go.sum b/go.sum index d08684ae..92ac4173 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +9fans.net/go v0.0.8-0.20250307142834-96bdba94b63f h1:1C7nZuxUMNz7eiQALRfiqNOm04+m3edWlRff/BYHf0Q= +9fans.net/go v0.0.8-0.20250307142834-96bdba94b63f/go.mod h1:hHyrZRryGqVdqrknjq5OWDLGCTJ2NeEvtrpR96mjraM= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= filippo.io/mkcert v1.4.4 h1:8eVbbwfVlaqUM7OwuftKc2nuYOoTDQWqsoXmzoXZdbc= @@ -10,42 +12,42 @@ github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7V github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= -github.com/aws/aws-sdk-go-v2 v1.24.1 h1:xAojnj+ktS95YZlDf0zxWBkbFtymPeDP+rvUQIH3uAU= -github.com/aws/aws-sdk-go-v2 v1.24.1/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4= -github.com/aws/aws-sdk-go-v2/config v1.26.5 h1:lodGSevz7d+kkFJodfauThRxK9mdJbyutUxGq1NNhvw= -github.com/aws/aws-sdk-go-v2/config v1.26.5/go.mod h1:DxHrz6diQJOc9EwDslVRh84VjjrE17g+pVZXUeSxaDU= -github.com/aws/aws-sdk-go-v2/credentials v1.16.16 h1:8q6Rliyv0aUFAVtzaldUEcS+T5gbadPbWdV1WcAddK8= -github.com/aws/aws-sdk-go-v2/credentials v1.16.16/go.mod h1:UHVZrdUsv63hPXFo1H7c5fEneoVo9UXiz36QG1GEPi0= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 h1:c5I5iH+DZcH3xOIMlz3/tCKJDaHFwYEmxvlh2fAcFo8= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11/go.mod h1:cRrYDYAMUohBJUtUnOhydaMHtiK/1NZ0Otc9lIb6O0Y= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 h1:vF+Zgd9s+H4vOXd5BMaPWykta2a6Ih0AKLq/X6NYKn4= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10/go.mod h1:6BkRjejp/GR4411UGqkX8+wFMbFbqsUIimfK4XjOKR4= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 h1:nYPe006ktcqUji8S2mqXf9c/7NdiKriOwMvWQHgYztw= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10/go.mod h1:6UV4SZkVvmODfXKql4LCbaZUpF7HO2BX38FgBf9ZOLw= -github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 h1:GrSw8s0Gs/5zZ0SX+gX4zQjRnRsMJDJ2sLur1gRBhEM= -github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 h1:/b31bi3YVNlkzkBrm9LfpaKoaYZUxIAj4sHfOTmLfqw= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4/go.mod h1:2aGXHFmbInwgP9ZfpmdIfOELL79zhdNYNmReK8qDfdQ= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 h1:DBYTXwIGQSGs9w4jKm60F5dmCQ3EEruxdc0MFh+3EY4= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10/go.mod h1:wohMUQiFdzo0NtxbBg0mSRGZ4vL3n0dKjLTINdcIino= +github.com/aws/aws-sdk-go-v2 v1.36.0 h1:b1wM5CcE65Ujwn565qcwgtOTT1aT4ADOHHgglKjG7fk= +github.com/aws/aws-sdk-go-v2 v1.36.0/go.mod h1:5PMILGVKiW32oDzjj6RU52yrNrDPUHcbZQYr1sM7qmM= +github.com/aws/aws-sdk-go-v2/config v1.29.5 h1:4lS2IB+wwkj5J43Tq/AwvnscBerBJtQQ6YS7puzCI1k= +github.com/aws/aws-sdk-go-v2/config v1.29.5/go.mod h1:SNzldMlDVbN6nWxM7XsUiNXPSa1LWlqiXtvh/1PrJGg= +github.com/aws/aws-sdk-go-v2/credentials v1.17.58 h1:/d7FUpAPU8Lf2KUdjniQvfNdlMID0Sd9pS23FJ3SS9Y= +github.com/aws/aws-sdk-go-v2/credentials v1.17.58/go.mod h1:aVYW33Ow10CyMQGFgC0ptMRIqJWvJ4nxZb0sUiuQT/A= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.27 h1:7lOW8NUwE9UZekS1DYoiPdVAqZ6A+LheHWb+mHbNOq8= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.27/go.mod h1:w1BASFIPOPUae7AgaH4SbjNbfdkxuggLyGfNFTn8ITY= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.31 h1:lWm9ucLSRFiI4dQQafLrEOmEDGry3Swrz0BIRdiHJqQ= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.31/go.mod h1:Huu6GG0YTfbPphQkDSo4dEGmQRTKb9k9G7RdtyQWxuI= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.31 h1:ACxDklUKKXb48+eg5ROZXi1vDgfMyfIA/WyvqHcHI0o= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.31/go.mod h1:yadnfsDwqXeVaohbGc/RaD287PuyRw2wugkh5ZL2J6k= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 h1:Pg9URiobXy85kgFev3og2CuOZ8JZUBENF+dcgWBaYNk= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 h1:D4oz8/CzT9bAEYtVhSBmFj2dNOtaHOtMKc2vHBwYizA= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2/go.mod h1:Za3IHqTQ+yNcRHxu1OFucBh0ACZT4j4VQFF0BqpZcLY= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.12 h1:O+8vD2rGjfihBewr5bT+QUfYUHIxCVgG61LHoT59shM= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.12/go.mod h1:usVdWJaosa66NMvmCrr08NcWDBRv4E6+YFG2pUdw1Lk= github.com/aws/aws-sdk-go-v2/service/ssm v1.44.7 h1:a8HvP/+ew3tKwSXqL3BCSjiuicr+XTU2eFYeogV9GJE= github.com/aws/aws-sdk-go-v2/service/ssm v1.44.7/go.mod h1:Q7XIWsMo0JcMpI/6TGD6XXcXcV1DbTj6e9BKNntIMIM= -github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 h1:eajuO3nykDPdYicLlP3AGgOyVN3MOlFmZv7WGTuJPow= -github.com/aws/aws-sdk-go-v2/service/sso v1.18.7/go.mod h1:+mJNDdF+qiUlNKNC3fxn74WWNN+sOiGOEImje+3ScPM= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 h1:QPMJf+Jw8E1l7zqhZmMlFw6w1NmfkfiSK8mS4zOx3BA= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7/go.mod h1:ykf3COxYI0UJmxcfcxcVuz7b6uADi1FkiUz6Eb7AgM8= -github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 h1:NzO4Vrau795RkUdSHKEwiR01FaGzGOH1EETJ+5QHnm0= -github.com/aws/aws-sdk-go-v2/service/sts v1.26.7/go.mod h1:6h2YuIoxaMSCFf5fi1EgZAwdfkGMgDY+DVfa61uLe4U= -github.com/aws/smithy-go v1.19.0 h1:KWFKQV80DpP3vJrrA9sVAHQ5gc2z8i4EzrLhLlWXcBM= -github.com/aws/smithy-go v1.19.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= -github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= -github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.14 h1:c5WJ3iHz7rLIgArznb3JCSQT3uUMiz9DLZhIX+1G8ok= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.14/go.mod h1:+JJQTxB6N4niArC14YNtxcQtwEqzS3o9Z32n7q33Rfs= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.13 h1:f1L/JtUkVODD+k1+IiSJUUv8A++2qVr+Xvb3xWXETMU= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.13/go.mod h1:tvqlFoja8/s0o+UruA1Nrezo/df0PzdunMDDurUfg6U= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.13 h1:3LXNnmtH3TURctC23hnC0p/39Q5gre3FI7BNOiDcVWc= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.13/go.mod h1:7Yn+p66q/jt38qMoVfNvjbm3D89mGBnkwDcijgtih8w= +github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ= +github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/cilium/ebpf v0.15.0 h1:7NxJhNiBT3NG8pZJ3c+yfrVdHY8ScgKD27sScgjLMMk= github.com/cilium/ebpf v0.15.0/go.mod h1:DHp1WyrLeiBh19Cf/tfiSMhqheEiK8fXFZ4No0P1Hso= github.com/coder/websocket v1.8.12 h1:5bUXkEPPIbewrnkU8LTCLVaxi4N4J8ahufH2vlo4NAo= github.com/coder/websocket v1.8.12/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 h1:8h5+bWd7R6AYUslN6c6iuZWTKsKxUFDlpnmilO6R2n0= github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= +github.com/creachadair/taskgroup v0.13.2 h1:3KyqakBuFsm3KkXi/9XIb0QcA8tEzLHLgaoidf0MdVc= +github.com/creachadair/taskgroup v0.13.2/go.mod h1:i3V1Zx7H8RjwljUEeUWYT30Lmb9poewSb2XI1yTwD0g= github.com/creack/pty v1.1.23 h1:4M6+isWdcStXEf15G/RbrMPOQj1dZ7HPZCGwE4kOeP0= github.com/creack/pty v1.1.23/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -57,20 +59,20 @@ github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e h1:vUmf0yez github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e/go.mod h1:YTIHhz/QFSYnu/EhlF2SpU2Uk+32abacUYA5ZPljz1A= github.com/djherbis/times v1.6.0 h1:w2ctJ92J8fBvWPxugmXIv7Nz7Q3iDMKNx9v5ocVH20c= github.com/djherbis/times v1.6.0/go.mod h1:gOHeRAz2h+VJNZ5Gmc/o7iD9k4wW7NMVqieYCY99oc0= -github.com/dsnet/try v0.0.3 h1:ptR59SsrcFUYbT/FhAbKTV6iLkeD6O18qfIWRml2fqI= -github.com/dsnet/try v0.0.3/go.mod h1:WBM8tRpUmnXXhY1U6/S8dt6UWdHTQ7y8A5YSkRCkq40= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/fxamacker/cbor/v2 v2.6.0 h1:sU6J2usfADwWlYDAFhZBQ6TnLFBHxgesMrQfQgk1tWA= -github.com/fxamacker/cbor/v2 v2.6.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= -github.com/gaissmai/bart v0.11.1 h1:5Uv5XwsaFBRo4E5VBcb9TzY8B7zxFf+U7isDxqOrRfc= -github.com/gaissmai/bart v0.11.1/go.mod h1:KHeYECXQiBjTzQz/om2tqn3sZF1J7hw9m6z41ftj3fg= +github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU= +github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/gaissmai/bart v0.18.0 h1:jQLBT/RduJu0pv/tLwXE+xKPgtWJejbxuXAR+wLJafo= +github.com/gaissmai/bart v0.18.0/go.mod h1:JJzMAhNF5Rjo4SF4jWBrANuJfqY+FvsFhW7t1UZJ+XY= github.com/github/fakeca v0.1.0 h1:Km/MVOFvclqxPM9dZBC4+QE564nU4gz4iZ0D9pMw28I= github.com/github/fakeca v0.1.0/go.mod h1:+bormgoGMMuamOscx7N91aOuUST7wdaJ2rNjeohylyo= -github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 h1:ymLjT4f35nQbASLnvxEde4XOBL+Sn7rFuV+FOJqkljg= -github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0/go.mod h1:6daplAwHHGbUGib4990V3Il26O0OC4aRyvewaaAihaA= +github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced h1:Q311OHjMh/u5E2TITc++WlTP5We0xNseRMkHDyvhW7I= +github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/go4org/plan9netshell v0.0.0-20250324183649-788daa080737 h1:cf60tHxREO3g1nroKr2osU3JWZsJzkfi7rEg+oAB0Lo= +github.com/go4org/plan9netshell v0.0.0-20250324183649-788daa080737/go.mod h1:MIS0jDzbU/vuM9MC4YnBITCv+RYuTRq8dJzmCrFsK9g= github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 h1:sQspH8M4niEijh3PFscJRLDnkL547IeP7kpPe3uUhEg= github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466/go.mod h1:ZiQxhyQ+bbbfxUKVvjfO498oPYvtYhZzycal3G/NHmU= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= @@ -79,20 +81,16 @@ github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= -github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/go-tpm v0.9.4 h1:awZRf9FwOeTunQmHoDYSHJps3ie6f1UlhS1fOdPEt1I= +github.com/google/go-tpm v0.9.4/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806 h1:wG8RYIyctLhdFk6Vl1yPGtSRtwGpVkWyZww1OCil2MI= github.com/google/nftables v0.2.1-0.20240414091927-5e242ec57806/go.mod h1:Beg6V6zZ3oEn0JuiUQ4wqwuyqqzasOltcoXPtgLbFp4= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/csrf v1.7.2 h1:oTUjx0vyf2T+wkrx09Trsev1TE+/EbDAeHtSTbtC2eI= -github.com/gorilla/csrf v1.7.2/go.mod h1:F1Fj3KG23WYHE6gozCmBAezKookxbIvUJT+121wTuLk= -github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= -github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= github.com/hdevalence/ed25519consensus v0.2.0 h1:37ICyZqdyj0lAZ8P4D1d1id3HqbbG1N3iBb1Tb4rdcU= github.com/hdevalence/ed25519consensus v0.2.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= -github.com/illarion/gonotify/v2 v2.0.3 h1:B6+SKPo/0Sw8cRJh1aLzNEeNVFfzE3c6N+o+vyxM+9A= -github.com/illarion/gonotify/v2 v2.0.3/go.mod h1:38oIJTgFqupkEydkkClkbL6i5lXV/bxdH9do5TALPEE= +github.com/illarion/gonotify/v3 v3.0.2 h1:O7S6vcopHexutmpObkeWsnzMJt/r1hONIEogeVNmJMk= +github.com/illarion/gonotify/v3 v3.0.2/go.mod h1:HWGPdPe817GfvY3w7cx6zkbzNZfi3QjcBm/wgVvEL1U= github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 h1:9K06NfxkBh25x56yVhWWlKFE8YpicaSfHwoV8SFbueA= github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2/go.mod h1:3A9PQ1cunSDF/1rbTq99Ts4pVnycWg+vlPkfeD2NLFI= github.com/jellydator/ttlcache/v3 v3.1.0 h1:0gPFG0IHHP6xyUyXq+JaD8fwkDCqgqwohXNJBcYE71g= @@ -101,11 +99,6 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= -github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= -github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86 h1:elKwZS1OcdQ0WwEDBeqxKwb7WB62QX8bvZ/FJnVXIfk= -github.com/josharian/native v1.1.1-0.20230202152459-5c7d0dd6ab86/go.mod h1:aFAMtuldEgx/4q7iSGazk22+IcgvtiC+HIimFO9XlS8= github.com/jsimonetti/rtnetlink v1.4.0 h1:Z1BF0fRgcETPEa0Kt0MRk3yV5+kF1FWTni6KUFKrq2I= github.com/jsimonetti/rtnetlink v1.4.0/go.mod h1:5W1jDvWdnthFJ7fxYX1GMK07BUpI4oskfOqvPteYS6E= github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= @@ -120,8 +113,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw= github.com/mdlayher/genetlink v1.3.2/go.mod h1:tcC3pkCrPUGIKKsCsp0B3AdaaKuHtaxoJRz3cc+528o= -github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= -github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= +github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 h1:A1Cq6Ysb0GM0tpKMbdCXCIfBclan4oHk1Jb+Hrejirg= +github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42/go.mod h1:BB4YCPDOzfy7FniQ/lxuYQ3dgmM2cZumHbK8RpTjN2o= github.com/mdlayher/sdnotify v1.0.0 h1:Ma9XeLVN/l0qpyx1tNeMSeTjCPH6NtuD6/N9XdTlQ3c= github.com/mdlayher/sdnotify v1.0.0/go.mod h1:HQUmpM4XgYkhDLtd+Uad8ZFK1T9D5+pNxnXQjCeJlGE= github.com/mdlayher/socket v0.5.0 h1:ilICZmJcQz70vrWVes1MFera4jGiWNocSkykwwoy3XI= @@ -130,9 +123,10 @@ github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= -github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo= @@ -142,107 +136,99 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus-community/pro-bing v0.4.0 h1:YMbv+i08gQz97OZZBwLyvmmQEEzyfyrrjEaAchdy3R4= github.com/prometheus-community/pro-bing v0.4.0/go.mod h1:b7wRYZtCcPmt4Sz319BykUU241rWLe1VFXyiyWK/dH4= -github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= -github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= -github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= -github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/safchain/ethtool v0.3.0 h1:gimQJpsI6sc1yIqP/y8GYgiXn/NjgvpM0RNoWLVVmP0= github.com/safchain/ethtool v0.3.0/go.mod h1:SA9BwrgyAqNo7M+uaL6IYbxpm5wk3L7Mm6ocLW+CJUs= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e h1:PtWT87weP5LWHEY//SWsYkSO3RWRZo4OSWagh3YD2vQ= github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e/go.mod h1:XrBNfAFN+pwoWuksbFS9Ccxnopa15zJGgXRFN90l3K4= github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 h1:Gzfnfk2TWrk8Jj4P4c1a3CtQyMaTVCznlkLZI++hok4= github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55/go.mod h1:4k4QO+dQ3R5FofL+SanAUZe+/QfeK0+OIuwDIRu2vSg= -github.com/tailscale/golang-x-crypto v0.0.0-20240604161659-3fde5e568aa4 h1:rXZGgEa+k2vJM8xT0PoSKfVXwFGPQ3z3CJfmnHJkZZw= -github.com/tailscale/golang-x-crypto v0.0.0-20240604161659-3fde5e568aa4/go.mod h1:ikbF+YT089eInTp9f2vmvy4+ZVnW5hzX1q2WknxSprQ= +github.com/tailscale/golang-x-crypto v0.0.0-20250404221719-a5573b049869 h1:SRL6irQkKGQKKLzvQP/ke/2ZuB7Py5+XuqtOgSj+iMM= +github.com/tailscale/golang-x-crypto v0.0.0-20250404221719-a5573b049869/go.mod h1:ikbF+YT089eInTp9f2vmvy4+ZVnW5hzX1q2WknxSprQ= github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 h1:4chzWmimtJPxRs2O36yuGRW3f9SYV+bMTTvMBI0EKio= github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05/go.mod h1:PdCqy9JzfWMJf1H5UJW2ip33/d4YkoKN0r67yKH1mG8= github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a h1:SJy1Pu0eH1C29XwJucQo73FrleVK6t4kYz4NVhp34Yw= github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a/go.mod h1:DFSS3NAGHthKo1gTlmEcSBiZrRJXi28rLNd/1udP1c8= github.com/tailscale/netlink v1.1.1-0.20240822203006-4d49adab4de7 h1:uFsXVBE9Qr4ZoF094vE6iYTLDl0qCiKzYXlL6UeWObU= github.com/tailscale/netlink v1.1.1-0.20240822203006-4d49adab4de7/go.mod h1:NzVQi3Mleb+qzq8VmcWpSkcSYxXIg0DkI6XDzpVkhJ0= -github.com/tailscale/peercred v0.0.0-20240214030740-b535050b2aa4 h1:Gz0rz40FvFVLTBk/K8UNAenb36EbDSnh+q7Z9ldcC8w= -github.com/tailscale/peercred v0.0.0-20240214030740-b535050b2aa4/go.mod h1:phI29ccmHQBc+wvroosENp1IF9195449VDnFDhJ4rJU= -github.com/tailscale/web-client-prebuilt v0.0.0-20240226180453-5db17b287bf1 h1:tdUdyPqJ0C97SJfjB9tW6EylTtreyee9C44de+UBG0g= -github.com/tailscale/web-client-prebuilt v0.0.0-20240226180453-5db17b287bf1/go.mod h1:agQPE6y6ldqCOui2gkIh7ZMztTkIQKH049tv8siLuNQ= +github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc h1:24heQPtnFR+yfntqhI3oAu9i27nEojcQ4NuBQOo5ZFA= +github.com/tailscale/peercred v0.0.0-20250107143737-35a0c7bd7edc/go.mod h1:f93CXfllFsO9ZQVq+Zocb1Gp4G5Fz0b0rXHLOzt/Djc= +github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976 h1:UBPHPtv8+nEAy2PD8RyAhOYvau1ek0HDJqLS/Pysi14= +github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976/go.mod h1:agQPE6y6ldqCOui2gkIh7ZMztTkIQKH049tv8siLuNQ= github.com/tailscale/wf v0.0.0-20240214030419-6fbb0a674ee6 h1:l10Gi6w9jxvinoiq15g8OToDdASBni4CyJOdHY1Hr8M= github.com/tailscale/wf v0.0.0-20240214030419-6fbb0a674ee6/go.mod h1:ZXRML051h7o4OcI0d3AaILDIad/Xw0IkXaHM17dic1Y= -github.com/tailscale/wireguard-go v0.0.0-20241113014420-4e883d38c8d3 h1:dmoPb3dG27tZgMtrvqfD/LW4w7gA6BSWl8prCPNmkCQ= -github.com/tailscale/wireguard-go v0.0.0-20241113014420-4e883d38c8d3/go.mod h1:BOm5fXUBFM+m9woLNBoxI9TaBXXhGNP50LX/TGIvGb4= +github.com/tailscale/wireguard-go v0.0.0-20250716170648-1d0488a3d7da h1:jVRUZPRs9sqyKlYHHzHjAqKN+6e/Vog6NpHYeNPJqOw= +github.com/tailscale/wireguard-go v0.0.0-20250716170648-1d0488a3d7da/go.mod h1:BOm5fXUBFM+m9woLNBoxI9TaBXXhGNP50LX/TGIvGb4= github.com/tailscale/xnet v0.0.0-20240729143630-8497ac4dab2e h1:zOGKqN5D5hHhiYUp091JqK7DPCqSARyUfduhGUY8Bek= github.com/tailscale/xnet v0.0.0-20240729143630-8497ac4dab2e/go.mod h1:orPd6JZXXRyuDusYilywte7k094d7dycXXU5YnWsrwg= github.com/tc-hib/winres v0.2.1 h1:YDE0FiP0VmtRaDn7+aaChp1KiF4owBiJa5l964l5ujA= github.com/tc-hib/winres v0.2.1/go.mod h1:C/JaNhH3KBvhNKVbvdlDWkbMDO9H4fKKDaN7/07SSuk= -github.com/tcnksm/go-httpstat v0.2.0 h1:rP7T5e5U2HfmOBmZzGgGZjBQ5/GluWUylujl0tJ04I0= -github.com/tcnksm/go-httpstat v0.2.0/go.mod h1:s3JVJFtQxtBEBC9dwcdTTXS9xFnM3SXAZwPG41aurT8= -github.com/u-root/u-root v0.12.0 h1:K0AuBFriwr0w/PGS3HawiAw89e3+MU7ks80GpghAsNs= -github.com/u-root/u-root v0.12.0/go.mod h1:FYjTOh4IkIZHhjsd17lb8nYW6udgXdJhG1c0r6u0arI= -github.com/u-root/uio v0.0.0-20240118234441-a3c409a6018e h1:BA9O3BmlTmpjbvajAwzWx4Wo2TRVdpPXZEeemGQcajw= -github.com/u-root/uio v0.0.0-20240118234441-a3c409a6018e/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= +github.com/u-root/u-root v0.14.0 h1:Ka4T10EEML7dQ5XDvO9c3MBN8z4nuSnGjcd1jmU2ivg= +github.com/u-root/u-root v0.14.0/go.mod h1:hAyZorapJe4qzbLWlAkmSVCJGbfoU9Pu4jpJ1WMluqE= +github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8RaCKgVpHZnecvArXvPXcFkM= +github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= -github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= +github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY= +github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= -go4.org/mem v0.0.0-20220726221520-4f986261bf13 h1:CbZeCBZ0aZj8EfVgnqQcYZgf0lpZ3H9rmp5nkDTAst8= -go4.org/mem v0.0.0-20220726221520-4f986261bf13/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g= +go4.org/mem v0.0.0-20240501181205-ae6ca9944745 h1:Tl++JLUCe4sxGu8cTpDzRLd3tN7US4hOxG5YpKCzkek= +go4.org/mem v0.0.0-20240501181205-ae6ca9944745/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= -golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= -golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= -golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA= -golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= +golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= +golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac h1:l5+whBCLH3iH2ZNHYLbAe58bo7yrN4mVcnkHDYz5vvs= +golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac/go.mod h1:hH+7mtFmImwwcMvScyxUhjuVHR3HGaDPMn9rMSUUbxo= golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f h1:phY1HzDcf18Aq9A8KkmRtY9WvOFIxN8wgfvy6Zm1DV8= golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= -golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ= -golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E= -golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= -golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= -golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w= +golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g= +golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= +golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= -golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.4.1-0.20230131160137-e7d7f63158de/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= -golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= -golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= -golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= +golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= +golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= +golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= +golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeunTOisW56dUokqW/FOteYJJ/yg= golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE= golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU= +google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gvisor.dev/gvisor v0.0.0-20240722211153-64c016c92987 h1:TU8z2Lh3Bbq77w0t1eG8yRlLcNHzZu3x6mhoH2Mk0c8= -gvisor.dev/gvisor v0.0.0-20240722211153-64c016c92987/go.mod h1:sxc3Uvk/vHcd3tj7/DHVBoR5wvWT/MmRq2pj7HRJnwU= +gvisor.dev/gvisor v0.0.0-20250205023644-9414b50a5633 h1:2gap+Kh/3F47cO6hAu3idFvsJ0ue6TRcEi2IUkv/F8k= +gvisor.dev/gvisor v0.0.0-20250205023644-9414b50a5633/go.mod h1:5DMfjtclAbTIjbXqO1qCe2K5GKKxWz2JHvCChuTcJEM= honnef.co/go/tools v0.5.1 h1:4bH5o3b5ZULQ4UrBmP+63W9r7qIkqJClEA9ko5YKx+I= honnef.co/go/tools v0.5.1/go.mod h1:e9irvo83WDG9/irijV44wr3tbhcFeRnfpVlRqVwpzMs= howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k= software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= -tailscale.com v1.78.3 h1:2BJepIEYA0ba0ZXn2rOuZjYzIV4Az+X9RS5XJF007Ug= -tailscale.com v1.78.3/go.mod h1:gT7ALbLFCr2YIu0kgc9Q3tBVaTlod65D2N6jMLH11Bk= +tailscale.com v1.88.2 h1:S8S+gt/Vx4KDlVjNHk7spcyGihTcJflKMroSnwjp5kQ= +tailscale.com v1.88.2/go.mod h1:LHaTiwRgzebPDLgZ6RQQVzX+1SR5fbNl51fzm7UtMaw= diff --git a/agent/internal/config/config.go b/internal/config/config.go similarity index 100% rename from agent/internal/config/config.go rename to internal/config/config.go diff --git a/agent/internal/config/preflight.go b/internal/config/preflight.go similarity index 95% rename from agent/internal/config/preflight.go rename to internal/config/preflight.go index 9634d8c3..ee06d9f6 100644 --- a/agent/internal/config/preflight.go +++ b/internal/config/preflight.go @@ -34,7 +34,7 @@ func validateTSReady(config *Config) error { testURL = testURL[:len(testURL)-1] } - testURL = fmt.Sprintf("%s/health", testURL) + testURL = fmt.Sprintf("%s/key?v=116", testURL) resp, err := http.Get(testURL) if err != nil { return fmt.Errorf("Failed to connect to TS control server: %s", err) diff --git a/internal/hp_ipn/ipnserver.go b/internal/hp_ipn/ipnserver.go new file mode 100644 index 00000000..d299b70f --- /dev/null +++ b/internal/hp_ipn/ipnserver.go @@ -0,0 +1,173 @@ +//go:build js && wasm + +package hp_ipn + +import ( + "context" + "fmt" + "log" + "net" + "net/netip" + + "tailscale.com/control/controlclient" + "tailscale.com/ipn" + "tailscale.com/ipn/ipnlocal" + "tailscale.com/ipn/ipnserver" + "tailscale.com/ipn/store/mem" + // "tailscale.com/net/netmon" + "tailscale.com/net/netns" + "tailscale.com/net/tsdial" + "tailscale.com/safesocket" + "tailscale.com/tsd" + "tailscale.com/types/logid" + "tailscale.com/wgengine" + "tailscale.com/wgengine/netstack" +) + +// Represents an in-state Tailscale backend that is WASM friendly. +// The bare minimum to have userspace Wireguard networking is a dialer, +// a server, and a backend. +type TsWasmIpn struct { + // The options used to initialize the TsWasmNet module. + options *TsWasmNetOptions + + // The Tailscale dialer, which is used to establish connections. + dialer *tsdial.Dialer + + // The Tailscale server, which handles incoming connections and requests. + server *ipnserver.Server + + // The Tailscale backend, which manages the local state and operations. + backend *ipnlocal.LocalBackend +} + +// NewTsWasmIpn initializes a new TsWasmIpn instance with the provided options. +// This intentionally does not initialize Logtail, as it is only available in +// the Tailscale SaaS and not on self-hosted instances. +func NewTsWasmIpn(options *TsWasmNetOptions, callbacks *TsWasmNetCallbacks) (*TsWasmIpn, error) { + logf := log.Printf // TODO: Update + + netns.SetEnabled(false) // netns is a separate process (not WASM friendly) + + // Base system (NewSystem() creates a bus automatically) + // We supply an in-memory store + sys := tsd.NewSystem() + // bus := sys.Bus.Get() + sys.Set(new(mem.Store)) + + dialer := &tsdial.Dialer{Logf: logf} + // netmon, err := netmon.New(bus, logf) + // if err != nil { + // return nil, err + // } + + // Userspace Wireguard engine + engine, err := wgengine.NewUserspaceEngine(logf, wgengine.Config{ + Dialer: dialer, + // NetMon: netmon, + SetSubsystem: sys.Set, + ControlKnobs: sys.ControlKnobs(), + HealthTracker: sys.HealthTracker(), + Metrics: sys.UserMetricsRegistry(), + EventBus: sys.Bus.Get(), + }) + + if err != nil { + return nil, err + } + + sys.Set(engine) + tun := sys.Tun.Get() + msock := sys.MagicSock.Get() + dnsman := sys.DNSManager.Get() + proxymap := sys.ProxyMapper() + wgstack, err := netstack.Create(logf, tun, engine, msock, dialer, dnsman, proxymap) + + sys.Set(wgstack) + if err != nil { + return nil, err + } + + // Configure the local Netstack and Dialer + wgstack.ProcessLocalIPs = true + wgstack.ProcessSubnets = true + + dialer.UseNetstackForIP = func(ip netip.Addr) bool { + return true + } + + dialer.NetstackDialTCP = func(ctx context.Context, dst netip.AddrPort) (net.Conn, error) { + return wgstack.DialContextTCP(ctx, dst) + } + + dialer.NetstackDialUDP = func(ctx context.Context, dst netip.AddrPort) (net.Conn, error) { + return wgstack.DialContextUDP(ctx, dst) + } + + // Dummy logid for the Tailscale backend + logid := logid.PublicID{} + sys.NetstackRouter.Set(true) + sys.Tun.Get().Start() + + server := ipnserver.New(logf, logid, sys.NetMon.Get()) + flags := controlclient.LoginDefault | controlclient.LoginEphemeral | controlclient.LocalBackendStartKeyOSNeutral + + backend, err := ipnlocal.NewLocalBackend(logf, logid, sys, flags) + if err != nil { + return nil, err + } + + err = wgstack.Start(backend) + if err != nil { + return nil, err + } + + server.SetLocalBackend(backend) + registerNotifyCallback(callbacks, backend) + + return &TsWasmIpn{ + options: options, + dialer: dialer, + server: server, + backend: backend, + }, nil +} + +// Starts the WASM backend which will connect to the Tailscale tailnet and +// register an ephemeral node viewable in the Tailscale admin console. +func (t *TsWasmIpn) Start(ctx context.Context) error { + // Blank "socket" is a requirement for WASM + // This NEEDS to happen before the LocalBackend is started, + listener, err := safesocket.Listen("") + if err != nil { + return fmt.Errorf("failed to create safesocket listener: %w", err) + } + + // Start the server BEFORE the LocalBackend is started + go func() { + err := t.server.Run(ctx, listener) + if err != nil { + // TODO: Handle this dispatch using a chan + log.Printf("Failed to run Tailscale server: %v", err) + } + }() + + // Start the LocalBackend + err = t.backend.Start(ipn.Options{ + AuthKey: t.options.PreAuthKey, + UpdatePrefs: &ipn.Prefs{ + ControlURL: t.options.ControlURL, + Hostname: t.options.Hostname, + WantRunning: true, + RunWebClient: false, + LoggedOut: false, + }, + }) + + if err != nil { + return fmt.Errorf("failed to start Tailscale backend: %w", err) + } + + log.Printf("Tailscale backend started successfully with hostname: %s", t.options.Hostname) + return nil +} diff --git a/internal/hp_ipn/jsfunc.go b/internal/hp_ipn/jsfunc.go new file mode 100644 index 00000000..0b631857 --- /dev/null +++ b/internal/hp_ipn/jsfunc.go @@ -0,0 +1,106 @@ +//go:build js && wasm + +package hp_ipn + +import ( + "errors" + "fmt" + "syscall/js" + + "tailscale.com/ipn" + "tailscale.com/types/netmap" +) + +// Maps ipn.State values to their string representations for the frontend. +var BackendState = map[ipn.State]string{ + ipn.NoState: "NoState", + ipn.Stopped: "Stopped", + ipn.Starting: "Starting", + ipn.Running: "Running", + ipn.InUseOtherUser: "InUseOtherUser", + ipn.NeedsMachineAuth: "NeedsMachineAuth", + ipn.NeedsLogin: "NeedsLogin", +} + +// Represents the callbacks that the TsWasmNet module can invoke to register +// data retrieval and notifications on the frontend. +type TsWasmNetCallbacks struct { + // Changes in the backend state. + NotifyState func(ipn.State) + + // Updates to the backend's network map. + NotifyNetMap func(*netmap.NetworkMap) + + // If interactive login is required, this passes a login URL. + NotifyBrowseToURL func(string) + + // If the process panics, this function is called in go.recover. + NotifyPanicRecover func(string) +} + +// Parses a JavaScript object containing the necessary callbacks for the +// TsWasmNet module to properly interact with the frontend. +func ParseTsWasmNetCallbacks(obj js.Value) (*TsWasmNetCallbacks, error) { + if obj.IsUndefined() || obj.IsNull() { + return nil, errors.New("callbacks object is undefined or null") + } + + state, err := validateCallback("NotifyState", obj) + if err != nil { + return nil, fmt.Errorf("invalid callback NotifyState: %w", err) + } + + // TODO: This is complicated, as the NetworkMap is a complex type. + _, err = validateCallback("NotifyNetMap", obj) + if err != nil { + return nil, fmt.Errorf("invalid callback NotifyNetMap: %w", err) + } + + browseURL, err := validateCallback("NotifyBrowseToURL", obj) + if err != nil { + return nil, fmt.Errorf("invalid callback NotifyBrowseToURL: %w", err) + } + + panicRecover, err := validateCallback("NotifyPanicRecover", obj) + if err != nil { + return nil, fmt.Errorf("invalid callback NotifyPanicRecover: %w", err) + } + + return &TsWasmNetCallbacks{ + NotifyState: func(ipnState ipn.State) { + state.Invoke(BackendState[ipnState]) + }, + + NotifyNetMap: func(nm *netmap.NetworkMap) { + // We need to build a JSON representation of the NetworkMap + // For now we just pass the NodeKey since that's what we need. + jsObj := js.ValueOf(map[string]any{ + "NodeKey": nm.NodeKey.String(), + }) + + obj.Get("NotifyNetMap").Invoke(jsObj) + }, + + NotifyBrowseToURL: func(url string) { + browseURL.Invoke(url) + }, + + NotifyPanicRecover: func(msg string) { + panicRecover.Invoke(msg) + }, + }, nil +} + +// Validates the specified key is a JS function and returns it. +func validateCallback(key string, obj js.Value) (*js.Value, error) { + val := obj.Get(key) + if val.IsUndefined() || val.IsNull() { + return nil, errors.New("callback is undefined or null") + } + + if val.Type() != js.TypeFunction { + return nil, errors.New("callback is not a function") + } + + return &val, nil +} diff --git a/internal/hp_ipn/jsmap.go b/internal/hp_ipn/jsmap.go new file mode 100644 index 00000000..38008735 --- /dev/null +++ b/internal/hp_ipn/jsmap.go @@ -0,0 +1,151 @@ +//go:build js && wasm + +package hp_ipn + +import ( + "errors" + "syscall/js" +) + +// Represents the options needed to initialize the TsWasmNet module. +type TsWasmNetOptions struct { + // Tailscale control URL, e.g., "https://controlplane.tailscale.com" + ControlURL string + + // Pre-authentication key for the Tailnet + PreAuthKey string + + // Optional hostname, autogenerated if not provided. + Hostname string +} + +// Parses the provided JS object to validate and extract the TsWasmNetOptions. +func ParseTsWasmNetOptions(obj js.Value) (*TsWasmNetOptions, error) { + if obj.IsUndefined() || obj.IsNull() { + return nil, errors.New("TsWasmNetOptions cannot be undefined or null") + } + + cUrl := safeString("ControlURL", obj) + preAuthKey := safeString("PreAuthKey", obj) + hostname := safeString("Hostname", obj) + + if cUrl == "" || preAuthKey == "" || hostname == "" { + return nil, errors.New("missing required fields in TsWasmNetOptions") + } + + return &TsWasmNetOptions{ + ControlURL: cUrl, + PreAuthKey: preAuthKey, + Hostname: hostname, + }, nil +} + +// Options passed from the JS side to pass data to xterm.js. +type SSHXtermConfig struct { + Timeout int // Timeout in seconds for the PTY connection. + Rows int // Number of rows in the PTY. + Cols int // Number of columns in the PTY. + OnStdout func(data js.Value) // Fires when the PTY has output. + OnStderr func(error js.Value) // Fires when the PTY has an error. + OnStdin js.Value // Passes a function to the JS side to provide input. + OnConnect func() // Fires when the PTY is opened. + OnDisconnect func() // Fires when the PTY is closed. +} + +// Parses the provided JS object to validate and extract SSHXtermConfig. +func ParseSSHXtermConfig(obj js.Value) (*SSHXtermConfig, error) { + if obj.IsUndefined() || obj.IsNull() { + return nil, errors.New("SSHXtermConfig cannot be undefined or null") + } + + timeout := safeInt("timeout", obj) + rows := safeInt("rows", obj) + cols := safeInt("cols", obj) + + if rows <= 0 || cols <= 0 { + return nil, errors.New("`rows` and `cols` must be positive integers") + } + + if timeout <= 0 { + timeout = 30 // Default timeout to 30 seconds if not specified + } + + config := &SSHXtermConfig{ + Timeout: timeout, + Rows: rows, + Cols: cols, + } + + onStdout := obj.Get("onStdout") + if onStdout.IsUndefined() || onStdout.IsNull() || (onStdout.Type() != js.TypeFunction) { + return nil, errors.New("`onStdout` is required and must be a function") + } + + config.OnStdout = func(data js.Value) { + onStdout.Invoke(data) + } + + onStderr := obj.Get("onStderr") + if onStderr.IsUndefined() || onStderr.IsNull() || (onStderr.Type() != js.TypeFunction) { + return nil, errors.New("`onStderr` is required and must be a function") + } + + config.OnStderr = func(error js.Value) { + onStderr.Invoke(error) + } + + onStdin := obj.Get("onStdin") + if onStdin.IsUndefined() || onStdin.IsNull() || (onStdin.Type() != js.TypeFunction) { + return nil, errors.New("`onStdin` is required and must be a function") + } + + config.OnStdin = onStdin + + onConnect := obj.Get("onConnect") + if onConnect.IsUndefined() || onConnect.IsNull() || (onConnect.Type() != js.TypeFunction) { + return nil, errors.New("`onConnect` is required and must be a function") + } + + config.OnConnect = func() { + onConnect.Invoke() + } + + onDisconnect := obj.Get("onDisconnect") + if onDisconnect.IsUndefined() || onDisconnect.IsNull() || (onDisconnect.Type() != js.TypeFunction) { + return nil, errors.New("`onDisconnect` is required and must be a function") + } + + config.OnDisconnect = func() { + onDisconnect.Invoke() + } + + return config, nil +} + +// Retrieves a string value from a JS object safely. +func safeString(key string, obj js.Value) string { + if obj.IsUndefined() || obj.IsNull() { + return "" + } + + val := obj.Get(key) + if val.IsUndefined() || val.IsNull() { + return "" + } + + return val.String() +} + +// Retrieves an integer value from a JS object safely. +func safeInt(key string, obj js.Value) int { + if obj.IsUndefined() || obj.IsNull() { + return 0 + } + + val := obj.Get(key) + if val.IsUndefined() || val.IsNull() { + return 0 + } + + return val.Int() +} diff --git a/internal/hp_ipn/notify.go b/internal/hp_ipn/notify.go new file mode 100644 index 00000000..c236654d --- /dev/null +++ b/internal/hp_ipn/notify.go @@ -0,0 +1,99 @@ +//go:build js && wasm + +package hp_ipn + +import ( + "context" + "fmt" + "log" + + "tailscale.com/ipn" + "tailscale.com/ipn/ipnlocal" +) + +func registerNotifyCallback(callbacks *TsWasmNetCallbacks, lb *ipnlocal.LocalBackend) { + lb.SetNotifyCallback(func(n ipn.Notify) { + // Panics should be treated with care in a JS/wasm environment. + // If a panic occurs, notify the user and either automatically reload + // or give the option to reload. + + defer func() { + rec := recover() + if rec != nil { + callbacks.NotifyPanicRecover(fmt.Sprint(rec)) + } + }() + + if n.State != nil { + callbacks.NotifyState(*n.State) + + if *n.State == ipn.NeedsLogin { + // If the state is NeedsLogin, we need to force an interactive login. + go forceInteractiveLogin(lb) + } + } + + if n.BrowseToURL != nil { + callbacks.NotifyBrowseToURL(*n.BrowseToURL) + } + + if n.NetMap != nil { + callbacks.NotifyNetMap(n.NetMap) + } + + log.Printf("NOTIFY: %+v", n) + + // if nm := n.NetMap; nm != nil { + // jsNetMap := jsNetMap{ + // Self: jsNetMapSelfNode{ + // jsNetMapNode: jsNetMapNode{ + // Name: nm.Name, + // Addresses: mapSliceView(nm.GetAddresses(), func(a netip.Prefix) string { return a.Addr().String() }), + // NodeKey: nm.NodeKey.String(), + // MachineKey: nm.MachineKey.String(), + // }, + // MachineStatus: jsMachineStatus[nm.GetMachineStatus()], + // }, + // Peers: mapSlice(nm.Peers, func(p tailcfg.NodeView) jsNetMapPeerNode { + // name := p.Name() + // if name == "" { + // // In practice this should only happen for Hello. + // name = p.Hostinfo().Hostname() + // } + // addrs := make([]string, p.Addresses().Len()) + // for i, ap := range p.Addresses().All() { + // addrs[i] = ap.Addr().String() + // } + // return jsNetMapPeerNode{ + // jsNetMapNode: jsNetMapNode{ + // Name: name, + // Addresses: addrs, + // MachineKey: p.Machine().String(), + // NodeKey: p.Key().String(), + // }, + // Online: p.Online().Clone(), + // TailscaleSSHEnabled: p.Hostinfo().TailscaleSSHEnabled(), + // } + // }), + // LockedOut: nm.TKAEnabled && nm.SelfNode.KeySignature().Len() == 0, + // } + // if jsonNetMap, err := json.Marshal(jsNetMap); err == nil { + // jsCallbacks.Call("notifyNetMap", string(jsonNetMap)) + // } else { + // log.Printf("Could not generate JSON netmap: %v", err) + // } + // } + // if n.BrowseToURL != nil { + // jsCallbacks.Call("notifyBrowseToURL", *n.BrowseToURL) + // } + }) +} + +// To get auth to work, even with a pre-auth key, we need to +// force an interactive login on the NeedsLogin state. +func forceInteractiveLogin(lb *ipnlocal.LocalBackend) { + err := lb.StartLoginInteractive(context.Background()) + if err != nil { + fmt.Printf("Error starting interactive login: %v\n", err) + } +} diff --git a/internal/hp_ipn/ssh.go b/internal/hp_ipn/ssh.go new file mode 100644 index 00000000..7fc5e743 --- /dev/null +++ b/internal/hp_ipn/ssh.go @@ -0,0 +1,240 @@ +//go:build js && wasm + +package hp_ipn + +import ( + "context" + "fmt" + "io" + "log" + "net" + "syscall/js" + "time" + + "golang.org/x/crypto/ssh" +) + +// Represents an SSH session over the Tailnet. +type SSHSession struct { + // Hostname on the Tailnet. + Hostname string + + // Username for the SSH connection. + Username string + + // Xterm configuration for the SSH session. + TermConfig *SSHXtermConfig + + // Handle to the current IPN connection. + Ipn *TsWasmIpn + + // Handle to the current SSH session. + Pty *ssh.Session + + // Tracks resize notifications for rows. + ResizeRows int + + // Tracks resize notifications for columns. + ResizeCols int + + // Reference to our stdin handler, released on close. + stdinHandler *js.Func +} + +// Creates a new SSH session given a hostname and username. +func (i *TsWasmIpn) NewSSHSession(hostname, username string, termConfig *SSHXtermConfig) *SSHSession { + return &SSHSession{ + Hostname: hostname, + Username: username, + TermConfig: termConfig, + Ipn: i, + } +} + +func (s *SSHSession) ConnectAndRun() { + defer s.TermConfig.OnDisconnect() + + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(s.TermConfig.Timeout)*time.Second) + defer cancel() + + // TODO: Log here + log.Printf("Attempting SSH dial to host: %s", net.JoinHostPort(s.Hostname, "22")) + conn, err := s.Ipn.dialer.UserDial(ctx, "tcp", net.JoinHostPort(s.Hostname, "22")) + if err != nil { + log.Printf("SSH dial error: %v", err) + s.writeError("Dial", err) + return + } + + defer conn.Close() + sshConf := &ssh.ClientConfig{ + User: s.Username, + HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { + // Tailscale SSH doesn't use host keys + // TODO: Log that the connection was established + return nil + }, + } + + // TODO: LOG: Starting SSH Client + sshConn, _, _, err := ssh.NewClientConn(conn, s.Hostname, sshConf) + if err != nil { + s.writeError("SSH", err) + return + } + + defer sshConn.Close() + sshClient := ssh.NewClient(sshConn, nil, nil) + defer sshClient.Close() + + pty, err := sshClient.NewSession() + if err != nil { + s.writeError("SSH", err) + return + } + + defer pty.Close() + s.Pty = pty + + rows := s.TermConfig.Rows + if s.ResizeRows != 0 { + rows = s.ResizeRows + } + + cols := s.TermConfig.Cols + if s.ResizeCols != 0 { + cols = s.ResizeCols + } + + err = pty.RequestPty("xterm", rows, cols, ssh.TerminalModes{ + ssh.ECHO: 1, // enable echoing + ssh.ICANON: 1, // canonical mode + ssh.ISIG: 1, // enable signals + ssh.ICRNL: 1, // map CR to NL on input + ssh.IUTF8: 1, // input is UTF-8 + ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud + ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud + }) + + if err != nil { + s.writeError("SSH", err) + return + } + + stdin, err := pty.StdinPipe() + if err != nil { + s.writeError("SSH", err) + return + } + + s.wireStdinHandler(stdin) + + stdout, err := pty.StdoutPipe() + if err != nil { + s.writeError("SSH", err) + return + } + + stderr, err := pty.StderrPipe() + if err != nil { + s.writeError("SSH", err) + return + } + + go io.Copy(XtermPipe{s.TermConfig.OnStdout}, stdout) + go io.Copy(XtermPipe{s.TermConfig.OnStderr}, stderr) + + // Create our shell + err = pty.Shell() + if err != nil { + s.writeError("SSH", err) + return + } + + s.TermConfig.OnConnect() + err = pty.Wait() + if err != nil { + s.writeError("SSH", err) + return + } +} + +// Resize resizes the terminal for the SSH session. +// TODO: This does NOT work correctly from Xterm.js +func (s *SSHSession) Resize(rows, cols int) error { + // Used to handle resizes while still connecting. + if s.Pty == nil { + s.ResizeRows = rows + s.ResizeCols = cols + return nil + } + + return s.Pty.WindowChange(cols, rows) +} + +// Closes the SSH session. +func (s *SSHSession) Close() error { + if s.stdinHandler != nil { + s.stdinHandler.Release() + s.stdinHandler = nil + } + + if s.Pty != nil { + err := s.Pty.Close() + if err != nil { + return err + } + } + + return nil +} + +// Wires up the stdin handler to pass data from JS to the SSH session. +func (s *SSHSession) wireStdinHandler(w io.Writer) { + if s.stdinHandler != nil { + s.stdinHandler.Release() + s.stdinHandler = nil + } + + cb := js.FuncOf(func(this js.Value, args []js.Value) any { + v := args[0] // This is ALWAYS a Uint8Array technically + len := v.Get("byteLength").Int() + buf := make([]byte, len) + js.CopyBytesToGo(buf, v) + + if _, err := w.Write(buf); err != nil { + s.writeError("SSH Stdin", err) + return nil + } + + // TODO: Remove debug log + log.Printf("SSH wrote %d bytes: %v (%q)", len, buf, string(buf)) + return nil + }) + + s.stdinHandler = &cb + s.TermConfig.OnStdin.Invoke(cb) +} + +// Quick easy formatter for writing errors to the terminal. +func (s *SSHSession) writeError(label string, err error) { + o := fmt.Sprintf("%s error: %v\r\n", label, err) + uint8Array := js.Global().Get("Uint8Array").New(len(o)) + + js.CopyBytesToJS(uint8Array, []byte(o)) + s.TermConfig.OnStderr(uint8Array) +} + +// io.Writer "emulator" to pass to the ssh module. +type XtermPipe struct { + // Function to call when data is written. + Send func(data js.Value) +} + +// Write implements the io.Writer interface for XtermPipe. +func (x XtermPipe) Write(data []byte) (int, error) { + uint8Array := js.Global().Get("Uint8Array").New(len(data)) + js.CopyBytesToJS(uint8Array, data) + x.Send(uint8Array) + return len(data), nil +} diff --git a/internal/tsnet/peers.go b/internal/tsnet/peers.go new file mode 100644 index 00000000..74a1ec1e --- /dev/null +++ b/internal/tsnet/peers.go @@ -0,0 +1,148 @@ +package tsnet + +import ( + "context" + "encoding/hex" + "encoding/json" + "fmt" + "strings" + "sync" + "time" + + "github.com/tale/headplane/internal/util" + "tailscale.com/ipn/ipnstate" + "tailscale.com/tailcfg" + "tailscale.com/types/key" + + "go4.org/mem" +) + +// Returns the raw hostinfo for a peer based on node ID. +func (s *TSAgent) GetStatusForPeer(id string) (*tailcfg.HostinfoView, error) { + log := util.GetLogger() + + if !strings.HasPrefix(id, "nodekey:") { + log.Debug("Node ID with missing prefix: %s", id) + return nil, fmt.Errorf("invalid node ID: %s", id) + } + + log.Debug("Querying status of peer: %s", id) + status, err := s.Lc.Status(context.Background()) + if err != nil { + log.Debug("Failed to get status: %s", err) + return nil, fmt.Errorf("failed to get status: %w", err) + } + + // We need to convert from 64 char hex to 32 byte raw. + bytes, err := hex.DecodeString(id[8:]) + if err != nil { + log.Debug("Failed to decode hex: %s", err) + return nil, fmt.Errorf("failed to decode hex: %w", err) + } + + raw := mem.B(bytes) + if raw.Len() != 32 { + log.Debug("Invalid node ID length: %d", raw.Len()) + return nil, fmt.Errorf("invalid node ID length: %d", raw.Len()) + } + + nodeKey := key.NodePublicFromRaw32(raw) + peer := status.Peer[nodeKey] + if peer == nil { + // Check if we are on Self. + if status.Self.PublicKey == nodeKey { + peer = status.Self + } else { + log.Debug("Peer not found in status: %s", id) + return nil, nil + } + } + + ip := peer.TailscaleIPs[0].String() + whois, err := s.Lc.WhoIs(context.Background(), ip) + if err != nil { + log.Debug("Failed to get whois: %s", err) + return nil, fmt.Errorf("failed to get whois: %w", err) + } + + log.Debug("Got whois for peer %s: %v", id, whois) + return &whois.Node.Hostinfo, nil +} + +// Dispatches ALL the HostInfo entries in our Tailnet to the master +func (s *TSAgent) DispatchHostInfo(ctx context.Context) error { + log := util.GetLogger() + + stat, err := s.Lc.Status(ctx) + if err != nil { + log.Debug("Failed to get status: %s", err) + return fmt.Errorf("failed to get status: %w", err) + } + + // Do lookups for all peers with a hint of parallelism for speed! + const maxParallel = 8 + sema := make(chan struct{}, maxParallel) + var wg sync.WaitGroup + var mu sync.Mutex + + nodeMap := make(map[key.NodePublic]*ipnstate.PeerStatus) + nodeMap[stat.Self.PublicKey] = stat.Self + for nodeKey, peer := range stat.Peer { + if peer == nil { + log.Debug("Skipping nil peer for node key: %s", nodeKey) + continue + } + + nodeMap[nodeKey] = peer + } + + for nodeKey, peer := range nodeMap { + idBytes, err := nodeKey.MarshalText() + if err != nil { + log.Debug("Failed to marshal node key: %s", err) + continue + } + + nodeID := string(idBytes) + wg.Add(1) + sema <- struct{}{} + + go func() { + defer wg.Done() + defer func() { <-sema }() + + wctx, cancel := context.WithTimeout(ctx, 3*time.Second) + defer cancel() + + ip := peer.TailscaleIPs[0].String() + if len(ip) == 0 { + log.Debug("Peer %s has no Tailscale IPs", nodeID) + return + } + + whois, err := s.Lc.WhoIs(wctx, ip) + if err != nil { + log.Debug("WhoIs failed for %s (%s): %s", nodeID, ip, err) + return + } + + if whois == nil || whois.Node == nil { + log.Debug("WhoIs returned nil node for %s (%s)", nodeID, ip) + return + } + + data, err := json.Marshal(whois.Node.Hostinfo) + if err != nil { + log.Debug("Failed to marshal hostinfo for %s (%s): %s", nodeID, ip, err) + return + } + + mu.Lock() + fmt.Println("HOSTINFO " + nodeID + " " + string(data)) + mu.Unlock() + }() + } + + wg.Wait() + return nil +} diff --git a/agent/internal/tsnet/server.go b/internal/tsnet/server.go similarity index 90% rename from agent/internal/tsnet/server.go rename to internal/tsnet/server.go index eb4ffe8f..2909911f 100644 --- a/agent/internal/tsnet/server.go +++ b/internal/tsnet/server.go @@ -5,16 +5,16 @@ import ( "os" "path/filepath" - "github.com/tale/headplane/agent/internal/config" - "github.com/tale/headplane/agent/internal/util" - "tailscale.com/client/tailscale" + "github.com/tale/headplane/internal/config" + "github.com/tale/headplane/internal/util" + "tailscale.com/client/local" "tailscale.com/tsnet" ) // Wrapper type so we can add methods to the server. type TSAgent struct { *tsnet.Server - Lc *tailscale.LocalClient + Lc *local.Client ID string } diff --git a/agent/internal/util/logger.go b/internal/util/logger.go similarity index 53% rename from agent/internal/util/logger.go rename to internal/util/logger.go index 213b4523..7e452404 100644 --- a/agent/internal/util/logger.go +++ b/internal/util/logger.go @@ -4,19 +4,16 @@ import ( "encoding/json" "fmt" "os" - "strings" "sync" - "time" ) type LogLevel string const ( - LevelInfo LogLevel = "info" - LevelDebug LogLevel = "debug" - LevelError LogLevel = "error" - LevelFatal LogLevel = "fatal" - LevelMsg LogLevel = "msg" + LevelInfo LogLevel = "INFO" + LevelDebug LogLevel = "DEBUG" + LevelError LogLevel = "ERROR" + LevelFatal LogLevel = "FATAL" ) type LogMessage struct { @@ -61,19 +58,8 @@ func (l *Logger) SetDebug(enabled bool) { func (l *Logger) log(level LogLevel, format string, v ...any) { msg := fmt.Sprintf(format, v...) - timestamp := time.Now().Format(time.RFC3339) - // Manually construct compact JSON line for performance - line := `{"Level":"` + string(level) + - `","Time":"` + timestamp + - `","Message":"` + escapeString(msg) + `"}` + "\n" - - if level == LevelError || level == LevelFatal { - os.Stderr.WriteString(line) - } - - // Always write to stdout but also write to stderr for errors - os.Stdout.WriteString(line) + fmt.Printf("LOG %s %s\n", level, msg) if level == LevelFatal { os.Exit(1) } @@ -88,30 +74,3 @@ func (l *Logger) Debug(format string, v ...any) { func (l *Logger) Info(format string, v ...any) { l.log(LevelInfo, format, v...) } func (l *Logger) Error(format string, v ...any) { l.log(LevelError, format, v...) } func (l *Logger) Fatal(format string, v ...any) { l.log(LevelFatal, format, v...) } - -func (l *Logger) Msg(obj any) { - entry := l.pool.Get().(*LogMessage) - defer l.pool.Put(entry) - - entry.Level = LevelMsg - entry.Time = time.Now().Format(time.RFC3339) - entry.Message = obj - - // Because the encoder is tied to STDOUT we get a message - _ = l.encoder.Encode(entry) - - // Reset the entry for reuse - entry.Level = "" - entry.Time = "" - entry.Message = nil -} - -func escapeString(s string) string { - replacer := strings.NewReplacer( - `"`, `\"`, - `\`, `\\`, - "\n", `\n`, - "\t", `\t`, - ) - return replacer.Replace(s) -} diff --git a/lefthook.yml b/lefthook.yml index 15961229..6f1be6e5 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -4,3 +4,7 @@ pre-commit: glob: "*.{js,ts,cjs,mjs,d.cts,d.mts,jsx,tsx,json,jsonc}" run: pnpm biome check --write --no-errors-on-unmatched --files-ignore-unknown=true --colors=off {staged_files} stage_fixed: true + check_go: + glob: "*.go" + run: gofmt -w {staged_files} + stage_fixed: true diff --git a/mise.toml b/mise.toml new file mode 100644 index 00000000..5462207f --- /dev/null +++ b/mise.toml @@ -0,0 +1,63 @@ +[tools] +# REMEMBER TO UPDATE .tool-versions TOO +go = "1.25.1" +pnpm = "10.4.0" +node = "22.16" + +[tasks.copy-wasm-shim] +alias = ["gojs"] +description = "Copies Go's wasm_exec.js to the public directory" +run = [ + "echo // $(go version) > app/wasm_exec.js", + "cat $(go env GOROOT)/lib/wasm/wasm_exec.js >> app/wasm_exec.js", +] + +[tasks.build-go-wasm] +alias = ["wasm"] +depends = ["copy-wasm-shim"] +description = "Builds the Go WebAssembly module for Tailscale SSH" +env = { GOOS = "js", GOARCH = "wasm" } +run = "go build -o app/hp_ssh.wasm ./cmd/hp_ssh" + +[tasks.build-go-agent] +alias = ["agent"] +description = "Builds the Go agent for HostInfo" +run = "go build -o build/hp_agent ./cmd/hp_agent" +# env = { CGO_ENABLED = "1" } +# run = "go build -o build/hp_agent.so -buildmode=c-shared ./cmd/hp_agent" + + +[tasks.build-fake-shell] +alias = ["fake-shell"] +description = "Builds the fake shell for Distroless docker images" +run = [ + 'test -n "$IMAGE_TAG" || (echo "IMAGE_TAG is not set" && exit 1)', + 'go build -ldflags="-s -w -X main.imageTag=$IMAGE_TAG" -o build/sh ./cmd/fake_sh' +] + +[tasks.build-nixos-docs] +alias = ["nixos-docs"] +description = "Builds NixOS module documentation" +run = [ + 'nix build .#headplane-nixos-docs', + 'cp --dereference --force ./result ./docs/NixOS-options.md', + 'sed -i "s;\[/nix.*;\[nix/options.nix\](https://github.com/tale/headplane/blob/main/nix/options.nix);" ./docs/NixOS-options.md' +] + +[tasks.generate-caddy-certs] +alias = ["mkcert"] +dir = "{{cwd}}/test/caddy/certs" +run = [ + "mkdir -p {{cwd}}/test/caddy/certs", + "mkcert -install", + "mkcert localhost" +] + +[tasks.ci] +description = "Runs the CI pipeline" +depends = ["build-go-wasm"] +depends_post = ["build-go-agent"] +run = [ + "pnpm install", + "pnpm run build" +] diff --git a/nix/agent.nix b/nix/agent.nix index 2c7bc705..d9d76978 100644 --- a/nix/agent.nix +++ b/nix/agent.nix @@ -3,7 +3,7 @@ buildGoModule { pname = "hp_agent"; version = (builtins.fromJSON (builtins.readFile ../package.json)).version; src = ../.; - vendorHash = "sha256-5TmX9ZUotNC3ZnNWRlyugAmzQG/WSZ66jFfGljql/ww="; + vendorHash = "sha256-MvrqKMD+A+qBZmzQv+T9920U5uJop+pjfJpZdm2ZqEA="; ldflags = ["-s" "-w"]; env.CGO_ENABLED = 0; } diff --git a/nix/docs.js b/nix/docs.js new file mode 100644 index 00000000..426d60a6 --- /dev/null +++ b/nix/docs.js @@ -0,0 +1,37 @@ +import fs from "node:fs"; + +function renderOptions(options) { + const blocks = Object.keys(options).map((key) => { + const opt = options[key]; + const name = key.split(".").slice(2).join("."); + const lines = []; + lines.push(`## ${name}`); + lines.push(`*Description:* ${opt.description}\n`); + lines.push(`*Type:* ${opt.type}\n`); + if (opt.default) { + lines.push(`*Default:* \`${opt.default.text}\`\n`); + } + if (opt.example) { + lines.push(`*Example:* \`${opt.example.text}\`\n`); + } + return lines.join("\n"); + }); + + return [ + `# NixOS module options + | + |All options must be under \`services.headplane\`. + | + |For example: \`settings.headscale.config_path\` becomes \`services.headplane.settings.headscale.config_path\`.` + .split("|") + .map((s) => s.replace(/\n\s+/g, "")) + .join("\n"), + ] + .concat(blocks) + .join("\n\n"); +} + +const filename = process.argv[2]; +const file = fs.readFileSync(filename); +const json = JSON.parse(file); +console.log(renderOptions(json)); diff --git a/nix/docs.nix b/nix/docs.nix new file mode 100644 index 00000000..a33b04fc --- /dev/null +++ b/nix/docs.nix @@ -0,0 +1,27 @@ +{ + lib, + nixosOptionsDoc, + runCommand, + nodejs, + ... +}: let + eval = lib.evalModules { + modules = [./options.nix]; + }; + transformOptions = opt: + if (lib.hasPrefix "_" opt.name) + then + opt + // { + internal = true; + visible = false; + } + else opt; + optionsDoc = nixosOptionsDoc { + inherit (eval) options; + inherit transformOptions; + }; +in + runCommand "headplane-nixos-docs.json" {} '' + ${nodejs}/bin/node ${./docs.js} ${optionsDoc.optionsJSON}/share/doc/nixos/options.json > $out + '' diff --git a/nix/module.nix b/nix/module.nix index 99476abb..08d77430 100644 --- a/nix/module.nix +++ b/nix/module.nix @@ -6,89 +6,41 @@ }: let inherit (lib) - attrsToList - listToAttrs - map - mkEnableOption + filterAttrs + filterAttrsRecursive mkIf - mkOption - mkPackageOption - typeOf - types + recursiveUpdate + updateManyAttrsByPath ; cfg = config.services.headplane; settingsFormat = pkgs.formats.yaml {}; - settingsFile = settingsFormat.generate "headplane-config.yaml" cfg.settings; - agentEnv = listToAttrs (map (n: { - name = n.name; - value = - if ((typeOf n.value) == "bool") - then - ( - if (n.value) - then "true" - else "false" - ) - else n.value; - }) (attrsToList cfg.agent.settings)); -in { - options.services.headplane = { - enable = mkEnableOption "headplane"; - package = mkPackageOption pkgs "headplane" {}; - - settings = mkOption { - type = types.submodule { - freeformType = settingsFormat.type; - }; - default = {}; - description = "Headplane config, generates a YAML config. See: https://github.com/tale/headplane/blob/main/config.example.yaml."; - }; - - agent = mkOption { - type = types.submodule { - options = { - enable = mkEnableOption "headplane-agent"; - package = mkPackageOption pkgs "headplane-agent" {}; - settings = mkOption { - type = types.attrsOf [types.str types.bool]; - description = "Headplane agent env vars config. See: https://github.com/tale/headplane/blob/main/docs/Headplane-Agent.md"; - default = {}; - }; - }; - }; - }; + settingsWithAgentExecutablePath = recursiveUpdate cfg.settings { + integration.agent.executable_path = "${cfg.settings.integration.agent.package}/bin/hp_agent"; }; - + settingsWithoutAgentPackage = + updateManyAttrsByPath [ + { + path = ["integration" "agent"]; + update = old: filterAttrs (key: value: key != "package") old; + } + ] + settingsWithAgentExecutablePath; + settingsWithoutNulls = filterAttrsRecursive (key: value: value != null) settingsWithoutAgentPackage; + settingsWithoutEmptyOidc = + if settingsWithoutNulls ? oidc && + ((settingsWithoutNulls.oidc.issuer or "") == "" && (settingsWithoutNulls.oidc.client_id or "") == "") then + builtins.removeAttrs settingsWithoutNulls ["oidc"] + else + settingsWithoutNulls; + settingsFile = settingsFormat.generate "headplane-config.yaml" settingsWithoutEmptyOidc; +in { + imports = [./options.nix]; config = mkIf cfg.enable { environment = { systemPackages = [cfg.package]; etc."headplane/config.yaml".source = "${settingsFile}"; }; - systemd.services.headplane-agent = - mkIf cfg.agent.enable - { - description = "Headplane side-running agent"; - - wantedBy = ["multi-user.target"]; - after = ["headplane.service"]; - requires = ["headplane.service"]; - - environment = agentEnv; - - serviceConfig = { - User = config.services.headscale.user; - Group = config.services.headscale.group; - - ExecStart = "${pkgs.headplane-agent}/bin/hp_agent"; - Restart = "always"; - RestartSec = 5; - - # TODO: Harden `systemd` security according to the "The Principle of Least Power". - # See: `$ systemd-analyze security headplane-agent`. - }; - }; - systemd.services.headplane = { description = "Headscale Web UI"; @@ -96,9 +48,12 @@ in { after = ["headscale.service"]; requires = ["headscale.service"]; + environment = {HEADPLANE_DEBUG_LOG = builtins.toString cfg.debug;}; + serviceConfig = { User = config.services.headscale.user; Group = config.services.headscale.group; + StateDirectory = "headplane"; ExecStart = "${pkgs.headplane}/bin/headplane"; Restart = "always"; diff --git a/nix/options.nix b/nix/options.nix new file mode 100644 index 00000000..d175597c --- /dev/null +++ b/nix/options.nix @@ -0,0 +1,320 @@ +{ + lib, + pkgs, + ... +}: let + inherit + (lib) + mkEnableOption + mkOption + mkPackageOption + types + ; +in { + options.services.headplane = { + enable = mkEnableOption "headplane"; + package = mkPackageOption pkgs "headplane" {}; + + debug = mkOption { + type = types.bool; + default = false; + description = "Enable debug logging"; + }; + + settings = mkOption { + description = '' + Headplane configuration options. Generates a YAML config file. + See: https://github.com/tale/headplane/blob/main/config.example.yaml + ''; + type = types.submodule { + options = { + server = mkOption { + type = types.submodule { + options = { + host = mkOption { + type = types.str; + default = "127.0.0.1"; + description = "The host address to bind to."; + example = "0.0.0.0"; + }; + + port = mkOption { + type = types.port; + default = 3000; + description = "The port to listen on."; + }; + + cookie_secret_path = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + Path to a file containing the cookie secret. + The secret must be exactly 32 characters long. + ''; + example = "config.sops.secrets.headplane_cookie.path"; + }; + + cookie_secure = mkOption { + type = types.bool; + default = true; + description = '' + Should the cookies only work over HTTPS? + Set to false if running via HTTP without a proxy. + Recommended to be true in production. + ''; + }; + + data_path = mkOption { + type = types.path; + default = "/var/lib/headplane"; + description = '' + The path to persist Headplane specific data. + All data going forward is stored in this directory, including the internal database and any cache related files. + Data formats prior to 0.6.1 will automatically be migrated. + ''; + example = "/var/lib/headplane"; + }; + }; + }; + default = {}; + description = "Server configuration for Headplane web application."; + }; + + headscale = mkOption { + type = types.submodule { + options = { + url = mkOption { + type = types.str; + default = "http://127.0.0.1:8080"; + description = '' + The URL to your Headscale instance. + All API requests are routed through this URL. + THIS IS NOT the gRPC endpoint, but the HTTP endpoint. + IMPORTANT: If you are using TLS this MUST be set to `https://`. + ''; + example = "https://headscale.example.com"; + }; + + tls_cert_path = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + Path to a file containing the TLS certificate. + ''; + example = "config.sops.secrets.tls_cert.path"; + }; + + public_url = mkOption { + type = types.nullOr types.str; + default = null; + description = "Public URL if differrent. This affects certain parts of the web UI."; + example = "https://headscale.example.com"; + }; + + config_path = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + Path to the Headscale configuration file. + This is optional, but HIGHLY recommended for the best experience. + If this is read only, Headplane will show your configuration settings + in the Web UI, but they cannot be changed. + ''; + example = "/etc/headscale/config.yaml"; + }; + + config_strict = mkOption { + type = types.bool; + default = true; + description = '' + Headplane internally validates the Headscale configuration + to ensure that it changes the configuration in a safe way. + If you want to disable this validation, set this to false. + ''; + }; + + dns_records_path = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + If you are using `dns.extra_records_path` in your Headscale configuration, you need to set this to the path for Headplane to be able to read the DNS records. + Ensure that the file is both readable and writable by the Headplane process. + When using this, Headplane will no longer need to automatically restart Headscale for DNS record changes. + ''; + example = "/var/lib/headplane/extra_records.json"; + }; + }; + }; + default = {}; + description = "Headscale specific settings for Headplane integration."; + }; + + integration = mkOption { + type = types.submodule { + options = { + agent = mkOption { + type = types.submodule { + options = { + enabled = mkOption { + type = types.bool; + default = false; + description = '' + The Headplane agent allows retrieving information about nodes. + This allows the UI to display version, OS, and connectivity data. + You will see the Headplane agent in your Tailnet as a node when it connects. + ''; + }; + + pre_authkey_path = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + Path to a file containing the agent preauth key. + To connect to your Tailnet, you need to generate a pre-auth key. + This can be done via the web UI or through the `headscale` CLI. + ''; + example = "config.sops.secrets.agent_pre_authkey.path"; + }; + + host_name = mkOption { + type = types.str; + default = "headplane-agent"; + description = "Optionally change the name of the agent in the Tailnet"; + }; + + cache_ttl = mkOption { + type = types.int; + default = 180000; + description = '' + How long to cache agent information (in milliseconds). + If you want data to update faster, reduce the TTL, but this will increase the frequency of requests to Headscale. + ''; + }; + + cache_path = mkOption { + type = types.path; + default = "/var/lib/headplane/agent_cache.json"; + description = "Where to store the agent cache."; + }; + + work_dir = mkOption { + type = types.path; + default = "/var/lib/headplane/agent"; + description = '' + Do not change this unless you are running a custom deployment. + The work_dir represents where the agent will store its data to be able to automatically reauthenticate with your Tailnet. + It needs to be writable by the user running the Headplane process. + ''; + }; + + package = mkPackageOption pkgs "headplane-agent" {}; + }; + }; + default = {}; + description = "Agent configuration for the Headplane agent."; + }; + + proc = mkOption { + type = types.submodule { + options = { + enabled = mkOption { + type = types.bool; + default = true; + description = '' + Enable "Native" integration that works when Headscale and + Headplane are running outside of a container. There is no additional + configuration, but you need to ensure that the Headplane process + can terminate the Headscale process. + ''; + }; + }; + }; + default = {}; + description = "Native process integration settings."; + }; + }; + }; + default = {}; + description = "Integration configurations for Headplane to interact with Headscale."; + }; + + oidc = mkOption { + type = types.submodule { + options = { + issuer = mkOption { + type = types.str; + default = ""; + description = "URL to OpenID issuer."; + example = "https://provider.example.com/issuer-url"; + }; + + client_id = mkOption { + type = types.str; + default = ""; + description = "The client ID for the OIDC client."; + example = "your-client-id"; + }; + + client_secret_path = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + Path to a file containing the OIDC client secret. + ''; + example = "config.sops.secrets.oidc_client_secret.path"; + }; + + disable_api_key_login = mkOption { + type = types.bool; + default = false; + description = "Whether to disable API key login."; + }; + + token_endpoint_auth_method = mkOption { + type = types.enum [ + "client_secret_post" + "client_secret_basic" + "client_secret_jwt" + ]; + default = "client_secret_post"; + description = "The token endpoint authentication method."; + }; + + headscale_api_key_path = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + Path to a file containing the Headscale API key. + ''; + example = "config.sops.secrets.headscale_api_key.path"; + }; + + redirect_uri = mkOption { + type = types.str; + default = ""; + description = '' + This should point to your publicly accessible URL + for your Headplane instance with /admin/oidc/callback. + ''; + example = "https://headscale.example.com/admin/oidc/callback"; + }; + + user_storage_file = mkOption { + type = types.path; + default = "/var/lib/headplane/users.json"; + description = '' + Path to a file containing the users and their permissions for Headplane. + ''; + example = "/var/lib/headplane/users.json"; + }; + }; + }; + default = {}; + description = "OIDC Configuration for authentication."; + }; + }; + }; + default = {}; + }; + }; +} diff --git a/nix/package.nix b/nix/package.nix index 7de674ed..8da1f85c 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -1,46 +1,55 @@ { git, + headplane-ssh-wasm, lib, makeWrapper, nodejs_22, pnpm_10, stdenv, - ... -}: -stdenv.mkDerivation (finalAttrs: { - pname = "headplane"; - version = (builtins.fromJSON (builtins.readFile ../package.json)).version; +}: let + pkg = builtins.fromJSON (builtins.readFile ../package.json); + pname = pkg.name; + version = pkg.version; src = ../.; +in + stdenv.mkDerivation (finalAttrs: { + pname = pname; + version = version; + src = src; - nativeBuildInputs = [ - makeWrapper - nodejs_22 - pnpm_10.configHook - git - ]; + nativeBuildInputs = [ + makeWrapper + nodejs_22 + pnpm_10.configHook + git + ]; - dontCheckForBrokenSymlinks = true; + dontCheckForBrokenSymlinks = true; pnpmDeps = pnpm_10.fetchDeps { inherit (finalAttrs) pname version src; - hash = "sha256-xjjkqbgjYaAGYAmlTFE+Lq3Hp6myZKaW3br0YTDNhQA="; + hash = "sha256-KyUcaR2Lvu5kT8arr4ZO8rCa5HWXTqmk8C7P8WoYK+c="; fetcherVersion = 1; }; - buildPhase = '' - runHook preBuild - pnpm build - runHook postBuild - ''; + buildPhase = '' + runHook preBuild + cp ${headplane-ssh-wasm}/hp_ssh.wasm app/hp_ssh.wasm + cp ${headplane-ssh-wasm}/wasm_exec.js app/wasm_exec.js + pnpm build + runHook postBuild + ''; - installPhase = '' - runHook preInstall - mkdir -p $out/{bin,share/headplane} - cp -r build $out/share/headplane/ - sed -i "s;$PWD;../..;" $out/share/headplane/build/server/index.js - makeWrapper ${lib.getExe nodejs_22} $out/bin/headplane \ + installPhase = '' + runHook preInstall + mkdir -p $out/{bin,share/headplane} + cp -r build $out/share/headplane/ + cp -r node_modules $out/share/headplane/ + cp -r drizzle $out/share/headplane/ + sed -i "s;$PWD;../..;" $out/share/headplane/build/server/index.js + makeWrapper ${lib.getExe nodejs_22} $out/bin/headplane \ --chdir $out/share/headplane \ --add-flags $out/share/headplane/build/server/index.js - runHook postInstall - ''; -}) + runHook postInstall + ''; + }) diff --git a/nix/ssh-wasm.nix b/nix/ssh-wasm.nix new file mode 100644 index 00000000..9c977fd8 --- /dev/null +++ b/nix/ssh-wasm.nix @@ -0,0 +1,33 @@ +{ + buildGoModule, + go, +}: let + wasmExecJs = + if builtins.pathExists "${go}/share/go/lib/wasm/wasm_exec.js" + then "${go}/share/go/lib/wasm/wasm_exec.js" + else if builtins.pathExists "${go}/lib/wasm/wasm_exec.js" + then "${go}/lib/wasm/wasm_exec.js" + else "${go}/share/go/misc/wasm/wasm_exec.js"; +in + buildGoModule { + pname = "headplane-ssh-wasm"; + version = (builtins.fromJSON (builtins.readFile ../package.json)).version; + src = ../.; + subPackages = ["cmd/hp_ssh"]; + vendorHash = "sha256-MvrqKMD+A+qBZmzQv+T9920U5uJop+pjfJpZdm2ZqEA="; + env.CGO_ENABLED = 0; + + nativeBuildInputs = [go]; + + buildPhase = '' + export GOOS=js + export GOARCH=wasm + go build -o hp_ssh.wasm ./cmd/hp_ssh + ''; + + installPhase = '' + mkdir -p $out + cp hp_ssh.wasm $out/ + cp ${wasmExecJs} $out/wasm_exec.js + ''; + } diff --git a/package.json b/package.json index 29786576..b21f705d 100644 --- a/package.json +++ b/package.json @@ -2,79 +2,113 @@ "name": "headplane", "private": true, "sideEffects": false, - "version": "0.6.0", + "version": "0.6.1", "type": "module", "scripts": { "preinstall": "npx only-allow pnpm", "build": "react-router build", "dev": "HEADPLANE_LOAD_ENV_OVERRIDES=true HEADPLANE_CONFIG_PATH=./config.example.yaml react-router dev", "start": "node build/server/index.js", - "typecheck": "tsc" + "typecheck": "react-router typegen && tsgo", + "test": "vitest run", + "docs:dev": "vitepress dev docs", + "docs:build": "vitepress build docs", + "docs:preview": "vitepress preview docs" }, "dependencies": { "@dnd-kit/core": "^6.3.1", "@dnd-kit/modifiers": "^7.0.0", "@dnd-kit/sortable": "^8.0.0", "@dnd-kit/utilities": "^3.2.2", - "@fontsource-variable/inter": "^5.2.5", + "@faker-js/faker": "9.9.0", + "@fontsource-variable/inter": "^5.2.6", "@kubernetes/client-node": "^1.3.0", - "@primer/octicons-react": "^19.15.2", - "@react-aria/toast": "3.0.3", - "@react-router/node": "^7.6.1", - "@react-stately/toast": "3.1.0", + "@libsql/client": "0.15.12", + "@react-aria/toast": "3.0.6", + "@react-router/node": "^7.8.1", + "@react-stately/toast": "3.1.2", "@shopify/lang-jsonc": "^1.0.1", - "@types/react": "^19.1.6", - "@types/react-dom": "^19.1.5", - "@uiw/codemirror-theme-github": "^4.23.12", - "@uiw/codemirror-theme-xcode": "^4.23.12", - "@uiw/react-codemirror": "^4.23.12", + "@types/react": "^19.1.10", + "@types/react-dom": "^19.1.7", + "@uiw/codemirror-theme-github": "4.25.1", + "@uiw/codemirror-theme-xcode": "4.25.1", + "@uiw/react-codemirror": "4.25.1", + "@xterm/addon-clipboard": "^0.1.0", + "@xterm/addon-fit": "^0.10.0", + "@xterm/addon-unicode11": "^0.8.0", + "@xterm/addon-web-links": "^0.11.0", + "@xterm/xterm": "^5.5.0", "arktype": "^2.1.20", "clsx": "^2.1.1", - "dotenv": "^16.5.0", - "isbot": "^5.1.28", - "lucide-react": "^0.511.0", + "dotenv": "17.2.1", + "drizzle-orm": "0.44.4", + "isbot": "5.1.30", + "jose": "6.1.0", + "lucide-react": "^0.540.0", "mime": "^4.0.7", - "openid-client": "^6.5.0", - "react": "19.1.0", - "react-aria": "^3.40.0", - "react-codemirror-merge": "^4.23.12", - "react-dom": "19.1.0", + "openid-client": "6.7.0", + "react": "19.1.1", + "react-aria": "3.42.0", + "react-codemirror-merge": "4.25.1", + "react-dom": "19.1.1", "react-error-boundary": "^6.0.0", "react-icons": "^5.5.0", - "react-router": "^7.6.1", - "react-router-hono-server": "^2.13.0", - "react-stately": "^3.38.0", - "remix-utils": "^8.7.0", - "tailwind-merge": "^3.3.0", - "undici": "^7.10.0", + "react-router": "^7.8.1", + "react-router-hono-server": "2.21.0", + "react-stately": "3.40.0", + "remix-utils": "^8.8.0", + "tailwind-merge": "3.3.1", + "ulidx": "2.4.1", + "undici": "7.14.0", "usehooks-ts": "^3.1.1", - "yaml": "^2.8.0" + "yaml": "2.8.1" }, "devDependencies": { - "@biomejs/biome": "^1.9.4", - "@react-router/dev": "^7.6.1", - "@tailwindcss/vite": "^4.1.8", - "@types/websocket": "^1.0.10", - "lefthook": "^1.11.13", - "postcss": "^8.5.4", - "react-router-dom": "^7.6.1", - "react-scan": "^0.3.4", - "tailwindcss": "^4.1.8", + "@biomejs/biome": "^2.2.0", + "@react-router/dev": "^7.8.1", + "@tailwindcss/vite": "^4.1.12", + "@types/node": "^24.3.0", + "@typescript/native-preview": "7.0.0-dev.20250821.1", + "drizzle-kit": "^0.31.4", + "js-yaml": "^4.1.0", + "lefthook": "^1.12.3", + "postcss": "^8.5.6", + "react-router-dom": "^7.8.1", + "react-scan": "^0.4.3", + "tailwindcss": "^4.1.12", "tailwindcss-animate": "^1.0.7", "tailwindcss-react-aria-components": "^2.0.0", - "typescript": "^5.8.3", - "vite": "^6.3.5", - "vite-tsconfig-paths": "^5.1.4" + "typescript": "^5.9.2", + "vite": "npm:rolldown-vite@7.1.4", + "vite-tsconfig-paths": "^5.1.4", + "vitepress": "next", + "vitest": "^3.1.3" }, "packageManager": "pnpm@10.4.0", "engines": { - "node": ">=22", + "node": ">=22.16", "pnpm": ">=10.4 <11" }, "pnpm": { + "supportedArchitectures": { + "os": [ + "current", + "linux" + ], + "cpu": [ + "x64", + "arm64" + ] + }, + "onlyBuiltDependencies": [ + "@biomejs/biome", + "@tailwindcss/oxide", + "better-sqlite3", + "esbuild", + "lefthook" + ], "patchedDependencies": { "react-router-hono-server": "patches/react-router-hono-server.patch" - }, - "onlyBuiltDependencies": ["@biomejs/biome", "esbuild", "lefthook"] + } } } diff --git a/patches/react-router-hono-server.patch b/patches/react-router-hono-server.patch index c2c68626..328e9e4b 100644 --- a/patches/react-router-hono-server.patch +++ b/patches/react-router-hono-server.patch @@ -1,34 +1,13 @@ diff --git a/dist/adapters/node.js b/dist/adapters/node.js -index 966604f94ca8528b684ef95fe7891c2e6352561b..8222cf31333668f8c2ebe65986b6ab9a3711b587 100644 +index ec81622898d583ddd8c2f4d9eaf5c0ed23776475..047ef1d45ad82e4b476a882b4ab5c8962faa0df1 100644 --- a/dist/adapters/node.js +++ b/dist/adapters/node.js -@@ -46,16 +46,25 @@ async function createHonoServer(options) { +@@ -49,7 +49,7 @@ async function createHonoServer(options) { } await mergedOptions.beforeAll?.(app); app.use( - `/${import.meta.env.REACT_ROUTER_HONO_SERVER_ASSETS_DIR}/*`, -+ `/${__PREFIX__}${import.meta.env.REACT_ROUTER_HONO_SERVER_ASSETS_DIR}/*`, ++ `${import.meta.env.REACT_ROUTER_HONO_SERVER_BASENAME}${import.meta.env.REACT_ROUTER_HONO_SERVER_ASSETS_DIR}/*`, cache(60 * 60 * 24 * 365), // 1 year -- serveStatic({ root: clientBuildPath, ...mergedOptions.serveStaticOptions?.clientAssets }) -+ serveStatic({ -+ root: clientBuildPath, -+ ...mergedOptions.serveStaticOptions?.clientAssets, -+ rewriteRequestPath: path => path.replace(__PREFIX__, "/") -+ }) - ); -+ app.use(__PREFIX__, (c) => c.redirect(`${__PREFIX__}/`)); - app.use( -- "*", -+ `${__PREFIX__}/*`, - cache(60 * 60), - // 1 hour -- serveStatic({ root: PRODUCTION ? clientBuildPath : "./public", ...mergedOptions.serveStaticOptions?.publicAssets }) -+ serveStatic({ -+ root: PRODUCTION ? clientBuildPath : "./public", -+ ...mergedOptions.serveStaticOptions?.publicAssets, -+ rewriteRequestPath: path => path.replace(__PREFIX__, "/") -+ }) - ); - if (mergedOptions.defaultLogger) { - app.use("*", logger()); + serveStatic({ root: clientBuildPath, ...mergedOptions.serveStaticOptions?.clientAssets }) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3cd1df90..f200cdbb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,7 +6,7 @@ settings: patchedDependencies: react-router-hono-server: - hash: 6549978df41006e07f1335bfe4ca86224ea36ed40d3f08dfef33143bad54005c + hash: b68723a36649e2c3bd9e9edcfff3a8bc0fdb48e1cf6d64eba37c04f7bfbb1417 path: patches/react-router-hono-server.patch importers: @@ -15,52 +15,70 @@ importers: dependencies: '@dnd-kit/core': specifier: ^6.3.1 - version: 6.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + version: 6.3.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@dnd-kit/modifiers': specifier: ^7.0.0 - version: 7.0.0(@dnd-kit/core@6.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0) + version: 7.0.0(@dnd-kit/core@6.3.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1) '@dnd-kit/sortable': specifier: ^8.0.0 - version: 8.0.0(@dnd-kit/core@6.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0) + version: 8.0.0(@dnd-kit/core@6.3.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1) '@dnd-kit/utilities': specifier: ^3.2.2 - version: 3.2.2(react@19.1.0) + version: 3.2.2(react@19.1.1) + '@faker-js/faker': + specifier: 9.9.0 + version: 9.9.0 '@fontsource-variable/inter': - specifier: ^5.2.5 - version: 5.2.5 + specifier: ^5.2.6 + version: 5.2.6 '@kubernetes/client-node': specifier: ^1.3.0 version: 1.3.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@primer/octicons-react': - specifier: ^19.15.2 - version: 19.15.2(react@19.1.0) + '@libsql/client': + specifier: 0.15.12 + version: 0.15.12(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@react-aria/toast': - specifier: 3.0.3 - version: 3.0.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: 3.0.6 + version: 3.0.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@react-router/node': - specifier: ^7.6.1 - version: 7.6.1(react-router@7.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(typescript@5.8.3) + specifier: ^7.8.1 + version: 7.8.1(react-router@7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(typescript@5.9.2) '@react-stately/toast': - specifier: 3.1.0 - version: 3.1.0(react@19.1.0) + specifier: 3.1.2 + version: 3.1.2(react@19.1.1) '@shopify/lang-jsonc': specifier: ^1.0.1 version: 1.0.1 '@types/react': - specifier: ^19.1.6 - version: 19.1.6 + specifier: ^19.1.10 + version: 19.1.10 '@types/react-dom': - specifier: ^19.1.5 - version: 19.1.5(@types/react@19.1.6) + specifier: ^19.1.7 + version: 19.1.7(@types/react@19.1.10) '@uiw/codemirror-theme-github': - specifier: ^4.23.12 - version: 4.23.12(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8) + specifier: 4.25.1 + version: 4.25.1(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8) '@uiw/codemirror-theme-xcode': - specifier: ^4.23.12 - version: 4.23.12(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8) + specifier: 4.25.1 + version: 4.25.1(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8) '@uiw/react-codemirror': - specifier: ^4.23.12 - version: 4.23.12(@babel/runtime@7.27.3)(@codemirror/autocomplete@6.18.2(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8)(@lezer/common@1.2.3))(@codemirror/language@6.11.0)(@codemirror/lint@6.8.2)(@codemirror/search@6.5.7)(@codemirror/state@6.5.2)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.36.8)(codemirror@6.0.1(@lezer/common@1.2.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: 4.25.1 + version: 4.25.1(@babel/runtime@7.27.3)(@codemirror/autocomplete@6.18.2(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8)(@lezer/common@1.2.3))(@codemirror/language@6.11.0)(@codemirror/lint@6.8.2)(@codemirror/search@6.5.7)(@codemirror/state@6.5.2)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.36.8)(codemirror@6.0.1(@lezer/common@1.2.3))(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@xterm/addon-clipboard': + specifier: ^0.1.0 + version: 0.1.0(@xterm/xterm@5.5.0) + '@xterm/addon-fit': + specifier: ^0.10.0 + version: 0.10.0(@xterm/xterm@5.5.0) + '@xterm/addon-unicode11': + specifier: ^0.8.0 + version: 0.8.0(@xterm/xterm@5.5.0) + '@xterm/addon-web-links': + specifier: ^0.11.0 + version: 0.11.0(@xterm/xterm@5.5.0) + '@xterm/xterm': + specifier: ^5.5.0 + version: 5.5.0 arktype: specifier: ^2.1.20 version: 2.1.20 @@ -68,105 +86,129 @@ importers: specifier: ^2.1.1 version: 2.1.1 dotenv: - specifier: ^16.5.0 - version: 16.5.0 + specifier: 17.2.1 + version: 17.2.1 + drizzle-orm: + specifier: 0.44.4 + version: 0.44.4(@libsql/client@0.15.12(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/better-sqlite3@7.6.13)(better-sqlite3@11.10.0) isbot: - specifier: ^5.1.28 - version: 5.1.28 + specifier: 5.1.30 + version: 5.1.30 + jose: + specifier: 6.1.0 + version: 6.1.0 lucide-react: - specifier: ^0.511.0 - version: 0.511.0(react@19.1.0) + specifier: ^0.540.0 + version: 0.540.0(react@19.1.1) mime: specifier: ^4.0.7 version: 4.0.7 openid-client: - specifier: ^6.5.0 - version: 6.5.0 + specifier: 6.7.0 + version: 6.7.0 react: - specifier: 19.1.0 - version: 19.1.0 + specifier: 19.1.1 + version: 19.1.1 react-aria: - specifier: ^3.40.0 - version: 3.40.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: 3.42.0 + version: 3.42.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) react-codemirror-merge: - specifier: ^4.23.12 - version: 4.23.12(@babel/runtime@7.27.3)(@codemirror/autocomplete@6.18.2(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8)(@lezer/common@1.2.3))(@codemirror/language@6.11.0)(@codemirror/lint@6.8.2)(@codemirror/search@6.5.7)(@codemirror/state@6.5.2)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.36.8)(codemirror@6.0.1(@lezer/common@1.2.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: 4.25.1 + version: 4.25.1(@babel/runtime@7.27.3)(@codemirror/autocomplete@6.18.2(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8)(@lezer/common@1.2.3))(@codemirror/language@6.11.0)(@codemirror/lint@6.8.2)(@codemirror/search@6.5.7)(@codemirror/state@6.5.2)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.36.8)(codemirror@6.0.1(@lezer/common@1.2.3))(react-dom@19.1.1(react@19.1.1))(react@19.1.1) react-dom: - specifier: 19.1.0 - version: 19.1.0(react@19.1.0) + specifier: 19.1.1 + version: 19.1.1(react@19.1.1) react-error-boundary: specifier: ^6.0.0 - version: 6.0.0(react@19.1.0) + version: 6.0.0(react@19.1.1) react-icons: specifier: ^5.5.0 - version: 5.5.0(react@19.1.0) + version: 5.5.0(react@19.1.1) react-router: - specifier: ^7.6.1 - version: 7.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: ^7.8.1 + version: 7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) react-router-hono-server: - specifier: ^2.13.0 - version: 2.13.0(patch_hash=6549978df41006e07f1335bfe4ca86224ea36ed40d3f08dfef33143bad54005c)(@react-router/dev@7.6.1(@types/node@22.15.24)(jiti@2.4.2)(lightningcss@1.30.1)(react-router@7.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(terser@5.39.0)(tsx@4.19.4)(typescript@5.8.3)(vite@6.3.5(@types/node@22.15.24)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0))(yaml@2.8.0))(@types/react@19.1.6)(bufferutil@4.0.9)(react-router@7.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(utf-8-validate@5.0.10)(vite@6.3.5(@types/node@22.15.24)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0)) + specifier: 2.21.0 + version: 2.21.0(patch_hash=b68723a36649e2c3bd9e9edcfff3a8bc0fdb48e1cf6d64eba37c04f7bfbb1417)(@hono/node-server@1.19.0(hono@4.7.10))(@react-router/dev@7.8.1(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(react-dom@19.1.1(react@19.1.1))(react-router@7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(rolldown-vite@7.1.4(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1))(terser@5.39.0)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1))(@types/react@19.1.10)(bufferutil@4.0.9)(react-router@7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(rolldown-vite@7.1.4(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1))(utf-8-validate@5.0.10) react-stately: - specifier: ^3.38.0 - version: 3.38.0(react@19.1.0) + specifier: 3.40.0 + version: 3.40.0(react@19.1.1) remix-utils: - specifier: ^8.7.0 - version: 8.7.0(react-router@7.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(zod@3.25.33) + specifier: ^8.8.0 + version: 8.8.0(@oslojs/crypto@1.0.1)(@oslojs/encoding@1.1.0)(react-router@7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1) tailwind-merge: - specifier: ^3.3.0 - version: 3.3.0 + specifier: 3.3.1 + version: 3.3.1 + ulidx: + specifier: 2.4.1 + version: 2.4.1 undici: - specifier: ^7.10.0 - version: 7.10.0 + specifier: 7.14.0 + version: 7.14.0 usehooks-ts: specifier: ^3.1.1 - version: 3.1.1(react@19.1.0) + version: 3.1.1(react@19.1.1) yaml: - specifier: ^2.8.0 - version: 2.8.0 + specifier: 2.8.1 + version: 2.8.1 devDependencies: '@biomejs/biome': - specifier: ^1.9.4 - version: 1.9.4 + specifier: ^2.2.0 + version: 2.2.0 '@react-router/dev': - specifier: ^7.6.1 - version: 7.6.1(@types/node@22.15.24)(jiti@2.4.2)(lightningcss@1.30.1)(react-router@7.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(terser@5.39.0)(tsx@4.19.4)(typescript@5.8.3)(vite@6.3.5(@types/node@22.15.24)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0))(yaml@2.8.0) + specifier: ^7.8.1 + version: 7.8.1(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(react-dom@19.1.1(react@19.1.1))(react-router@7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(rolldown-vite@7.1.4(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1))(terser@5.39.0)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1) '@tailwindcss/vite': - specifier: ^4.1.8 - version: 4.1.8(vite@6.3.5(@types/node@22.15.24)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0)) - '@types/websocket': - specifier: ^1.0.10 - version: 1.0.10 + specifier: ^4.1.12 + version: 4.1.12(rolldown-vite@7.1.4(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1)) + '@types/node': + specifier: ^24.3.0 + version: 24.3.0 + '@typescript/native-preview': + specifier: 7.0.0-dev.20250821.1 + version: 7.0.0-dev.20250821.1 + drizzle-kit: + specifier: ^0.31.4 + version: 0.31.4 + js-yaml: + specifier: ^4.1.0 + version: 4.1.0 lefthook: - specifier: ^1.11.13 - version: 1.11.13 + specifier: ^1.12.3 + version: 1.12.3 postcss: - specifier: ^8.5.4 - version: 8.5.4 + specifier: ^8.5.6 + version: 8.5.6 react-router-dom: - specifier: ^7.6.1 - version: 7.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + specifier: ^7.8.1 + version: 7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) react-scan: - specifier: ^0.3.4 - version: 0.3.4(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react-router-dom@7.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-router@7.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(rollup@4.36.0) + specifier: ^0.4.3 + version: 0.4.3(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react-router-dom@7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-router@7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(rollup@4.46.3) tailwindcss: - specifier: ^4.1.8 - version: 4.1.8 + specifier: ^4.1.12 + version: 4.1.12 tailwindcss-animate: specifier: ^1.0.7 - version: 1.0.7(tailwindcss@4.1.8) + version: 1.0.7(tailwindcss@4.1.12) tailwindcss-react-aria-components: specifier: ^2.0.0 - version: 2.0.0(tailwindcss@4.1.8) + version: 2.0.0(tailwindcss@4.1.12) typescript: - specifier: ^5.8.3 - version: 5.8.3 + specifier: ^5.9.2 + version: 5.9.2 vite: - specifier: ^6.3.5 - version: 6.3.5(@types/node@22.15.24)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0) + specifier: npm:rolldown-vite@7.1.4 + version: rolldown-vite@7.1.4(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.3)(vite@6.3.5(@types/node@22.15.24)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0)) + version: 5.1.4(rolldown-vite@7.1.4(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1))(typescript@5.9.2) + vitepress: + specifier: next + version: 2.0.0-alpha.11(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(postcss@8.5.6)(terser@5.39.0)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1) + vitest: + specifier: ^3.1.3 + version: 3.2.4(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1) packages: @@ -188,14 +230,18 @@ packages: resolution: {integrity: sha512-V42wFfx1ymFte+ecf6iXghnnP8kWTO+ZLXIyZq+1LAXHHvTZdVxicn4yiVYdYMGaCO3tmqub11AorKkv+iodqw==} engines: {node: '>=6.9.0'} - '@babel/core@7.27.3': - resolution: {integrity: sha512-hyrN8ivxfvJ4i0fIJuV4EOlV0WDMz5Ui4StRTgVaAvWeiRCilXgwVvxJKtFQ3TKtHgJscB2YiXKGNJuVwhQMtA==} + '@babel/core@7.28.3': + resolution: {integrity: sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==} engines: {node: '>=6.9.0'} '@babel/generator@7.27.3': resolution: {integrity: sha512-xnlJYj5zepml8NXtjkG0WquFUv8RskFqyFcVgTBp5k+NaA/8uw/K+OSVf8AMGw5e9HKP2ETd5xpK5MLZQD6b4Q==} engines: {node: '>=6.9.0'} + '@babel/generator@7.28.3': + resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} + engines: {node: '>=6.9.0'} + '@babel/helper-annotate-as-pure@7.27.3': resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} engines: {node: '>=6.9.0'} @@ -204,12 +250,16 @@ packages: resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} engines: {node: '>=6.9.0'} - '@babel/helper-create-class-features-plugin@7.27.1': - resolution: {integrity: sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A==} + '@babel/helper-create-class-features-plugin@7.28.3': + resolution: {integrity: sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + '@babel/helper-member-expression-to-functions@7.27.1': resolution: {integrity: sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==} engines: {node: '>=6.9.0'} @@ -218,8 +268,8 @@ packages: resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.27.3': - resolution: {integrity: sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==} + '@babel/helper-module-transforms@7.28.3': + resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -254,8 +304,8 @@ packages: resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.27.3': - resolution: {integrity: sha512-h/eKy9agOya1IGuLaZ9tEUgz+uIRXcbtOhRtUyyMf8JFmn1iT13vnl/IGVWSkdOCG/pC57U4S1jnAabAavTMwg==} + '@babel/helpers@7.28.3': + resolution: {integrity: sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw==} engines: {node: '>=6.9.0'} '@babel/parser@7.27.3': @@ -263,11 +313,15 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - '@babel/plugin-syntax-decorators@7.27.1': - resolution: {integrity: sha512-YMq8Z87Lhl8EGkmb0MwYkt36QnxC+fzCgrl66ereamPlYToRpIk5nUjKUY3QKLWq8mwUB1BgbeXcTJhZOCDg5A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/parser@7.28.0': + resolution: {integrity: sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/parser@7.28.3': + resolution: {integrity: sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==} + engines: {node: '>=6.0.0'} + hasBin: true '@babel/plugin-syntax-jsx@7.27.1': resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} @@ -287,8 +341,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-typescript@7.27.1': - resolution: {integrity: sha512-Q5sT5+O4QUebHdbwKedFBEwRLb02zJ7r4A5Gg2hUoLuU3FjdMcyqcywqUrLCaDsFCxzokf7u9kuy7qz51YUuAg==} + '@babel/plugin-transform-typescript@7.28.0': + resolution: {integrity: sha512-4AEiDEBPIZvLQaWlc9liCavE0xRM0dNca41WtBeM3jgFptfUOSG9z0uteLhq6+3rq+WB6jIvUwKDTpXEHPJ2Vg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -311,59 +365,67 @@ packages: resolution: {integrity: sha512-lId/IfN/Ye1CIu8xG7oKBHXd2iNb2aW1ilPszzGcJug6M8RCKfVNcYhpI5+bMvFYjK7lXIM0R+a+6r8xhHp2FQ==} engines: {node: '>=6.9.0'} + '@babel/traverse@7.28.3': + resolution: {integrity: sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==} + engines: {node: '>=6.9.0'} + '@babel/types@7.27.3': resolution: {integrity: sha512-Y1GkI4ktrtvmawoSq+4FCVHNryea6uR+qUQy0AGxLSsjCX0nVmkYQMBLHDkXZuo5hGx7eYdnIaslsdBFm7zbUw==} engines: {node: '>=6.9.0'} - '@biomejs/biome@1.9.4': - resolution: {integrity: sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==} + '@babel/types@7.28.2': + resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==} + engines: {node: '>=6.9.0'} + + '@biomejs/biome@2.2.0': + resolution: {integrity: sha512-3On3RSYLsX+n9KnoSgfoYlckYBoU6VRM22cw1gB4Y0OuUVSYd/O/2saOJMrA4HFfA1Ff0eacOvMN1yAAvHtzIw==} engines: {node: '>=14.21.3'} hasBin: true - '@biomejs/cli-darwin-arm64@1.9.4': - resolution: {integrity: sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==} + '@biomejs/cli-darwin-arm64@2.2.0': + resolution: {integrity: sha512-zKbwUUh+9uFmWfS8IFxmVD6XwqFcENjZvEyfOxHs1epjdH3wyyMQG80FGDsmauPwS2r5kXdEM0v/+dTIA9FXAg==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [darwin] - '@biomejs/cli-darwin-x64@1.9.4': - resolution: {integrity: sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==} + '@biomejs/cli-darwin-x64@2.2.0': + resolution: {integrity: sha512-+OmT4dsX2eTfhD5crUOPw3RPhaR+SKVspvGVmSdZ9y9O/AgL8pla6T4hOn1q+VAFBHuHhsdxDRJgFCSC7RaMOw==} engines: {node: '>=14.21.3'} cpu: [x64] os: [darwin] - '@biomejs/cli-linux-arm64-musl@1.9.4': - resolution: {integrity: sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==} + '@biomejs/cli-linux-arm64-musl@2.2.0': + resolution: {integrity: sha512-egKpOa+4FL9YO+SMUMLUvf543cprjevNc3CAgDNFLcjknuNMcZ0GLJYa3EGTCR2xIkIUJDVneBV3O9OcIlCEZQ==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - '@biomejs/cli-linux-arm64@1.9.4': - resolution: {integrity: sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==} + '@biomejs/cli-linux-arm64@2.2.0': + resolution: {integrity: sha512-6eoRdF2yW5FnW9Lpeivh7Mayhq0KDdaDMYOJnH9aT02KuSIX5V1HmWJCQQPwIQbhDh68Zrcpl8inRlTEan0SXw==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - '@biomejs/cli-linux-x64-musl@1.9.4': - resolution: {integrity: sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==} + '@biomejs/cli-linux-x64-musl@2.2.0': + resolution: {integrity: sha512-I5J85yWwUWpgJyC1CcytNSGusu2p9HjDnOPAFG4Y515hwRD0jpR9sT9/T1cKHtuCvEQ/sBvx+6zhz9l9wEJGAg==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - '@biomejs/cli-linux-x64@1.9.4': - resolution: {integrity: sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==} + '@biomejs/cli-linux-x64@2.2.0': + resolution: {integrity: sha512-5UmQx/OZAfJfi25zAnAGHUMuOd+LOsliIt119x2soA2gLggQYrVPA+2kMUxR6Mw5M1deUF/AWWP2qpxgH7Nyfw==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - '@biomejs/cli-win32-arm64@1.9.4': - resolution: {integrity: sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==} + '@biomejs/cli-win32-arm64@2.2.0': + resolution: {integrity: sha512-n9a1/f2CwIDmNMNkFs+JI0ZjFnMO0jdOyGNtihgUNFnlmd84yIYY2KMTBmMV58ZlVHjgmY5Y6E1hVTnSRieggA==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [win32] - '@biomejs/cli-win32-x64@1.9.4': - resolution: {integrity: sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==} + '@biomejs/cli-win32-x64@2.2.0': + resolution: {integrity: sha512-Nawu5nHjP/zPKTIryh2AavzTc/KEg4um/MxWdXW0A6P/RZOyIpa7+QSjeXwAwX/utJGaCoXRPWtF3m5U/bB3Ww==} engines: {node: '>=14.21.3'} cpu: [x64] os: [win32] @@ -434,161 +496,329 @@ packages: peerDependencies: react: '>=16.8.0' + '@docsearch/css@4.0.0-beta.7': + resolution: {integrity: sha512-hBIwf14yLasrUcDNS7jrneM1ibFD/JFJVDjdxd1h/LUHx7eyLrS726pKHVr3cTdToNXP/7jrTbnC1MAuDHPoow==} + + '@docsearch/js@4.0.0-beta.7': + resolution: {integrity: sha512-0RJALbDpLMuFy3H/26rjms/qwi5KjsGMN8Lu4k/bs6kBfOWHUN6Dzg/ybj8qB2OLdT2UegsavRIDZKW3QrzQ4Q==} + + '@drizzle-team/brocli@0.10.2': + resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==} + '@drizzle-team/brocli@0.11.0': resolution: {integrity: sha512-hD3pekGiPg0WPCCGAZmusBBJsDqGUR66Y452YgQsZOnkdQ7ViEPKuyP4huUGEZQefp8g34RRodXYmJ2TbCH+tg==} - '@esbuild/aix-ppc64@0.25.5': - resolution: {integrity: sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==} + '@emnapi/core@1.4.5': + resolution: {integrity: sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q==} + + '@emnapi/runtime@1.4.5': + resolution: {integrity: sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==} + + '@emnapi/wasi-threads@1.0.4': + resolution: {integrity: sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g==} + + '@esbuild-kit/core-utils@3.3.2': + resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} + deprecated: 'Merged into tsx: https://tsx.is' + + '@esbuild-kit/esm-loader@2.6.5': + resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==} + deprecated: 'Merged into tsx: https://tsx.is' + + '@esbuild/aix-ppc64@0.25.9': + resolution: {integrity: sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.25.5': - resolution: {integrity: sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==} + '@esbuild/android-arm64@0.18.20': + resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.25.9': + resolution: {integrity: sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.5': - resolution: {integrity: sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==} + '@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.9': + resolution: {integrity: sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.25.5': - resolution: {integrity: sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==} + '@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.9': + resolution: {integrity: sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.5': - resolution: {integrity: sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==} + '@esbuild/darwin-arm64@0.18.20': + resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.25.9': + resolution: {integrity: sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.25.5': - resolution: {integrity: sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==} + '@esbuild/darwin-x64@0.18.20': + resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.9': + resolution: {integrity: sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.25.5': - resolution: {integrity: sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==} + '@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.9': + resolution: {integrity: sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.5': - resolution: {integrity: sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==} + '@esbuild/freebsd-x64@0.18.20': + resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.9': + resolution: {integrity: sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.25.5': - resolution: {integrity: sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==} + '@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.9': + resolution: {integrity: sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.5': - resolution: {integrity: sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==} + '@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.9': + resolution: {integrity: sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.25.5': - resolution: {integrity: sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==} + '@esbuild/linux-ia32@0.18.20': + resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.25.9': + resolution: {integrity: sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.25.5': - resolution: {integrity: sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==} + '@esbuild/linux-loong64@0.18.20': + resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.25.9': + resolution: {integrity: sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.25.5': - resolution: {integrity: sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==} + '@esbuild/linux-mips64el@0.18.20': + resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.25.9': + resolution: {integrity: sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.5': - resolution: {integrity: sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==} + '@esbuild/linux-ppc64@0.18.20': + resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.25.9': + resolution: {integrity: sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.5': - resolution: {integrity: sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==} + '@esbuild/linux-riscv64@0.18.20': + resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.9': + resolution: {integrity: sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.25.5': - resolution: {integrity: sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==} + '@esbuild/linux-s390x@0.18.20': + resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.25.9': + resolution: {integrity: sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.25.5': - resolution: {integrity: sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==} + '@esbuild/linux-x64@0.18.20': + resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.25.9': + resolution: {integrity: sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.5': - resolution: {integrity: sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==} + '@esbuild/netbsd-arm64@0.25.9': + resolution: {integrity: sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.5': - resolution: {integrity: sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==} + '@esbuild/netbsd-x64@0.18.20': + resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.9': + resolution: {integrity: sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.5': - resolution: {integrity: sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==} + '@esbuild/openbsd-arm64@0.25.9': + resolution: {integrity: sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.5': - resolution: {integrity: sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==} + '@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.9': + resolution: {integrity: sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/sunos-x64@0.25.5': - resolution: {integrity: sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==} + '@esbuild/openharmony-arm64@0.25.9': + resolution: {integrity: sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==} + 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.9': + resolution: {integrity: sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.25.5': - resolution: {integrity: sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==} + '@esbuild/win32-arm64@0.18.20': + resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.25.9': + resolution: {integrity: sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.25.5': - resolution: {integrity: sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==} + '@esbuild/win32-ia32@0.18.20': + resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.25.9': + resolution: {integrity: sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.25.5': - resolution: {integrity: sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==} + '@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.9': + resolution: {integrity: sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==} engines: {node: '>=18'} cpu: [x64] os: [win32] - '@fontsource-variable/inter@5.2.5': - resolution: {integrity: sha512-TrWffUAFOnT8zroE9YmGybagoOgM/HjRqMQ8k9R0vVgXlnUh/vnpbGPAS/Caz1KIlOPnPGh6fvJbb7DHbFCncA==} + '@faker-js/faker@9.9.0': + resolution: {integrity: sha512-OEl393iCOoo/z8bMezRlJu+GlRGlsKbUAN7jKB6LhnKoqKve5DXRpalbItIIcwnCjs1k/FOPjFzcA6Qn+H+YbA==} + engines: {node: '>=18.0.0', npm: '>=9.0.0'} + + '@fontsource-variable/inter@5.2.6': + resolution: {integrity: sha512-jks/bficUPQ9nn7GvXvHtlQIPudW7Wx8CrlZoY8bhxgeobNxlQan8DclUJuYF2loYRrGpfrhCIZZspXYysiVGg==} '@formatjs/ecma402-abstract@2.3.4': resolution: {integrity: sha512-qrycXDeaORzIqNhBOx0btnhpD1c+/qFIHAN9znofuMJX6QBwtbrmlpWfD4oiUUD2vJUOIYFA/gYtg2KAMGG7sA==} @@ -605,21 +835,21 @@ packages: '@formatjs/intl-localematcher@0.6.1': resolution: {integrity: sha512-ePEgLgVCqi2BBFnTMWPfIghu6FkbZnnBVhO2sSxvLfrdFw7wCHAHiDoM2h4NRgjbaY7+B7HgOLZGkK187pZTZg==} - '@hono/node-server@1.14.0': - resolution: {integrity: sha512-YUCxJwgHRKSqjrdTk9e4VMGKN27MK5r4+MGPyZTgKH+IYbK+KtYbHeOcPGJ91KGGD6RIQiz2dAHxvjauNhOS8g==} + '@hono/node-server@1.19.0': + resolution: {integrity: sha512-1k8/8OHf5VIymJEcJyVksFpT+AQ5euY0VA5hUkCnlKpD4mr8FSbvXaHblxeTTEr90OaqWzAkQaqD80qHZQKxBA==} engines: {node: '>=18.14.1'} peerDependencies: hono: ^4 - '@hono/node-ws@1.1.1': - resolution: {integrity: sha512-iFJrAw5GuBTstehBzLY2FyW5rRlXmO3Uwpijpm4Liv75owNP/UjZe3KExsLuEK4w+u+xhvHqOoQUyEKWUvyghw==} + '@hono/node-ws@1.2.0': + resolution: {integrity: sha512-OBPQ8OSHBw29mj00wT/xGYtB6HY54j0fNSdVZ7gZM3TUeq0So11GXaWtFf1xWxQNfumKIsj0wRuLKWfVsO5GgQ==} engines: {node: '>=18.14.1'} peerDependencies: '@hono/node-server': ^1.11.1 hono: ^4.6.0 - '@hono/vite-dev-server@0.19.0': - resolution: {integrity: sha512-myMc4Nm0nFQSPaeE6I/a1ODyDR5KpQ4EHodX4Tu/7qlB31GfUemhUH/WsO91HJjDEpRRpsT4Zbg+PleMlpTljw==} + '@hono/vite-dev-server@0.20.1': + resolution: {integrity: sha512-wXikV0C5tPqwH6udA68VTsmnFKWGhIeBuhuxgdGDQIbVNbv5gD0vqKLhx4nG1o4dhksaWPiiSqZV58sTKUzNxA==} engines: {node: '>=18.14.1'} peerDependencies: hono: '*' @@ -631,17 +861,23 @@ packages: wrangler: optional: true - '@internationalized/date@3.8.1': - resolution: {integrity: sha512-PgVE6B6eIZtzf9Gu5HvJxRK3ufUFz9DhspELuhW/N0GuMGMTLvPQNRkHP2hTuP9lblOk+f+1xi96sPiPXANXAA==} + '@iconify-json/simple-icons@1.2.48': + resolution: {integrity: sha512-EACOtZMoPJtERiAbX1De0asrrCtlwI27+03c9OJlYWsly9w1O5vcD8rTzh+kDPjo+K8FOVnq2Qy+h/CzljSKDA==} + + '@iconify/types@2.0.0': + resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} + + '@internationalized/date@3.8.2': + resolution: {integrity: sha512-/wENk7CbvLbkUvX1tu0mwq49CVkkWpkXubGel6birjRPyo6uQ4nQpnq5xZu823zRCwwn82zgHrvgF1vZyvmVgA==} - '@internationalized/message@3.1.7': - resolution: {integrity: sha512-gLQlhEW4iO7DEFPf/U7IrIdA3UyLGS0opeqouaFwlMObLUzwexRjbygONHDVbC9G9oFLXsLyGKYkJwqXw/QADg==} + '@internationalized/message@3.1.8': + resolution: {integrity: sha512-Rwk3j/TlYZhn3HQ6PyXUV0XP9Uv42jqZGNegt0BXlxjE6G3+LwHjbQZAGHhCnCPdaA6Tvd3ma/7QzLlLkJxAWA==} - '@internationalized/number@3.6.2': - resolution: {integrity: sha512-E5QTOlMg9wo5OrKdHD6edo1JJlIoOsylh0+mbf0evi1tHJwMZfJSaBpGtnJV9N7w3jeiioox9EG/EWRWPh82vg==} + '@internationalized/number@3.6.4': + resolution: {integrity: sha512-P+/h+RDaiX8EGt3shB9AYM1+QgkvHmJ5rKi4/59k4sg9g58k9rqsRW0WxRO7jCoHyvVbFRRFKmVTdFYdehrxHg==} - '@internationalized/string@3.2.6': - resolution: {integrity: sha512-LR2lnM4urJta5/wYJVV7m8qk5DrMZmLRTuFhbQO5b9/sKLHgty6unQy1Li4+Su2DWydmB4aZdS5uxBRXIq2aAw==} + '@internationalized/string@3.2.7': + resolution: {integrity: sha512-D4OHBjrinH+PFZPvfCXvG28n2LSykWcJ7GIioQL+ok0LON15SdfoUssoHzzOUmVZLbRoREsQXVzA6r8JKsbP6A==} '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} @@ -651,10 +887,16 @@ packages: resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} engines: {node: '>=18.0.0'} + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + '@jridgewell/gen-mapping@0.3.8': resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} engines: {node: '>=6.0.0'} + '@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'} @@ -663,8 +905,8 @@ packages: resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} engines: {node: '>=6.0.0'} - '@jridgewell/source-map@0.3.6': - resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} '@jridgewell/sourcemap-codec@1.4.15': resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} @@ -672,9 +914,15 @@ packages: '@jridgewell/sourcemap-codec@1.5.0': resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@jridgewell/trace-mapping@0.3.30': + resolution: {integrity: sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==} + '@jsep-plugin/assignment@1.3.0': resolution: {integrity: sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==} engines: {node: '>= 10.16.0'} @@ -699,12 +947,82 @@ packages: '@lezer/lr@1.4.2': resolution: {integrity: sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==} + '@libsql/client@0.15.12': + resolution: {integrity: sha512-JIqB0XsNrqYqBQZuhcgZdTcQoNOoQ5AMF+1yxc7vcZrLtm42QJwRazmTuBfyDwtWASEmVgjxeaLF4NT1iyVX8g==} + + '@libsql/core@0.15.12': + resolution: {integrity: sha512-S3tF6885ZizVjfym7f8SevL2VId/+DzxiKmP5zFbrhA8oMLh2XH8bYXChmhab7o9qUSHx+XjK4jCFpUwR5g+Ig==} + + '@libsql/darwin-arm64@0.5.17': + resolution: {integrity: sha512-WTYG2skZsUnZmfZ2v7WFj7s3/5s2PfrYBZOWBKOnxHA8g4XCDc/4bFDaqob9Q2e88+GC7cWeJ8VNkVBFpD2Xxg==} + cpu: [arm64] + os: [darwin] + + '@libsql/darwin-x64@0.5.17': + resolution: {integrity: sha512-ab0RlTR4KYrxgjNrZhAhY/10GibKoq6G0W4oi0kdm+eYiAv/Ip8GDMpSaZdAcoKA4T+iKR/ehczKHnMEB8MFxA==} + cpu: [x64] + os: [darwin] + + '@libsql/hrana-client@0.7.0': + resolution: {integrity: sha512-OF8fFQSkbL7vJY9rfuegK1R7sPgQ6kFMkDamiEccNUvieQ+3urzfDFI616oPl8V7T9zRmnTkSjMOImYCAVRVuw==} + + '@libsql/isomorphic-fetch@0.3.1': + resolution: {integrity: sha512-6kK3SUK5Uu56zPq/Las620n5aS9xJq+jMBcNSOmjhNf/MUvdyji4vrMTqD7ptY7/4/CAVEAYDeotUz60LNQHtw==} + engines: {node: '>=18.0.0'} + + '@libsql/isomorphic-ws@0.1.5': + resolution: {integrity: sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg==} + + '@libsql/linux-arm-gnueabihf@0.5.17': + resolution: {integrity: sha512-PcASh4k47RqC+kMWAbLUKf1y6Do0q8vnUGi0yhKY4ghJcimMExViBimjbjYRSa+WIb/zh3QxNoXOhQAXx3tiuw==} + cpu: [arm] + os: [linux] + + '@libsql/linux-arm-musleabihf@0.5.17': + resolution: {integrity: sha512-vxOkSLG9Wspit+SNle84nuIzMtr2G2qaxFzW7BhsZBjlZ8+kErf9RXcT2YJQdJYxmBYRbsOrc91gg0jLEQVCqg==} + cpu: [arm] + os: [linux] + + '@libsql/linux-arm64-gnu@0.5.17': + resolution: {integrity: sha512-L8jnaN01TxjBJlDuDTX2W2BKzBkAOhcnKfCOf3xzvvygblxnDOK0whkYwIXeTfwtd/rr4jN/d6dZD/bcHiDxEQ==} + cpu: [arm64] + os: [linux] + + '@libsql/linux-arm64-musl@0.5.17': + resolution: {integrity: sha512-HfFD7TzQtmmTwyQsuiHhWZdMRtdNpKJ1p4tbMMTMRECk+971NFHrj69D64cc2ClVTAmn7fA9XibKPil7WN/Q7w==} + cpu: [arm64] + os: [linux] + + '@libsql/linux-x64-gnu@0.5.17': + resolution: {integrity: sha512-5l3XxWqUPVFrtX0xnZaXwqsXs0BFbP4w6ahRFTPSdXU50YBfUOajFznJRB6bJTMsCvraDSD0IkHhjSNfrE1CuQ==} + cpu: [x64] + os: [linux] + + '@libsql/linux-x64-musl@0.5.17': + resolution: {integrity: sha512-FvSpWlwc+dIeYIFYlsSv+UdQ/NiZWr+SstwVji+QZ//8NnvzwWQU9cgP+Vpps6Qiq4jyYQm9chJhTYOVT9Y3BA==} + cpu: [x64] + os: [linux] + + '@libsql/win32-x64-msvc@0.5.17': + resolution: {integrity: sha512-f5bGH8+3A5sn6Lrqg8FsQ09a1pYXPnKGXGTFiAYlfQXVst1tUTxDTugnuWcJYKXyzDe/T7ccxyIZXeSmPOhq8A==} + cpu: [x64] + os: [win32] + '@marijn/find-cluster-break@1.0.2': resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==} '@mjackson/node-fetch-server@0.2.0': resolution: {integrity: sha512-EMlH1e30yzmTpGLQjlFmaDAjyOeZhng1/XCd7DExR8PNAnG/G1tyruZxEoUe11ClnwGhGrtsdnyyUx1frSzjng==} + '@mjackson/node-fetch-server@0.7.0': + resolution: {integrity: sha512-un8diyEBKU3BTVj3GzlTPA1kIjCkGdD+AMYQy31Gf9JCkfoZzwgJ79GUtHrF2BN3XPNMLpubbzPcxys+a3uZEw==} + + '@napi-rs/wasm-runtime@1.0.3': + resolution: {integrity: sha512-rZxtMsLwjdXkMUGC3WwsPwLNVqVqnTJT6MNIB6e+5fhMcSCPP0AOsNWuMQ5mdCq6HNjs/ZeWAEchpqeprqBD2Q==} + + '@neon-rs/load@0.0.4': + resolution: {integrity: sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw==} + '@npmcli/git@4.1.0': resolution: {integrity: sha512-9hwoB3gStVfa0N31ymBmrX+GuDGdVA/QWShZVqE0HK2Af+7QGGrCTbZia/SW0ImUTjTne7SP91qxDmtXvDHRPQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -717,6 +1035,25 @@ packages: resolution: {integrity: sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + '@oslojs/asn1@1.0.0': + resolution: {integrity: sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA==} + + '@oslojs/binary@1.0.0': + resolution: {integrity: sha512-9RCU6OwXU6p67H4NODbuxv2S3eenuQ4/WFLrsq+K/k682xrznH5EVWA7N4VFk9VYVcbFtKqur5YQQZc0ySGhsQ==} + + '@oslojs/crypto@1.0.1': + resolution: {integrity: sha512-7n08G8nWjAr/Yu3vu9zzrd0L9XnrJfpMioQcvCMxBIiF5orECHe5/3J0jmXRVvgfqMm/+4oxlQ+Sq39COYLcNQ==} + + '@oslojs/encoding@1.1.0': + resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==} + + '@oxc-project/runtime@0.82.2': + resolution: {integrity: sha512-cYxcj5CPn/vo5QSpCZcYzBiLidU5+GlFSqIeNaMgBDtcVRBsBJHZg3pHw999W6nHamFQ1EHuPPByB26tjaJiJw==} + engines: {node: '>=6.9.0'} + + '@oxc-project/types@0.82.2': + resolution: {integrity: sha512-WMGSwd9FsNBs/WfqIOH0h3k1LBdjZJQGYjGnC+vla/fh6HUsu5HzGPerRljiq1hgMQ6gs031YJR12VyP57b/hQ==} + '@pivanov/utils@0.0.2': resolution: {integrity: sha512-q9CN0bFWxWgMY5hVVYyBgez1jGiLBa6I+LkG37ycylPhFvEGOOeaADGtUSu46CaZasPnlY8fCdVJZmrgKb1EPA==} peerDependencies: @@ -727,302 +1064,296 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@preact/signals-core@1.8.0': - resolution: {integrity: sha512-OBvUsRZqNmjzCZXWLxkZfhcgT+Fk8DDcT/8vD6a1xhDemodyy87UJRJfASMuSD8FaAIeGgGm85ydXhm7lr4fyA==} + '@preact/signals-core@1.12.0': + resolution: {integrity: sha512-etWpENXm469RHMWIZGblgWrapbIGcRcbccEGGaLkFez3PjlI3XkBrUtSiNFsIfV/DN16PxMOxbWAZUIaLFyJDg==} '@preact/signals@1.3.2': resolution: {integrity: sha512-naxcJgUJ6BTOROJ7C3QML7KvwKwCXQJYTc5L/b0eEsdYgPB6SxwoQ1vDGcS0Q7GVjAenVq/tXrybVdFShHYZWg==} peerDependencies: preact: 10.x - '@primer/octicons-react@19.15.2': - resolution: {integrity: sha512-bVpBKLm5wOdVlwvjCU/uD4JeeVv5iQWpCO0kgkUYX7yzGgV0mf427kdzqKacYMY5rgcbpmiCKAqFe4j6hXz0ow==} - engines: {node: '>=8'} - peerDependencies: - react: '>=16.3' - - '@react-aria/breadcrumbs@3.5.24': - resolution: {integrity: sha512-CRheGyyM8afPJvDHLXn/mmGG/WAr/z2LReK3DlPdxVKcsOn7g3NIRxAcAIAJQlDLdOiu1SXHiZe6uu2jPhHrxA==} + '@react-aria/breadcrumbs@3.5.27': + resolution: {integrity: sha512-fuXD9nvBaBVZO0Z6EntBlxQD621/2Ldcxz76jFjc4V/jNOq/6BIVQRtpnAYYrSTiW3ZV2IoAyxRWNxQU22hOow==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/button@3.13.1': - resolution: {integrity: sha512-E49qcbBRgofXYfWbli50bepWVNtQBq7qewL9XsX7nHkwPPUe1IRwJOnWZqYMgwwhUBOXfnsR6/TssiXqZsrJdw==} + '@react-aria/button@3.14.0': + resolution: {integrity: sha512-we6z+2GpZO8lGD6EPmYH2S87kLCpU14D2E3tD2vES+SS2sZM2qcm2dUGpeo4+gZqBToLWKEBAGCSlkWEtgS19A==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/calendar@3.8.1': - resolution: {integrity: sha512-S931yi8jJ6CgUQJk+h/PEl+V0n1dUYr9n6nKXmZeU3940to4DauqwvmD9sg67hFHJ0QGroHT/s29yIfa5MfQcg==} + '@react-aria/calendar@3.9.0': + resolution: {integrity: sha512-YxHLqL/LZrgwYGKzlQ96Fgt6gC+Q1L8k56sD51jJAtiD+YtT/pKJfK1zjZ3rtHtPTDYzosJ8vFgOmZNpnKQpXQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/checkbox@3.15.5': - resolution: {integrity: sha512-b9c76DBSYTdacSogbsvjkdZomTo5yhBNMmR5ufO544HQ718Ry8q8JmVbtmF/+dkZN7KGnBQCltzGLzXH0Vc0Zg==} + '@react-aria/checkbox@3.16.0': + resolution: {integrity: sha512-XPaMz1/iVBG6EbJOPYlNtvr+q4f0axJeoIvyzWW3ciIdDSX/3jYuFg/sv/b3OQQl389cbQ/WUBQyWre/uXWVEg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/color@3.0.7': - resolution: {integrity: sha512-3DcYxEWBrcuHSBq0OqCs6GySuy6eOue8/ngC31j/8aMXR+O4mGpXi0wo3rSQGFmGq/4Ri986cI2iGwZOkzpMHg==} + '@react-aria/color@3.1.0': + resolution: {integrity: sha512-95qcCmz5Ss6o1Z4Z7X3pEEQxoUA83qGNQkpjOvobcHbNWKfhvOAsUzdBleOx2NpyBzY16OAnhWR7PJZwR4AqiA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/combobox@3.12.3': - resolution: {integrity: sha512-nCLFSQjOR3r3tB1AURtZKSZhi2euBMw0QxsIjnMVF73BQOfwfHMrIFctNULbL070gEnXofzeBd3ykJQpnsGH+Q==} + '@react-aria/combobox@3.13.0': + resolution: {integrity: sha512-eBa8aWcL3Ar/BvgSaqYDmNQP70LPZ7us2myM31QQt2YDRptqGHd44wzXCts9SaDVIeMVy+AEY2NkuxrVE6yNrw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/datepicker@3.14.3': - resolution: {integrity: sha512-gDc+bM0EaY3BuIW8IJu/ARJV78bRpOaHp+B08EW4N2qJvc7Bs+EmGLnxMrB6Ny+YxNxsYdQRA/FqiytVYOEk8w==} + '@react-aria/datepicker@3.15.0': + resolution: {integrity: sha512-AONeLj7sMKz4JmzCu4bhsqwcNFXCSWoaBhi4wOJO9+WYmxudn5mSI9ez8NMCVn+s5kcYpyvzrrAFf/DvQ4UDgw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/dialog@3.5.25': - resolution: {integrity: sha512-hVP/TvjUnPgckg4qibc/TDH54O+BzW95hxApxBw1INyViRm95PxdCQDqBdQ/ZW7Gv6J2aUBCGihX7kINPf70ow==} + '@react-aria/dialog@3.5.28': + resolution: {integrity: sha512-S9dgdFBQc9LbhyBiHwGPSATwtvsIl6h+UnxDJ4oKBSse+wxdAyshbZv2tyO5RFbe3k73SAgU7yKocfg7YyRM0A==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/disclosure@3.0.5': - resolution: {integrity: sha512-YrazXoIzVq48soJpVMb2Iq/CB+lglwfKLsml5UfpE0MGlJJ/jWtIZtodqQ8ree1YguMNTvtESazTlMo7ZLsasQ==} + '@react-aria/disclosure@3.0.7': + resolution: {integrity: sha512-g17smH+5v7B6JijzN20rIRUmE2N8owYK/4blR6tIyS+oLIHr+Crkt1ErNoUWynibj2/4gDd9KGrKyzwB4vxK9g==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/dnd@3.9.3': - resolution: {integrity: sha512-Sjb+UQxG58/paOZXsVKiqLautV4FyILr3tLxMG4Q04QOUzatqlz91APt7RsVMdizk6bVB7Lg74AEypHbXVzhDQ==} + '@react-aria/dnd@3.11.0': + resolution: {integrity: sha512-jr47o7Fy55eYjSKWqRyuWKPnynpgC4cE9YXnYg5xa+1woRefIF2IyteOxgSHeX16+6ef2UDSsvC61T3gS6NWxQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/focus@3.20.3': - resolution: {integrity: sha512-rR5uZUMSY4xLHmpK/I8bP1V6vUNHFo33gTvrvNUsAKKqvMfa7R2nu5A6v97dr5g6tVH6xzpdkPsOJCWh90H2cw==} + '@react-aria/focus@3.21.0': + resolution: {integrity: sha512-7NEGtTPsBy52EZ/ToVKCu0HSelE3kq9qeis+2eEq90XSuJOMaDHUQrA7RC2Y89tlEwQB31bud/kKRi9Qme1dkA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/form@3.0.16': - resolution: {integrity: sha512-N1bDsJfmnyDesayK0Ii6UPH6JWiF6Wz8WSveQ2y5004XHoIWn5LpWmOqnRedvyw4Yedw33schlvrY7ENEwMdpg==} + '@react-aria/form@3.1.0': + resolution: {integrity: sha512-aDAOZafrn0V8e09mDAtCvc+JnpnkFM9X8cbI5+fdXsXAA+JxO+3uRRfnJHBlIL0iLc4C4OVWxBxWToV95pg1KA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/grid@3.14.0': - resolution: {integrity: sha512-/tJB7xnSruORJ8tlFHja4SfL8/EW5v4cBLiyD5z48m7IdG33jXR8Cv4Pi5uQqs8zKdnpqZ1wDG3GQxNDwZavpg==} + '@react-aria/grid@3.14.3': + resolution: {integrity: sha512-O4Ius5tJqKcMGfQT6IXD4MnEOeq6f/59nKmfCLTXMREFac/oxafqanUx3zrEVYbaqLOjEmONcd8S61ptQM6aPg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/gridlist@3.13.0': - resolution: {integrity: sha512-RHURMo063qbbA8WXCJxGL+5xmSx6yW7Z/V2jycrVcZFOYqj2EgU953aVjpaT/FSyH8/AEioU9oE64YmiEfWUUA==} + '@react-aria/gridlist@3.13.3': + resolution: {integrity: sha512-U2x/1MpdrAgK/vay2s2nVSko4WysajlMS+L8c18HE/ig2to+C8tCPWH2UuK4jTQWrK5x/PxTH+/yvtytljnIuQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/i18n@3.12.9': - resolution: {integrity: sha512-Fim0FLfY05kcpIILdOtqcw58c3sksvmVY8kICSwKCuSek4wYfwJdU28p/sRptw4adJhqN8Cbssvkf/J8zL2GgA==} + '@react-aria/i18n@3.12.11': + resolution: {integrity: sha512-1mxUinHbGJ6nJ/uSl62dl48vdZfWTBZePNF/wWQy98gR0qNFXLeusd7CsEmJT1971CR5i/WNYUo1ezNlIJnu6A==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/interactions@3.25.1': - resolution: {integrity: sha512-ntLrlgqkmZupbbjekz3fE/n3eQH2vhncx8gUp0+N+GttKWevx7jos11JUBjnJwb1RSOPgRUFcrluOqBp0VgcfQ==} + '@react-aria/interactions@3.25.4': + resolution: {integrity: sha512-HBQMxgUPHrW8V63u9uGgBymkMfj6vdWbB0GgUJY49K9mBKMsypcHeWkWM6+bF7kxRO728/IK8bWDV6whDbqjHg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/label@3.7.18': - resolution: {integrity: sha512-Ht9D+xkI2Aysn+JNiHE+UZT4FUOGPF7Lfrmp7xdJCA/tEqqF3xW/pAh+UCNOnnWmH8jTYnUg3bCp4G6GQUxKCQ==} + '@react-aria/label@3.7.20': + resolution: {integrity: sha512-Hw7OsC2GBnjptyW1lC1+SNoSIZA0eIh02QnNDr1XX2S+BPfn958NxoI7sJIstO/TUpQVNqdjEN/NI6+cyuJE6g==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/landmark@3.0.3': - resolution: {integrity: sha512-mcmHijInDZZY3W9r0SeRuXsHW8Km9rBWKB3eoBz+PVuyJYMuabhQ2mUB5xTbqbnV++Srr7j/59g+Lbw5gAN4lw==} + '@react-aria/landmark@3.0.5': + resolution: {integrity: sha512-klUgRGQyTv5qWFQ0EMMLBOLa87qSTGjWoiMvytL9EgJCACkn/OzNMPbqVSkMADvadDyWCMWFYWvfweLxl3T5yw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/link@3.8.1': - resolution: {integrity: sha512-ujq7+XIP7OXHu7m2NObvHsl41B/oIBAYI0D+hsxEQo3+x6Q/OUxp9EX2sX4d7TBWvchFmhr6jJdER0QMmeSO/A==} + '@react-aria/link@3.8.4': + resolution: {integrity: sha512-7cPRGIo7x6ZZv1dhp2xGjqLR1snazSQgl7tThrBDL5E8f6Yr7SVpxOOK5/EBmfpFkhkmmXEO/Fgo/GPJdc6Vmw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/listbox@3.14.4': - resolution: {integrity: sha512-bW3D7KcnQIF77F3zDRMIGQ6e5e1wHTNUtbKJLE423u1Dhc7K2x0pksir0gLGwElhiBW544lY1jv3kFLOeKa6ng==} + '@react-aria/listbox@3.14.7': + resolution: {integrity: sha512-U5a+AIDblaeQTIA1MDFUaYIKoPwPNAuY7SwkuA5Z7ClDOeQJkiyExmAoKcUXwUkrLULQcbOPKr401q38IL3T7Q==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/live-announcer@3.4.2': - resolution: {integrity: sha512-6+yNF9ZrZ4YJ60Oxy2gKI4/xy6WUv1iePDCFJkgpNVuOEYi8W8czff8ctXu/RPB25OJx5v2sCw9VirRogTo2zA==} + '@react-aria/live-announcer@3.4.4': + resolution: {integrity: sha512-PTTBIjNRnrdJOIRTDGNifY2d//kA7GUAwRFJNOEwSNG4FW+Bq9awqLiflw0JkpyB0VNIwou6lqKPHZVLsGWOXA==} - '@react-aria/menu@3.18.3': - resolution: {integrity: sha512-D0C4CM/QaxhCo2pLWNP+nfgnAeaSZWOdPMo9pnH/toRsoeTbnD6xO1hLhYsOx5ge+hrzjQvthjUrsjPB1AM/BQ==} + '@react-aria/menu@3.19.0': + resolution: {integrity: sha512-VLUGbZedKJvK2OFWEpa86GPIaj9QcWox/R9JXmNk6nyrAz/V46OBQENdliV26PEdBZgzrVxGvmkjaH7ZsN/32Q==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/meter@3.4.23': - resolution: {integrity: sha512-FgmB/+cTE/sz+wTpTSmj9hFXw4nzfMUJGvXIePnF6f5Gx6J/U7aLEvNk7sXCp76apOu8k7ccma1nCsEvj74x7w==} + '@react-aria/meter@3.4.25': + resolution: {integrity: sha512-6IqOnwuEt8z6UDy8Ru3ZZRZIUiELD0N3Wi/udMfR8gz4oznutvnRCMpRXkVVaVLYQfRglybu2/Lxfe+rq8WiRg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/numberfield@3.11.14': - resolution: {integrity: sha512-UvhPlRwVmbNEBBqfgL41P10H1jL4C7P2hWqsVw72tZQJl5k5ujeOzRWk8mkmg+D4FCZvv4iSPJhmyEP8HkgsWg==} + '@react-aria/numberfield@3.12.0': + resolution: {integrity: sha512-JkgkjYsZ9lN5m3//X3buOKVrA/QJEeeXJ+5T5r6AmF29YdIhD1Plf5AEOWoRpZWQ25chH7FI/Orsf4h3/SLOpg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/overlays@3.27.1': - resolution: {integrity: sha512-wepzwNLkgem6kVlLm6yk7zNIMAt0KPy8vAWlxdfpXWD/hBI30ULl71gL/BxRa5EYG1GMvlOwNti3whzy9lm3eQ==} + '@react-aria/overlays@3.28.0': + resolution: {integrity: sha512-qaHahAXTmxXULgg2/UfWEIwfgdKsn27XYryXAWWDu2CAZTcbI+5mGwYrQZSDWraM6v5PUUepzOVvm7hjTqiMFw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/progress@3.4.23': - resolution: {integrity: sha512-uSQBVY64k+CCey82U67KyWnjAfuuHF0fG6y76kIB8GHI8tGfd1NkXo4ioaxiY0SS+BYGqwqJYYMUzQMpOBTN1A==} + '@react-aria/progress@3.4.25': + resolution: {integrity: sha512-KD9Gow+Ip6ZCBdsarR+Hby3c4d99I6L95Ruf7tbCh4ut9i9Dbr+x99OwhpAbT0g549cOyeIqxutPkT+JuzrRuA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/radio@3.11.3': - resolution: {integrity: sha512-o10G8RUuHnAGZYzkc5PQw7mj4LMZqmGkoihDeHF2NDa9h44Ce5oeCPwRvCKYbumZDOyDY15ZIZhTUzjHt2w6fA==} + '@react-aria/radio@3.12.0': + resolution: {integrity: sha512-//0zZUuHtbm6uZR9+sNRNzVcQpjJKjZj57bDD0lMNj3NZp/Tkw+zXIFy6j1adv3JMe6iYkzEgaB7YRDD1Fe/ZA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/searchfield@3.8.4': - resolution: {integrity: sha512-WnAvU9ct8+Asb8FFhGw6bggBmRaPe9qZPgYacenmRItwN+7UVTwEBVB9umO2bN3PLGm3CKgop10znd6ATiAbJA==} + '@react-aria/searchfield@3.8.7': + resolution: {integrity: sha512-15jfALRyz5EAA5tvIELVfUlqTFdk8oG442OiS3Xq/jJij8uKRzwUdnL57EVTFYyg+VMLp/t5wX+obXYcRG+kdQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/select@3.15.5': - resolution: {integrity: sha512-2v8QmcPsZzlOjc/zsLbMcKeMKZoa+FZboxfjq4koUXtuaLhgopENChkfPLaXEGxqsejANs4dAoqiOiwwrGAaLQ==} + '@react-aria/select@3.16.0': + resolution: {integrity: sha512-UkiLSxMOKWW24qnhZdOObkFLpauvmu0T6wuPXbdQgwlis/UeLzDamPAWc6loRFJgHCpJftaaaWVQG3ks4NX7ew==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/selection@3.24.1': - resolution: {integrity: sha512-nHUksgjg92iHgseH9L+krk9rX19xGJLTDeobKBX7eoAXQMqQjefu+oDwT0VYdI/qqNURNELE/KPZIVLC4PB81w==} + '@react-aria/selection@3.25.0': + resolution: {integrity: sha512-Q3U0Ya0PTP/TR0a2g+7YEbFVLphiWthmEkHyvOx9HsKSjE8w9wXY3C14DZWKskB/BBrXKJuOWxBDa0xhC83S+A==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/separator@3.4.9': - resolution: {integrity: sha512-5ZKVQ/5I2+fw8WyVCQLGjQKsMKlTIieLPf8NvdC24a+pmiUluyUuqfPYdI8s6lcnjG0gbOzZB+jKvDRQbIvMPQ==} + '@react-aria/separator@3.4.11': + resolution: {integrity: sha512-WwYEb7Wga4YQvlEwbzlVcVkfByullcORKtIe30pmh1YkTRRVJhbRPaE/mwcSMufbfjSYdtDavxmF+WY7Tdb9/A==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/slider@3.7.19': - resolution: {integrity: sha512-GONrMMz9zsx0ySbUTebWdqRjAuu6EEW+lLf3qUzcqkIYR8QZVTS8RLPt7FmGHKCTDIaBs8D2yv9puIfKAo1QAA==} + '@react-aria/slider@3.8.0': + resolution: {integrity: sha512-D7Sa7q21cV3gBid7frjoYw6924qYqNdJn2oai1BEemHSuwQatRlm1o2j+fnPTy9sYZfNOqXYnv5YjEn0o1T+Gw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/spinbutton@3.6.15': - resolution: {integrity: sha512-dVKaRgrSU2utxCd4kqAA8BPrC1PVI1eiJ8gvlVbg25LbwK4dg1WPXQUK+80TbrJc9mOEooPiJvzw59IoQLMNRg==} + '@react-aria/spinbutton@3.6.17': + resolution: {integrity: sha512-gdGc3kkqpvFUd9XsrhPwQHMrG2TY0LVuGGgjvaZwF/ONm9FMz393ogCM0P484HsjU50hClO+yiRRgNjdwDIzPQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/ssr@3.9.8': - resolution: {integrity: sha512-lQDE/c9uTfBSDOjaZUJS8xP2jCKVk4zjQeIlCH90xaLhHDgbpCdns3xvFpJJujfj3nI4Ll9K7A+ONUBDCASOuw==} + '@react-aria/ssr@3.9.10': + resolution: {integrity: sha512-hvTm77Pf+pMBhuBm760Li0BVIO38jv1IBws1xFm1NoL26PU+fe+FMW5+VZWyANR6nYL65joaJKZqOdTQMkO9IQ==} engines: {node: '>= 12'} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/switch@3.7.3': - resolution: {integrity: sha512-tFdJmcHaLgW23cS2R713vcJdVbsjDTRk8OLdG/sMziPBY3C00/exuSIb57xTS7KrE0hBYfnLJQTcmDNqdM8+9Q==} + '@react-aria/switch@3.7.6': + resolution: {integrity: sha512-C+Od8hZNZCf3thgtZnZKzHl5b/63Q9xf+Pw6ugLA1qaKazwp46x1EwUVVqVhfAeVhmag++eHs8Lol5ZwQEinjQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/table@3.17.3': - resolution: {integrity: sha512-hs3akyNMeeAPIfa+YKMxJyupSjywW5OGzJtOw/Z0j6pV8KXSeMEXNYkSuJY+m5Q1mdunoiiogs0kE3B0r2izQA==} + '@react-aria/table@3.17.6': + resolution: {integrity: sha512-PSEaeKOIazVEaykeTLudPbDLytJgOPLZJalS/xXY0/KL+Gi0Olchmz4tvS0WBe87ChmlVi6GQqU+stk23aZVWg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/tabs@3.10.3': - resolution: {integrity: sha512-TYfwaRrI0mQMefmoHeTKXdczpb53qpPr+3nnveGl+BocG94wmjIqK6kncboVbPdykgQCIAMd2d9GFpK01+zXrA==} + '@react-aria/tabs@3.10.6': + resolution: {integrity: sha512-L8MaE7+bu6ByDOUxNPpMMYxdHULhKUfBoXdsSsXqb1z3QxdFW2zovfag0dvpyVWB6ALghX2T0PlTUNqaKA5tGw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/tag@3.6.0': - resolution: {integrity: sha512-OkLyFYTFVUYB339eugw2r6vIcrWq47O15x4sKNkDUo6YBx9ci9tdoib4DlzwuiiKVr/vmw1WMow6VK4zOtuLng==} + '@react-aria/tag@3.7.0': + resolution: {integrity: sha512-nU0Sl7u82RBn8XLNyrjkXhtw+xbJD9fyjesmDu7zeOq78e4eunKW7OZ/9+t+Lyu5wW+B7vKvetIgkdXKPQm3MA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/textfield@3.17.3': - resolution: {integrity: sha512-p/Z0fyE0CnzIrnCf42gxeSCNYon7//XkcbPwUS4U9dz2VLk2GnEn9NZXPYgTp+08ebQEn0pB1QIchX79yFEguw==} + '@react-aria/textfield@3.18.0': + resolution: {integrity: sha512-kCwbyDHi2tRaD/OjagA3m3q2mMZUPeXY7hRqhDxpl2MwyIdd+/PQOJLM8tZr5+m2zvBx+ffOcjZMGTMwMtoV5w==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/toast@3.0.3': - resolution: {integrity: sha512-7HWTKIVwS1JFC8//BQbRtGFaAdq4SljvI3yI5amLr90CyVM0sugTtcSX9a8BPnp1j9ao+6bmOi/wrV48mze1PA==} + '@react-aria/toast@3.0.6': + resolution: {integrity: sha512-PoCLWoZzdHIMYY0zIU3WYsHAHPS52sN1gzGRJ+cr5zogU8wwg8lwFZCvs/yql0IhQLsO930zcCXWeL/NsCMrlA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/toggle@3.11.3': - resolution: {integrity: sha512-S6ShToNR6TukRJh8qDdyl9b2Bcsx43eurUB5USANn4ycPov8+bIxQnxiknjssZx7jD8vX4jruuNh7BjFbNsGFw==} + '@react-aria/toggle@3.12.0': + resolution: {integrity: sha512-JfcrF8xUEa2CbbUXp+WQiTBVwSM/dm21v5kueQlksvLfXG6DGE8/zjM6tJFErrFypAasc1JXyrI4dspLOWCfRA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/toolbar@3.0.0-beta.16': - resolution: {integrity: sha512-TnNvtxADalMzs9Et51hWPpGyiHr1dt++UYR7pIo1H7vO+HwXl6uH4HxbFDS5CyV69j2cQlcGrkj13LoWFkBECw==} + '@react-aria/toolbar@3.0.0-beta.19': + resolution: {integrity: sha512-G4sgtOUTUUJHznXlpKcY64SxD2gKOqIQXZXjWTVcY/Q5hAjl8gbTt5XIED22GmeIgd/tVl6+lddGj6ESze4vSg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/tooltip@3.8.3': - resolution: {integrity: sha512-8JHRqffH5vUw7og6mlCRzb4h95/R5RpOxGFfEGw7aami14XMo6tZg7wMgwDUAEiVqNerRWYaw+tk7nCUQXo1Sg==} + '@react-aria/tooltip@3.8.6': + resolution: {integrity: sha512-lW/PegiswGLlCP0CM4FH2kbIrEe4Li2SoklzIRh4nXZtiLIexswoE5/5af7PMtoMAl31or6fHZleVLzZD4VcfA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/tree@3.0.3': - resolution: {integrity: sha512-kdA0CCUD8luCrXZFo0rX1c0LI8jovYMuWsPiI5OpmiEKGA5HaVFFW/H9t/XSYdVc/JO08zbeZ/WacTusKeOT3Q==} + '@react-aria/tree@3.1.2': + resolution: {integrity: sha512-duyAoxSIzgIEP1UvCivx8uY7GZxo8nhfSsHW77GO+UMgwBjWkrvHnYQXBYbLq1GLqLxuDN+U7SFe8Az7+HcbOg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/utils@3.29.0': - resolution: {integrity: sha512-jSOrZimCuT1iKNVlhjIxDkAhgF7HSp3pqyT6qjg/ZoA0wfqCi/okmrMPiWSAKBnkgX93N8GYTLT3CIEO6WZe9Q==} + '@react-aria/utils@3.30.0': + resolution: {integrity: sha512-ydA6y5G1+gbem3Va2nczj/0G0W7/jUVo/cbN10WA5IizzWIwMP5qhFr7macgbKfHMkZ+YZC3oXnt2NNre5odKw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-aria/visually-hidden@3.8.23': - resolution: {integrity: sha512-D37GHtAcxCck8BtCiGTNDniGqtldJuN0cRlW1PJ684zM4CdmkSPqKbt5IUKUfqheS9Vt7HxYsj1VREDW+0kaGA==} + '@react-aria/visually-hidden@3.8.26': + resolution: {integrity: sha512-Lz36lTVaQbv5Kn74sPv0l9SnLQ5XHKCoq2zilP14Eb4QixDIqR7Ovj43m+6wi9pynf29jtOb/8D/9jrTjbmmgw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-router/dev@7.6.1': - resolution: {integrity: sha512-E4pzxViSQ1Z4EPUz1p47ldm+qIbzfFbJtbXvxi+KSidpftf/ttjr+DtLEiTEdIqZTYv8trBASRtV6C5hn9GZQQ==} + '@react-router/dev@7.8.1': + resolution: {integrity: sha512-ESFe7DbMvCvl7e8N7L9NmI64VJGNCc60/VX1DUZYw/jFfzA5098/6D1aUojcxyVYBbMbVTfw0xmEvD4CsJzy1Q==} engines: {node: '>=20.0.0'} hasBin: true peerDependencies: - '@react-router/serve': ^7.6.1 - react-router: ^7.6.1 + '@react-router/serve': ^7.8.1 + react-router: ^7.8.1 typescript: ^5.1.0 - vite: ^5.1.0 || ^6.0.0 + vite: ^5.1.0 || ^6.0.0 || ^7.0.0 wrangler: ^3.28.2 || ^4.0.0 peerDependenciesMeta: '@react-router/serve': @@ -1032,286 +1363,362 @@ packages: wrangler: optional: true - '@react-router/node@7.6.1': - resolution: {integrity: sha512-RZ9IatEarjF1GSHV+OUHNaRKtfp27UXP2J8dVdax6K/UXHc45k3t9Zp6splqT88wob4CUt4loDQw/7srNvsQhQ==} + '@react-router/node@7.8.1': + resolution: {integrity: sha512-NC8eVQir2CRdcokzyyBsfxdq85Yu8B5XynDt581CzjBOreHAFfqIsNjGnqmg+aqBLiknQb2De9fH/TjyeYNeqw==} engines: {node: '>=20.0.0'} peerDependencies: - react-router: 7.6.1 + react-router: 7.8.1 typescript: ^5.1.0 peerDependenciesMeta: typescript: optional: true - '@react-stately/calendar@3.8.1': - resolution: {integrity: sha512-pTPRmPRD/0JeKhCRvXhVIH/yBimtIHnZGUxH12dcTl3MLxjXQDTn6/LWK0s4rzJcjsC+EzGUCVBBXgESb7PUlw==} + '@react-stately/calendar@3.8.3': + resolution: {integrity: sha512-HTWD6ZKQcXDlvj6glEEG0oi2Tpkaw19y5rK526s04zJs894wFqM9PK0WHthEYqjCeQJ5B/OkyG19XX4lENxnZw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/checkbox@3.6.14': - resolution: {integrity: sha512-eGl0GP/F/nUrA33gDCYikyXK+Yer7sFOx8T4EU2AF4E8n1VQIRiVNaxDg7Ar6L3CMKor01urppFHFJsBUnSgyw==} + '@react-stately/checkbox@3.7.0': + resolution: {integrity: sha512-opViVhNvxFVHjXhM4nA/E03uvbLazsIKloXX9JtyBCZAQRUag17dpmkekfIkHvP4o7z7AWFoibD8JBFV1IrMcQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/collections@3.12.4': - resolution: {integrity: sha512-H+47fRkwYX2/BdSA+NLTzbR+8QclZXyBgC7tHH3dzljyxNimhrMDnbmk520nvGCebNf3nuxtFHq9iVTLpazSVA==} + '@react-stately/collections@3.12.6': + resolution: {integrity: sha512-S158RKWGZSodbJXKZDdcnrLzFxzFmyRWDNakQd1nBGhSrW2JV8lDn9ku5Og7TrjoEpkz//B2oId648YT792ilw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/color@3.8.5': - resolution: {integrity: sha512-yi1MQAbYuAYKu0AtMO+mWQWlWk6OzGMa9j4PGtQN2PI5Uv1NylWOvdquxbUJ4GUAuSYNopYG8Ci9MZMwtito8w==} + '@react-stately/color@3.9.0': + resolution: {integrity: sha512-9eG0gDxVIu+A+DTdfwyYuU4pR788pVdq1Snpk8el787OsOb5WiuT4C4VWJb5Qbrq2PiFhhZmxuJXpzz4B1gW3A==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/combobox@3.10.5': - resolution: {integrity: sha512-27SkClMqbMAKuVnmXhYzYisbLfzV7MO/DEiqWO4/3l+PZ+whL7Wi/Ek7Wqlfluid/y4pN4EkHCKNt4HJ2mhORQ==} + '@react-stately/combobox@3.11.0': + resolution: {integrity: sha512-W9COXdSOC+uqCZrRHJI0K7emlPb/Tx4A89JHWBcFmiAk+hs1Cnlyjw3aaqEiT8A8/HxDNMO9QcfisWC1iNyE9A==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/data@3.13.0': - resolution: {integrity: sha512-7LYPxVbWB6tvmLYKO19H5G5YtXV6eKCSXisOUiL9fVnOcGOPDK5z310sj9TP5vaX7zVPtwy0lDBUrZuRfhvQIQ==} + '@react-stately/data@3.13.2': + resolution: {integrity: sha512-xdCqR8dJ3cnvO8EdCeuQ335dOuBqEV4z/3LnpxmR11gyn8dWwtY5O794g5+AS0KqCgd9W0v7iBrRywq5UT2pCA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/datepicker@3.14.1': - resolution: {integrity: sha512-ad3IOrRppy/F8FZpznGacsaWWHdzUGZ4vpymD+y6TYeQ+RQvS9PLA5Z1TanH9iqLZgkf6bvVggJFg/hhDh2hmg==} + '@react-stately/datepicker@3.15.0': + resolution: {integrity: sha512-OuBx+h802CoANy6KNR6XuZCndiyRf9vpB32CYZX86nqWy21GSTeT73G41ze5cAH88A/6zmtpYK24nTlk8bdfWA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/disclosure@3.0.4': - resolution: {integrity: sha512-RE4hYnDYgsd5bi01z/hZHShRGKxW++xCA6PCufxtipc1sxZGUF4Sb1tTSIxOjh1dq5iDVdrAQAS6en0weaGgLA==} + '@react-stately/disclosure@3.0.6': + resolution: {integrity: sha512-tR2IzcS7JbgAXy9U0gxQQGRHKIqgC7nj3xsY5U9QGCE1BKzwf/84iDE63AXpLRje31yuYzwXsJs6UrE9wSjb3g==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/dnd@3.5.4': - resolution: {integrity: sha512-YkvkehpsSeGZPH7S7EYyLchSxZPhzShdf9Zjh6UAsM7mAcxjRsChMqsf6zuM+l0jgMo40Ka1mvwDYegz92Qkyg==} + '@react-stately/dnd@3.6.1': + resolution: {integrity: sha512-cbBLptL+tpXFQ0oU0v6GBtSvzP0doohyhCIr8pOzk6aYutFI0c5JZw8LGoKN/GLfXkm7iPyrfCKeKqDlDTHCzQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/flags@3.1.1': - resolution: {integrity: sha512-XPR5gi5LfrPdhxZzdIlJDz/B5cBf63l4q6/AzNqVWFKgd0QqY5LvWJftXkklaIUpKSJkIKQb8dphuZXDtkWNqg==} + '@react-stately/flags@3.1.2': + resolution: {integrity: sha512-2HjFcZx1MyQXoPqcBGALwWWmgFVUk2TuKVIQxCbRq7fPyWXIl6VHcakCLurdtYC2Iks7zizvz0Idv48MQ38DWg==} - '@react-stately/form@3.1.4': - resolution: {integrity: sha512-A6GOaZ9oEIo5/XOE+JT9Z8OBt0osIOfes4EcIxGS1C9ght/Smg0gNcIJ2/Wle8qmro4RoJcza2yJ+EglVOuE0w==} + '@react-stately/form@3.2.0': + resolution: {integrity: sha512-PfefxvT7/BIhAGpD4oQpdcxnL8cfN0ZTQxQq+Wmb9z3YzK1oM8GFxb8eGdDRG71JeF8WUNMAQVZFhgl00Z/YKg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/grid@3.11.2': - resolution: {integrity: sha512-P0vfK5B1NW8glYD6QMrR2X/7UMXx2J8v48QIQV6KgLZjFbyXhzRb+MY0BoIy4tUfJL0yQU2GKbKKVSUIQxbv0g==} + '@react-stately/grid@3.11.4': + resolution: {integrity: sha512-oaXFSk2eM0PJ0GVniGA0ZlTpAA0AL0O4MQ7V3cHqZAQbwSO0n2pT31GM0bSVnYP/qTF5lQHo3ECmRQCz0fVyMw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/list@3.12.2': - resolution: {integrity: sha512-XPGvdPidOV4hnpmaUNc4C/1jX7ZhBwmAI9p6bEXDA3du3XrWess6MWcaQvPxXbrZ6ZX8/OyOC2wp7ixJoJRGyA==} + '@react-stately/list@3.12.4': + resolution: {integrity: sha512-r7vMM//tpmagyNlRzl2NFPPtx+az5R9pM6q7aI4aBf6/zpZt2eX2UW5gaDTGlkQng7r6OGyAgJD52jmGcCJk7Q==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/menu@3.9.4': - resolution: {integrity: sha512-sqYcSBuTEtCebZuByUou2aZzwlnrrOlrvmGwFNJy49N3LXXXPENCcCERuWa8TE9eBevIVTQorBZlID6rFG+wdQ==} + '@react-stately/menu@3.9.6': + resolution: {integrity: sha512-2rVtgeVAiyr7qL8BhmCK/4el49rna/5kADRH5NfPdpXw8ZzaiiHq2RtX443Txj7pUU82CJWQn+CRobq7k6ZTEw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/numberfield@3.9.12': - resolution: {integrity: sha512-E56RuRRdu/lzd8e5aEifP4n8CL/as0sZqIQFSyMv/ZUIIGeksqy+zykzo01skaHKY8u2NixrVHPVDtvPcRuooA==} + '@react-stately/numberfield@3.10.0': + resolution: {integrity: sha512-6C8ML4/e2tcn01BRNfFLxetVaWwz0n0pVROnVpo8p761c6lmTqohqEMNcXCVNw9H0wsa1hug2a1S5PcN2OXgag==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/overlays@3.6.16': - resolution: {integrity: sha512-+Ve/TBlUNg3otVC4ZfCq1a8q8FwC7xNebWkVOCGviTqiYodPCGqBwR9Z1xonuFLF/HuQYqALHHTOZtxceU+nVQ==} + '@react-stately/overlays@3.6.18': + resolution: {integrity: sha512-g8n2FtDCxIg2wQ09R7lrM2niuxMPCdP17bxsPV9hyYnN6m42aAKGOhzWrFOK+3phQKgk/E1JQZEvKw1cyyGo1A==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/radio@3.10.13': - resolution: {integrity: sha512-q7UKcVYY7rqpxKfYRzvKVEqFhxElDFX2c+xliZQtjXuSexhxRb2xjEh+bDkhzbXzrJkrBT6VmE/rSYPurC3xTw==} + '@react-stately/radio@3.11.0': + resolution: {integrity: sha512-hsCmKb9e/ygmzBADFYIGpEQ43LrxjWnlKESgxphvlv0Klla4d6XLAYSFOTX1kcjSztpvVWrdl4cIfmKVF1pz2g==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/searchfield@3.5.12': - resolution: {integrity: sha512-RC3QTEPVNUbgtuqzpwPUfbV9UkUC1j4XkHoynWDbMt0bE0tPe2Picnl0/r/kq6MO527idV6Ur4zuOF4x9a97LQ==} + '@react-stately/searchfield@3.5.14': + resolution: {integrity: sha512-OAycTULyF/UWy7Odyzw5lZV2yWH+Cy7fWsZxDUedeUs4Aiwbb6D4ph9pGb0RvhD4S3+B490a2ijGgfsaDeorMA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/select@3.6.13': - resolution: {integrity: sha512-saZo67CreQZPdmqvz9+P6N4kjohpwdVncH98qBi0Q2FvxGAMnpJQgx97rtfDvnSziST5Yx1JnMI4kSSndbtFwg==} + '@react-stately/select@3.7.0': + resolution: {integrity: sha512-OWLOCKBEj8/XI+vzBSSHQAJu0Hf9Xl/flMhYh47f2b45bO++DRLcVsi8nycPNisudvK6xMQ8a/h4FwjePrCXfg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/selection@3.20.2': - resolution: {integrity: sha512-Fw6nnG+VKMsncsY4SNxGYOhnHojVFzFv+Uhy6P39QBp6AXtSaRKMg2VR4MPxQ7XgOjHh5ZuSvCY1RwocweqjwQ==} + '@react-stately/selection@3.20.4': + resolution: {integrity: sha512-Hxmc6NtECStYo+Z2uBRhQ80KPhbSF7xXv9eb4qN8dhyuSnsD6c0wc6oAJsv18dldcFz8VrD48aP/uff9mj0hxQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/slider@3.6.4': - resolution: {integrity: sha512-6SdG0VJZLMRIBnPjqkbIsdyQcW9zJ5Br716cl/7kLT9owiIwMJiAdjdYHab5+8ShWzU2D8Ae+LdQk8ZxIiIjkg==} + '@react-stately/slider@3.7.0': + resolution: {integrity: sha512-quxqkyyxrxLELYEkPrIrucpVPdYDK8yyliv/vvNuHrjuLRIvx6UmssxqESp2EpZfwPYtEB29QXbAKT9+KuXoCQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/table@3.14.2': - resolution: {integrity: sha512-SqE5A/Ve5H2ApnAblMGBMGRzY7cgdQmNPzXB8tGVc38NsC/STmMkq9m54gAl8dBVNbLzzd6HJBe9lqz5keYIhQ==} + '@react-stately/table@3.14.4': + resolution: {integrity: sha512-uhwk8z3DemozD+yHBjSa4WyxKczpDkxhJhW7ZVOY+1jNuTYxc9/JxzPsHICrlDVV8EPWwwyMUz8eO/8rKN7DbA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/tabs@3.8.2': - resolution: {integrity: sha512-lNpby7zUVdAeqo3mjGdPBxppEskOLyqR82LWBtP8Xg4olnjA5RmDFOuoJkIFttDX689zamjN3OE+Ra6WWgJczg==} + '@react-stately/tabs@3.8.4': + resolution: {integrity: sha512-2Tr4yXkcNDLyyxrZr+c4FnAW/wkSim3UhDUWoOgTCy3mwlQzdh9r5qJrOZRghn1QvF7p8Ahp7O7qxwd2ZGJrvQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/toast@3.1.0': - resolution: {integrity: sha512-9W2+evz+EARrjkR1QPLlOL5lcNpVo6PjMAIygRSaCPJ6ftQAZ6B+7xTFGPFabWh83gwXQDUgoSwC3/vosvxZaQ==} + '@react-stately/toast@3.1.2': + resolution: {integrity: sha512-HiInm7bck32khFBHZThTQaAF6e6/qm57F4mYRWdTq8IVeGDzpkbUYibnLxRhk0UZ5ybc6me+nqqPkG/lVmM42Q==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/toggle@3.8.4': - resolution: {integrity: sha512-JbKoXhkJ5P5nCrNXChMos3yNqkIeGXPDEMS/dfkHlsjQYxJfylRm4j/nWoDXxxkUmfkvXcNEMofMn9iO1+H0DQ==} + '@react-stately/toggle@3.9.0': + resolution: {integrity: sha512-1URd97R5nbFF9Hc1nQBhvln55EnOkLNz6pjtXU7TCnV4tYVbe+tc++hgr5XRt6KAfmuXxVDujlzRc6QjfCn0cQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/tooltip@3.5.4': - resolution: {integrity: sha512-HxNTqn9nMBuGbEVeeuZyhrzNbyW7sgwk+8o0mN/BrMrk7E/UBhyL2SUxXnAUQftpTjX+29hmx1sPhIprIDzR3Q==} + '@react-stately/tooltip@3.5.6': + resolution: {integrity: sha512-BnOtE7726t1sCKPGbwzzEtEx40tjpbJvw5yqpoVnAV0OLfrXtLVYfd7tWRHmZOYmhELaUnY+gm3ZFYtwvnjs+A==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/tree@3.8.10': - resolution: {integrity: sha512-sMqBRKAAZMiXJwlzAFpkXqUaGlNBfKnL8usAiKdoeGcLLJt2Ni9gPoPOLBJSPqLOAFCgLWtr5IYjdhel9aXRzQ==} + '@react-stately/tree@3.9.1': + resolution: {integrity: sha512-dyoPIvPK/cs03Tg/MQSODi2kKYW1zaiOG9KC2P0c8b44mywU2ojBKzhSJky3dBkJ4VVGy7L+voBh50ELMjEa8Q==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-stately/utils@3.10.6': - resolution: {integrity: sha512-O76ip4InfTTzAJrg8OaZxKU4vvjMDOpfA/PGNOytiXwBbkct2ZeZwaimJ8Bt9W1bj5VsZ81/o/tW4BacbdDOMA==} + '@react-stately/utils@3.10.8': + resolution: {integrity: sha512-SN3/h7SzRsusVQjQ4v10LaVsDc81jyyR0DD5HnsQitm/I5WDpaSr2nRHtyloPFU48jlql1XX/S04T2DLQM7Y3g==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/breadcrumbs@3.7.13': - resolution: {integrity: sha512-x94KEZaLIeHt9lqAkuaOopX5+rqCTMSHsciThUsBHK7QT64zrw6x2G1WKQ4zB4h52RGF5b+3sFXeR4bgX2sVLQ==} + '@react-types/breadcrumbs@3.7.15': + resolution: {integrity: sha512-0RsymrsOAsx443XRDJ1krK+Lusr4t0qqExmzFe7/XYXOn/RbGKjzSdezsoWfTy8Hjks0YbfQPVKnNxg9LKv4XA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/button@3.12.1': - resolution: {integrity: sha512-z87stl4llWTi4C5qhUK1PKcEsG59uF/ZQpkRhMzX0KfgXobJY6yiIrry2xrpnlTPIVST6K1+kARhhSDOZ8zhLw==} + '@react-types/button@3.13.0': + resolution: {integrity: sha512-hwvcNnBjDeNvWheWfBhmkJSzC48ub5rZq0DnpemB3XKOvv5WcF9p6rrQZsQ3egNGkh0Z+bKfr2QfotgOkccHSw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/calendar@3.7.1': - resolution: {integrity: sha512-a/wGT9vZewPNL72Xni8T/gv4IS2w6iRtryqMF425OL+kaCQrxJYlkDxb74bQs9+k9ZYabrxJgz9vFcFnY7S9gw==} + '@react-types/calendar@3.7.3': + resolution: {integrity: sha512-gofPgVpSawJ0iGO01SbVH46u3gdykHlGT5BfGU1cRnsOR2tJX38dekO/rnuGsMQYF0+kU6U9YVae+XoOFJNnWg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/checkbox@3.9.4': - resolution: {integrity: sha512-fU3Q1Nw+zbXKm68ba8V7cQzpiX0rIiAUKrBTl2BK97QiTlGBDvMCf4TfEuaNoGbJq+gx+X3n/3yr6c3IAb0ZIg==} + '@react-types/checkbox@3.10.0': + resolution: {integrity: sha512-DJ84ilBDvZddE/Sul97Otee4M6psrPRaJm2a1Bc7M3Y5UKo6d6RGXdcDarRRpbnS7BeAbVanKiMS2ygI9QHh9g==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/color@3.0.5': - resolution: {integrity: sha512-72uZ0B3EcaC2DGOpnhwHSVxcvQ3UDNSVR2gVx7PgUCGlEjhnn9i0UErIP8ZzV2RsAvjK6MrGs7ZCwZtl+LxCcg==} + '@react-types/color@3.1.0': + resolution: {integrity: sha512-mqx76zdq/GyI7hdx+NTdTrCG6qmf1Uk3w/zWKF80OAesLqqs9XavQQZlRPu1Cg/fHiAHIBOLYTnLf8w+T2IMsw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/combobox@3.13.5': - resolution: {integrity: sha512-wqHBF0YDkrp4Ylyxpd3xhnDECe5eao27bsu+4AvjlVKtaxaoppNq2MwSzkuSSS/GEUXT6K9DDjrGFcp07ad5gA==} + '@react-types/combobox@3.13.7': + resolution: {integrity: sha512-R7MQ4Qm4fryo6FCg3Vo/l9wxkYVG05trsLbxzMvvxCMkpcoHUPhy8Ll33eXA3YP74Rs/IaM9d0d/amSUZ4M9wg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/datepicker@3.12.1': - resolution: {integrity: sha512-+wv57fVd6Y/+KnHNEmVzfrQtWs85Ga1Xb63AIkBk+E294aMqFYqRg0dQds6V/qrP758TWnXUrhKza1zMbjHalw==} + '@react-types/datepicker@3.13.0': + resolution: {integrity: sha512-AG/iGcdQ5SVSjw8Ta7bCdGNkMda+e+Z7lOHxDawL44SII8LtZroBDlaCpb178Tvo17bBfJ6TvWXlvSpBY8GPRg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/dialog@3.5.18': - resolution: {integrity: sha512-g18CzT5xmiX/numpS6MrOGEGln8Xp9rr+zO70Dg+jM4GBOjXZp3BeclYQr9uisxGaj2uFLnORv9gNMMKxLNF6A==} + '@react-types/dialog@3.5.20': + resolution: {integrity: sha512-ebn8jW/xW/nmRATaWIPHVBIpIFWSaqjrAxa58f5TXer5FtCD9pUuzAQDmy/o22ucB0yvn6Kl+fjb3SMbMdALZQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/grid@3.3.2': - resolution: {integrity: sha512-NwfydUbPc1zVi/Rp7+oRN2+vE1xMokc2J+nr0VcHwFGt1bR1psakHu45Pk/t763BDvPr/A3xIHc1rk3eWEhxJw==} + '@react-types/grid@3.3.4': + resolution: {integrity: sha512-8XNn7Czhl+D1b2zRwdO8c3oBJmKgevT/viKJB4qBVFOhK0l/p3HYDZUMdeclvUfSt4wx4ASpI7MD3v1vmN54oA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/link@3.6.1': - resolution: {integrity: sha512-IZDSc10AuVKe7V8Te+3q8d220oANE4N43iljQe3yHg7GZOfH/51bv8FPUukreLs1t2fgtGeNAzG71Ep+j/jXIw==} + '@react-types/link@3.6.3': + resolution: {integrity: sha512-XIYEl9ZPa5mLy8uGQabdhPaFVmnvxNSYF59t0vs/IV0yxeoPvrjKjRAbXS+WP9zYMXIkHYNYYucriCkqKhotJA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/listbox@3.7.0': - resolution: {integrity: sha512-26Lp0Gou502VJLDSrIpMg7LQuVHznxzyuSY/zzyNX9eopukXvHn682u90fwDqgmZz7dzxUOWtuwDea+bp/UjtA==} + '@react-types/listbox@3.7.2': + resolution: {integrity: sha512-MRpBhApR1jJNASoVWsEvH5vf89TJw+l9Lt1ssawop0K2iYF5PmkthRdqcpYcTkFu5+f5QvFchVsNJ3TKD4cf2A==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/menu@3.10.1': - resolution: {integrity: sha512-wkyWzIqaCbUYiD7YXr8YvdimB1bxQHqgj6uE4MKzryCbVqb4L8fRUM0V6AHkQS1TxBYNkNn1h4g7XNd5Vmyf3Q==} + '@react-types/menu@3.10.3': + resolution: {integrity: sha512-Vd3t7fEbIOiq7kBAHaihfYf+/3Fuh0yK2KNjJ70BPtlAhMRMDVG3m0PheSTm3FFfj+uAdQdfc2YKPnMBbWjDuQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/meter@3.4.9': - resolution: {integrity: sha512-Jhd873zc/Bx/86NB9nasMUWc013VnURVtMYbbkuRWiFr/ZoEvZzO1uoSIXf+Sob4xpiVhT/ltvJZTK4t4B9lTg==} + '@react-types/meter@3.4.11': + resolution: {integrity: sha512-c4jnDWFxDp09fNpCDrq6l2RxOxcolmf/frvdtVA/d4SGvfEOoqeUakpVDuOqDD0bU58tQPG3fqT2zH8vpWiJew==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/numberfield@3.8.11': - resolution: {integrity: sha512-D66Bop7M3JKzBV2vsECsVYfPrx8eRIx4/K2KLo/XjwMA7C34+Ou07f/bnD1TQQ/wr6XwiFxZTi6JsKDwnST+9Q==} + '@react-types/numberfield@3.8.13': + resolution: {integrity: sha512-zRSqInmxOTQJZt2fjAhuQK3Wa1vCOlKsRzUVvxTrE8gtQxlgFxirmobuUnjTEhwkFyb0bq8GvVfQV1E95Si2yw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/overlays@3.8.15': - resolution: {integrity: sha512-ppDfezvVYOJDHLZmTSmIXajxAo30l2a1jjy4G65uBYy8J8kTZU7mcfQql5Pii1TwybcNMsayf2WtPItiWmJnOA==} + '@react-types/overlays@3.9.0': + resolution: {integrity: sha512-T2DqMcDN5p8vb4vu2igoLrAtuewaNImLS8jsK7th7OjwQZfIWJn5Y45jSxHtXJUddEg1LkUjXYPSXCMerMcULw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/progress@3.5.12': - resolution: {integrity: sha512-wvhFz6vdlfKBtnzKvD/89N+0PF3yPQ+IVFRQvZ2TBrP7nF+ZA2pNLcZVcEYbKjHzmvEZRGu//ePC9hRJD9K30w==} + '@react-types/progress@3.5.14': + resolution: {integrity: sha512-GeGrjOeHR/p5qQ1gGlN68jb+lL47kuddxMgdR1iEnAlYGY4OtJoEN/EM5W2ZxJRKPcJmzdcY/p/J0PXa8URbSg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/radio@3.8.9': - resolution: {integrity: sha512-l4uzlxmGGuR8IkWrMYdKj1sc3Pgo/LdfEGuIgK+d8kjPu0AZcnSgp5Oz035bCosZUabY6dEWxQHIoAH2zN7YZA==} + '@react-types/radio@3.9.0': + resolution: {integrity: sha512-phndlgqMF6/9bOOhO3le00eozNfDU1E7OHWV2cWWhGSMRFuRdf7/d+NjVtavCX75+GJ50MxvXk+KB0fjTuvKyg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/searchfield@3.6.2': - resolution: {integrity: sha512-XQRQyJLNC9uLyCq+97eiqeQuM6+dCMrHu6aH6KSVt1Xh6HMmdx/TdSf6JrMkN+1xSxcW3lDE2iSf3jXDT87gag==} + '@react-types/searchfield@3.6.4': + resolution: {integrity: sha512-gRVWnRHf7pqU0lBVlkU6XsLxvaWTPnn0EomddIBCVh0msVIyvEea8CXJppu7EpvRh+grNpiMEYeijQ+u8hixlQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/select@3.9.12': - resolution: {integrity: sha512-qo+9JS1kfMxuibmSmMp0faGKbeVftYnSk1f7Rh5PKi4tzMe3C0A9IAr27hUOfWeJMBOdetaoTpYmoXW6+CgW3g==} + '@react-types/select@3.10.0': + resolution: {integrity: sha512-+xJwYWJoJTCGsaiPAqb6QB79ub1WKIHSmOS9lh/fPUXfUszVs05jhajaN9KjrKmnXds5uh4u6l1JH5J1l2K5pw==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/shared@3.29.1': - resolution: {integrity: sha512-KtM+cDf2CXoUX439rfEhbnEdAgFZX20UP2A35ypNIawR7/PFFPjQDWyA2EnClCcW/dLWJDEPX2U8+EJff8xqmQ==} + '@react-types/shared@3.31.0': + resolution: {integrity: sha512-ua5U6V66gDcbLZe4P2QeyNgPp4YWD1ymGA6j3n+s8CGExtrCPe64v+g4mvpT8Bnb985R96e4zFT61+m0YCwqMg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/slider@3.7.11': - resolution: {integrity: sha512-uNhNLhVrt/2teXBOJSoZXyXg308A72qe1HOmlGdJcnh8iXA35y5ZHzeK1P6ZOJ37Aeh7bYGm3/UdURmFgSlW7w==} + '@react-types/slider@3.8.0': + resolution: {integrity: sha512-eN6Fd3YCPseGfvfOJDtn9Lh9CrAb8tF3cTAprEcpnGrsxmdW9JQpcuciYuLM871X5D2fYg4WaYMpZaiYssjxBQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/switch@3.5.11': - resolution: {integrity: sha512-PJbZHwlE98OSuLzI6b1ei6Qa+FaiwlCRH3tOTdx/wPSdqmD3mRWEn7E9ftM6FC8hnxl/LrGLszQMT62yEQp5vQ==} + '@react-types/switch@3.5.13': + resolution: {integrity: sha512-C2EhKBu7g7xhKboPPxhyKtROEti80Ck7TBnKclXt0D4LiwbzpR3qGfuzB+7YFItnhiauP7Uxe+bAfM5ojjtm9w==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/table@3.13.0': - resolution: {integrity: sha512-kn+OsEWJfUSSb4N4J0yl+tqx5grDpcaWcu2J8hA62hQCr/Leuj946ScYaKA9a/p0MAaOAaeCWx/Zcss6F8gJIQ==} + '@react-types/table@3.13.2': + resolution: {integrity: sha512-3/BpFIWHXTcGgQEfip87gMNCWPtPNsc3gFkW4qtsevQ+V0577KyNyvQgvFrqMZKnvz3NWFKyshBb7PTevsus4Q==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/tabs@3.3.15': - resolution: {integrity: sha512-VLgh9YLQdS4FQSk0sGTNHEVN2jeC0fZvOqEFHaEDgDyDgVOukxYuHjqVIx2IavYu1yNBrGO2b6P4M6dF+hcgwQ==} + '@react-types/tabs@3.3.17': + resolution: {integrity: sha512-cLcdxWNJe0Kf/pKuPQbEF9Fl+axiP4gB/WVjmAdhCgQ5LCJw2dGcy1LI1SXrlS3PVclbnujD1DJ8z1lIW4Tmww==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/textfield@3.12.2': - resolution: {integrity: sha512-dMm0cGLG5bkJYvt6lqXIty5HXTZjuIpa9I8jAIYua//J8tESAOE9BA285Zl43kx7cZGtgrHKHVFjITDLNUrNhA==} + '@react-types/textfield@3.12.4': + resolution: {integrity: sha512-cOgzI1dT8X1JMNQ9u2UKoV2L28ROkbFEtzY9At0MqTZYYSxYp3Q7i+XRqIBehu8jOMuCtN9ed9EgwVSfkicyLQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-types/tooltip@3.4.17': - resolution: {integrity: sha512-yjySKA1uzJAbio+xGv03DUoWIajteqtsXMd4Y3AJEdBFqSYhXbyrgAxw0oJDgRAgRxY4Rx5Hrhvbt/z7Di94QQ==} + '@react-types/tooltip@3.4.19': + resolution: {integrity: sha512-OR/pwZReWbCIxuHJYB1L4fTwliA+mzVvUJMWwXIRy6Eh5d07spS3FZEKFvOgjMxA1nyv5PLf8eyr5RuuP1GGAA==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@rollup/pluginutils@5.1.4': - resolution: {integrity: sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==} + '@rolldown/binding-android-arm64@1.0.0-beta.33': + resolution: {integrity: sha512-xhDQXKftRkEULIxCddrKMR8y0YO/Y+6BKk/XrQP2B29YjV2wr8DByoEz+AHX9BfLHb2srfpdN46UquBW2QXWpQ==} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.0-beta.33': + resolution: {integrity: sha512-7lhhY08v5ZtRq8JJQaJ49fnJombAPnqllKKCDLU/UvaqNAOEyTGC8J1WVOLC4EA4zbXO5U3CCRgVGyAFNH2VtQ==} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.0-beta.33': + resolution: {integrity: sha512-U2iGjcDV7NWyYyhap8YuY0nwrLX6TvX/9i7gBtdEMPm9z3wIUVGNMVdGlA43uqg7xDpRGpEqGnxbeDgiEwYdnA==} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.0-beta.33': + resolution: {integrity: sha512-gd6ASromVHFLlzrjJWMG5CXHkS7/36DEZ8HhvGt2NN8eZALCIuyEx8HMMLqvKA7z4EAztVkdToVrdxpGMsKZxw==} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.33': + resolution: {integrity: sha512-xmeLfkfGthuynO1EpCdyTVr0r4G+wqvnKCuyR6rXOet+hLrq5HNAC2XtP/jU2TB4Bc6aiLYxl868B8CGtFDhcw==} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.33': + resolution: {integrity: sha512-cHGp8yfHL4pes6uaLbO5L58ceFkUK4efd8iE86jClD1QPPDLKiqEXJCFYeuK3OfODuF5EBOmf0SlcUZNEYGdmw==} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-arm64-musl@1.0.0-beta.33': + resolution: {integrity: sha512-wZ1t7JAvVeFgskH1L9y7c47ITitPytpL0s8FmAT8pVfXcaTmS58ZyoXT+y6cz8uCkQnETjrX3YezTGI18u3ecg==} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-x64-gnu@1.0.0-beta.33': + resolution: {integrity: sha512-cDndWo3VEYbm7yeujOV6Ie2XHz0K8YX/R/vbNmMo03m1QwtBKKvbYNSyJb3B9+8igltDjd8zNM9mpiNNrq/ekQ==} + cpu: [x64] + os: [linux] + + '@rolldown/binding-linux-x64-musl@1.0.0-beta.33': + resolution: {integrity: sha512-bl7uzi6es/l6LT++NZcBpiX43ldLyKXCPwEZGY1rZJ99HQ7m1g3KxWwYCcGxtKjlb2ExVvDZicF6k+96vxOJKg==} + cpu: [x64] + os: [linux] + + '@rolldown/binding-openharmony-arm64@1.0.0-beta.33': + resolution: {integrity: sha512-TrgzQanpLgcmmzolCbYA9BPZgF1gYxkIGZhU/HROnJPsq67gcyaYw/JBLioqQLjIwMipETkn25YY799D2OZzJA==} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.0-beta.33': + resolution: {integrity: sha512-z0LltdUfvoKak9SuaLz/M9AVSg+RTOZjFksbZXzC6Svl1odyW4ai21VHhZy3m2Faeeb/rl/9efVLayj+qYEGxw==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.33': + resolution: {integrity: sha512-CpvOHyqDNOYx9riD4giyXQDIu72bWRU2Dwt1xFSPlBudk6NumK0OJl6Ch+LPnkp5podQHcQg0mMauAXPVKct7g==} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.33': + resolution: {integrity: sha512-/tNTvZTWHz6HiVuwpR3zR0kGIyCNb+/tFhnJmti+Aw2fAXs3l7Aj0DcXd0646eFKMX8L2w5hOW9H08FXTUkN0g==} + cpu: [ia32] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.0-beta.33': + resolution: {integrity: sha512-Bb2qK3z7g2mf4zaKRvkohHzweaP1lLbaoBmXZFkY6jJWMm0Z8Pfnh8cOoRlH1IVM1Ufbo8ZZ1WXp1LbOpRMtXw==} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.0-beta.29': + resolution: {integrity: sha512-NIJgOsMjbxAXvoGq/X0gD7VPMQ8j9g0BiDaNjVNVjvl+iKXxL3Jre0v31RmBYeLEmkbj2s02v8vFTbUXi5XS2Q==} + + '@rolldown/pluginutils@1.0.0-beta.33': + resolution: {integrity: sha512-she25NCG6NoEPC/SEB4pHs5STcnfI4VBFOzjeI63maSPrWME5J2XC8ogrBgp8NaE/xzj28/kbpSaebiMvFRj+w==} + + '@rollup/pluginutils@5.2.0': + resolution: {integrity: sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 @@ -1319,166 +1726,195 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.36.0': - resolution: {integrity: sha512-jgrXjjcEwN6XpZXL0HUeOVGfjXhPyxAbbhD0BlXUB+abTOpbPiN5Wb3kOT7yb+uEtATNYF5x5gIfwutmuBA26w==} + '@rollup/rollup-android-arm-eabi@4.46.3': + resolution: {integrity: sha512-UmTdvXnLlqQNOCJnyksjPs1G4GqXNGW1LrzCe8+8QoaLhhDeTXYBgJ3k6x61WIhlHX2U+VzEJ55TtIjR/HTySA==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.36.0': - resolution: {integrity: sha512-NyfuLvdPdNUfUNeYKUwPwKsE5SXa2J6bCt2LdB/N+AxShnkpiczi3tcLJrm5mA+eqpy0HmaIY9F6XCa32N5yzg==} + '@rollup/rollup-android-arm64@4.46.3': + resolution: {integrity: sha512-8NoxqLpXm7VyeI0ocidh335D6OKT0UJ6fHdnIxf3+6oOerZZc+O7r+UhvROji6OspyPm+rrIdb1gTXtVIqn+Sg==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.36.0': - resolution: {integrity: sha512-JQ1Jk5G4bGrD4pWJQzWsD8I1n1mgPXq33+/vP4sk8j/z/C2siRuxZtaUA7yMTf71TCZTZl/4e1bfzwUmFb3+rw==} + '@rollup/rollup-darwin-arm64@4.46.3': + resolution: {integrity: sha512-csnNavqZVs1+7/hUKtgjMECsNG2cdB8F7XBHP6FfQjqhjF8rzMzb3SLyy/1BG7YSfQ+bG75Ph7DyedbUqwq1rA==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.36.0': - resolution: {integrity: sha512-6c6wMZa1lrtiRsbDziCmjE53YbTkxMYhhnWnSW8R/yqsM7a6mSJ3uAVT0t8Y/DGt7gxUWYuFM4bwWk9XCJrFKA==} + '@rollup/rollup-darwin-x64@4.46.3': + resolution: {integrity: sha512-r2MXNjbuYabSIX5yQqnT8SGSQ26XQc8fmp6UhlYJd95PZJkQD1u82fWP7HqvGUf33IsOC6qsiV+vcuD4SDP6iw==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.36.0': - resolution: {integrity: sha512-KXVsijKeJXOl8QzXTsA+sHVDsFOmMCdBRgFmBb+mfEb/7geR7+C8ypAml4fquUt14ZyVXaw2o1FWhqAfOvA4sg==} + '@rollup/rollup-freebsd-arm64@4.46.3': + resolution: {integrity: sha512-uluObTmgPJDuJh9xqxyr7MV61Imq+0IvVsAlWyvxAaBSNzCcmZlhfYcRhCdMaCsy46ccZa7vtDDripgs9Jkqsw==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.36.0': - resolution: {integrity: sha512-dVeWq1ebbvByI+ndz4IJcD4a09RJgRYmLccwlQ8bPd4olz3Y213uf1iwvc7ZaxNn2ab7bjc08PrtBgMu6nb4pQ==} + '@rollup/rollup-freebsd-x64@4.46.3': + resolution: {integrity: sha512-AVJXEq9RVHQnejdbFvh1eWEoobohUYN3nqJIPI4mNTMpsyYN01VvcAClxflyk2HIxvLpRcRggpX1m9hkXkpC/A==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.36.0': - resolution: {integrity: sha512-bvXVU42mOVcF4le6XSjscdXjqx8okv4n5vmwgzcmtvFdifQ5U4dXFYaCB87namDRKlUL9ybVtLQ9ztnawaSzvg==} + '@rollup/rollup-linux-arm-gnueabihf@4.46.3': + resolution: {integrity: sha512-byyflM+huiwHlKi7VHLAYTKr67X199+V+mt1iRgJenAI594vcmGGddWlu6eHujmcdl6TqSNnvqaXJqZdnEWRGA==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.36.0': - resolution: {integrity: sha512-JFIQrDJYrxOnyDQGYkqnNBtjDwTgbasdbUiQvcU8JmGDfValfH1lNpng+4FWlhaVIR4KPkeddYjsVVbmJYvDcg==} + '@rollup/rollup-linux-arm-musleabihf@4.46.3': + resolution: {integrity: sha512-aLm3NMIjr4Y9LklrH5cu7yybBqoVCdr4Nvnm8WB7PKCn34fMCGypVNpGK0JQWdPAzR/FnoEoFtlRqZbBBLhVoQ==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.36.0': - resolution: {integrity: sha512-KqjYVh3oM1bj//5X7k79PSCZ6CvaVzb7Qs7VMWS+SlWB5M8p3FqufLP9VNp4CazJ0CsPDLwVD9r3vX7Ci4J56A==} + '@rollup/rollup-linux-arm64-gnu@4.46.3': + resolution: {integrity: sha512-VtilE6eznJRDIoFOzaagQodUksTEfLIsvXymS+UdJiSXrPW7Ai+WG4uapAc3F7Hgs791TwdGh4xyOzbuzIZrnw==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.36.0': - resolution: {integrity: sha512-QiGnhScND+mAAtfHqeT+cB1S9yFnNQ/EwCg5yE3MzoaZZnIV0RV9O5alJAoJKX/sBONVKeZdMfO8QSaWEygMhw==} + '@rollup/rollup-linux-arm64-musl@4.46.3': + resolution: {integrity: sha512-dG3JuS6+cRAL0GQ925Vppafi0qwZnkHdPeuZIxIPXqkCLP02l7ka+OCyBoDEv8S+nKHxfjvjW4OZ7hTdHkx8/w==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loongarch64-gnu@4.36.0': - resolution: {integrity: sha512-1ZPyEDWF8phd4FQtTzMh8FQwqzvIjLsl6/84gzUxnMNFBtExBtpL51H67mV9xipuxl1AEAerRBgBwFNpkw8+Lg==} + '@rollup/rollup-linux-loongarch64-gnu@4.46.3': + resolution: {integrity: sha512-iU8DxnxEKJptf8Vcx4XvAUdpkZfaz0KWfRrnIRrOndL0SvzEte+MTM7nDH4A2Now4FvTZ01yFAgj6TX/mZl8hQ==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-powerpc64le-gnu@4.36.0': - resolution: {integrity: sha512-VMPMEIUpPFKpPI9GZMhJrtu8rxnp6mJR3ZzQPykq4xc2GmdHj3Q4cA+7avMyegXy4n1v+Qynr9fR88BmyO74tg==} + '@rollup/rollup-linux-ppc64-gnu@4.46.3': + resolution: {integrity: sha512-VrQZp9tkk0yozJoQvQcqlWiqaPnLM6uY1qPYXvukKePb0fqaiQtOdMJSxNFUZFsGw5oA5vvVokjHrx8a9Qsz2A==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.36.0': - resolution: {integrity: sha512-ttE6ayb/kHwNRJGYLpuAvB7SMtOeQnVXEIpMtAvx3kepFQeowVED0n1K9nAdraHUPJ5hydEMxBpIR7o4nrm8uA==} + '@rollup/rollup-linux-riscv64-gnu@4.46.3': + resolution: {integrity: sha512-uf2eucWSUb+M7b0poZ/08LsbcRgaDYL8NCGjUeFMwCWFwOuFcZ8D9ayPl25P3pl+D2FH45EbHdfyUesQ2Lt9wA==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.46.3': + resolution: {integrity: sha512-7tnUcDvN8DHm/9ra+/nF7lLzYHDeODKKKrh6JmZejbh1FnCNZS8zMkZY5J4sEipy2OW1d1Ncc4gNHUd0DLqkSg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.36.0': - resolution: {integrity: sha512-4a5gf2jpS0AIe7uBjxDeUMNcFmaRTbNv7NxI5xOCs4lhzsVyGR/0qBXduPnoWf6dGC365saTiwag8hP1imTgag==} + '@rollup/rollup-linux-s390x-gnu@4.46.3': + resolution: {integrity: sha512-MUpAOallJim8CsJK+4Lc9tQzlfPbHxWDrGXZm2z6biaadNpvh3a5ewcdat478W+tXDoUiHwErX/dOql7ETcLqg==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.36.0': - resolution: {integrity: sha512-5KtoW8UWmwFKQ96aQL3LlRXX16IMwyzMq/jSSVIIyAANiE1doaQsx/KRyhAvpHlPjPiSU/AYX/8m+lQ9VToxFQ==} + '@rollup/rollup-linux-x64-gnu@4.46.3': + resolution: {integrity: sha512-F42IgZI4JicE2vM2PWCe0N5mR5vR0gIdORPqhGQ32/u1S1v3kLtbZ0C/mi9FFk7C5T0PgdeyWEPajPjaUpyoKg==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.36.0': - resolution: {integrity: sha512-sycrYZPrv2ag4OCvaN5js+f01eoZ2U+RmT5as8vhxiFz+kxwlHrsxOwKPSA8WyS+Wc6Epid9QeI/IkQ9NkgYyQ==} + '@rollup/rollup-linux-x64-musl@4.46.3': + resolution: {integrity: sha512-oLc+JrwwvbimJUInzx56Q3ujL3Kkhxehg7O1gWAYzm8hImCd5ld1F2Gry5YDjR21MNb5WCKhC9hXgU7rRlyegQ==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.36.0': - resolution: {integrity: sha512-qbqt4N7tokFwwSVlWDsjfoHgviS3n/vZ8LK0h1uLG9TYIRuUTJC88E1xb3LM2iqZ/WTqNQjYrtmtGmrmmawB6A==} + '@rollup/rollup-win32-arm64-msvc@4.46.3': + resolution: {integrity: sha512-lOrQ+BVRstruD1fkWg9yjmumhowR0oLAAzavB7yFSaGltY8klttmZtCLvOXCmGE9mLIn8IBV/IFrQOWz5xbFPg==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.36.0': - resolution: {integrity: sha512-t+RY0JuRamIocMuQcfwYSOkmdX9dtkr1PbhKW42AMvaDQa+jOdpUYysroTF/nuPpAaQMWp7ye+ndlmmthieJrQ==} + '@rollup/rollup-win32-ia32-msvc@4.46.3': + resolution: {integrity: sha512-vvrVKPRS4GduGR7VMH8EylCBqsDcw6U+/0nPDuIjXQRbHJc6xOBj+frx8ksfZAh6+Fptw5wHrN7etlMmQnPQVg==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.36.0': - resolution: {integrity: sha512-aRXd7tRZkWLqGbChgcMMDEHjOKudo1kChb1Jt1IfR8cY/KIpgNviLeJy5FUb9IpSuQj8dU2fAYNMPW/hLKOSTw==} + '@rollup/rollup-win32-x64-msvc@4.46.3': + resolution: {integrity: sha512-fi3cPxCnu3ZeM3EwKZPgXbWoGzm2XHgB/WShKI81uj8wG0+laobmqy5wbgEwzstlbLu4MyO8C19FyhhWseYKNQ==} cpu: [x64] os: [win32] + '@shikijs/core@3.9.2': + resolution: {integrity: sha512-3q/mzmw09B2B6PgFNeiaN8pkNOixWS726IHmJEpjDAcneDPMQmUg2cweT9cWXY4XcyQS3i6mOOUgQz9RRUP6HA==} + + '@shikijs/engine-javascript@3.9.2': + resolution: {integrity: sha512-kUTRVKPsB/28H5Ko6qEsyudBiWEDLst+Sfi+hwr59E0GLHV0h8RfgbQU7fdN5Lt9A8R1ulRiZyTvAizkROjwDA==} + + '@shikijs/engine-oniguruma@3.9.2': + resolution: {integrity: sha512-Vn/w5oyQ6TUgTVDIC/BrpXwIlfK6V6kGWDVVz2eRkF2v13YoENUvaNwxMsQU/t6oCuZKzqp9vqtEtEzKl9VegA==} + + '@shikijs/langs@3.9.2': + resolution: {integrity: sha512-X1Q6wRRQXY7HqAuX3I8WjMscjeGjqXCg/Sve7J2GWFORXkSrXud23UECqTBIdCSNKJioFtmUGJQNKtlMMZMn0w==} + + '@shikijs/themes@3.9.2': + resolution: {integrity: sha512-6z5lBPBMRfLyyEsgf6uJDHPa6NAGVzFJqH4EAZ+03+7sedYir2yJBRu2uPZOKmj43GyhVHWHvyduLDAwJQfDjA==} + + '@shikijs/transformers@3.9.2': + resolution: {integrity: sha512-MW5hT4TyUp6bNAgTExRYLk1NNasVQMTCw1kgbxHcEC0O5cbepPWaB+1k+JzW9r3SP2/R8kiens8/3E6hGKfgsA==} + + '@shikijs/types@3.9.2': + resolution: {integrity: sha512-/M5L0Uc2ljyn2jKvj4Yiah7ow/W+DJSglVafvWAJ/b8AZDeeRAdMu3c2riDzB7N42VD+jSnWxeP9AKtd4TfYVw==} + + '@shikijs/vscode-textmate@10.0.2': + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + '@shopify/lang-jsonc@1.0.1': resolution: {integrity: sha512-KrBrRFhvr1qJiZBODAtqbL1u1e67UR3plBN79Z8nd5TQAAzpx66jS4zs7Ss9M22ygGrpWFhyhSoNVlp5VCYktQ==} '@swc/helpers@0.5.17': resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==} - '@tailwindcss/node@4.1.8': - resolution: {integrity: sha512-OWwBsbC9BFAJelmnNcrKuf+bka2ZxCE2A4Ft53Tkg4uoiE67r/PMEYwCsourC26E+kmxfwE0hVzMdxqeW+xu7Q==} + '@tailwindcss/node@4.1.12': + resolution: {integrity: sha512-3hm9brwvQkZFe++SBt+oLjo4OLDtkvlE8q2WalaD/7QWaeM7KEJbAiY/LJZUaCs7Xa8aUu4xy3uoyX4q54UVdQ==} - '@tailwindcss/oxide-android-arm64@4.1.8': - resolution: {integrity: sha512-Fbz7qni62uKYceWYvUjRqhGfZKwhZDQhlrJKGtnZfuNtHFqa8wmr+Wn74CTWERiW2hn3mN5gTpOoxWKk0jRxjg==} + '@tailwindcss/oxide-android-arm64@4.1.12': + resolution: {integrity: sha512-oNY5pq+1gc4T6QVTsZKwZaGpBb2N1H1fsc1GD4o7yinFySqIuRZ2E4NvGasWc6PhYJwGK2+5YT1f9Tp80zUQZQ==} engines: {node: '>= 10'} cpu: [arm64] os: [android] - '@tailwindcss/oxide-darwin-arm64@4.1.8': - resolution: {integrity: sha512-RdRvedGsT0vwVVDztvyXhKpsU2ark/BjgG0huo4+2BluxdXo8NDgzl77qh0T1nUxmM11eXwR8jA39ibvSTbi7A==} + '@tailwindcss/oxide-darwin-arm64@4.1.12': + resolution: {integrity: sha512-cq1qmq2HEtDV9HvZlTtrj671mCdGB93bVY6J29mwCyaMYCP/JaUBXxrQQQm7Qn33AXXASPUb2HFZlWiiHWFytw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@tailwindcss/oxide-darwin-x64@4.1.8': - resolution: {integrity: sha512-t6PgxjEMLp5Ovf7uMb2OFmb3kqzVTPPakWpBIFzppk4JE4ix0yEtbtSjPbU8+PZETpaYMtXvss2Sdkx8Vs4XRw==} + '@tailwindcss/oxide-darwin-x64@4.1.12': + resolution: {integrity: sha512-6UCsIeFUcBfpangqlXay9Ffty9XhFH1QuUFn0WV83W8lGdX8cD5/+2ONLluALJD5+yJ7k8mVtwy3zMZmzEfbLg==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@tailwindcss/oxide-freebsd-x64@4.1.8': - resolution: {integrity: sha512-g8C8eGEyhHTqwPStSwZNSrOlyx0bhK/V/+zX0Y+n7DoRUzyS8eMbVshVOLJTDDC+Qn9IJnilYbIKzpB9n4aBsg==} + '@tailwindcss/oxide-freebsd-x64@4.1.12': + resolution: {integrity: sha512-JOH/f7j6+nYXIrHobRYCtoArJdMJh5zy5lr0FV0Qu47MID/vqJAY3r/OElPzx1C/wdT1uS7cPq+xdYYelny1ww==} engines: {node: '>= 10'} cpu: [x64] os: [freebsd] - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.8': - resolution: {integrity: sha512-Jmzr3FA4S2tHhaC6yCjac3rGf7hG9R6Gf2z9i9JFcuyy0u79HfQsh/thifbYTF2ic82KJovKKkIB6Z9TdNhCXQ==} + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.12': + resolution: {integrity: sha512-v4Ghvi9AU1SYgGr3/j38PD8PEe6bRfTnNSUE3YCMIRrrNigCFtHZ2TCm8142X8fcSqHBZBceDx+JlFJEfNg5zQ==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@tailwindcss/oxide-linux-arm64-gnu@4.1.8': - resolution: {integrity: sha512-qq7jXtO1+UEtCmCeBBIRDrPFIVI4ilEQ97qgBGdwXAARrUqSn/L9fUrkb1XP/mvVtoVeR2bt/0L77xx53bPZ/Q==} + '@tailwindcss/oxide-linux-arm64-gnu@4.1.12': + resolution: {integrity: sha512-YP5s1LmetL9UsvVAKusHSyPlzSRqYyRB0f+Kl/xcYQSPLEw/BvGfxzbH+ihUciePDjiXwHh+p+qbSP3SlJw+6g==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@tailwindcss/oxide-linux-arm64-musl@4.1.8': - resolution: {integrity: sha512-O6b8QesPbJCRshsNApsOIpzKt3ztG35gfX9tEf4arD7mwNinsoCKxkj8TgEE0YRjmjtO3r9FlJnT/ENd9EVefQ==} + '@tailwindcss/oxide-linux-arm64-musl@4.1.12': + resolution: {integrity: sha512-V8pAM3s8gsrXcCv6kCHSuwyb/gPsd863iT+v1PGXC4fSL/OJqsKhfK//v8P+w9ThKIoqNbEnsZqNy+WDnwQqCA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@tailwindcss/oxide-linux-x64-gnu@4.1.8': - resolution: {integrity: sha512-32iEXX/pXwikshNOGnERAFwFSfiltmijMIAbUhnNyjFr3tmWmMJWQKU2vNcFX0DACSXJ3ZWcSkzNbaKTdngH6g==} + '@tailwindcss/oxide-linux-x64-gnu@4.1.12': + resolution: {integrity: sha512-xYfqYLjvm2UQ3TZggTGrwxjYaLB62b1Wiysw/YE3Yqbh86sOMoTn0feF98PonP7LtjsWOWcXEbGqDL7zv0uW8Q==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@tailwindcss/oxide-linux-x64-musl@4.1.8': - resolution: {integrity: sha512-s+VSSD+TfZeMEsCaFaHTaY5YNj3Dri8rST09gMvYQKwPphacRG7wbuQ5ZJMIJXN/puxPcg/nU+ucvWguPpvBDg==} + '@tailwindcss/oxide-linux-x64-musl@4.1.12': + resolution: {integrity: sha512-ha0pHPamN+fWZY7GCzz5rKunlv9L5R8kdh+YNvP5awe3LtuXb5nRi/H27GeL2U+TdhDOptU7T6Is7mdwh5Ar3A==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@tailwindcss/oxide-wasm32-wasi@4.1.8': - resolution: {integrity: sha512-CXBPVFkpDjM67sS1psWohZ6g/2/cd+cq56vPxK4JeawelxwK4YECgl9Y9TjkE2qfF+9/s1tHHJqrC4SS6cVvSg==} + '@tailwindcss/oxide-wasm32-wasi@4.1.12': + resolution: {integrity: sha512-4tSyu3dW+ktzdEpuk6g49KdEangu3eCYoqPhWNsZgUhyegEda3M9rG0/j1GV/JjVVsj+lG7jWAyrTlLzd/WEBg==} engines: {node: '>=14.0.0'} cpu: [wasm32] bundledDependencies: @@ -1489,50 +1925,77 @@ packages: - '@emnapi/wasi-threads' - tslib - '@tailwindcss/oxide-win32-arm64-msvc@4.1.8': - resolution: {integrity: sha512-7GmYk1n28teDHUjPlIx4Z6Z4hHEgvP5ZW2QS9ygnDAdI/myh3HTHjDqtSqgu1BpRoI4OiLx+fThAyA1JePoENA==} + '@tailwindcss/oxide-win32-arm64-msvc@4.1.12': + resolution: {integrity: sha512-iGLyD/cVP724+FGtMWslhcFyg4xyYyM+5F4hGvKA7eifPkXHRAUDFaimu53fpNg9X8dfP75pXx/zFt/jlNF+lg==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@tailwindcss/oxide-win32-x64-msvc@4.1.8': - resolution: {integrity: sha512-fou+U20j+Jl0EHwK92spoWISON2OBnCazIc038Xj2TdweYV33ZRkS9nwqiUi2d/Wba5xg5UoHfvynnb/UB49cQ==} + '@tailwindcss/oxide-win32-x64-msvc@4.1.12': + resolution: {integrity: sha512-NKIh5rzw6CpEodv/++r0hGLlfgT/gFN+5WNdZtvh6wpU2BpGNgdjvj6H2oFc8nCM839QM1YOhjpgbAONUb4IxA==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@tailwindcss/oxide@4.1.8': - resolution: {integrity: sha512-d7qvv9PsM5N3VNKhwVUhpK6r4h9wtLkJ6lz9ZY9aeZgrUWk1Z8VPyqyDT9MZlem7GTGseRQHkeB1j3tC7W1P+A==} + '@tailwindcss/oxide@4.1.12': + resolution: {integrity: sha512-gM5EoKHW/ukmlEtphNwaGx45fGoEmP10v51t9unv55voWh6WrOL19hfuIdo2FjxIaZzw776/BUQg7Pck++cIVw==} engines: {node: '>= 10'} - '@tailwindcss/vite@4.1.8': - resolution: {integrity: sha512-CQ+I8yxNV5/6uGaJjiuymgw0kEQiNKRinYbZXPdx1fk5WgiyReG0VaUx/Xq6aVNSUNJFzxm6o8FNKS5aMaim5A==} + '@tailwindcss/vite@4.1.12': + resolution: {integrity: sha512-4pt0AMFDx7gzIrAOIYgYP0KCBuKWqyW8ayrdiLEjoJTT4pKTjrzG/e4uzWtTLDziC+66R9wbUqZBccJalSE5vQ==} peerDependencies: - vite: ^5.2.0 || ^6 + vite: ^5.2.0 || ^6 || ^7 - '@types/estree@1.0.6': - resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + '@tybys/wasm-util@0.10.0': + resolution: {integrity: sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==} + + '@types/better-sqlite3@7.6.13': + resolution: {integrity: sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==} + + '@types/chai@5.2.2': + resolution: {integrity: sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} '@types/estree@1.0.7': resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + '@types/js-yaml@4.0.9': resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==} + '@types/linkify-it@5.0.0': + resolution: {integrity: sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==} + + '@types/markdown-it@14.1.2': + resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/mdurl@2.0.0': + resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} + '@types/node-fetch@2.6.12': resolution: {integrity: sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==} - '@types/node@20.17.52': - resolution: {integrity: sha512-2aj++KfxubvW/Lc0YyXE3OEW7Es8TWn1MsRzYgcOGyTNQxi0L8rxQUCZ7ZbyOBWZQD5I63PV9egZWMsapVaklg==} + '@types/node@20.19.11': + resolution: {integrity: sha512-uug3FEEGv0r+jrecvUUpbY8lLisvIjg6AAic6a2bSP5OEOLeJsDSnvhCDov7ipFFMXS3orMpzlmi0ZcuGkBbow==} - '@types/node@22.10.7': - resolution: {integrity: sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg==} + '@types/node@22.17.2': + resolution: {integrity: sha512-gL6z5N9Jm9mhY+U2KXZpteb+09zyffliRkZyZOHODGATyC5B1Jt/7TzuuiLkFsSUMLbS1OLmlj/E+/3KF4Q/4w==} - '@types/node@22.15.24': - resolution: {integrity: sha512-w9CZGm9RDjzTh/D+hFwlBJ3ziUaVw7oufKA3vOFSOZlzmW9AkZnfjPb+DLnrV6qtgL/LNmP0/2zBNCFHL3F0ng==} + '@types/node@24.3.0': + resolution: {integrity: sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==} - '@types/react-dom@19.1.5': - resolution: {integrity: sha512-CMCjrWucUBZvohgZxkjd6S9h0nZxXjzus6yDfUb+xLxYM7VvjKNH1tQrE9GWLql1XoOP4/Ds3bwFqShHUYraGg==} + '@types/react-dom@19.1.7': + resolution: {integrity: sha512-i5ZzwYpqjmrKenzkoLM2Ibzt6mAsM7pxB6BCIouEVVmgiqaMj1TjaK7hnA36hbW5aZv20kx7Lw6hWzPWg0Rurw==} peerDependencies: '@types/react': ^19.0.0 @@ -1541,52 +2004,267 @@ packages: peerDependencies: '@types/react': '*' - '@types/react@19.1.6': - resolution: {integrity: sha512-JeG0rEWak0N6Itr6QUx+X60uQmN+5t3j9r/OVDtWzFXKaj6kD1BwJzOksD0FF6iWxZlbE1kB0q9vtnU2ekqa1Q==} + '@types/react@19.1.10': + resolution: {integrity: sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg==} '@types/stream-buffers@3.0.7': resolution: {integrity: sha512-azOCy05sXVXrO+qklf0c/B07H/oHaIuDDAiHPVwlk3A9Ek+ksHyTeMajLZl3r76FxpPpxem//4Te61G1iW3Giw==} - '@types/websocket@1.0.10': - resolution: {integrity: sha512-svjGZvPB7EzuYS94cI7a+qhwgGU1y89wUgjT6E2wVUfmAGIvRfT7obBvRtnhXCSsoMdlG4gBFGE7MfkIXZLoww==} + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} - '@uiw/codemirror-extensions-basic-setup@4.23.12': - resolution: {integrity: sha512-l9vuiXOTFDBetYrRLDmz3jDxQHDsrVAZ2Y6dVfmrqi2AsulsDu+y7csW0JsvaMqo79rYkaIZg8yeqmDgMb7VyQ==} - peerDependencies: - '@codemirror/autocomplete': '>=6.0.0' - '@codemirror/commands': '>=6.0.0' - '@codemirror/language': '>=6.0.0' - '@codemirror/lint': '>=6.0.0' - '@codemirror/search': '>=6.0.0' - '@codemirror/state': '>=6.0.0' - '@codemirror/view': '>=6.0.0' + '@types/web-bluetooth@0.0.21': + resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} - '@uiw/codemirror-theme-github@4.23.12': - resolution: {integrity: sha512-yxgycQxA1fNVdrjIZ7H7pq+9Q+BeKLmD5oq5oOlw7kVJrnToOMBylv5oIWplVd2s2LFo47lIhWrVC9Ay3b6Baw==} + '@types/ws@8.18.1': + resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} - '@uiw/codemirror-theme-xcode@4.23.12': - resolution: {integrity: sha512-9KnTjhXFqwGphQl18CGRzRc6yB8SZkyv4L7u+j1QOq/nFmk3i44HKuHiuKY+J+XfFq3Cmxg629o3CK4ecMsvUQ==} + '@typescript/native-preview-darwin-arm64@7.0.0-dev.20250821.1': + resolution: {integrity: sha512-b3L13MVLvigBTf8jc6fDQnbWi4RC5XoXgaakftm+gQtFNtriU5Iqfl3ROBjiwPgUMmuXfjnSpau1zKwDY8M5zw==} + engines: {node: '>=20.6.0'} + cpu: [arm64] + os: [darwin] - '@uiw/codemirror-themes@4.23.12': - resolution: {integrity: sha512-8etEByfS9yttFZW0rcWhdZc7/JXJKRWlU5lHmJCI3GydZNGCzydNA+HtK9nWKpJUndVc58Q2sqSC5OIcwq8y6A==} - peerDependencies: - '@codemirror/language': '>=6.0.0' - '@codemirror/state': '>=6.0.0' - '@codemirror/view': '>=6.0.0' + '@typescript/native-preview-darwin-x64@7.0.0-dev.20250821.1': + resolution: {integrity: sha512-EIFcmzaFhM176D6jHD1aJ1FGos9sTokWeFvVfJVDSk27box/xMNtfwM7OXg17OIWoF2IDC6zpyOV4mOs+9ADCg==} + engines: {node: '>=20.6.0'} + cpu: [x64] + os: [darwin] - '@uiw/react-codemirror@4.23.12': - resolution: {integrity: sha512-yseqWdzoAAGAW7i/NiU8YrfSLVOEBjQvSx1KpDTFVV/nn0AlAZoDVTIPEBgdXrPlVUQoCrwgpEaj3uZCklk9QA==} - peerDependencies: - '@babel/runtime': '>=7.11.0' - '@codemirror/state': '>=6.0.0' - '@codemirror/theme-one-dark': '>=6.0.0' - '@codemirror/view': '>=6.0.0' - codemirror: '>=6.0.0' - react: '>=16.8.0' - react-dom: '>=16.8.0' + '@typescript/native-preview-linux-arm64@7.0.0-dev.20250821.1': + resolution: {integrity: sha512-V1Ok+gnzLrrMIjUdIOf8uiNEy7t9OJ7/x3G8/0F/WRfVyT0p1Tcv70g1nEStiMk+60wjyyP76F81GDn9wXg0aQ==} + engines: {node: '>=20.6.0'} + cpu: [arm64] + os: [linux] + + '@typescript/native-preview-linux-arm@7.0.0-dev.20250821.1': + resolution: {integrity: sha512-oFv7qu8uLmJtHcebQYbP6s7tG3kq+hstXHkOU76d2Ke1F1kJDaQmOz4MU1nY/AVtOs6dqQPPJ0jfpnrgsq8fYg==} + engines: {node: '>=20.6.0'} + cpu: [arm] + os: [linux] + + '@typescript/native-preview-linux-x64@7.0.0-dev.20250821.1': + resolution: {integrity: sha512-l5UPAxtM10B0nECUHpmSwcxxDZJhGB44uaFaMpKrDVC3Cl4/4M//HgRcYA83+VSDA+Nz1naanXBNTWFgTY6ygw==} + engines: {node: '>=20.6.0'} + cpu: [x64] + os: [linux] + + '@typescript/native-preview-win32-arm64@7.0.0-dev.20250821.1': + resolution: {integrity: sha512-79ICW5hDFZRjNDXpvKdnCYuNaDo/SlGrL2x2cwqm7CXor/bh1QJ9v993AQHP2ZRc13GxHT+SIIUi4FXVhy47ug==} + engines: {node: '>=20.6.0'} + cpu: [arm64] + os: [win32] + + '@typescript/native-preview-win32-x64@7.0.0-dev.20250821.1': + resolution: {integrity: sha512-n9DOZc8e3azx5FedX5U4llAsUF250Z0TOfNxnB/E9njWCkoh8mguKFMM+RQpoppV2jl7nhfpzlNJ1Vgp1OA45Q==} + engines: {node: '>=20.6.0'} + cpu: [x64] + os: [win32] + + '@typescript/native-preview@7.0.0-dev.20250821.1': + resolution: {integrity: sha512-o6rAnWoRc+IDZ+sxblSn2ZEbdhl5ggK4IvYcNrYAF1phiZKC3PS2WT12O0EJ9MT9Xtu3+32gxqJZ4YORaEIGKQ==} + engines: {node: '>=20.6.0'} + hasBin: true + + '@uiw/codemirror-extensions-basic-setup@4.25.1': + resolution: {integrity: sha512-zxgA2QkvP3ZDKxTBc9UltNFTrSeFezGXcZtZj6qcsBxiMzowoEMP5mVwXcKjpzldpZVRuY+JCC+RsekEgid4vg==} + peerDependencies: + '@codemirror/autocomplete': '>=6.0.0' + '@codemirror/commands': '>=6.0.0' + '@codemirror/language': '>=6.0.0' + '@codemirror/lint': '>=6.0.0' + '@codemirror/search': '>=6.0.0' + '@codemirror/state': '>=6.0.0' + '@codemirror/view': '>=6.0.0' + + '@uiw/codemirror-theme-github@4.25.1': + resolution: {integrity: sha512-l70gUrYAxHlpMWmG8A/I4PN5h5zzPxV+c9pRtsw+VtdmdgVWMh3JaSsuFZlf6h311s+/WB2FMZKdFw5SwrFWaA==} + + '@uiw/codemirror-theme-xcode@4.25.1': + resolution: {integrity: sha512-Pgf6jNz6T8+h7e94xJN0VpyJuJjbQSH/3xWEmEwP22d+Fkupsf+Bjz2oyfDjKpHIdMhIzSlcPF1qrFL7H5m5Lw==} + + '@uiw/codemirror-themes@4.25.1': + resolution: {integrity: sha512-6o8tQ8bdq14RuVFpZ7l9u8KnuPq824uG3U1VV933Uhv8mfaxaoaOQSjv6T2bQUPhjH6ZlEu5+tAMkOfIL21eIQ==} + peerDependencies: + '@codemirror/language': '>=6.0.0' + '@codemirror/state': '>=6.0.0' + '@codemirror/view': '>=6.0.0' + + '@uiw/react-codemirror@4.25.1': + resolution: {integrity: sha512-eESBKHndoYkaEGlKCwRO4KrnTw1HkWBxVpEeqntoWTpoFEUYxdLWUYmkPBVk4/u8YzVy9g91nFfIRpqe5LjApg==} + peerDependencies: + '@babel/runtime': '>=7.11.0' + '@codemirror/state': '>=6.0.0' + '@codemirror/theme-one-dark': '>=6.0.0' + '@codemirror/view': '>=6.0.0' + codemirror: '>=6.0.0' + react: '>=17.0.0' + react-dom: '>=17.0.0' + + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + + '@vitejs/plugin-rsc@0.4.11': + resolution: {integrity: sha512-+4H4wLi+Y9yF58znBfKgGfX8zcqUGt8ngnmNgzrdGdF1SVz7EO0sg7WnhK5fFVHt6fUxsVEjmEabsCWHKPL1Tw==} + peerDependencies: + react: '*' + react-dom: '*' + vite: '*' + + '@vitejs/plugin-vue@6.0.1': + resolution: {integrity: sha512-+MaE752hU0wfPFJEUAIxqw18+20euHHdxVtMvbFcOEpjEyfqXH/5DCoTHiVJ0J29EhTJdoTkjEv5YBKU9dnoTw==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 + vue: ^3.2.25 + + '@vitest/expect@3.2.4': + resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} + + '@vitest/mocker@3.2.4': + resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@3.2.4': + resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} + + '@vitest/runner@3.2.4': + resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} + + '@vitest/snapshot@3.2.4': + resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==} + + '@vitest/spy@3.2.4': + resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} + + '@vitest/utils@3.2.4': + resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} + + '@vue/compiler-core@3.5.18': + resolution: {integrity: sha512-3slwjQrrV1TO8MoXgy3aynDQ7lslj5UqDxuHnrzHtpON5CBinhWjJETciPngpin/T3OuW3tXUf86tEurusnztw==} + + '@vue/compiler-dom@3.5.18': + resolution: {integrity: sha512-RMbU6NTU70++B1JyVJbNbeFkK+A+Q7y9XKE2EM4NLGm2WFR8x9MbAtWxPPLdm0wUkuZv9trpwfSlL6tjdIa1+A==} + + '@vue/compiler-sfc@3.5.18': + resolution: {integrity: sha512-5aBjvGqsWs+MoxswZPoTB9nSDb3dhd1x30xrrltKujlCxo48j8HGDNj3QPhF4VIS0VQDUrA1xUfp2hEa+FNyXA==} + + '@vue/compiler-ssr@3.5.18': + resolution: {integrity: sha512-xM16Ak7rSWHkM3m22NlmcdIM+K4BMyFARAfV9hYFl+SFuRzrZ3uGMNW05kA5pmeMa0X9X963Kgou7ufdbpOP9g==} + + '@vue/devtools-api@8.0.0': + resolution: {integrity: sha512-I2jF/knesMU36zTw1hnExjoixDZvDoantiWKVrHpLd2J160zqqe8vp3vrGfjWdfuHmPJwSXe/YNG3rYOYiwy1Q==} - acorn@8.14.1: - resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==} + '@vue/devtools-kit@8.0.0': + resolution: {integrity: sha512-b11OeQODkE0bctdT0RhL684pEV2DPXJ80bjpywVCbFn1PxuL3bmMPDoJKjbMnnoWbrnUYXYzFfmMWBZAMhORkQ==} + + '@vue/devtools-shared@8.0.0': + resolution: {integrity: sha512-jrKnbjshQCiOAJanoeJjTU7WaCg0Dz2BUal6SaR6VM/P3hiFdX5Q6Pxl73ZMnrhCxNK9nAg5hvvRGqs+6dtU1g==} + + '@vue/reactivity@3.5.18': + resolution: {integrity: sha512-x0vPO5Imw+3sChLM5Y+B6G1zPjwdOri9e8V21NnTnlEvkxatHEH5B5KEAJcjuzQ7BsjGrKtfzuQ5eQwXh8HXBg==} + + '@vue/runtime-core@3.5.18': + resolution: {integrity: sha512-DUpHa1HpeOQEt6+3nheUfqVXRog2kivkXHUhoqJiKR33SO4x+a5uNOMkV487WPerQkL0vUuRvq/7JhRgLW3S+w==} + + '@vue/runtime-dom@3.5.18': + resolution: {integrity: sha512-YwDj71iV05j4RnzZnZtGaXwPoUWeRsqinblgVJwR8XTXYZ9D5PbahHQgsbmzUvCWNF6x7siQ89HgnX5eWkr3mw==} + + '@vue/server-renderer@3.5.18': + resolution: {integrity: sha512-PvIHLUoWgSbDG7zLHqSqaCoZvHi6NNmfVFOqO+OnwvqMz/tqQr3FuGWS8ufluNddk7ZLBJYMrjcw1c6XzR12mA==} + peerDependencies: + vue: 3.5.18 + + '@vue/shared@3.5.18': + resolution: {integrity: sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA==} + + '@vueuse/core@13.7.0': + resolution: {integrity: sha512-myagn09+c6BmS6yHc1gTwwsdZilAovHslMjyykmZH3JNyzI5HoWhv114IIdytXiPipdHJ2gDUx0PB93jRduJYg==} + peerDependencies: + vue: ^3.5.0 + + '@vueuse/integrations@13.7.0': + resolution: {integrity: sha512-Na5p0ONLepNV/xCBi8vBMuzCOZh9CFT/OHnrUlABWXgWTWSHM3wrVaLS1xvAijPLU5B1ysyJDDW/hKak80oLGA==} + peerDependencies: + async-validator: ^4 + axios: ^1 + change-case: ^5 + drauu: ^0.4 + focus-trap: ^7 + fuse.js: ^7 + idb-keyval: ^6 + jwt-decode: ^4 + nprogress: ^0.2 + qrcode: ^1.5 + sortablejs: ^1 + universal-cookie: ^7 || ^8 + vue: ^3.5.0 + peerDependenciesMeta: + async-validator: + optional: true + axios: + optional: true + change-case: + optional: true + drauu: + optional: true + focus-trap: + optional: true + fuse.js: + optional: true + idb-keyval: + optional: true + jwt-decode: + optional: true + nprogress: + optional: true + qrcode: + optional: true + sortablejs: + optional: true + universal-cookie: + optional: true + + '@vueuse/metadata@13.7.0': + resolution: {integrity: sha512-8okFhS/1ite8EwUdZZfvTYowNTfXmVCOrBFlA31O0HD8HKXhY+WtTRyF0LwbpJfoFPc+s9anNJIXMVrvP7UTZg==} + + '@vueuse/shared@13.7.0': + resolution: {integrity: sha512-Wi2LpJi4UA9kM0OZ0FCZslACp92HlVNw1KPaDY6RAzvQ+J1s7seOtcOpmkfbD5aBSmMn9NvOakc8ZxMxmDXTIg==} + peerDependencies: + vue: ^3.5.0 + + '@xterm/addon-clipboard@0.1.0': + resolution: {integrity: sha512-zdoM7p53T5sv/HbRTyp4hY0kKmEQ3MZvAvEtiXqNIHc/JdpqwByCtsTaQF5DX2n4hYdXRPO4P/eOS0QEhX1nPw==} + peerDependencies: + '@xterm/xterm': ^5.4.0 + + '@xterm/addon-fit@0.10.0': + resolution: {integrity: sha512-UFYkDm4HUahf2lnEyHvio51TNGiLK66mqP2JoATy7hRZeXaGMRDr00JiSF7m63vR5WKATF605yEggJKsw0JpMQ==} + peerDependencies: + '@xterm/xterm': ^5.0.0 + + '@xterm/addon-unicode11@0.8.0': + resolution: {integrity: sha512-LxinXu8SC4OmVa6FhgwsVCBZbr8WoSGzBl2+vqe8WcQ6hb1r6Gj9P99qTNdPiFPh4Ceiu2pC8xukZ6+2nnh49Q==} + peerDependencies: + '@xterm/xterm': ^5.0.0 + + '@xterm/addon-web-links@0.11.0': + resolution: {integrity: sha512-nIHQ38pQI+a5kXnRaTgwqSHnX7KE6+4SVoceompgHL26unAxdfP6IPqUTSYPQgSwM56hsElfoNrrW5V7BUED/Q==} + peerDependencies: + '@xterm/xterm': ^5.0.0 + + '@xterm/xterm@5.5.0': + resolution: {integrity: sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==} + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} engines: {node: '>=0.4.0'} hasBin: true @@ -1610,6 +2288,10 @@ packages: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} + ansis@4.1.0: + resolution: {integrity: sha512-BGcItUBWSMRgOCe+SVZJ+S7yTRG0eGt9cXAHev72yuGcY23hnLA7Bky5L/xLyPINoSN95geovfBkqoTlNZYa7w==} + engines: {node: '>=14'} + arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} @@ -1619,6 +2301,10 @@ packages: arktype@2.1.20: resolution: {integrity: sha512-IZCEEXaJ8g+Ijd59WtSYwtjnqXiwM8sWQ5EjGamcto7+HVN9eK0C4p0zDlCuAwWhpqr6fIBkxPuYDl4/Mcj/+Q==} + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -1661,11 +2347,26 @@ packages: bare-events: optional: true - bippy@0.3.14: - resolution: {integrity: sha512-lg8i4YjVBcAsF8mKVaWjbgG/yo1fY9SUbGgilsnkOnLyU37Jj0XDLWTBeuZjFrrd6LNf1od8/tO/soIi2KUTrw==} + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + better-sqlite3@11.10.0: + resolution: {integrity: sha512-EwhOpyXiOEL/lKzHz9AW1msWFNzGc/z+LzeB3/jnFJpxu+th2yqvzsSWas1v9jgs9+xiXJcD5A8CJxAG2TaghQ==} + + bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + + bippy@0.3.18: + resolution: {integrity: sha512-ndTOYOJh/yf988NVRS8W0dhhqSXS88kWVbmKbePtbUP1eaRCN07cjjRVZwIFSdL1HtQ4mhtxJYmqCBT8NyAl/g==} peerDependencies: react: '>=17.0.1' + birpc@2.5.0: + resolution: {integrity: sha512-VSWO/W6nNQdyP520F1mhf+Lc2f8pjGQOtoHHm7Ze8Go1kX7akpVIrtTa0fn+HB0QJEDVacl6aO08YE0PgXfdnQ==} + + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} @@ -1677,6 +2378,9 @@ packages: buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + bufferutil@4.0.9: resolution: {integrity: sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==} engines: {node: '>=6.14.2'} @@ -1692,10 +2396,30 @@ packages: caniuse-lite@1.0.30001718: resolution: {integrity: sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw==} + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + chai@5.2.1: + resolution: {integrity: sha512-5nFxhUrX0PqtyogoYOA8IPswy5sZFTOsBFl/9bNsmDLgsxYTzSZQJDPppDnZPTQbzSEm0hqGjWPzRemQCYbD6A==} + engines: {node: '>=18'} + + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + check-error@2.1.1: + resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} + engines: {node: '>= 16'} + chokidar@4.0.3: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} + chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + chownr@3.0.0: resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} engines: {node: '>=18'} @@ -1718,6 +2442,9 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} @@ -1728,6 +2455,10 @@ packages: resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} engines: {node: '>=18'} + copy-anything@3.0.5: + resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} + engines: {node: '>=12.13'} + crelt@1.0.6: resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} @@ -1738,6 +2469,10 @@ packages: csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + debug@4.4.0: resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} engines: {node: '>=6.0'} @@ -1759,6 +2494,10 @@ packages: decimal.js@10.5.0: resolution: {integrity: sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==} + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + dedent@1.6.0: resolution: {integrity: sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA==} peerDependencies: @@ -1767,18 +2506,133 @@ packages: babel-plugin-macros: optional: true + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + detect-libc@2.0.2: + resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} + engines: {node: '>=8'} + detect-libc@2.0.4: resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} engines: {node: '>=8'} - dotenv@16.5.0: - resolution: {integrity: sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==} + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + dotenv@17.2.1: + resolution: {integrity: sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78BCHNbSxEQ==} engines: {node: '>=12'} + drizzle-kit@0.31.4: + resolution: {integrity: sha512-tCPWVZWZqWVx2XUsVpJRnH9Mx0ClVOf5YUHerZ5so1OKSlqww4zy1R5ksEdGRcO3tM3zj0PYN6V48TbQCL1RfA==} + hasBin: true + + drizzle-orm@0.44.4: + resolution: {integrity: sha512-ZyzKFpTC/Ut3fIqc2c0dPZ6nhchQXriTsqTNs4ayRgl6sZcFlMs9QZKPSHXK4bdOf41GHGWf+FrpcDDYwW+W6Q==} + 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' + '@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 + '@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 + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -1798,10 +2652,17 @@ packages: end-of-stream@1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} - enhanced-resolve@5.18.1: - resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==} + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + + enhanced-resolve@5.18.3: + resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} engines: {node: '>=10.13.0'} + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + err-code@2.0.3: resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} @@ -1824,8 +2685,18 @@ packages: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} - esbuild@0.25.5: - resolution: {integrity: sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==} + esbuild-register@3.6.0: + resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==} + peerDependencies: + esbuild: '>=0.12 <1' + + esbuild@0.18.20: + resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} + engines: {node: '>=12'} + hasBin: true + + esbuild@0.25.9: + resolution: {integrity: sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==} engines: {node: '>=18'} hasBin: true @@ -1843,6 +2714,14 @@ packages: resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==} engines: {node: '>=6'} + expand-template@2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} + + expect-type@1.2.2: + resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} + engines: {node: '>=12.0.0'} + fast-fifo@1.3.2: resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} @@ -1854,6 +2733,25 @@ packages: picomatch: optional: true + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + + file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + + focus-trap@7.6.5: + resolution: {integrity: sha512-7Ke1jyybbbPZyZXFxEftUtxFGLMpE2n6A+z//m4CRDlj0hW+o3iYSmh8nFlYMurOiJVDmJRilUQtJr08KfIxlg==} + foreground-child@3.3.0: resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} engines: {node: '>=14'} @@ -1862,9 +2760,12 @@ packages: resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==} engines: {node: '>= 6'} - fs-extra@10.1.0: - resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} - engines: {node: '>=12'} + formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} fsevents@2.3.2: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} @@ -1894,6 +2795,9 @@ packages: get-tsconfig@4.10.1: resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==} + github-from-package@0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + glob@10.4.5: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} hasBin: true @@ -1924,10 +2828,19 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - hono@4.7.6: - resolution: {integrity: sha512-564rVzELU+9BRqqx5k8sT2NFwGD3I3Vifdb6P7CmM6FiarOSY+fDC+6B+k9wcCb86ReoayteZP2ki0cRLN1jbw==} + hast-util-to-html@9.0.5: + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + + hono@4.7.10: + resolution: {integrity: sha512-QkACju9MiN59CKSY5JsGZCYmPZkA6sIW6OFCUp7qDjZu6S6KHtJHhAc9Uy9mV9F8PJ1/HQ3ybZF2yjCa/73fvQ==} engines: {node: '>=16.9.0'} + hookable@5.5.3: + resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + hosted-git-info@6.1.3: resolution: {integrity: sha512-HVJyzUrLIL1c0QmviVh5E8VGyUS7xCFPS6yydaVd1UegW+ibV/CohqTH9MkOLDp5o+rb82DMo77PTuc9F/8GKw==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -1936,6 +2849,18 @@ packages: resolution: {integrity: sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==} engines: {node: '>=14'} + html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + intl-messageformat@10.7.16: resolution: {integrity: sha512-UmdmHUmp5CIKKjSoE10la5yfU+AYJAaiYLsodbjL4lji83JNvgOQUjGaGhGrpFCb0Uh7sl7qfP1IyILa8Z40ug==} @@ -1951,8 +2876,15 @@ packages: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} - isbot@5.1.28: - resolution: {integrity: sha512-qrOp4g3xj8YNse4biorv6O5ZShwsJM0trsoda4y7j/Su7ZtTTfVXFzbKkpgcSoDrHS8FcTuUwcU04YimZlZOxw==} + is-reference@3.0.3: + resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} + + is-what@4.1.16: + resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} + engines: {node: '>=12.13'} + + isbot@5.1.30: + resolution: {integrity: sha512-3wVJEonAns1OETX83uWsk5IAne2S5zfDcntD2hbtU23LelSqNXzXs9zKjMPOLMzroCgIjCfjYAEHrd2D6FOkiA==} engines: {node: '>=18'} isexe@2.0.0: @@ -1966,16 +2898,22 @@ packages: jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - jiti@2.4.2: - resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} + jiti@2.5.1: + resolution: {integrity: sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==} hasBin: true - jose@6.0.11: - resolution: {integrity: sha512-QxG7EaliDARm1O1S8BGakqncGT9s25bKL1WSf6/oa17Tkqwi8D2ZNglqCF+DsYF88/rV66Q/Q2mFAy697E1DUg==} + jose@6.1.0: + resolution: {integrity: sha512-TTQJyoEoKcC1lscpVDCSsVgYzUDg/0Bt3WE//WiTPK6uOCQC2KZS4MpugbMWt/zyjkopgZoXhZuCi00gLudfUA==} + + js-base64@3.7.7: + resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==} js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + js-tokens@9.0.1: + resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true @@ -2001,9 +2939,6 @@ packages: engines: {node: '>=6'} hasBin: true - jsonfile@6.1.0: - resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} - jsonpath-plus@10.3.0: resolution: {integrity: sha512-8TNmfeTCk2Le33A3vRRwtuworG/L5RrgMvdjhKZxvyShO+mBu2fP50OWUjRLNtvw344DdDarFh9buFAZs5ujeA==} engines: {node: '>=18.0.0'} @@ -2013,60 +2948,67 @@ packages: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} - lefthook-darwin-arm64@1.11.13: - resolution: {integrity: sha512-gHwHofXupCtzNLN+8esdWfFTnAEkmBxE/WKA0EwxPPJXdZYa1GUsiG5ipq/CdG/0j8ekYyM9Hzyrrk5BqJ42xw==} + layerr@3.0.0: + resolution: {integrity: sha512-tv754Ki2dXpPVApOrjTyRo4/QegVb9eVFq4mjqp4+NM5NaX7syQvN5BBNfV/ZpAHCEHV24XdUVrBAoka4jt3pA==} + + lefthook-darwin-arm64@1.12.3: + resolution: {integrity: sha512-j1lwaosWRy3vhz8oQgCS1M6EUFN95aIYeNuqkczsBoAA6BDNAmVP1ctYEIYUK4bYaIgENbqbA9prYMAhyzh6Og==} cpu: [arm64] os: [darwin] - lefthook-darwin-x64@1.11.13: - resolution: {integrity: sha512-zYxkWNUirmTidhskY9J9AwxvdMi3YKH+TqZ3AQ1EOqkOwPBWJQW5PbnzsXDrd3YnrtZScYm/tE/moXJpEPPIpQ==} + lefthook-darwin-x64@1.12.3: + resolution: {integrity: sha512-x6aWFfLQX4m5zQ4X9zh5+hHOE5XTvNjz2zB9DI+xbIBLs2RRg0xJNT3OfgSrBU1QtEBneJ5dRQP5nl47td9GDQ==} cpu: [x64] os: [darwin] - lefthook-freebsd-arm64@1.11.13: - resolution: {integrity: sha512-gJzWnllcMcivusmPorEkXPpEciKotlBHn7QxWwYaSjss/U3YdZu+NTjDO30b3qeiVlyq4RAZ4BPKJODXxHHwUA==} + lefthook-freebsd-arm64@1.12.3: + resolution: {integrity: sha512-41OmulLqVZ0EOHmmHouJrpL59SwDD7FLoso4RsQVIBPaf8fHacdLo07Ye28VWQ5XolZQvnWcr1YXKo4JhqQMyw==} cpu: [arm64] os: [freebsd] - lefthook-freebsd-x64@1.11.13: - resolution: {integrity: sha512-689XdchgtDvZQWFFx1szUvm/mqrq/v6laki0odq5FAfcSgUeLu3w+z6UicBS5l55eFJuQTDNKARFqrKJ04e+Vw==} + lefthook-freebsd-x64@1.12.3: + resolution: {integrity: sha512-741/JRCJIS++hgYEH2uefN4FsH872V7gy2zDhcfQofiZnWP7+qhl4Wmwi8IpjIu4X7hLOC4cT18LOVU5L8KV9Q==} cpu: [x64] os: [freebsd] - lefthook-linux-arm64@1.11.13: - resolution: {integrity: sha512-ujCLbaZg5S/Ao8KZAcNSb+Y3gl898ZEM0YKyiZmZo22dFFpm/5gcV46pF3xaqIw5IpH+3YYDTKDU+qTetmARyQ==} + lefthook-linux-arm64@1.12.3: + resolution: {integrity: sha512-BXIy1aDFZmFgmebJliNrEqZfX1lSOD4b/USvANv1UirFrNgTq5SRssd1CKfflT2PwKX6LsJTD4WabLLWZOxp9A==} cpu: [arm64] os: [linux] - lefthook-linux-x64@1.11.13: - resolution: {integrity: sha512-O5WdodeBtFOXQlvPcckqp4W/yqVM9DbVQBkvOxwSJlmsxO4sGYK1TqdxH9ihLB85B2kPPssZj9ze36/oizzhVQ==} + lefthook-linux-x64@1.12.3: + resolution: {integrity: sha512-FRdwdj5jsQAP2eVrtkVUqMqYNCbQ2Ix84izy29/BvLlu/hVypAGbDfUkgFnsmAd6ZsCBeYCEtPuqyg3E3SO0Rg==} cpu: [x64] os: [linux] - lefthook-openbsd-arm64@1.11.13: - resolution: {integrity: sha512-SyBpciUfvY/lUDbZu7L6MtL/SVG2+yMTckBgb4PdJQhJlisY0IsyOYdlTw2icPPrY7JnwdsFv8UW0EJOB76W4g==} + lefthook-openbsd-arm64@1.12.3: + resolution: {integrity: sha512-tch5wXY4GOjKAYohH7OFoxNdVHuUSYt2Pulo2VTkMYEG8IrvJnRO5MkvgHtKDHzU5mfABQYv5+ccJykDx5hQWA==} cpu: [arm64] os: [openbsd] - lefthook-openbsd-x64@1.11.13: - resolution: {integrity: sha512-6+/0j6O2dzo9cjTWUKfL2J6hRR7Krna/ssqnW8cWh8QHZKO9WJn34epto9qgjeHwSysou8byI7Mwv5zOGthLCQ==} + lefthook-openbsd-x64@1.12.3: + resolution: {integrity: sha512-IHbHg/rUFXrAN7LnjcQEtutCHBaD49CZge96Hpk0GZ2eEG5GTCNRnUyEf+Kf3+RTqHFgwtADdpeDa/ZaGZTM4g==} cpu: [x64] os: [openbsd] - lefthook-windows-arm64@1.11.13: - resolution: {integrity: sha512-w5TwZ8bsZ17uOMtYGc5oEb4tCHjNTSeSXRy6H9Yic8E7IsPZtZLkaZGnIIwgXFuhhrcCdc6FuTvKt2tyV7EW2g==} + lefthook-windows-arm64@1.12.3: + resolution: {integrity: sha512-wghcE5TSpb+mbtemUV6uAo9hEK09kxRzhf2nPdeDX+fw42cL2TGZsbaCnDyzaY144C+L2/wEWrLIHJMnZYkuqA==} cpu: [arm64] os: [win32] - lefthook-windows-x64@1.11.13: - resolution: {integrity: sha512-7lvwnIs8CNOXKU4y3i1Pbqna+QegIORkSD2VCuHBNpIJ8H84NpjoG3tKU91IM/aI1a2eUvCk+dw+1rfMRz7Ytg==} + lefthook-windows-x64@1.12.3: + resolution: {integrity: sha512-7Co/L8e2x2hGC1L33jDJ4ZlTkO3PJm25GOGpLfN1kqwhGB/uzMLeTI/PBczjlIN8isUv26ouNd9rVR7Bibrwyg==} cpu: [x64] os: [win32] - lefthook@1.11.13: - resolution: {integrity: sha512-SDTk3D4nW1XRpR9u9fdYQ/qj1xeZVIwZmIFdJUnyq+w9ZLdCCvIrOmtD8SFiJowSevISjQDC+f9nqyFXUxc0SQ==} + lefthook@1.12.3: + resolution: {integrity: sha512-huMg+mGp6wHPjkaLdchuOvxVRMzvz6OVdhivatiH2Qn47O5Zm46jwzbVPYIanX6N/8ZTjGLBxv8tZ0KYmKt/Jg==} hasBin: true + libsql@0.5.17: + resolution: {integrity: sha512-RRlj5XQI9+Wq+/5UY8EnugSWfRmHEw4hn3DKlPrkUgZONsge1PwTtHcpStP6MSNi8ohcbsRgEHJaymA33a8cBw==} + os: [darwin, linux, win32] + lightningcss-darwin-arm64@1.30.1: resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==} engines: {node: '>= 12.0.0'} @@ -2137,6 +3079,9 @@ packages: lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + loupe@3.1.4: + resolution: {integrity: sha512-wJzkKwJrheKtknCOKNEtDK4iqg/MxmZheEMtSTYvnzRdEYaZzmgH976nenp8WdJRdx5Vc1X/9MO0Oszl6ezeXg==} + lru-cache@10.2.2: resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==} engines: {node: 14 || >=16.14} @@ -2148,18 +3093,39 @@ packages: resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} engines: {node: '>=12'} - lucide-react@0.511.0: - resolution: {integrity: sha512-VK5a2ydJ7xm8GvBeKLS9mu1pVK6ucef9780JVUjw6bAjJL/QXnd4Y0p7SPeOUMC27YhzNCZvm5d/QX0Tp3rc0w==} + lucide-react@0.540.0: + resolution: {integrity: sha512-armkCAqQvO62EIX4Hq7hqX/q11WSZu0Jd23cnnqx0/49yIxGXyL/zyZfBxNN9YDx0ensPTb4L+DjTh3yQXUxtQ==} peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + mark.js@8.11.1: + resolution: {integrity: sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==} + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} + mdast-util-to-hast@13.2.0: + resolution: {integrity: sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} @@ -2173,18 +3139,34 @@ packages: engines: {node: '>=16'} hasBin: true + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + minipass@7.1.2: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} - minizlib@3.0.1: - resolution: {integrity: sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==} + minisearch@7.1.2: + resolution: {integrity: sha512-R1Pd9eF+MD5JYDDSPAp/q1ougKglm14uEkPMvQ/05RGmx6G9wvmLTrTI/Q5iPNJLYqNdsDQ7qTGIcNWR+FrHmA==} + + minizlib@3.0.2: + resolution: {integrity: sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==} engines: {node: '>= 18'} + mitt@3.0.1: + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + + mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + mkdirp@3.0.1: resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} engines: {node: '>=10'} @@ -2202,6 +3184,18 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + napi-build-utils@2.0.0: + resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} + + node-abi@3.75.0: + resolution: {integrity: sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg==} + engines: {node: '>=10'} + + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead + node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -2211,6 +3205,10 @@ packages: encoding: optional: true + node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + node-gyp-build@4.8.4: resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} hasBin: true @@ -2238,14 +3236,20 @@ packages: resolution: {integrity: sha512-1dKY+86/AIiq1tkKVD3l0WI+Gd3vkknVGAggsFeBkTvbhMQ1OND/LKkYv4JtXPKUJ8bOTCyLiqEg2P6QNdK+Gg==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - oauth4webapi@3.5.1: - resolution: {integrity: sha512-txg/jZQwcbaF7PMJgY7aoxc9QuCxHVFMiEkDIJ60DwDz3PbtXPQnrzo+3X4IRYGChIwWLabRBRpf1k9hO9+xrQ==} + oauth4webapi@3.8.0: + resolution: {integrity: sha512-RSu64fjsBIs6D7s9g5LOCnOohOkI0nnPtlIp/4rrHj2Vb8jGepq+fujkv2Srw4tuw9qa02aETXQzyQUle8nfnQ==} once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - openid-client@6.5.0: - resolution: {integrity: sha512-fAfYaTnOYE2kQCqEJGX9KDObW2aw7IQy4jWpU/+3D3WoCFLbix5Hg6qIPQ6Js9r7f8jDUmsnnguRNCSw4wU/IQ==} + oniguruma-parser@0.12.1: + resolution: {integrity: sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==} + + oniguruma-to-es@4.3.3: + resolution: {integrity: sha512-rPiZhzC3wXwE59YQMRDodUwwT9FZ9nNBwQQfsd1wfdtlKEyCdRV0avrTcSZ5xlIvGRVPd/cx6ZN45ECmS39xvg==} + + openid-client@6.7.0: + resolution: {integrity: sha512-mA8Cex9wGK6Jaqq4vd1sPDK/a+cQ6G+lExVJ9IRjwInN4NcEEntYqLAZsBhZOyHwDx7V1nmPKOvnxOcdLtSpoA==} package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} @@ -2261,6 +3265,19 @@ packages: pathe@1.1.2: resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + pathval@2.0.1: + resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} + engines: {node: '>= 14.16'} + + perfect-debounce@1.0.0: + resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + + periscopic@4.0.2: + resolution: {integrity: sha512-sqpQDUy8vgB7ycLkendSKS6HnVz1Rneoc3Rc+ZBUCe2pbqlVuCC5vF52l0NJ1aiMg/r1qfYF9/myz8CZeI2rjA==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -2268,26 +3285,35 @@ packages: resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} engines: {node: '>=12'} - playwright-core@1.52.0: - resolution: {integrity: sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==} + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + playwright-core@1.55.0: + resolution: {integrity: sha512-GvZs4vU3U5ro2nZpeiwyb0zuFaqb9sUiAJuyrWpcGouD8y9/HLgGbNRjIph7zU9D3hnPaisMl9zG9CgFi/biIg==} engines: {node: '>=18'} hasBin: true - playwright@1.52.0: - resolution: {integrity: sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw==} + playwright@1.55.0: + resolution: {integrity: sha512-sdCWStblvV1YU909Xqx0DhOjPZE4/5lJsIS84IfN9dAZfcl/CIZ5O8l3o0j7hPMjDvqoTF8ZUcc+i/GL5erstA==} engines: {node: '>=18'} hasBin: true - postcss@8.5.4: - resolution: {integrity: sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==} + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} - preact@10.26.7: - resolution: {integrity: sha512-43xS+QYc1X1IPbw03faSgY6I6OYWcLrJRv3hU0+qMOfh/XCHcP0MX2CVjNARYR2cC/guu975sta4OcjlczxD7g==} + preact@10.27.1: + resolution: {integrity: sha512-V79raXEWch/rbqoNc7nT9E4ep7lu+mI3+sBmfRD4i1M73R3WLYcCtdI0ibxGVf4eQL8ZIz2nFacqEC+rmnOORQ==} - prettier@2.8.8: - resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} - engines: {node: '>=10.13.0'} + prebuild-install@7.1.3: + resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} + engines: {node: '>=10'} + hasBin: true + + prettier@3.6.2: + resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} + engines: {node: '>=14'} hasBin: true proc-log@3.0.0: @@ -2302,21 +3328,34 @@ packages: bluebird: optional: true + promise-limit@2.7.0: + resolution: {integrity: sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==} + promise-retry@2.0.1: resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} engines: {node: '>=10'} + property-information@7.1.0: + resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + pump@3.0.2: resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} - react-aria@3.40.0: - resolution: {integrity: sha512-pxZusRI1jCBIvJkORJnhAXey/5U/VJa1whCeP6ETzRKepJiXLRPjJerHHJw+3Q6kAJXADL9qds5xdq4nvmyLRA==} + pump@3.0.3: + resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} + + rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + + react-aria@3.42.0: + resolution: {integrity: sha512-lZF1tVmcO6mTWBHpmo4r58lBxIkt/DeF1gu5vrLv2lF4H213VGdSIG8ogQgMc2NaLHK720wafYVM2m5pRUIKdg==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - react-codemirror-merge@4.23.12: - resolution: {integrity: sha512-BRacz67tcZ5KQnNodJ9ltMd1WmZyQdREOnxcRfVWUr8USSuIcgn1fVYr+6xaEWFS2tTRJJzjUbemZURrlefIXw==} + react-codemirror-merge@4.25.1: + resolution: {integrity: sha512-zjWLz/I1/OkBcAXGxE2vX5LiTOBKQXxmFFGpnUYV7+ZuZr4/UKogpWsY+AI3+ZdDkbn47w+CL8hjRwN7nS7Cqw==} peerDependencies: '@babel/runtime': '>=7.11.0' '@codemirror/state': '>=6.0.0' @@ -2326,10 +3365,10 @@ packages: react: '>=16.8.0' react-dom: '>=16.8.0' - react-dom@19.1.0: - resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==} + react-dom@19.1.1: + resolution: {integrity: sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==} peerDependencies: - react: ^19.1.0 + react: ^19.1.1 react-error-boundary@6.0.0: resolution: {integrity: sha512-gdlJjD7NWr0IfkPlaREN2d9uUZUlksrfOx7SX62VRerwXbMY6ftGCIZua1VG1aXFNOimhISsTq+Owp725b9SiA==} @@ -2345,24 +3384,25 @@ packages: resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} engines: {node: '>=0.10.0'} - react-router-dom@7.6.1: - resolution: {integrity: sha512-vxU7ei//UfPYQ3iZvHuO1D/5fX3/JOqhNTbRR+WjSBWxf9bIvpWK+ftjmdfJHzPOuMQKe2fiEdG+dZX6E8uUpA==} + react-router-dom@7.8.1: + resolution: {integrity: sha512-NkgBCF3sVgCiAWIlSt89GR2PLaksMpoo3HDCorpRfnCEfdtRPLiuTf+CNXvqZMI5SJLZCLpVCvcZrTdtGW64xQ==} engines: {node: '>=20.0.0'} peerDependencies: react: '>=18' react-dom: '>=18' - react-router-hono-server@2.13.0: - resolution: {integrity: sha512-YcxmFpphZL9Jc4CnOgsKw35wcurmiOpTg3vBzjOROIUhEo6rKvUHOg7AM2QJi2Fa8BRJK6MvHaN4haedYo1iiA==} + react-router-hono-server@2.21.0: + resolution: {integrity: sha512-Sq5W6Kv8ttNUScgE+zHPbJEGw4ZXdlmuGpkpeskqi0yv263joDwESIKYU47WMmz5CTpFoSL/QyQ/TzHn3n1Edw==} engines: {node: '>=22.12.0'} hasBin: true peerDependencies: '@cloudflare/workers-types': ^4.20250317.0 - '@react-router/dev': ^7.2.0 + '@hono/node-server': ^1.18.1 + '@react-router/dev': ^7.8.0 '@types/react': ^18.3.10 || ^19.0.0 miniflare: ^3.20241205.0 react-router: ^7.2.0 - vite: ^6.0.0 + vite: ^6.0.0 || ^7.0.0 wrangler: ^4.2.0 peerDependenciesMeta: '@cloudflare/workers-types': @@ -2372,8 +3412,8 @@ packages: wrangler: optional: true - react-router@7.6.1: - resolution: {integrity: sha512-hPJXXxHJZEsPFNVbtATH7+MMX43UDeOauz+EAU4cgqTn7ojdI9qQORqS8Z0qmDlL1TclO/6jLRYUEtbWidtdHQ==} + react-router@7.8.1: + resolution: {integrity: sha512-5cy/M8DHcG51/KUIka1nfZ2QeylS4PJRs6TT8I4PF5axVsI5JUxp0hC0NZ/AEEj8Vw7xsEoD7L/6FY+zoYaOGA==} engines: {node: '>=20.0.0'} peerDependencies: react: '>=18' @@ -2382,8 +3422,8 @@ packages: react-dom: optional: true - react-scan@0.3.4: - resolution: {integrity: sha512-jUkgs+sfK1B7T1jvZ0rQmKZtvUUE7cHB6qDTfCfOTmTJYH2aAFB1fGmE4DXBbQ1kUF+AdjyNT0Lc73LL/dQIbg==} + react-scan@0.4.3: + resolution: {integrity: sha512-jhAQuQ1nja6HUYrSpbmNFHqZPsRCXk8Yqu0lHoRIw9eb8N96uTfXCpVyQhTTnJ/nWqnwuvxbpKVG/oWZT8+iTQ==} hasBin: true peerDependencies: '@remix-run/react': '>=1.0.0' @@ -2402,21 +3442,34 @@ packages: react-router-dom: optional: true - react-stately@3.38.0: - resolution: {integrity: sha512-zS06DsDhH44z7bsOkMHJ0gnjuLO3UWZ33l7JOgFscrv1qa33IG9fn707sI7GAJdLgDiWXJbeFvXdix2jR1fU1w==} + react-stately@3.40.0: + resolution: {integrity: sha512-Icg2q1pxTskx2dph3cFUu9RUQcInq25WZfUcKroX1Kl4jWxBobnfMvuxvJHHkysJh77IsnLmhF3+8If5oCoMFQ==} peerDependencies: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - react@19.1.0: - resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==} + react@19.1.1: + resolution: {integrity: sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==} engines: {node: '>=0.10.0'} + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + readdirp@4.1.2: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} - remix-utils@8.7.0: - resolution: {integrity: sha512-oRumofsYFaxHyPtqLuYe3g2nQi4SMYjCoebaeed0gYHIOKBiPPYdNP6cgmQbFjQQ5pwXV+uQiKLqO6pM9ep3VA==} + regex-recursion@6.0.2: + resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} + + regex-utilities@2.3.0: + resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} + + regex@6.0.1: + resolution: {integrity: sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==} + + remix-utils@8.8.0: + resolution: {integrity: sha512-5CR4a3YwPaCoPUHg+O69UMek05tnFMrtQsoXTU4KzsyU7heDO94IFTjKVzEFhi+s+SSo+ebRMxWvjf/QiPpqiQ==} engines: {node: '>=20.0.0'} peerDependencies: '@edgefirst-dev/batcher': ^1.0.0 @@ -2424,6 +3477,7 @@ packages: '@edgefirst-dev/server-timing': ^0.0.1 '@oslojs/crypto': ^1.0.1 '@oslojs/encoding': ^1.1.0 + '@standard-schema/spec': ^1.0.0 intl-parse-accept-language: ^1.0.0 is-ip: ^5.0.1 react: ^18.0.0 || ^19.0.0 @@ -2440,6 +3494,8 @@ packages: optional: true '@oslojs/encoding': optional: true + '@standard-schema/spec': + optional: true intl-parse-accept-language: optional: true is-ip: @@ -2461,20 +3517,66 @@ packages: rfc4648@1.5.4: resolution: {integrity: sha512-rRg/6Lb+IGfJqO05HZkN50UtY7K/JhxJag1kP23+zyMfrvoB0B7RWv06MbOzoc79RgCdNTiUaNsTT1AJZ7Z+cg==} - rimraf@5.0.10: - resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==} - hasBin: true - - rollup@4.36.0: - resolution: {integrity: sha512-zwATAXNQxUcd40zgtQG0ZafcRK4g004WtEl7kbuhTWPvf07PsfohXl39jVUvPF7jvNAIkKPQ2XrsDlWuxBd++Q==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - - scheduler@0.26.0: - resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + rolldown-vite@7.1.4: + resolution: {integrity: sha512-VE0cXhJfTypUhm71w4pR62dMyqw8JKHWMdbUBSDVqZTGGpZz5Zkw+cT47rvBR/SQ9E9F2GtlW02rWIY2T9HdLg==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + esbuild: ^0.25.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 + 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 + + rolldown@1.0.0-beta.33: + resolution: {integrity: sha512-mgu118ZuRguC8unhPCbdZbyRbjQfEMiWqlojBA5aRIncBelRaBomnHNpGKYkYWeK7twRz5Cql30xgqqrA3Xelw==} + hasBin: true + + rollup@4.46.3: + resolution: {integrity: sha512-RZn2XTjXb8t5g13f5YclGoilU/kwT696DIkY3sywjdZidNSi3+vseaQov7D7BZXVJCPv3pDWUN69C78GGbXsKw==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + scheduler@0.26.0: + resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true semver@7.7.2: @@ -2493,10 +3595,22 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + shiki@3.9.2: + resolution: {integrity: sha512-t6NKl5e/zGTvw/IyftLcumolgOczhuroqwXngDeMqJ3h3EQiTY/7wmfgPlsmloD8oYfqkEDqxiaH37Pjm1zUhQ==} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + + simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} @@ -2523,6 +3637,9 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + spdx-correct@3.2.0: resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} @@ -2532,19 +3649,26 @@ packages: spdx-expression-parse@3.0.1: resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} - spdx-license-ids@3.0.21: - resolution: {integrity: sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==} + spdx-license-ids@3.0.22: + resolution: {integrity: sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==} + + speakingurl@14.0.1: + resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} + engines: {node: '>=0.10.0'} sprintf-js@1.1.3: resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@3.9.0: + resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} + stream-buffers@3.0.3: resolution: {integrity: sha512-pqMqwQCso0PBJt2PQmDO0cFj0lyqmiwOMiMSkVtRokl7e+ZTRYgDHKnuZNbqjiJXgsg4nuqtD/zxuo9KqTp0Yw==} engines: {node: '>= 0.10.0'} - stream-slice@0.1.2: - resolution: {integrity: sha512-QzQxpoacatkreL6jsxnVb7X5R/pGw9OUv2qWTYWnmLpg4NdN31snPy/f3TdQE1ZUXaThRvj1Zw4/OGg0ZkaLMA==} - streamx@2.22.0: resolution: {integrity: sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==} @@ -2556,6 +3680,12 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -2564,11 +3694,25 @@ packages: resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} engines: {node: '>=12'} + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + + strip-literal@3.0.0: + resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==} + style-mod@4.1.2: resolution: {integrity: sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==} - tailwind-merge@3.3.0: - resolution: {integrity: sha512-fyW/pEfcQSiigd5SNn0nApUOxx0zB/dm6UDU/rEwc2c3sX2smWUNbapHv+QRqLGVp9GWX3THIa7MUGPo+YkDzQ==} + superjson@2.2.2: + resolution: {integrity: sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==} + engines: {node: '>=16'} + + tabbable@6.2.0: + resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} + + tailwind-merge@3.3.1: + resolution: {integrity: sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==} tailwindcss-animate@1.0.7: resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} @@ -2580,16 +3724,23 @@ packages: peerDependencies: tailwindcss: ^4.0.0 - tailwindcss@4.1.8: - resolution: {integrity: sha512-kjeW8gjdxasbmFKpVGrGd5T4i40mV5J2Rasw48QARfYeQ8YS9x02ON9SFWax3Qf616rt4Cp3nVNIj6Hd1mP3og==} + tailwindcss@4.1.12: + resolution: {integrity: sha512-DzFtxOi+7NsFf7DBtI3BJsynR+0Yp6etH+nRPTbpWnS2pZBaSksv/JGctNwSWzbFjp0vxSqknaUylseZqMDGrA==} tapable@2.2.2: resolution: {integrity: sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==} engines: {node: '>=6'} + tar-fs@2.1.3: + resolution: {integrity: sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==} + tar-fs@3.0.9: resolution: {integrity: sha512-XF4w9Xp+ZQgifKakjZYmFdkLoSWd34VGKcsTCwlNWM7QG3ZbaxnTsaBwnjFZqHRf/rROxaR8rXnbtwdvaDI+lA==} + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + tar-stream@3.1.7: resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} @@ -2605,13 +3756,34 @@ packages: text-decoder@1.2.3: resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==} + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinyglobby@0.2.14: resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} engines: {node: '>=12.0.0'} + tinypool@1.1.1: + resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@2.0.0: + resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} + engines: {node: '>=14.0.0'} + + tinyspy@4.0.3: + resolution: {integrity: sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==} + engines: {node: '>=14.0.0'} + tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + tsconfck@3.1.4: resolution: {integrity: sha512-kdqWFGVJqe+KGYvlSO9NIaWn9jT1Ny4oKVzAJsKii5eoE9snzTJzL4+MMVOMn+fikWGFmKEylcXL710V/kIPJQ==} engines: {node: ^18 || >=20} @@ -2628,40 +3800,54 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - tsx@4.19.4: - resolution: {integrity: sha512-gK5GVzDkJK1SI1zwHf32Mqxf2tSJkNx+eYcNly5+nHvWqXUJYUkWBQtKauoESz3ymezAI++ZwT855x5p5eop+Q==} + tsx@4.20.4: + resolution: {integrity: sha512-yyxBKfORQ7LuRt/BQKBXrpcq59ZvSW0XxwfjAt3w2/8PmdxaFzijtMhTawprSHhpzeM5BgU2hXHG3lklIERZXg==} engines: {node: '>=18.0.0'} hasBin: true + tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + + turbo-stream@3.1.0: + resolution: {integrity: sha512-tVI25WEXl4fckNEmrq70xU1XumxUwEx/FZD5AgEcV8ri7Wvrg2o7GEq8U7htrNx3CajciGm+kDyhRf5JB6t7/A==} + type-fest@4.41.0: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} - typescript@5.8.3: - resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} + typescript@5.9.2: + resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} engines: {node: '>=14.17'} hasBin: true - undici-types@6.19.8: - resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} - - undici-types@6.20.0: - resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + ulidx@2.4.1: + resolution: {integrity: sha512-xY7c8LPyzvhvew0Fn+Ek3wBC9STZAuDI/Y5andCKi9AX6/jvfaX45PhsDX8oxgPL0YFp0Jhr8qWMbS/p9375Xg==} + engines: {node: '>=16'} undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - undici@6.21.3: - resolution: {integrity: sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==} - engines: {node: '>=18.17'} + undici-types@7.10.0: + resolution: {integrity: sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==} - undici@7.10.0: - resolution: {integrity: sha512-u5otvFBOBZvmdjWLVW+5DAc9Nkq8f24g0O9oY7qw2JVIF1VocIFoyz9JFkuVOS2j41AufeO0xnlweJ2RLT8nGw==} + undici@7.14.0: + resolution: {integrity: sha512-Vqs8HTzjpQXZeXdpsfChQTlafcMQaaIwnGwLam1wudSSjlJeQ3bw1j+TLPePgrCnCpUXx7Ba5Pdpf5OBih62NQ==} engines: {node: '>=20.18.1'} - universalify@2.0.1: - resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} - engines: {node: '>= 10.0.0'} + unist-util-is@6.0.0: + resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.1: + resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==} + + unist-util-visit@5.0.0: + resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} unplugin@2.1.0: resolution: {integrity: sha512-us4j03/499KhbGP8BU7Hrzrgseo+KdfJYWcbcajCOqsAyb8Gk0Yn2kiUIcZISYCb1JFaZfIuG3b42HmguVOKCQ==} @@ -2688,6 +3874,9 @@ packages: resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==} engines: {node: '>=6.14.2'} + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + valibot@0.41.0: resolution: {integrity: sha512-igDBb8CTYr8YTQlOKgaN9nSS0Be7z+WRuaeYqGf3Cjz3aKmSnqEmYnkfVjzIuumGqfHpa3fLIvMEAfhrpqN8ng==} peerDependencies: @@ -2703,8 +3892,14 @@ packages: resolution: {integrity: sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - vite-node@3.0.0-beta.2: - resolution: {integrity: sha512-ofTf6cfRdL30Wbl9n/BX81EyIR5s4PReLmSurrxQ+koLaWUNOEo8E0lCM53OJkb8vpa2URM2nSrxZsIFyvY1rg==} + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + + vite-node@3.2.4: + resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true @@ -2716,19 +3911,19 @@ packages: vite: optional: true - vite@6.3.5: - resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + vite@7.1.2: + resolution: {integrity: sha512-J0SQBPlQiEXAF7tajiH+rUooJPo0l8KQgyg4/aMunNtrOa7bwuZJsJbDWzeljqQpgftxuq5yNJxQ91O9ts29UQ==} + engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@types/node': ^20.19.0 || >=22.12.0 jiti: '>=1.21.0' - less: '*' + less: ^4.0.0 lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' + 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 @@ -2756,9 +3951,72 @@ packages: yaml: optional: true + vitefu@1.1.1: + resolution: {integrity: sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==} + peerDependencies: + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0 + peerDependenciesMeta: + vite: + optional: true + + vitepress@2.0.0-alpha.11: + resolution: {integrity: sha512-l3FFkGtcB3u3iMlpnvkCR+MdOYqNaz2z+xPRlgZZnx8Xne4XLgQR0yfEfTqY/UyloTymXwxvRvu443Yo9Cr8pA==} + hasBin: true + peerDependencies: + markdown-it-mathjax3: ^4 + oxc-minify: ^0.81.0 + postcss: ^8 + peerDependenciesMeta: + markdown-it-mathjax3: + optional: true + oxc-minify: + optional: true + postcss: + optional: true + + vitest@3.2.4: + resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/debug': ^4.1.12 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@vitest/browser': 3.2.4 + '@vitest/ui': 3.2.4 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/debug': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + vue@3.5.18: + resolution: {integrity: sha512-7W4Y4ZbMiQ3SEo+m9lnoNpV9xG7QVMLa+/0RFwwiAVkeYoyGXqWE85jabU4pllJNUzqfLShJ5YLptewhCWUgNA==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + w3c-keyname@2.2.8: resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -2778,6 +4036,11 @@ packages: engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} hasBin: true + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -2789,18 +4052,6 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - ws@8.18.1: - resolution: {integrity: sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==} - 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 - ws@8.18.2: resolution: {integrity: sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==} engines: {node: '>=10.0.0'} @@ -2820,13 +4071,16 @@ packages: resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} engines: {node: '>=18'} - yaml@2.8.0: - resolution: {integrity: sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==} + yaml@2.8.1: + resolution: {integrity: sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==} engines: {node: '>= 14.6'} hasBin: true - zod@3.25.33: - resolution: {integrity: sha512-RnBGYCwJFrLi/hUmeqbYjSIrS/strWjN5PHWgUfyVq96nKycSa4gp4+p6hQGwvcabZs0DWRGzyLhEeQWl+5NhA==} + zimmerframe@1.1.2: + resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==} + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} snapshots: @@ -2849,18 +4103,18 @@ snapshots: '@babel/compat-data@7.27.3': {} - '@babel/core@7.27.3': + '@babel/core@7.28.3': dependencies: '@ampproject/remapping': 2.3.0 '@babel/code-frame': 7.27.1 - '@babel/generator': 7.27.3 + '@babel/generator': 7.28.3 '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.27.3(@babel/core@7.27.3) - '@babel/helpers': 7.27.3 - '@babel/parser': 7.27.3 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.3) + '@babel/helpers': 7.28.3 + '@babel/parser': 7.28.3 '@babel/template': 7.27.2 - '@babel/traverse': 7.27.3 - '@babel/types': 7.27.3 + '@babel/traverse': 7.28.3 + '@babel/types': 7.28.2 convert-source-map: 2.0.0 debug: 4.4.1 gensync: 1.0.0-beta.2 @@ -2877,9 +4131,17 @@ snapshots: '@jridgewell/trace-mapping': 0.3.25 jsesc: 3.0.2 + '@babel/generator@7.28.3': + dependencies: + '@babel/parser': 7.28.3 + '@babel/types': 7.28.2 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.30 + jsesc: 3.0.2 + '@babel/helper-annotate-as-pure@7.27.3': dependencies: - '@babel/types': 7.27.3 + '@babel/types': 7.28.2 '@babel/helper-compilation-targets@7.27.2': dependencies: @@ -2889,23 +4151,25 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.27.1(@babel/core@7.27.3)': + '@babel/helper-create-class-features-plugin@7.28.3(@babel/core@7.28.3)': dependencies: - '@babel/core': 7.27.3 + '@babel/core': 7.28.3 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-member-expression-to-functions': 7.27.1 '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.27.3) + '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.3) '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.27.3 + '@babel/traverse': 7.28.3 semver: 6.3.1 transitivePeerDependencies: - supports-color + '@babel/helper-globals@7.28.0': {} + '@babel/helper-member-expression-to-functions@7.27.1': dependencies: - '@babel/traverse': 7.27.3 - '@babel/types': 7.27.3 + '@babel/traverse': 7.28.3 + '@babel/types': 7.28.2 transitivePeerDependencies: - supports-color @@ -2916,34 +4180,34 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.27.3(@babel/core@7.27.3)': + '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.3)': dependencies: - '@babel/core': 7.27.3 + '@babel/core': 7.28.3 '@babel/helper-module-imports': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.27.3 + '@babel/traverse': 7.28.3 transitivePeerDependencies: - supports-color '@babel/helper-optimise-call-expression@7.27.1': dependencies: - '@babel/types': 7.27.3 + '@babel/types': 7.28.2 '@babel/helper-plugin-utils@7.27.1': {} - '@babel/helper-replace-supers@7.27.1(@babel/core@7.27.3)': + '@babel/helper-replace-supers@7.27.1(@babel/core@7.28.3)': dependencies: - '@babel/core': 7.27.3 + '@babel/core': 7.28.3 '@babel/helper-member-expression-to-functions': 7.27.1 '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.27.3 + '@babel/traverse': 7.28.3 transitivePeerDependencies: - supports-color '@babel/helper-skip-transparent-expression-wrappers@7.27.1': dependencies: - '@babel/traverse': 7.27.3 - '@babel/types': 7.27.3 + '@babel/traverse': 7.28.3 + '@babel/types': 7.28.2 transitivePeerDependencies: - supports-color @@ -2953,57 +4217,60 @@ snapshots: '@babel/helper-validator-option@7.27.1': {} - '@babel/helpers@7.27.3': + '@babel/helpers@7.28.3': dependencies: '@babel/template': 7.27.2 - '@babel/types': 7.27.3 + '@babel/types': 7.28.2 '@babel/parser@7.27.3': dependencies: '@babel/types': 7.27.3 - '@babel/plugin-syntax-decorators@7.27.1(@babel/core@7.27.3)': + '@babel/parser@7.28.0': dependencies: - '@babel/core': 7.27.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/types': 7.28.2 - '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.27.3)': + '@babel/parser@7.28.3': dependencies: - '@babel/core': 7.27.3 + '@babel/types': 7.28.2 + + '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.3)': + dependencies: + '@babel/core': 7.28.3 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.27.3)': + '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.3)': dependencies: - '@babel/core': 7.27.3 + '@babel/core': 7.28.3 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-modules-commonjs@7.27.1(@babel/core@7.27.3)': + '@babel/plugin-transform-modules-commonjs@7.27.1(@babel/core@7.28.3)': dependencies: - '@babel/core': 7.27.3 - '@babel/helper-module-transforms': 7.27.3(@babel/core@7.27.3) + '@babel/core': 7.28.3 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.3) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-typescript@7.27.1(@babel/core@7.27.3)': + '@babel/plugin-transform-typescript@7.28.0(@babel/core@7.28.3)': dependencies: - '@babel/core': 7.27.3 + '@babel/core': 7.28.3 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.27.1(@babel/core@7.27.3) + '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.3) '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.27.3) + '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.3) transitivePeerDependencies: - supports-color - '@babel/preset-typescript@7.27.1(@babel/core@7.27.3)': + '@babel/preset-typescript@7.27.1(@babel/core@7.28.3)': dependencies: - '@babel/core': 7.27.3 + '@babel/core': 7.28.3 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.27.3) - '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.27.3) - '@babel/plugin-transform-typescript': 7.27.1(@babel/core@7.27.3) + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.3) + '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.3) + '@babel/plugin-transform-typescript': 7.28.0(@babel/core@7.28.3) transitivePeerDependencies: - supports-color @@ -3027,44 +4294,61 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/traverse@7.28.3': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.3 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.3 + '@babel/template': 7.27.2 + '@babel/types': 7.28.2 + debug: 4.4.1 + transitivePeerDependencies: + - supports-color + '@babel/types@7.27.3': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 - '@biomejs/biome@1.9.4': - optionalDependencies: - '@biomejs/cli-darwin-arm64': 1.9.4 - '@biomejs/cli-darwin-x64': 1.9.4 - '@biomejs/cli-linux-arm64': 1.9.4 - '@biomejs/cli-linux-arm64-musl': 1.9.4 - '@biomejs/cli-linux-x64': 1.9.4 - '@biomejs/cli-linux-x64-musl': 1.9.4 - '@biomejs/cli-win32-arm64': 1.9.4 - '@biomejs/cli-win32-x64': 1.9.4 + '@babel/types@7.28.2': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 - '@biomejs/cli-darwin-arm64@1.9.4': + '@biomejs/biome@2.2.0': + optionalDependencies: + '@biomejs/cli-darwin-arm64': 2.2.0 + '@biomejs/cli-darwin-x64': 2.2.0 + '@biomejs/cli-linux-arm64': 2.2.0 + '@biomejs/cli-linux-arm64-musl': 2.2.0 + '@biomejs/cli-linux-x64': 2.2.0 + '@biomejs/cli-linux-x64-musl': 2.2.0 + '@biomejs/cli-win32-arm64': 2.2.0 + '@biomejs/cli-win32-x64': 2.2.0 + + '@biomejs/cli-darwin-arm64@2.2.0': optional: true - '@biomejs/cli-darwin-x64@1.9.4': + '@biomejs/cli-darwin-x64@2.2.0': optional: true - '@biomejs/cli-linux-arm64-musl@1.9.4': + '@biomejs/cli-linux-arm64-musl@2.2.0': optional: true - '@biomejs/cli-linux-arm64@1.9.4': + '@biomejs/cli-linux-arm64@2.2.0': optional: true - '@biomejs/cli-linux-x64-musl@1.9.4': + '@biomejs/cli-linux-x64-musl@2.2.0': optional: true - '@biomejs/cli-linux-x64@1.9.4': + '@biomejs/cli-linux-x64@2.2.0': optional: true - '@biomejs/cli-win32-arm64@1.9.4': + '@biomejs/cli-win32-arm64@2.2.0': optional: true - '@biomejs/cli-win32-x64@1.9.4': + '@biomejs/cli-win32-x64@2.2.0': optional: true '@clack/core@0.3.5': @@ -3138,116 +4422,219 @@ snapshots: style-mod: 4.1.2 w3c-keyname: 2.2.8 - '@dnd-kit/accessibility@3.1.1(react@19.1.0)': + '@dnd-kit/accessibility@3.1.1(react@19.1.1)': dependencies: - react: 19.1.0 + react: 19.1.1 tslib: 2.8.1 - '@dnd-kit/core@6.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@dnd-kit/core@6.3.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@dnd-kit/accessibility': 3.1.1(react@19.1.0) - '@dnd-kit/utilities': 3.2.2(react@19.1.0) - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + '@dnd-kit/accessibility': 3.1.1(react@19.1.1) + '@dnd-kit/utilities': 3.2.2(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) tslib: 2.8.1 - '@dnd-kit/modifiers@7.0.0(@dnd-kit/core@6.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)': + '@dnd-kit/modifiers@7.0.0(@dnd-kit/core@6.3.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)': dependencies: - '@dnd-kit/core': 6.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@dnd-kit/utilities': 3.2.2(react@19.1.0) - react: 19.1.0 + '@dnd-kit/core': 6.3.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@dnd-kit/utilities': 3.2.2(react@19.1.1) + react: 19.1.1 tslib: 2.8.1 - '@dnd-kit/sortable@8.0.0(@dnd-kit/core@6.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)': + '@dnd-kit/sortable@8.0.0(@dnd-kit/core@6.3.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)': dependencies: - '@dnd-kit/core': 6.3.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@dnd-kit/utilities': 3.2.2(react@19.1.0) - react: 19.1.0 + '@dnd-kit/core': 6.3.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@dnd-kit/utilities': 3.2.2(react@19.1.1) + react: 19.1.1 tslib: 2.8.1 - '@dnd-kit/utilities@3.2.2(react@19.1.0)': + '@dnd-kit/utilities@3.2.2(react@19.1.1)': dependencies: - react: 19.1.0 + react: 19.1.1 tslib: 2.6.2 + '@docsearch/css@4.0.0-beta.7': {} + + '@docsearch/js@4.0.0-beta.7': {} + + '@drizzle-team/brocli@0.10.2': {} + '@drizzle-team/brocli@0.11.0': {} - '@esbuild/aix-ppc64@0.25.5': + '@emnapi/core@1.4.5': + dependencies: + '@emnapi/wasi-threads': 1.0.4 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.4.5': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.0.4': + 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.10.1 + + '@esbuild/aix-ppc64@0.25.9': + optional: true + + '@esbuild/android-arm64@0.18.20': + optional: true + + '@esbuild/android-arm64@0.25.9': + optional: true + + '@esbuild/android-arm@0.18.20': + optional: true + + '@esbuild/android-arm@0.25.9': + optional: true + + '@esbuild/android-x64@0.18.20': + optional: true + + '@esbuild/android-x64@0.25.9': + optional: true + + '@esbuild/darwin-arm64@0.18.20': optional: true - '@esbuild/android-arm64@0.25.5': + '@esbuild/darwin-arm64@0.25.9': optional: true - '@esbuild/android-arm@0.25.5': + '@esbuild/darwin-x64@0.18.20': optional: true - '@esbuild/android-x64@0.25.5': + '@esbuild/darwin-x64@0.25.9': optional: true - '@esbuild/darwin-arm64@0.25.5': + '@esbuild/freebsd-arm64@0.18.20': optional: true - '@esbuild/darwin-x64@0.25.5': + '@esbuild/freebsd-arm64@0.25.9': optional: true - '@esbuild/freebsd-arm64@0.25.5': + '@esbuild/freebsd-x64@0.18.20': optional: true - '@esbuild/freebsd-x64@0.25.5': + '@esbuild/freebsd-x64@0.25.9': optional: true - '@esbuild/linux-arm64@0.25.5': + '@esbuild/linux-arm64@0.18.20': optional: true - '@esbuild/linux-arm@0.25.5': + '@esbuild/linux-arm64@0.25.9': optional: true - '@esbuild/linux-ia32@0.25.5': + '@esbuild/linux-arm@0.18.20': optional: true - '@esbuild/linux-loong64@0.25.5': + '@esbuild/linux-arm@0.25.9': optional: true - '@esbuild/linux-mips64el@0.25.5': + '@esbuild/linux-ia32@0.18.20': optional: true - '@esbuild/linux-ppc64@0.25.5': + '@esbuild/linux-ia32@0.25.9': optional: true - '@esbuild/linux-riscv64@0.25.5': + '@esbuild/linux-loong64@0.18.20': optional: true - '@esbuild/linux-s390x@0.25.5': + '@esbuild/linux-loong64@0.25.9': optional: true - '@esbuild/linux-x64@0.25.5': + '@esbuild/linux-mips64el@0.18.20': optional: true - '@esbuild/netbsd-arm64@0.25.5': + '@esbuild/linux-mips64el@0.25.9': optional: true - '@esbuild/netbsd-x64@0.25.5': + '@esbuild/linux-ppc64@0.18.20': optional: true - '@esbuild/openbsd-arm64@0.25.5': + '@esbuild/linux-ppc64@0.25.9': optional: true - '@esbuild/openbsd-x64@0.25.5': + '@esbuild/linux-riscv64@0.18.20': optional: true - '@esbuild/sunos-x64@0.25.5': + '@esbuild/linux-riscv64@0.25.9': optional: true - '@esbuild/win32-arm64@0.25.5': + '@esbuild/linux-s390x@0.18.20': optional: true - '@esbuild/win32-ia32@0.25.5': + '@esbuild/linux-s390x@0.25.9': optional: true - '@esbuild/win32-x64@0.25.5': + '@esbuild/linux-x64@0.18.20': optional: true - '@fontsource-variable/inter@5.2.5': {} + '@esbuild/linux-x64@0.25.9': + optional: true + + '@esbuild/netbsd-arm64@0.25.9': + optional: true + + '@esbuild/netbsd-x64@0.18.20': + optional: true + + '@esbuild/netbsd-x64@0.25.9': + optional: true + + '@esbuild/openbsd-arm64@0.25.9': + optional: true + + '@esbuild/openbsd-x64@0.18.20': + optional: true + + '@esbuild/openbsd-x64@0.25.9': + optional: true + + '@esbuild/openharmony-arm64@0.25.9': + optional: true + + '@esbuild/sunos-x64@0.18.20': + optional: true + + '@esbuild/sunos-x64@0.25.9': + optional: true + + '@esbuild/win32-arm64@0.18.20': + optional: true + + '@esbuild/win32-arm64@0.25.9': + optional: true + + '@esbuild/win32-ia32@0.18.20': + optional: true + + '@esbuild/win32-ia32@0.25.9': + optional: true + + '@esbuild/win32-x64@0.18.20': + optional: true + + '@esbuild/win32-x64@0.25.9': + optional: true + + '@faker-js/faker@9.9.0': {} + + '@fontsource-variable/inter@5.2.6': {} '@formatjs/ecma402-abstract@2.3.4': dependencies: @@ -3275,39 +4662,45 @@ snapshots: dependencies: tslib: 2.8.1 - '@hono/node-server@1.14.0(hono@4.7.6)': + '@hono/node-server@1.19.0(hono@4.7.10)': dependencies: - hono: 4.7.6 + hono: 4.7.10 - '@hono/node-ws@1.1.1(@hono/node-server@1.14.0(hono@4.7.6))(bufferutil@4.0.9)(hono@4.7.6)(utf-8-validate@5.0.10)': + '@hono/node-ws@1.2.0(@hono/node-server@1.19.0(hono@4.7.10))(bufferutil@4.0.9)(hono@4.7.10)(utf-8-validate@5.0.10)': dependencies: - '@hono/node-server': 1.14.0(hono@4.7.6) - hono: 4.7.6 - ws: 8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@hono/node-server': 1.19.0(hono@4.7.10) + hono: 4.7.10 + ws: 8.18.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) transitivePeerDependencies: - bufferutil - utf-8-validate - '@hono/vite-dev-server@0.19.0(hono@4.7.6)': + '@hono/vite-dev-server@0.20.1(hono@4.7.10)': dependencies: - '@hono/node-server': 1.14.0(hono@4.7.6) - hono: 4.7.6 + '@hono/node-server': 1.19.0(hono@4.7.10) + hono: 4.7.10 minimatch: 9.0.5 - '@internationalized/date@3.8.1': + '@iconify-json/simple-icons@1.2.48': + dependencies: + '@iconify/types': 2.0.0 + + '@iconify/types@2.0.0': {} + + '@internationalized/date@3.8.2': dependencies: '@swc/helpers': 0.5.17 - '@internationalized/message@3.1.7': + '@internationalized/message@3.1.8': dependencies: '@swc/helpers': 0.5.17 intl-messageformat: 10.7.16 - '@internationalized/number@3.6.2': + '@internationalized/number@3.6.4': dependencies: '@swc/helpers': 0.5.17 - '@internationalized/string@3.2.6': + '@internationalized/string@3.2.7': dependencies: '@swc/helpers': 0.5.17 @@ -3324,31 +4717,48 @@ snapshots: dependencies: minipass: 7.1.2 + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.30 + '@jridgewell/gen-mapping@0.3.8': dependencies: '@jridgewell/set-array': 1.2.1 '@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.30 + '@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/set-array@1.2.1': {} - '@jridgewell/source-map@0.3.6': + '@jridgewell/source-map@0.3.11': dependencies: - '@jridgewell/gen-mapping': 0.3.8 - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.30 optional: true '@jridgewell/sourcemap-codec@1.4.15': {} '@jridgewell/sourcemap-codec@1.5.0': {} + '@jridgewell/sourcemap-codec@1.5.5': {} + '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping@0.3.30': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + '@jsep-plugin/assignment@1.3.0(jsep@1.4.0)': dependencies: jsep: 1.4.0 @@ -3360,7 +4770,7 @@ snapshots: '@kubernetes/client-node@1.3.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': dependencies: '@types/js-yaml': 4.0.9 - '@types/node': 22.15.24 + '@types/node': 22.17.2 '@types/node-fetch': 2.6.12 '@types/stream-buffers': 3.0.7 form-data: 4.0.2 @@ -3369,7 +4779,7 @@ snapshots: js-yaml: 4.1.0 jsonpath-plus: 10.3.0 node-fetch: 2.7.0 - openid-client: 6.5.0 + openid-client: 6.7.0 rfc4648: 1.5.4 socks-proxy-agent: 8.0.5 stream-buffers: 3.0.3 @@ -3392,10 +4802,83 @@ snapshots: dependencies: '@lezer/common': 1.2.3 + '@libsql/client@0.15.12(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@libsql/core': 0.15.12 + '@libsql/hrana-client': 0.7.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + js-base64: 3.7.7 + libsql: 0.5.17 + promise-limit: 2.7.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@libsql/core@0.15.12': + dependencies: + js-base64: 3.7.7 + + '@libsql/darwin-arm64@0.5.17': + optional: true + + '@libsql/darwin-x64@0.5.17': + optional: true + + '@libsql/hrana-client@0.7.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@libsql/isomorphic-fetch': 0.3.1 + '@libsql/isomorphic-ws': 0.1.5(bufferutil@4.0.9)(utf-8-validate@5.0.10) + js-base64: 3.7.7 + node-fetch: 3.3.2 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@libsql/isomorphic-fetch@0.3.1': {} + + '@libsql/isomorphic-ws@0.1.5(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@types/ws': 8.18.1 + ws: 8.18.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@libsql/linux-arm-gnueabihf@0.5.17': + optional: true + + '@libsql/linux-arm-musleabihf@0.5.17': + optional: true + + '@libsql/linux-arm64-gnu@0.5.17': + optional: true + + '@libsql/linux-arm64-musl@0.5.17': + optional: true + + '@libsql/linux-x64-gnu@0.5.17': + optional: true + + '@libsql/linux-x64-musl@0.5.17': + optional: true + + '@libsql/win32-x64-msvc@0.5.17': + optional: true + '@marijn/find-cluster-break@1.0.2': {} '@mjackson/node-fetch-server@0.2.0': {} + '@mjackson/node-fetch-server@0.7.0': {} + + '@napi-rs/wasm-runtime@1.0.3': + dependencies: + '@emnapi/core': 1.4.5 + '@emnapi/runtime': 1.4.5 + '@tybys/wasm-util': 0.10.0 + optional: true + + '@neon-rs/load@0.0.4': {} + '@npmcli/git@4.1.0': dependencies: '@npmcli/promise-spawn': 6.0.2 @@ -3425,649 +4908,667 @@ snapshots: dependencies: which: 3.0.1 - '@pivanov/utils@0.0.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@oslojs/asn1@1.0.0': dependencies: - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + '@oslojs/binary': 1.0.0 + optional: true - '@pkgjs/parseargs@0.11.0': + '@oslojs/binary@1.0.0': + optional: true + + '@oslojs/crypto@1.0.1': + dependencies: + '@oslojs/asn1': 1.0.0 + '@oslojs/binary': 1.0.0 + optional: true + + '@oslojs/encoding@1.1.0': optional: true - '@preact/signals-core@1.8.0': {} + '@oxc-project/runtime@0.82.2': {} - '@preact/signals@1.3.2(preact@10.26.7)': + '@oxc-project/types@0.82.2': {} + + '@pivanov/utils@0.0.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@preact/signals-core': 1.8.0 - preact: 10.26.7 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@pkgjs/parseargs@0.11.0': + optional: true - '@primer/octicons-react@19.15.2(react@19.1.0)': + '@preact/signals-core@1.12.0': {} + + '@preact/signals@1.3.2(preact@10.27.1)': dependencies: - react: 19.1.0 + '@preact/signals-core': 1.12.0 + preact: 10.27.1 - '@react-aria/breadcrumbs@3.5.24(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@react-aria/breadcrumbs@3.5.27(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@react-aria/i18n': 3.12.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/link': 3.8.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-types/breadcrumbs': 3.7.13(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-aria/i18n': 3.12.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/link': 3.8.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-types/breadcrumbs': 3.7.15(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) - '@react-aria/button@3.13.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@react-aria/button@3.14.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@react-aria/interactions': 3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/toolbar': 3.0.0-beta.16(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/toggle': 3.8.4(react@19.1.0) - '@react-types/button': 3.12.1(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-aria/interactions': 3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/toolbar': 3.0.0-beta.19(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/toggle': 3.9.0(react@19.1.1) + '@react-types/button': 3.13.0(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - - '@react-aria/calendar@3.8.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': - dependencies: - '@internationalized/date': 3.8.1 - '@react-aria/i18n': 3.12.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/interactions': 3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/live-announcer': 3.4.2 - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/calendar': 3.8.1(react@19.1.0) - '@react-types/button': 3.12.1(react@19.1.0) - '@react-types/calendar': 3.7.1(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@react-aria/calendar@3.9.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@internationalized/date': 3.8.2 + '@react-aria/i18n': 3.12.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/interactions': 3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/live-announcer': 3.4.4 + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/calendar': 3.8.3(react@19.1.1) + '@react-types/button': 3.13.0(react@19.1.1) + '@react-types/calendar': 3.7.3(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - - '@react-aria/checkbox@3.15.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': - dependencies: - '@react-aria/form': 3.0.16(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/interactions': 3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/label': 3.7.18(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/toggle': 3.11.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/checkbox': 3.6.14(react@19.1.0) - '@react-stately/form': 3.1.4(react@19.1.0) - '@react-stately/toggle': 3.8.4(react@19.1.0) - '@react-types/checkbox': 3.9.4(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@react-aria/checkbox@3.16.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@react-aria/form': 3.1.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/interactions': 3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/label': 3.7.20(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/toggle': 3.12.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/checkbox': 3.7.0(react@19.1.1) + '@react-stately/form': 3.2.0(react@19.1.1) + '@react-stately/toggle': 3.9.0(react@19.1.1) + '@react-types/checkbox': 3.10.0(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - - '@react-aria/color@3.0.7(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': - dependencies: - '@react-aria/i18n': 3.12.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/interactions': 3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/numberfield': 3.11.14(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/slider': 3.7.19(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/spinbutton': 3.6.15(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/textfield': 3.17.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/visually-hidden': 3.8.23(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/color': 3.8.5(react@19.1.0) - '@react-stately/form': 3.1.4(react@19.1.0) - '@react-types/color': 3.0.5(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@react-aria/color@3.1.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@react-aria/i18n': 3.12.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/interactions': 3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/numberfield': 3.12.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/slider': 3.8.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/spinbutton': 3.6.17(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/textfield': 3.18.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/visually-hidden': 3.8.26(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/color': 3.9.0(react@19.1.1) + '@react-stately/form': 3.2.0(react@19.1.1) + '@react-types/color': 3.1.0(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - - '@react-aria/combobox@3.12.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': - dependencies: - '@react-aria/focus': 3.20.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/i18n': 3.12.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/listbox': 3.14.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/live-announcer': 3.4.2 - '@react-aria/menu': 3.18.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/overlays': 3.27.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/selection': 3.24.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/textfield': 3.17.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/collections': 3.12.4(react@19.1.0) - '@react-stately/combobox': 3.10.5(react@19.1.0) - '@react-stately/form': 3.1.4(react@19.1.0) - '@react-types/button': 3.12.1(react@19.1.0) - '@react-types/combobox': 3.13.5(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@react-aria/combobox@3.13.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@react-aria/focus': 3.21.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/i18n': 3.12.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/listbox': 3.14.7(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/live-announcer': 3.4.4 + '@react-aria/menu': 3.19.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/overlays': 3.28.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/selection': 3.25.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/textfield': 3.18.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/collections': 3.12.6(react@19.1.1) + '@react-stately/combobox': 3.11.0(react@19.1.1) + '@react-stately/form': 3.2.0(react@19.1.1) + '@react-types/button': 3.13.0(react@19.1.1) + '@react-types/combobox': 3.13.7(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - - '@react-aria/datepicker@3.14.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': - dependencies: - '@internationalized/date': 3.8.1 - '@internationalized/number': 3.6.2 - '@internationalized/string': 3.2.6 - '@react-aria/focus': 3.20.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/form': 3.0.16(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/i18n': 3.12.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/interactions': 3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/label': 3.7.18(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/spinbutton': 3.6.15(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/datepicker': 3.14.1(react@19.1.0) - '@react-stately/form': 3.1.4(react@19.1.0) - '@react-types/button': 3.12.1(react@19.1.0) - '@react-types/calendar': 3.7.1(react@19.1.0) - '@react-types/datepicker': 3.12.1(react@19.1.0) - '@react-types/dialog': 3.5.18(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@react-aria/datepicker@3.15.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@internationalized/date': 3.8.2 + '@internationalized/number': 3.6.4 + '@internationalized/string': 3.2.7 + '@react-aria/focus': 3.21.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/form': 3.1.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/i18n': 3.12.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/interactions': 3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/label': 3.7.20(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/spinbutton': 3.6.17(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/datepicker': 3.15.0(react@19.1.1) + '@react-stately/form': 3.2.0(react@19.1.1) + '@react-types/button': 3.13.0(react@19.1.1) + '@react-types/calendar': 3.7.3(react@19.1.1) + '@react-types/datepicker': 3.13.0(react@19.1.1) + '@react-types/dialog': 3.5.20(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) - '@react-aria/dialog@3.5.25(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@react-aria/dialog@3.5.28(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@react-aria/interactions': 3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/overlays': 3.27.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-types/dialog': 3.5.18(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-aria/interactions': 3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/overlays': 3.28.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-types/dialog': 3.5.20(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) - '@react-aria/disclosure@3.0.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@react-aria/disclosure@3.0.7(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@react-aria/ssr': 3.9.8(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/disclosure': 3.0.4(react@19.1.0) - '@react-types/button': 3.12.1(react@19.1.0) + '@react-aria/ssr': 3.9.10(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/disclosure': 3.0.6(react@19.1.1) + '@react-types/button': 3.13.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - - '@react-aria/dnd@3.9.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': - dependencies: - '@internationalized/string': 3.2.6 - '@react-aria/i18n': 3.12.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/interactions': 3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/live-announcer': 3.4.2 - '@react-aria/overlays': 3.27.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/dnd': 3.5.4(react@19.1.0) - '@react-types/button': 3.12.1(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@react-aria/dnd@3.11.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@internationalized/string': 3.2.7 + '@react-aria/i18n': 3.12.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/interactions': 3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/live-announcer': 3.4.4 + '@react-aria/overlays': 3.28.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/collections': 3.12.6(react@19.1.1) + '@react-stately/dnd': 3.6.1(react@19.1.1) + '@react-types/button': 3.13.0(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) - '@react-aria/focus@3.20.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@react-aria/focus@3.21.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@react-aria/interactions': 3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-aria/interactions': 3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 clsx: 2.1.1 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) - '@react-aria/form@3.0.16(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@react-aria/form@3.1.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@react-aria/interactions': 3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/form': 3.1.4(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-aria/interactions': 3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/form': 3.2.0(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - - '@react-aria/grid@3.14.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': - dependencies: - '@react-aria/focus': 3.20.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/i18n': 3.12.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/interactions': 3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/live-announcer': 3.4.2 - '@react-aria/selection': 3.24.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/collections': 3.12.4(react@19.1.0) - '@react-stately/grid': 3.11.2(react@19.1.0) - '@react-stately/selection': 3.20.2(react@19.1.0) - '@react-types/checkbox': 3.9.4(react@19.1.0) - '@react-types/grid': 3.3.2(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@react-aria/grid@3.14.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@react-aria/focus': 3.21.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/i18n': 3.12.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/interactions': 3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/live-announcer': 3.4.4 + '@react-aria/selection': 3.25.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/collections': 3.12.6(react@19.1.1) + '@react-stately/grid': 3.11.4(react@19.1.1) + '@react-stately/selection': 3.20.4(react@19.1.1) + '@react-types/checkbox': 3.10.0(react@19.1.1) + '@react-types/grid': 3.3.4(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - - '@react-aria/gridlist@3.13.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': - dependencies: - '@react-aria/focus': 3.20.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/grid': 3.14.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/i18n': 3.12.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/interactions': 3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/selection': 3.24.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/collections': 3.12.4(react@19.1.0) - '@react-stately/list': 3.12.2(react@19.1.0) - '@react-stately/tree': 3.8.10(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@react-aria/gridlist@3.13.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@react-aria/focus': 3.21.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/grid': 3.14.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/i18n': 3.12.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/interactions': 3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/selection': 3.25.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/list': 3.12.4(react@19.1.1) + '@react-stately/tree': 3.9.1(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - - '@react-aria/i18n@3.12.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': - dependencies: - '@internationalized/date': 3.8.1 - '@internationalized/message': 3.1.7 - '@internationalized/number': 3.6.2 - '@internationalized/string': 3.2.6 - '@react-aria/ssr': 3.9.8(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@react-aria/i18n@3.12.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@internationalized/date': 3.8.2 + '@internationalized/message': 3.1.8 + '@internationalized/number': 3.6.4 + '@internationalized/string': 3.2.7 + '@react-aria/ssr': 3.9.10(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) - '@react-aria/interactions@3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@react-aria/interactions@3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@react-aria/ssr': 3.9.8(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/flags': 3.1.1 - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-aria/ssr': 3.9.10(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/flags': 3.1.2 + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) - '@react-aria/label@3.7.18(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@react-aria/label@3.7.20(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) - '@react-aria/landmark@3.0.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@react-aria/landmark@3.0.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - use-sync-external-store: 1.5.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + use-sync-external-store: 1.5.0(react@19.1.1) - '@react-aria/link@3.8.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@react-aria/link@3.8.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@react-aria/interactions': 3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-types/link': 3.6.1(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-aria/interactions': 3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-types/link': 3.6.3(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - - '@react-aria/listbox@3.14.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': - dependencies: - '@react-aria/interactions': 3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/label': 3.7.18(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/selection': 3.24.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/collections': 3.12.4(react@19.1.0) - '@react-stately/list': 3.12.2(react@19.1.0) - '@react-types/listbox': 3.7.0(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@react-aria/listbox@3.14.7(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@react-aria/interactions': 3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/label': 3.7.20(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/selection': 3.25.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/collections': 3.12.6(react@19.1.1) + '@react-stately/list': 3.12.4(react@19.1.1) + '@react-types/listbox': 3.7.2(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) - '@react-aria/live-announcer@3.4.2': + '@react-aria/live-announcer@3.4.4': dependencies: '@swc/helpers': 0.5.17 - '@react-aria/menu@3.18.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': - dependencies: - '@react-aria/focus': 3.20.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/i18n': 3.12.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/interactions': 3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/overlays': 3.27.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/selection': 3.24.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/collections': 3.12.4(react@19.1.0) - '@react-stately/menu': 3.9.4(react@19.1.0) - '@react-stately/selection': 3.20.2(react@19.1.0) - '@react-stately/tree': 3.8.10(react@19.1.0) - '@react-types/button': 3.12.1(react@19.1.0) - '@react-types/menu': 3.10.1(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-aria/menu@3.19.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@react-aria/focus': 3.21.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/i18n': 3.12.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/interactions': 3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/overlays': 3.28.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/selection': 3.25.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/collections': 3.12.6(react@19.1.1) + '@react-stately/menu': 3.9.6(react@19.1.1) + '@react-stately/selection': 3.20.4(react@19.1.1) + '@react-stately/tree': 3.9.1(react@19.1.1) + '@react-types/button': 3.13.0(react@19.1.1) + '@react-types/menu': 3.10.3(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) - '@react-aria/meter@3.4.23(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@react-aria/meter@3.4.25(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@react-aria/progress': 3.4.23(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-types/meter': 3.4.9(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-aria/progress': 3.4.25(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-types/meter': 3.4.11(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - - '@react-aria/numberfield@3.11.14(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': - dependencies: - '@react-aria/i18n': 3.12.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/interactions': 3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/spinbutton': 3.6.15(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/textfield': 3.17.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/form': 3.1.4(react@19.1.0) - '@react-stately/numberfield': 3.9.12(react@19.1.0) - '@react-types/button': 3.12.1(react@19.1.0) - '@react-types/numberfield': 3.8.11(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@react-aria/numberfield@3.12.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@react-aria/i18n': 3.12.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/interactions': 3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/spinbutton': 3.6.17(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/textfield': 3.18.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/form': 3.2.0(react@19.1.1) + '@react-stately/numberfield': 3.10.0(react@19.1.1) + '@react-types/button': 3.13.0(react@19.1.1) + '@react-types/numberfield': 3.8.13(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - - '@react-aria/overlays@3.27.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': - dependencies: - '@react-aria/focus': 3.20.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/i18n': 3.12.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/interactions': 3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/ssr': 3.9.8(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/visually-hidden': 3.8.23(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/overlays': 3.6.16(react@19.1.0) - '@react-types/button': 3.12.1(react@19.1.0) - '@react-types/overlays': 3.8.15(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@react-aria/overlays@3.28.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@react-aria/focus': 3.21.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/i18n': 3.12.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/interactions': 3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/ssr': 3.9.10(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/visually-hidden': 3.8.26(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/overlays': 3.6.18(react@19.1.1) + '@react-types/button': 3.13.0(react@19.1.1) + '@react-types/overlays': 3.9.0(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) - '@react-aria/progress@3.4.23(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@react-aria/progress@3.4.25(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@react-aria/i18n': 3.12.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/label': 3.7.18(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-types/progress': 3.5.12(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-aria/i18n': 3.12.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/label': 3.7.20(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-types/progress': 3.5.14(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - - '@react-aria/radio@3.11.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': - dependencies: - '@react-aria/focus': 3.20.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/form': 3.0.16(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/i18n': 3.12.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/interactions': 3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/label': 3.7.18(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/radio': 3.10.13(react@19.1.0) - '@react-types/radio': 3.8.9(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@react-aria/radio@3.12.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@react-aria/focus': 3.21.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/form': 3.1.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/i18n': 3.12.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/interactions': 3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/label': 3.7.20(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/radio': 3.11.0(react@19.1.1) + '@react-types/radio': 3.9.0(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - - '@react-aria/searchfield@3.8.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': - dependencies: - '@react-aria/i18n': 3.12.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/textfield': 3.17.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/searchfield': 3.5.12(react@19.1.0) - '@react-types/button': 3.12.1(react@19.1.0) - '@react-types/searchfield': 3.6.2(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@react-aria/searchfield@3.8.7(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@react-aria/i18n': 3.12.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/textfield': 3.18.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/searchfield': 3.5.14(react@19.1.1) + '@react-types/button': 3.13.0(react@19.1.1) + '@react-types/searchfield': 3.6.4(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - - '@react-aria/select@3.15.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': - dependencies: - '@react-aria/form': 3.0.16(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/i18n': 3.12.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/interactions': 3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/label': 3.7.18(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/listbox': 3.14.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/menu': 3.18.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/selection': 3.24.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/visually-hidden': 3.8.23(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/select': 3.6.13(react@19.1.0) - '@react-types/button': 3.12.1(react@19.1.0) - '@react-types/select': 3.9.12(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@react-aria/select@3.16.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@react-aria/form': 3.1.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/i18n': 3.12.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/interactions': 3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/label': 3.7.20(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/listbox': 3.14.7(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/menu': 3.19.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/selection': 3.25.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/visually-hidden': 3.8.26(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/select': 3.7.0(react@19.1.1) + '@react-types/button': 3.13.0(react@19.1.1) + '@react-types/select': 3.10.0(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) - '@react-aria/selection@3.24.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@react-aria/selection@3.25.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@react-aria/focus': 3.20.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/i18n': 3.12.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/interactions': 3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/selection': 3.20.2(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-aria/focus': 3.21.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/i18n': 3.12.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/interactions': 3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/selection': 3.20.4(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) - '@react-aria/separator@3.4.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@react-aria/separator@3.4.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - - '@react-aria/slider@3.7.19(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': - dependencies: - '@react-aria/i18n': 3.12.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/interactions': 3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/label': 3.7.18(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/slider': 3.6.4(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) - '@react-types/slider': 3.7.11(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@react-aria/slider@3.8.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@react-aria/i18n': 3.12.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/interactions': 3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/label': 3.7.20(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/slider': 3.7.0(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) + '@react-types/slider': 3.8.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) - '@react-aria/spinbutton@3.6.15(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@react-aria/spinbutton@3.6.17(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@react-aria/i18n': 3.12.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/live-announcer': 3.4.2 - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-types/button': 3.12.1(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-aria/i18n': 3.12.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/live-announcer': 3.4.4 + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-types/button': 3.13.0(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) - '@react-aria/ssr@3.9.8(react@19.1.0)': + '@react-aria/ssr@3.9.10(react@19.1.1)': dependencies: '@swc/helpers': 0.5.17 - react: 19.1.0 + react: 19.1.1 - '@react-aria/switch@3.7.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@react-aria/switch@3.7.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@react-aria/toggle': 3.11.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/toggle': 3.8.4(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) - '@react-types/switch': 3.5.11(react@19.1.0) + '@react-aria/toggle': 3.12.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/toggle': 3.9.0(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) + '@react-types/switch': 3.5.13(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - - '@react-aria/table@3.17.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': - dependencies: - '@react-aria/focus': 3.20.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/grid': 3.14.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/i18n': 3.12.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/interactions': 3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/live-announcer': 3.4.2 - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/visually-hidden': 3.8.23(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/collections': 3.12.4(react@19.1.0) - '@react-stately/flags': 3.1.1 - '@react-stately/table': 3.14.2(react@19.1.0) - '@react-types/checkbox': 3.9.4(react@19.1.0) - '@react-types/grid': 3.3.2(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) - '@react-types/table': 3.13.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@react-aria/table@3.17.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@react-aria/focus': 3.21.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/grid': 3.14.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/i18n': 3.12.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/interactions': 3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/live-announcer': 3.4.4 + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/visually-hidden': 3.8.26(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/collections': 3.12.6(react@19.1.1) + '@react-stately/flags': 3.1.2 + '@react-stately/table': 3.14.4(react@19.1.1) + '@react-types/checkbox': 3.10.0(react@19.1.1) + '@react-types/grid': 3.3.4(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) + '@react-types/table': 3.13.2(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - - '@react-aria/tabs@3.10.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': - dependencies: - '@react-aria/focus': 3.20.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/i18n': 3.12.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/selection': 3.24.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/tabs': 3.8.2(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) - '@react-types/tabs': 3.3.15(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@react-aria/tabs@3.10.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@react-aria/focus': 3.21.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/i18n': 3.12.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/selection': 3.25.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/tabs': 3.8.4(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) + '@react-types/tabs': 3.3.17(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - - '@react-aria/tag@3.6.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': - dependencies: - '@react-aria/gridlist': 3.13.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/i18n': 3.12.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/interactions': 3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/label': 3.7.18(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/selection': 3.24.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/list': 3.12.2(react@19.1.0) - '@react-types/button': 3.12.1(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@react-aria/tag@3.7.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@react-aria/gridlist': 3.13.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/i18n': 3.12.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/interactions': 3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/label': 3.7.20(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/selection': 3.25.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/list': 3.12.4(react@19.1.1) + '@react-types/button': 3.13.0(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - - '@react-aria/textfield@3.17.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': - dependencies: - '@react-aria/form': 3.0.16(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/interactions': 3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/label': 3.7.18(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/form': 3.1.4(react@19.1.0) - '@react-stately/utils': 3.10.6(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) - '@react-types/textfield': 3.12.2(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@react-aria/textfield@3.18.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@react-aria/form': 3.1.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/interactions': 3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/label': 3.7.20(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/form': 3.2.0(react@19.1.1) + '@react-stately/utils': 3.10.8(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) + '@react-types/textfield': 3.12.4(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - - '@react-aria/toast@3.0.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': - dependencies: - '@react-aria/i18n': 3.12.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/interactions': 3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/landmark': 3.0.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/toast': 3.1.0(react@19.1.0) - '@react-types/button': 3.12.1(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@react-aria/toast@3.0.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@react-aria/i18n': 3.12.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/interactions': 3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/landmark': 3.0.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/toast': 3.1.2(react@19.1.1) + '@react-types/button': 3.13.0(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) - '@react-aria/toggle@3.11.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@react-aria/toggle@3.12.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@react-aria/interactions': 3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/toggle': 3.8.4(react@19.1.0) - '@react-types/checkbox': 3.9.4(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-aria/interactions': 3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/toggle': 3.9.0(react@19.1.1) + '@react-types/checkbox': 3.10.0(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) - '@react-aria/toolbar@3.0.0-beta.16(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@react-aria/toolbar@3.0.0-beta.19(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@react-aria/focus': 3.20.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/i18n': 3.12.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-aria/focus': 3.21.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/i18n': 3.12.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) - '@react-aria/tooltip@3.8.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@react-aria/tooltip@3.8.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@react-aria/interactions': 3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/tooltip': 3.5.4(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) - '@react-types/tooltip': 3.4.17(react@19.1.0) + '@react-aria/interactions': 3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/tooltip': 3.5.6(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) + '@react-types/tooltip': 3.4.19(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - - '@react-aria/tree@3.0.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': - dependencies: - '@react-aria/gridlist': 3.13.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/i18n': 3.12.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/selection': 3.24.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-stately/tree': 3.8.10(react@19.1.0) - '@react-types/button': 3.12.1(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@react-aria/tree@3.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@react-aria/gridlist': 3.13.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/i18n': 3.12.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/selection': 3.25.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-stately/tree': 3.9.1(react@19.1.1) + '@react-types/button': 3.13.0(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) - '@react-aria/utils@3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@react-aria/utils@3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@react-aria/ssr': 3.9.8(react@19.1.0) - '@react-stately/flags': 3.1.1 - '@react-stately/utils': 3.10.6(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-aria/ssr': 3.9.10(react@19.1.1) + '@react-stately/flags': 3.1.2 + '@react-stately/utils': 3.10.8(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 clsx: 2.1.1 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) - '@react-aria/visually-hidden@3.8.23(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@react-aria/visually-hidden@3.8.26(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: - '@react-aria/interactions': 3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-aria/interactions': 3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - - '@react-router/dev@7.6.1(@types/node@22.15.24)(jiti@2.4.2)(lightningcss@1.30.1)(react-router@7.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(terser@5.39.0)(tsx@4.19.4)(typescript@5.8.3)(vite@6.3.5(@types/node@22.15.24)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0))(yaml@2.8.0)': - dependencies: - '@babel/core': 7.27.3 - '@babel/generator': 7.27.3 - '@babel/parser': 7.27.3 - '@babel/plugin-syntax-decorators': 7.27.1(@babel/core@7.27.3) - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.27.3) - '@babel/preset-typescript': 7.27.1(@babel/core@7.27.3) - '@babel/traverse': 7.27.3 - '@babel/types': 7.27.3 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@react-router/dev@7.8.1(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(react-dom@19.1.1(react@19.1.1))(react-router@7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(rolldown-vite@7.1.4(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1))(terser@5.39.0)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1)': + dependencies: + '@babel/core': 7.28.3 + '@babel/generator': 7.28.3 + '@babel/parser': 7.28.3 + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.3) + '@babel/preset-typescript': 7.27.1(@babel/core@7.28.3) + '@babel/traverse': 7.28.3 + '@babel/types': 7.28.2 '@npmcli/package-json': 4.0.1 - '@react-router/node': 7.6.1(react-router@7.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(typescript@5.8.3) + '@react-router/node': 7.8.1(react-router@7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(typescript@5.9.2) + '@vitejs/plugin-rsc': 0.4.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(rolldown-vite@7.1.4(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1)) arg: 5.0.2 babel-dead-code-elimination: 1.0.10 chokidar: 4.0.3 dedent: 1.6.0 es-module-lexer: 1.7.0 exit-hook: 2.2.1 - fs-extra: 10.1.0 + isbot: 5.1.30 jsesc: 3.0.2 lodash: 4.17.21 pathe: 1.1.2 picocolors: 1.1.1 - prettier: 2.8.8 + prettier: 3.6.2 react-refresh: 0.14.2 - react-router: 7.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react-router: 7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) semver: 7.7.2 set-cookie-parser: 2.7.1 - valibot: 0.41.0(typescript@5.8.3) - vite: 6.3.5(@types/node@22.15.24)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0) - vite-node: 3.0.0-beta.2(@types/node@22.15.24)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0) + tinyglobby: 0.2.14 + valibot: 0.41.0(typescript@5.9.2) + vite: rolldown-vite@7.1.4(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1) + vite-node: 3.2.4(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1) optionalDependencies: - typescript: 5.8.3 + typescript: 5.9.2 transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -4075,6 +5576,8 @@ snapshots: - jiti - less - lightningcss + - react + - react-dom - sass - sass-embedded - stylus @@ -4084,453 +5587,539 @@ snapshots: - tsx - yaml - '@react-router/node@7.6.1(react-router@7.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(typescript@5.8.3)': + '@react-router/node@7.8.1(react-router@7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(typescript@5.9.2)': dependencies: '@mjackson/node-fetch-server': 0.2.0 - react-router: 7.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - source-map-support: 0.5.21 - stream-slice: 0.1.2 - undici: 6.21.3 + react-router: 7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) optionalDependencies: - typescript: 5.8.3 + typescript: 5.9.2 - '@react-stately/calendar@3.8.1(react@19.1.0)': + '@react-stately/calendar@3.8.3(react@19.1.1)': dependencies: - '@internationalized/date': 3.8.1 - '@react-stately/utils': 3.10.6(react@19.1.0) - '@react-types/calendar': 3.7.1(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@internationalized/date': 3.8.2 + '@react-stately/utils': 3.10.8(react@19.1.1) + '@react-types/calendar': 3.7.3(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 + react: 19.1.1 - '@react-stately/checkbox@3.6.14(react@19.1.0)': + '@react-stately/checkbox@3.7.0(react@19.1.1)': dependencies: - '@react-stately/form': 3.1.4(react@19.1.0) - '@react-stately/utils': 3.10.6(react@19.1.0) - '@react-types/checkbox': 3.9.4(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-stately/form': 3.2.0(react@19.1.1) + '@react-stately/utils': 3.10.8(react@19.1.1) + '@react-types/checkbox': 3.10.0(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 + react: 19.1.1 - '@react-stately/collections@3.12.4(react@19.1.0)': + '@react-stately/collections@3.12.6(react@19.1.1)': dependencies: - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - - '@react-stately/color@3.8.5(react@19.1.0)': - dependencies: - '@internationalized/number': 3.6.2 - '@internationalized/string': 3.2.6 - '@react-stately/form': 3.1.4(react@19.1.0) - '@react-stately/numberfield': 3.9.12(react@19.1.0) - '@react-stately/slider': 3.6.4(react@19.1.0) - '@react-stately/utils': 3.10.6(react@19.1.0) - '@react-types/color': 3.0.5(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + react: 19.1.1 + + '@react-stately/color@3.9.0(react@19.1.1)': + dependencies: + '@internationalized/number': 3.6.4 + '@internationalized/string': 3.2.7 + '@react-stately/form': 3.2.0(react@19.1.1) + '@react-stately/numberfield': 3.10.0(react@19.1.1) + '@react-stately/slider': 3.7.0(react@19.1.1) + '@react-stately/utils': 3.10.8(react@19.1.1) + '@react-types/color': 3.1.0(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - - '@react-stately/combobox@3.10.5(react@19.1.0)': - dependencies: - '@react-stately/collections': 3.12.4(react@19.1.0) - '@react-stately/form': 3.1.4(react@19.1.0) - '@react-stately/list': 3.12.2(react@19.1.0) - '@react-stately/overlays': 3.6.16(react@19.1.0) - '@react-stately/select': 3.6.13(react@19.1.0) - '@react-stately/utils': 3.10.6(react@19.1.0) - '@react-types/combobox': 3.13.5(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + react: 19.1.1 + + '@react-stately/combobox@3.11.0(react@19.1.1)': + dependencies: + '@react-stately/collections': 3.12.6(react@19.1.1) + '@react-stately/form': 3.2.0(react@19.1.1) + '@react-stately/list': 3.12.4(react@19.1.1) + '@react-stately/overlays': 3.6.18(react@19.1.1) + '@react-stately/select': 3.7.0(react@19.1.1) + '@react-stately/utils': 3.10.8(react@19.1.1) + '@react-types/combobox': 3.13.7(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 + react: 19.1.1 - '@react-stately/data@3.13.0(react@19.1.0)': + '@react-stately/data@3.13.2(react@19.1.1)': dependencies: - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 + react: 19.1.1 - '@react-stately/datepicker@3.14.1(react@19.1.0)': + '@react-stately/datepicker@3.15.0(react@19.1.1)': dependencies: - '@internationalized/date': 3.8.1 - '@internationalized/string': 3.2.6 - '@react-stately/form': 3.1.4(react@19.1.0) - '@react-stately/overlays': 3.6.16(react@19.1.0) - '@react-stately/utils': 3.10.6(react@19.1.0) - '@react-types/datepicker': 3.12.1(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@internationalized/date': 3.8.2 + '@internationalized/string': 3.2.7 + '@react-stately/form': 3.2.0(react@19.1.1) + '@react-stately/overlays': 3.6.18(react@19.1.1) + '@react-stately/utils': 3.10.8(react@19.1.1) + '@react-types/datepicker': 3.13.0(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 + react: 19.1.1 - '@react-stately/disclosure@3.0.4(react@19.1.0)': + '@react-stately/disclosure@3.0.6(react@19.1.1)': dependencies: - '@react-stately/utils': 3.10.6(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-stately/utils': 3.10.8(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 + react: 19.1.1 - '@react-stately/dnd@3.5.4(react@19.1.0)': + '@react-stately/dnd@3.6.1(react@19.1.1)': dependencies: - '@react-stately/selection': 3.20.2(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-stately/selection': 3.20.4(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 + react: 19.1.1 - '@react-stately/flags@3.1.1': + '@react-stately/flags@3.1.2': dependencies: '@swc/helpers': 0.5.17 - '@react-stately/form@3.1.4(react@19.1.0)': + '@react-stately/form@3.2.0(react@19.1.1)': dependencies: - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 + react: 19.1.1 - '@react-stately/grid@3.11.2(react@19.1.0)': + '@react-stately/grid@3.11.4(react@19.1.1)': dependencies: - '@react-stately/collections': 3.12.4(react@19.1.0) - '@react-stately/selection': 3.20.2(react@19.1.0) - '@react-types/grid': 3.3.2(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-stately/collections': 3.12.6(react@19.1.1) + '@react-stately/selection': 3.20.4(react@19.1.1) + '@react-types/grid': 3.3.4(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 + react: 19.1.1 - '@react-stately/list@3.12.2(react@19.1.0)': + '@react-stately/list@3.12.4(react@19.1.1)': dependencies: - '@react-stately/collections': 3.12.4(react@19.1.0) - '@react-stately/selection': 3.20.2(react@19.1.0) - '@react-stately/utils': 3.10.6(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-stately/collections': 3.12.6(react@19.1.1) + '@react-stately/selection': 3.20.4(react@19.1.1) + '@react-stately/utils': 3.10.8(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 + react: 19.1.1 - '@react-stately/menu@3.9.4(react@19.1.0)': + '@react-stately/menu@3.9.6(react@19.1.1)': dependencies: - '@react-stately/overlays': 3.6.16(react@19.1.0) - '@react-types/menu': 3.10.1(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-stately/overlays': 3.6.18(react@19.1.1) + '@react-types/menu': 3.10.3(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 + react: 19.1.1 - '@react-stately/numberfield@3.9.12(react@19.1.0)': + '@react-stately/numberfield@3.10.0(react@19.1.1)': dependencies: - '@internationalized/number': 3.6.2 - '@react-stately/form': 3.1.4(react@19.1.0) - '@react-stately/utils': 3.10.6(react@19.1.0) - '@react-types/numberfield': 3.8.11(react@19.1.0) + '@internationalized/number': 3.6.4 + '@react-stately/form': 3.2.0(react@19.1.1) + '@react-stately/utils': 3.10.8(react@19.1.1) + '@react-types/numberfield': 3.8.13(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 + react: 19.1.1 - '@react-stately/overlays@3.6.16(react@19.1.0)': + '@react-stately/overlays@3.6.18(react@19.1.1)': dependencies: - '@react-stately/utils': 3.10.6(react@19.1.0) - '@react-types/overlays': 3.8.15(react@19.1.0) + '@react-stately/utils': 3.10.8(react@19.1.1) + '@react-types/overlays': 3.9.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 + react: 19.1.1 - '@react-stately/radio@3.10.13(react@19.1.0)': + '@react-stately/radio@3.11.0(react@19.1.1)': dependencies: - '@react-stately/form': 3.1.4(react@19.1.0) - '@react-stately/utils': 3.10.6(react@19.1.0) - '@react-types/radio': 3.8.9(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-stately/form': 3.2.0(react@19.1.1) + '@react-stately/utils': 3.10.8(react@19.1.1) + '@react-types/radio': 3.9.0(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 + react: 19.1.1 - '@react-stately/searchfield@3.5.12(react@19.1.0)': + '@react-stately/searchfield@3.5.14(react@19.1.1)': dependencies: - '@react-stately/utils': 3.10.6(react@19.1.0) - '@react-types/searchfield': 3.6.2(react@19.1.0) + '@react-stately/utils': 3.10.8(react@19.1.1) + '@react-types/searchfield': 3.6.4(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 + react: 19.1.1 - '@react-stately/select@3.6.13(react@19.1.0)': + '@react-stately/select@3.7.0(react@19.1.1)': dependencies: - '@react-stately/form': 3.1.4(react@19.1.0) - '@react-stately/list': 3.12.2(react@19.1.0) - '@react-stately/overlays': 3.6.16(react@19.1.0) - '@react-types/select': 3.9.12(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-stately/form': 3.2.0(react@19.1.1) + '@react-stately/list': 3.12.4(react@19.1.1) + '@react-stately/overlays': 3.6.18(react@19.1.1) + '@react-types/select': 3.10.0(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 + react: 19.1.1 - '@react-stately/selection@3.20.2(react@19.1.0)': + '@react-stately/selection@3.20.4(react@19.1.1)': dependencies: - '@react-stately/collections': 3.12.4(react@19.1.0) - '@react-stately/utils': 3.10.6(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-stately/collections': 3.12.6(react@19.1.1) + '@react-stately/utils': 3.10.8(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 + react: 19.1.1 - '@react-stately/slider@3.6.4(react@19.1.0)': + '@react-stately/slider@3.7.0(react@19.1.1)': dependencies: - '@react-stately/utils': 3.10.6(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) - '@react-types/slider': 3.7.11(react@19.1.0) + '@react-stately/utils': 3.10.8(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) + '@react-types/slider': 3.8.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 - - '@react-stately/table@3.14.2(react@19.1.0)': - dependencies: - '@react-stately/collections': 3.12.4(react@19.1.0) - '@react-stately/flags': 3.1.1 - '@react-stately/grid': 3.11.2(react@19.1.0) - '@react-stately/selection': 3.20.2(react@19.1.0) - '@react-stately/utils': 3.10.6(react@19.1.0) - '@react-types/grid': 3.3.2(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) - '@react-types/table': 3.13.0(react@19.1.0) + react: 19.1.1 + + '@react-stately/table@3.14.4(react@19.1.1)': + dependencies: + '@react-stately/collections': 3.12.6(react@19.1.1) + '@react-stately/flags': 3.1.2 + '@react-stately/grid': 3.11.4(react@19.1.1) + '@react-stately/selection': 3.20.4(react@19.1.1) + '@react-stately/utils': 3.10.8(react@19.1.1) + '@react-types/grid': 3.3.4(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) + '@react-types/table': 3.13.2(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 + react: 19.1.1 - '@react-stately/tabs@3.8.2(react@19.1.0)': + '@react-stately/tabs@3.8.4(react@19.1.1)': dependencies: - '@react-stately/list': 3.12.2(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) - '@react-types/tabs': 3.3.15(react@19.1.0) + '@react-stately/list': 3.12.4(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) + '@react-types/tabs': 3.3.17(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 + react: 19.1.1 - '@react-stately/toast@3.1.0(react@19.1.0)': + '@react-stately/toast@3.1.2(react@19.1.1)': dependencies: '@swc/helpers': 0.5.17 - react: 19.1.0 - use-sync-external-store: 1.5.0(react@19.1.0) + react: 19.1.1 + use-sync-external-store: 1.5.0(react@19.1.1) - '@react-stately/toggle@3.8.4(react@19.1.0)': + '@react-stately/toggle@3.9.0(react@19.1.1)': dependencies: - '@react-stately/utils': 3.10.6(react@19.1.0) - '@react-types/checkbox': 3.9.4(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-stately/utils': 3.10.8(react@19.1.1) + '@react-types/checkbox': 3.10.0(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 + react: 19.1.1 - '@react-stately/tooltip@3.5.4(react@19.1.0)': + '@react-stately/tooltip@3.5.6(react@19.1.1)': dependencies: - '@react-stately/overlays': 3.6.16(react@19.1.0) - '@react-types/tooltip': 3.4.17(react@19.1.0) + '@react-stately/overlays': 3.6.18(react@19.1.1) + '@react-types/tooltip': 3.4.19(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 + react: 19.1.1 - '@react-stately/tree@3.8.10(react@19.1.0)': + '@react-stately/tree@3.9.1(react@19.1.1)': dependencies: - '@react-stately/collections': 3.12.4(react@19.1.0) - '@react-stately/selection': 3.20.2(react@19.1.0) - '@react-stately/utils': 3.10.6(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) + '@react-stately/collections': 3.12.6(react@19.1.1) + '@react-stately/selection': 3.20.4(react@19.1.1) + '@react-stately/utils': 3.10.8(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) '@swc/helpers': 0.5.17 - react: 19.1.0 + react: 19.1.1 - '@react-stately/utils@3.10.6(react@19.1.0)': + '@react-stately/utils@3.10.8(react@19.1.1)': dependencies: '@swc/helpers': 0.5.17 - react: 19.1.0 + react: 19.1.1 - '@react-types/breadcrumbs@3.7.13(react@19.1.0)': + '@react-types/breadcrumbs@3.7.15(react@19.1.1)': dependencies: - '@react-types/link': 3.6.1(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) - react: 19.1.0 + '@react-types/link': 3.6.3(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) + react: 19.1.1 - '@react-types/button@3.12.1(react@19.1.0)': + '@react-types/button@3.13.0(react@19.1.1)': dependencies: - '@react-types/shared': 3.29.1(react@19.1.0) - react: 19.1.0 + '@react-types/shared': 3.31.0(react@19.1.1) + react: 19.1.1 - '@react-types/calendar@3.7.1(react@19.1.0)': + '@react-types/calendar@3.7.3(react@19.1.1)': dependencies: - '@internationalized/date': 3.8.1 - '@react-types/shared': 3.29.1(react@19.1.0) - react: 19.1.0 + '@internationalized/date': 3.8.2 + '@react-types/shared': 3.31.0(react@19.1.1) + react: 19.1.1 - '@react-types/checkbox@3.9.4(react@19.1.0)': + '@react-types/checkbox@3.10.0(react@19.1.1)': dependencies: - '@react-types/shared': 3.29.1(react@19.1.0) - react: 19.1.0 + '@react-types/shared': 3.31.0(react@19.1.1) + react: 19.1.1 - '@react-types/color@3.0.5(react@19.1.0)': + '@react-types/color@3.1.0(react@19.1.1)': dependencies: - '@react-types/shared': 3.29.1(react@19.1.0) - '@react-types/slider': 3.7.11(react@19.1.0) - react: 19.1.0 + '@react-types/shared': 3.31.0(react@19.1.1) + '@react-types/slider': 3.8.0(react@19.1.1) + react: 19.1.1 - '@react-types/combobox@3.13.5(react@19.1.0)': + '@react-types/combobox@3.13.7(react@19.1.1)': dependencies: - '@react-types/shared': 3.29.1(react@19.1.0) - react: 19.1.0 + '@react-types/shared': 3.31.0(react@19.1.1) + react: 19.1.1 - '@react-types/datepicker@3.12.1(react@19.1.0)': + '@react-types/datepicker@3.13.0(react@19.1.1)': dependencies: - '@internationalized/date': 3.8.1 - '@react-types/calendar': 3.7.1(react@19.1.0) - '@react-types/overlays': 3.8.15(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) - react: 19.1.0 + '@internationalized/date': 3.8.2 + '@react-types/calendar': 3.7.3(react@19.1.1) + '@react-types/overlays': 3.9.0(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) + react: 19.1.1 - '@react-types/dialog@3.5.18(react@19.1.0)': + '@react-types/dialog@3.5.20(react@19.1.1)': dependencies: - '@react-types/overlays': 3.8.15(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) - react: 19.1.0 + '@react-types/overlays': 3.9.0(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) + react: 19.1.1 - '@react-types/grid@3.3.2(react@19.1.0)': + '@react-types/grid@3.3.4(react@19.1.1)': dependencies: - '@react-types/shared': 3.29.1(react@19.1.0) - react: 19.1.0 + '@react-types/shared': 3.31.0(react@19.1.1) + react: 19.1.1 - '@react-types/link@3.6.1(react@19.1.0)': + '@react-types/link@3.6.3(react@19.1.1)': dependencies: - '@react-types/shared': 3.29.1(react@19.1.0) - react: 19.1.0 + '@react-types/shared': 3.31.0(react@19.1.1) + react: 19.1.1 - '@react-types/listbox@3.7.0(react@19.1.0)': + '@react-types/listbox@3.7.2(react@19.1.1)': dependencies: - '@react-types/shared': 3.29.1(react@19.1.0) - react: 19.1.0 + '@react-types/shared': 3.31.0(react@19.1.1) + react: 19.1.1 - '@react-types/menu@3.10.1(react@19.1.0)': + '@react-types/menu@3.10.3(react@19.1.1)': dependencies: - '@react-types/overlays': 3.8.15(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) - react: 19.1.0 + '@react-types/overlays': 3.9.0(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) + react: 19.1.1 - '@react-types/meter@3.4.9(react@19.1.0)': + '@react-types/meter@3.4.11(react@19.1.1)': dependencies: - '@react-types/progress': 3.5.12(react@19.1.0) - react: 19.1.0 + '@react-types/progress': 3.5.14(react@19.1.1) + react: 19.1.1 - '@react-types/numberfield@3.8.11(react@19.1.0)': + '@react-types/numberfield@3.8.13(react@19.1.1)': dependencies: - '@react-types/shared': 3.29.1(react@19.1.0) - react: 19.1.0 + '@react-types/shared': 3.31.0(react@19.1.1) + react: 19.1.1 - '@react-types/overlays@3.8.15(react@19.1.0)': + '@react-types/overlays@3.9.0(react@19.1.1)': dependencies: - '@react-types/shared': 3.29.1(react@19.1.0) - react: 19.1.0 + '@react-types/shared': 3.31.0(react@19.1.1) + react: 19.1.1 - '@react-types/progress@3.5.12(react@19.1.0)': + '@react-types/progress@3.5.14(react@19.1.1)': dependencies: - '@react-types/shared': 3.29.1(react@19.1.0) - react: 19.1.0 + '@react-types/shared': 3.31.0(react@19.1.1) + react: 19.1.1 - '@react-types/radio@3.8.9(react@19.1.0)': + '@react-types/radio@3.9.0(react@19.1.1)': dependencies: - '@react-types/shared': 3.29.1(react@19.1.0) - react: 19.1.0 + '@react-types/shared': 3.31.0(react@19.1.1) + react: 19.1.1 - '@react-types/searchfield@3.6.2(react@19.1.0)': + '@react-types/searchfield@3.6.4(react@19.1.1)': dependencies: - '@react-types/shared': 3.29.1(react@19.1.0) - '@react-types/textfield': 3.12.2(react@19.1.0) - react: 19.1.0 + '@react-types/shared': 3.31.0(react@19.1.1) + '@react-types/textfield': 3.12.4(react@19.1.1) + react: 19.1.1 - '@react-types/select@3.9.12(react@19.1.0)': + '@react-types/select@3.10.0(react@19.1.1)': dependencies: - '@react-types/shared': 3.29.1(react@19.1.0) - react: 19.1.0 + '@react-types/shared': 3.31.0(react@19.1.1) + react: 19.1.1 - '@react-types/shared@3.29.1(react@19.1.0)': + '@react-types/shared@3.31.0(react@19.1.1)': dependencies: - react: 19.1.0 + react: 19.1.1 - '@react-types/slider@3.7.11(react@19.1.0)': + '@react-types/slider@3.8.0(react@19.1.1)': dependencies: - '@react-types/shared': 3.29.1(react@19.1.0) - react: 19.1.0 + '@react-types/shared': 3.31.0(react@19.1.1) + react: 19.1.1 - '@react-types/switch@3.5.11(react@19.1.0)': + '@react-types/switch@3.5.13(react@19.1.1)': dependencies: - '@react-types/shared': 3.29.1(react@19.1.0) - react: 19.1.0 + '@react-types/shared': 3.31.0(react@19.1.1) + react: 19.1.1 - '@react-types/table@3.13.0(react@19.1.0)': + '@react-types/table@3.13.2(react@19.1.1)': dependencies: - '@react-types/grid': 3.3.2(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) - react: 19.1.0 + '@react-types/grid': 3.3.4(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) + react: 19.1.1 - '@react-types/tabs@3.3.15(react@19.1.0)': + '@react-types/tabs@3.3.17(react@19.1.1)': dependencies: - '@react-types/shared': 3.29.1(react@19.1.0) - react: 19.1.0 + '@react-types/shared': 3.31.0(react@19.1.1) + react: 19.1.1 - '@react-types/textfield@3.12.2(react@19.1.0)': + '@react-types/textfield@3.12.4(react@19.1.1)': dependencies: - '@react-types/shared': 3.29.1(react@19.1.0) - react: 19.1.0 + '@react-types/shared': 3.31.0(react@19.1.1) + react: 19.1.1 - '@react-types/tooltip@3.4.17(react@19.1.0)': + '@react-types/tooltip@3.4.19(react@19.1.1)': dependencies: - '@react-types/overlays': 3.8.15(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) - react: 19.1.0 + '@react-types/overlays': 3.9.0(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) + react: 19.1.1 + + '@rolldown/binding-android-arm64@1.0.0-beta.33': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.0-beta.33': + optional: true + + '@rolldown/binding-darwin-x64@1.0.0-beta.33': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.0-beta.33': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.33': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.33': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.0-beta.33': + optional: true - '@rollup/pluginutils@5.1.4(rollup@4.36.0)': + '@rolldown/binding-linux-x64-gnu@1.0.0-beta.33': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.0-beta.33': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.0-beta.33': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.0-beta.33': dependencies: - '@types/estree': 1.0.7 + '@napi-rs/wasm-runtime': 1.0.3 + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.33': + optional: true + + '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.33': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.0-beta.33': + optional: true + + '@rolldown/pluginutils@1.0.0-beta.29': {} + + '@rolldown/pluginutils@1.0.0-beta.33': {} + + '@rollup/pluginutils@5.2.0(rollup@4.46.3)': + dependencies: + '@types/estree': 1.0.8 estree-walker: 2.0.2 - picomatch: 4.0.2 + picomatch: 4.0.3 optionalDependencies: - rollup: 4.36.0 + rollup: 4.46.3 - '@rollup/rollup-android-arm-eabi@4.36.0': + '@rollup/rollup-android-arm-eabi@4.46.3': optional: true - '@rollup/rollup-android-arm64@4.36.0': + '@rollup/rollup-android-arm64@4.46.3': optional: true - '@rollup/rollup-darwin-arm64@4.36.0': + '@rollup/rollup-darwin-arm64@4.46.3': optional: true - '@rollup/rollup-darwin-x64@4.36.0': + '@rollup/rollup-darwin-x64@4.46.3': optional: true - '@rollup/rollup-freebsd-arm64@4.36.0': + '@rollup/rollup-freebsd-arm64@4.46.3': optional: true - '@rollup/rollup-freebsd-x64@4.36.0': + '@rollup/rollup-freebsd-x64@4.46.3': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.36.0': + '@rollup/rollup-linux-arm-gnueabihf@4.46.3': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.36.0': + '@rollup/rollup-linux-arm-musleabihf@4.46.3': optional: true - '@rollup/rollup-linux-arm64-gnu@4.36.0': + '@rollup/rollup-linux-arm64-gnu@4.46.3': optional: true - '@rollup/rollup-linux-arm64-musl@4.36.0': + '@rollup/rollup-linux-arm64-musl@4.46.3': optional: true - '@rollup/rollup-linux-loongarch64-gnu@4.36.0': + '@rollup/rollup-linux-loongarch64-gnu@4.46.3': optional: true - '@rollup/rollup-linux-powerpc64le-gnu@4.36.0': + '@rollup/rollup-linux-ppc64-gnu@4.46.3': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.36.0': + '@rollup/rollup-linux-riscv64-gnu@4.46.3': optional: true - '@rollup/rollup-linux-s390x-gnu@4.36.0': + '@rollup/rollup-linux-riscv64-musl@4.46.3': optional: true - '@rollup/rollup-linux-x64-gnu@4.36.0': + '@rollup/rollup-linux-s390x-gnu@4.46.3': optional: true - '@rollup/rollup-linux-x64-musl@4.36.0': + '@rollup/rollup-linux-x64-gnu@4.46.3': optional: true - '@rollup/rollup-win32-arm64-msvc@4.36.0': + '@rollup/rollup-linux-x64-musl@4.46.3': optional: true - '@rollup/rollup-win32-ia32-msvc@4.36.0': + '@rollup/rollup-win32-arm64-msvc@4.46.3': optional: true - '@rollup/rollup-win32-x64-msvc@4.36.0': + '@rollup/rollup-win32-ia32-msvc@4.46.3': optional: true + '@rollup/rollup-win32-x64-msvc@4.46.3': + optional: true + + '@shikijs/core@3.9.2': + dependencies: + '@shikijs/types': 3.9.2 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 + + '@shikijs/engine-javascript@3.9.2': + dependencies: + '@shikijs/types': 3.9.2 + '@shikijs/vscode-textmate': 10.0.2 + oniguruma-to-es: 4.3.3 + + '@shikijs/engine-oniguruma@3.9.2': + dependencies: + '@shikijs/types': 3.9.2 + '@shikijs/vscode-textmate': 10.0.2 + + '@shikijs/langs@3.9.2': + dependencies: + '@shikijs/types': 3.9.2 + + '@shikijs/themes@3.9.2': + dependencies: + '@shikijs/types': 3.9.2 + + '@shikijs/transformers@3.9.2': + dependencies: + '@shikijs/core': 3.9.2 + '@shikijs/types': 3.9.2 + + '@shikijs/types@3.9.2': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + '@shikijs/vscode-textmate@10.0.2': {} + '@shopify/lang-jsonc@1.0.1': dependencies: '@lezer/highlight': 1.2.1 @@ -4540,121 +6129,189 @@ snapshots: dependencies: tslib: 2.8.1 - '@tailwindcss/node@4.1.8': + '@tailwindcss/node@4.1.12': dependencies: - '@ampproject/remapping': 2.3.0 - enhanced-resolve: 5.18.1 - jiti: 2.4.2 + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.18.3 + jiti: 2.5.1 lightningcss: 1.30.1 magic-string: 0.30.17 source-map-js: 1.2.1 - tailwindcss: 4.1.8 + tailwindcss: 4.1.12 - '@tailwindcss/oxide-android-arm64@4.1.8': + '@tailwindcss/oxide-android-arm64@4.1.12': optional: true - '@tailwindcss/oxide-darwin-arm64@4.1.8': + '@tailwindcss/oxide-darwin-arm64@4.1.12': optional: true - '@tailwindcss/oxide-darwin-x64@4.1.8': + '@tailwindcss/oxide-darwin-x64@4.1.12': optional: true - '@tailwindcss/oxide-freebsd-x64@4.1.8': + '@tailwindcss/oxide-freebsd-x64@4.1.12': optional: true - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.8': + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.12': optional: true - '@tailwindcss/oxide-linux-arm64-gnu@4.1.8': + '@tailwindcss/oxide-linux-arm64-gnu@4.1.12': optional: true - '@tailwindcss/oxide-linux-arm64-musl@4.1.8': + '@tailwindcss/oxide-linux-arm64-musl@4.1.12': optional: true - '@tailwindcss/oxide-linux-x64-gnu@4.1.8': + '@tailwindcss/oxide-linux-x64-gnu@4.1.12': optional: true - '@tailwindcss/oxide-linux-x64-musl@4.1.8': + '@tailwindcss/oxide-linux-x64-musl@4.1.12': optional: true - '@tailwindcss/oxide-wasm32-wasi@4.1.8': + '@tailwindcss/oxide-wasm32-wasi@4.1.12': optional: true - '@tailwindcss/oxide-win32-arm64-msvc@4.1.8': + '@tailwindcss/oxide-win32-arm64-msvc@4.1.12': optional: true - '@tailwindcss/oxide-win32-x64-msvc@4.1.8': + '@tailwindcss/oxide-win32-x64-msvc@4.1.12': optional: true - '@tailwindcss/oxide@4.1.8': + '@tailwindcss/oxide@4.1.12': dependencies: detect-libc: 2.0.4 tar: 7.4.3 optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.1.8 - '@tailwindcss/oxide-darwin-arm64': 4.1.8 - '@tailwindcss/oxide-darwin-x64': 4.1.8 - '@tailwindcss/oxide-freebsd-x64': 4.1.8 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.8 - '@tailwindcss/oxide-linux-arm64-gnu': 4.1.8 - '@tailwindcss/oxide-linux-arm64-musl': 4.1.8 - '@tailwindcss/oxide-linux-x64-gnu': 4.1.8 - '@tailwindcss/oxide-linux-x64-musl': 4.1.8 - '@tailwindcss/oxide-wasm32-wasi': 4.1.8 - '@tailwindcss/oxide-win32-arm64-msvc': 4.1.8 - '@tailwindcss/oxide-win32-x64-msvc': 4.1.8 - - '@tailwindcss/vite@4.1.8(vite@6.3.5(@types/node@22.15.24)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0))': - dependencies: - '@tailwindcss/node': 4.1.8 - '@tailwindcss/oxide': 4.1.8 - tailwindcss: 4.1.8 - vite: 6.3.5(@types/node@22.15.24)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0) - - '@types/estree@1.0.6': {} + '@tailwindcss/oxide-android-arm64': 4.1.12 + '@tailwindcss/oxide-darwin-arm64': 4.1.12 + '@tailwindcss/oxide-darwin-x64': 4.1.12 + '@tailwindcss/oxide-freebsd-x64': 4.1.12 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.12 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.12 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.12 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.12 + '@tailwindcss/oxide-linux-x64-musl': 4.1.12 + '@tailwindcss/oxide-wasm32-wasi': 4.1.12 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.12 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.12 + + '@tailwindcss/vite@4.1.12(rolldown-vite@7.1.4(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1))': + dependencies: + '@tailwindcss/node': 4.1.12 + '@tailwindcss/oxide': 4.1.12 + tailwindcss: 4.1.12 + vite: rolldown-vite@7.1.4(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1) + + '@tybys/wasm-util@0.10.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/better-sqlite3@7.6.13': + dependencies: + '@types/node': 24.3.0 + optional: true + + '@types/chai@5.2.2': + dependencies: + '@types/deep-eql': 4.0.2 + + '@types/deep-eql@4.0.2': {} '@types/estree@1.0.7': {} + '@types/estree@1.0.8': {} + + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + '@types/js-yaml@4.0.9': {} + '@types/linkify-it@5.0.0': {} + + '@types/markdown-it@14.1.2': + dependencies: + '@types/linkify-it': 5.0.0 + '@types/mdurl': 2.0.0 + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/mdurl@2.0.0': {} + '@types/node-fetch@2.6.12': dependencies: - '@types/node': 22.15.24 + '@types/node': 24.3.0 form-data: 4.0.2 - '@types/node@20.17.52': + '@types/node@20.19.11': dependencies: - undici-types: 6.19.8 + undici-types: 6.21.0 - '@types/node@22.10.7': + '@types/node@22.17.2': dependencies: - undici-types: 6.20.0 + undici-types: 6.21.0 - '@types/node@22.15.24': + '@types/node@24.3.0': dependencies: - undici-types: 6.21.0 + undici-types: 7.10.0 - '@types/react-dom@19.1.5(@types/react@19.1.6)': + '@types/react-dom@19.1.7(@types/react@19.1.10)': dependencies: - '@types/react': 19.1.6 + '@types/react': 19.1.10 - '@types/react-reconciler@0.28.9(@types/react@19.1.6)': + '@types/react-reconciler@0.28.9(@types/react@19.1.10)': dependencies: - '@types/react': 19.1.6 + '@types/react': 19.1.10 - '@types/react@19.1.6': + '@types/react@19.1.10': dependencies: csstype: 3.1.3 '@types/stream-buffers@3.0.7': dependencies: - '@types/node': 22.15.24 + '@types/node': 24.3.0 + + '@types/unist@3.0.3': {} - '@types/websocket@1.0.10': + '@types/web-bluetooth@0.0.21': {} + + '@types/ws@8.18.1': dependencies: - '@types/node': 22.10.7 + '@types/node': 24.3.0 + + '@typescript/native-preview-darwin-arm64@7.0.0-dev.20250821.1': + optional: true + + '@typescript/native-preview-darwin-x64@7.0.0-dev.20250821.1': + optional: true + + '@typescript/native-preview-linux-arm64@7.0.0-dev.20250821.1': + optional: true + + '@typescript/native-preview-linux-arm@7.0.0-dev.20250821.1': + optional: true + + '@typescript/native-preview-linux-x64@7.0.0-dev.20250821.1': + optional: true + + '@typescript/native-preview-win32-arm64@7.0.0-dev.20250821.1': + optional: true + + '@typescript/native-preview-win32-x64@7.0.0-dev.20250821.1': + optional: true + + '@typescript/native-preview@7.0.0-dev.20250821.1': + optionalDependencies: + '@typescript/native-preview-darwin-arm64': 7.0.0-dev.20250821.1 + '@typescript/native-preview-darwin-x64': 7.0.0-dev.20250821.1 + '@typescript/native-preview-linux-arm': 7.0.0-dev.20250821.1 + '@typescript/native-preview-linux-arm64': 7.0.0-dev.20250821.1 + '@typescript/native-preview-linux-x64': 7.0.0-dev.20250821.1 + '@typescript/native-preview-win32-arm64': 7.0.0-dev.20250821.1 + '@typescript/native-preview-win32-x64': 7.0.0-dev.20250821.1 - '@uiw/codemirror-extensions-basic-setup@4.23.12(@codemirror/autocomplete@6.18.2(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8)(@lezer/common@1.2.3))(@codemirror/commands@6.8.1)(@codemirror/language@6.11.0)(@codemirror/lint@6.8.2)(@codemirror/search@6.5.7)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8)': + '@uiw/codemirror-extensions-basic-setup@4.25.1(@codemirror/autocomplete@6.18.2(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8)(@lezer/common@1.2.3))(@codemirror/commands@6.8.1)(@codemirror/language@6.11.0)(@codemirror/lint@6.8.2)(@codemirror/search@6.5.7)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8)': dependencies: '@codemirror/autocomplete': 6.18.2(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8)(@lezer/common@1.2.3) '@codemirror/commands': 6.8.1 @@ -4664,46 +6321,221 @@ snapshots: '@codemirror/state': 6.5.2 '@codemirror/view': 6.36.8 - '@uiw/codemirror-theme-github@4.23.12(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8)': + '@uiw/codemirror-theme-github@4.25.1(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8)': dependencies: - '@uiw/codemirror-themes': 4.23.12(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8) + '@uiw/codemirror-themes': 4.25.1(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8) transitivePeerDependencies: - '@codemirror/language' - '@codemirror/state' - '@codemirror/view' - '@uiw/codemirror-theme-xcode@4.23.12(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8)': + '@uiw/codemirror-theme-xcode@4.25.1(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8)': dependencies: - '@uiw/codemirror-themes': 4.23.12(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8) + '@uiw/codemirror-themes': 4.25.1(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8) transitivePeerDependencies: - '@codemirror/language' - '@codemirror/state' - '@codemirror/view' - '@uiw/codemirror-themes@4.23.12(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8)': + '@uiw/codemirror-themes@4.25.1(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8)': dependencies: '@codemirror/language': 6.11.0 '@codemirror/state': 6.5.2 '@codemirror/view': 6.36.8 - '@uiw/react-codemirror@4.23.12(@babel/runtime@7.27.3)(@codemirror/autocomplete@6.18.2(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8)(@lezer/common@1.2.3))(@codemirror/language@6.11.0)(@codemirror/lint@6.8.2)(@codemirror/search@6.5.7)(@codemirror/state@6.5.2)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.36.8)(codemirror@6.0.1(@lezer/common@1.2.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@uiw/react-codemirror@4.25.1(@babel/runtime@7.27.3)(@codemirror/autocomplete@6.18.2(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8)(@lezer/common@1.2.3))(@codemirror/language@6.11.0)(@codemirror/lint@6.8.2)(@codemirror/search@6.5.7)(@codemirror/state@6.5.2)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.36.8)(codemirror@6.0.1(@lezer/common@1.2.3))(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': dependencies: '@babel/runtime': 7.27.3 '@codemirror/commands': 6.8.1 '@codemirror/state': 6.5.2 '@codemirror/theme-one-dark': 6.1.2 '@codemirror/view': 6.36.8 - '@uiw/codemirror-extensions-basic-setup': 4.23.12(@codemirror/autocomplete@6.18.2(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8)(@lezer/common@1.2.3))(@codemirror/commands@6.8.1)(@codemirror/language@6.11.0)(@codemirror/lint@6.8.2)(@codemirror/search@6.5.7)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8) + '@uiw/codemirror-extensions-basic-setup': 4.25.1(@codemirror/autocomplete@6.18.2(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8)(@lezer/common@1.2.3))(@codemirror/commands@6.8.1)(@codemirror/language@6.11.0)(@codemirror/lint@6.8.2)(@codemirror/search@6.5.7)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8) codemirror: 6.0.1(@lezer/common@1.2.3) - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) transitivePeerDependencies: - '@codemirror/autocomplete' - '@codemirror/language' - '@codemirror/lint' - '@codemirror/search' - acorn@8.14.1: + '@ungap/structured-clone@1.3.0': {} + + '@vitejs/plugin-rsc@0.4.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(rolldown-vite@7.1.4(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1))': + dependencies: + '@mjackson/node-fetch-server': 0.7.0 + es-module-lexer: 1.7.0 + estree-walker: 3.0.3 + magic-string: 0.30.17 + periscopic: 4.0.2 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + turbo-stream: 3.1.0 + vite: rolldown-vite@7.1.4(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1) + vitefu: 1.1.1(rolldown-vite@7.1.4(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1)) + + '@vitejs/plugin-vue@6.0.1(vite@7.1.2(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1))(vue@3.5.18(typescript@5.9.2))': + dependencies: + '@rolldown/pluginutils': 1.0.0-beta.29 + vite: 7.1.2(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1) + vue: 3.5.18(typescript@5.9.2) + + '@vitest/expect@3.2.4': + dependencies: + '@types/chai': 5.2.2 + '@vitest/spy': 3.2.4 + '@vitest/utils': 3.2.4 + chai: 5.2.1 + tinyrainbow: 2.0.0 + + '@vitest/mocker@3.2.4(vite@7.1.2(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1))': + dependencies: + '@vitest/spy': 3.2.4 + estree-walker: 3.0.3 + magic-string: 0.30.17 + optionalDependencies: + vite: 7.1.2(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1) + + '@vitest/pretty-format@3.2.4': + dependencies: + tinyrainbow: 2.0.0 + + '@vitest/runner@3.2.4': + dependencies: + '@vitest/utils': 3.2.4 + pathe: 2.0.3 + strip-literal: 3.0.0 + + '@vitest/snapshot@3.2.4': + dependencies: + '@vitest/pretty-format': 3.2.4 + magic-string: 0.30.17 + pathe: 2.0.3 + + '@vitest/spy@3.2.4': + dependencies: + tinyspy: 4.0.3 + + '@vitest/utils@3.2.4': + dependencies: + '@vitest/pretty-format': 3.2.4 + loupe: 3.1.4 + tinyrainbow: 2.0.0 + + '@vue/compiler-core@3.5.18': + dependencies: + '@babel/parser': 7.28.0 + '@vue/shared': 3.5.18 + entities: 4.5.0 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + '@vue/compiler-dom@3.5.18': + dependencies: + '@vue/compiler-core': 3.5.18 + '@vue/shared': 3.5.18 + + '@vue/compiler-sfc@3.5.18': + dependencies: + '@babel/parser': 7.28.0 + '@vue/compiler-core': 3.5.18 + '@vue/compiler-dom': 3.5.18 + '@vue/compiler-ssr': 3.5.18 + '@vue/shared': 3.5.18 + estree-walker: 2.0.2 + magic-string: 0.30.17 + postcss: 8.5.6 + source-map-js: 1.2.1 + + '@vue/compiler-ssr@3.5.18': + dependencies: + '@vue/compiler-dom': 3.5.18 + '@vue/shared': 3.5.18 + + '@vue/devtools-api@8.0.0': + dependencies: + '@vue/devtools-kit': 8.0.0 + + '@vue/devtools-kit@8.0.0': + dependencies: + '@vue/devtools-shared': 8.0.0 + birpc: 2.5.0 + hookable: 5.5.3 + mitt: 3.0.1 + perfect-debounce: 1.0.0 + speakingurl: 14.0.1 + superjson: 2.2.2 + + '@vue/devtools-shared@8.0.0': + dependencies: + rfdc: 1.4.1 + + '@vue/reactivity@3.5.18': + dependencies: + '@vue/shared': 3.5.18 + + '@vue/runtime-core@3.5.18': + dependencies: + '@vue/reactivity': 3.5.18 + '@vue/shared': 3.5.18 + + '@vue/runtime-dom@3.5.18': + dependencies: + '@vue/reactivity': 3.5.18 + '@vue/runtime-core': 3.5.18 + '@vue/shared': 3.5.18 + csstype: 3.1.3 + + '@vue/server-renderer@3.5.18(vue@3.5.18(typescript@5.9.2))': + dependencies: + '@vue/compiler-ssr': 3.5.18 + '@vue/shared': 3.5.18 + vue: 3.5.18(typescript@5.9.2) + + '@vue/shared@3.5.18': {} + + '@vueuse/core@13.7.0(vue@3.5.18(typescript@5.9.2))': + dependencies: + '@types/web-bluetooth': 0.0.21 + '@vueuse/metadata': 13.7.0 + '@vueuse/shared': 13.7.0(vue@3.5.18(typescript@5.9.2)) + vue: 3.5.18(typescript@5.9.2) + + '@vueuse/integrations@13.7.0(focus-trap@7.6.5)(vue@3.5.18(typescript@5.9.2))': + dependencies: + '@vueuse/core': 13.7.0(vue@3.5.18(typescript@5.9.2)) + '@vueuse/shared': 13.7.0(vue@3.5.18(typescript@5.9.2)) + vue: 3.5.18(typescript@5.9.2) + optionalDependencies: + focus-trap: 7.6.5 + + '@vueuse/metadata@13.7.0': {} + + '@vueuse/shared@13.7.0(vue@3.5.18(typescript@5.9.2))': + dependencies: + vue: 3.5.18(typescript@5.9.2) + + '@xterm/addon-clipboard@0.1.0(@xterm/xterm@5.5.0)': + dependencies: + '@xterm/xterm': 5.5.0 + js-base64: 3.7.7 + + '@xterm/addon-fit@0.10.0(@xterm/xterm@5.5.0)': + dependencies: + '@xterm/xterm': 5.5.0 + + '@xterm/addon-unicode11@0.8.0(@xterm/xterm@5.5.0)': + dependencies: + '@xterm/xterm': 5.5.0 + + '@xterm/addon-web-links@0.11.0(@xterm/xterm@5.5.0)': + dependencies: + '@xterm/xterm': 5.5.0 + + '@xterm/xterm@5.5.0': {} + + acorn@8.15.0: optional: true agent-base@7.1.3: {} @@ -4718,6 +6550,8 @@ snapshots: ansi-styles@6.2.1: {} + ansis@4.1.0: {} + arg@5.0.2: {} argparse@2.0.1: {} @@ -4727,16 +6561,18 @@ snapshots: '@ark/schema': 0.46.0 '@ark/util': 0.46.0 + assertion-error@2.0.1: {} + asynckit@0.4.0: {} b4a@1.6.7: {} babel-dead-code-elimination@1.0.10: dependencies: - '@babel/core': 7.27.3 - '@babel/parser': 7.27.3 - '@babel/traverse': 7.27.3 - '@babel/types': 7.27.3 + '@babel/core': 7.28.3 + '@babel/parser': 7.28.3 + '@babel/traverse': 7.28.3 + '@babel/types': 7.28.2 transitivePeerDependencies: - supports-color @@ -4767,13 +6603,36 @@ snapshots: bare-events: 2.5.4 optional: true - bippy@0.3.14(@types/react@19.1.6)(react@19.1.0): + base64-js@1.5.1: + optional: true + + better-sqlite3@11.10.0: dependencies: - '@types/react-reconciler': 0.28.9(@types/react@19.1.6) - react: 19.1.0 + bindings: 1.5.0 + prebuild-install: 7.1.3 + optional: true + + bindings@1.5.0: + dependencies: + file-uri-to-path: 1.0.0 + optional: true + + bippy@0.3.18(@types/react@19.1.10)(react@19.1.1): + dependencies: + '@types/react-reconciler': 0.28.9(@types/react@19.1.10) + react: 19.1.1 transitivePeerDependencies: - '@types/react' + birpc@2.5.0: {} + + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + optional: true + brace-expansion@2.0.1: dependencies: balanced-match: 1.0.2 @@ -4787,6 +6646,12 @@ snapshots: buffer-from@1.1.2: {} + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + optional: true + bufferutil@4.0.9: dependencies: node-gyp-build: 4.8.4 @@ -4801,10 +6666,29 @@ snapshots: caniuse-lite@1.0.30001718: {} + ccount@2.0.1: {} + + chai@5.2.1: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.1 + deep-eql: 5.0.2 + loupe: 3.1.4 + pathval: 2.0.1 + + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + check-error@2.1.1: {} + chokidar@4.0.3: dependencies: readdirp: 4.1.2 + chownr@1.1.4: + optional: true + chownr@3.0.0: {} clsx@2.1.1: {} @@ -4831,6 +6715,8 @@ snapshots: dependencies: delayed-stream: 1.0.0 + comma-separated-tokens@2.0.3: {} + commander@2.20.3: optional: true @@ -4838,6 +6724,10 @@ snapshots: cookie@1.0.2: {} + copy-anything@3.0.5: + dependencies: + is-what: 4.1.16 + crelt@1.0.6: {} cross-spawn@7.0.3: @@ -4848,6 +6738,8 @@ snapshots: csstype@3.1.3: {} + data-uri-to-buffer@4.0.1: {} + debug@4.4.0: dependencies: ms: 2.1.3 @@ -4858,13 +6750,46 @@ snapshots: decimal.js@10.5.0: {} + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + optional: true + dedent@1.6.0: {} + deep-eql@5.0.2: {} + + deep-extend@0.6.0: + optional: true + delayed-stream@1.0.0: {} + dequal@2.0.3: {} + + detect-libc@2.0.2: {} + detect-libc@2.0.4: {} - dotenv@16.5.0: {} + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + dotenv@17.2.1: {} + + drizzle-kit@0.31.4: + dependencies: + '@drizzle-team/brocli': 0.10.2 + '@esbuild-kit/esm-loader': 2.6.5 + esbuild: 0.25.9 + esbuild-register: 3.6.0(esbuild@0.25.9) + transitivePeerDependencies: + - supports-color + + drizzle-orm@0.44.4(@libsql/client@0.15.12(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@types/better-sqlite3@7.6.13)(better-sqlite3@11.10.0): + optionalDependencies: + '@libsql/client': 0.15.12(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@types/better-sqlite3': 7.6.13 + better-sqlite3: 11.10.0 dunder-proto@1.0.1: dependencies: @@ -4884,11 +6809,18 @@ snapshots: dependencies: once: 1.4.0 - enhanced-resolve@5.18.1: + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + optional: true + + enhanced-resolve@5.18.3: dependencies: graceful-fs: 4.2.11 tapable: 2.2.2 + entities@4.5.0: {} + err-code@2.0.3: {} es-define-property@1.0.1: {} @@ -4908,33 +6840,66 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.2 - esbuild@0.25.5: + esbuild-register@3.6.0(esbuild@0.25.9): + dependencies: + debug: 4.4.1 + esbuild: 0.25.9 + transitivePeerDependencies: + - supports-color + + esbuild@0.18.20: optionalDependencies: - '@esbuild/aix-ppc64': 0.25.5 - '@esbuild/android-arm': 0.25.5 - '@esbuild/android-arm64': 0.25.5 - '@esbuild/android-x64': 0.25.5 - '@esbuild/darwin-arm64': 0.25.5 - '@esbuild/darwin-x64': 0.25.5 - '@esbuild/freebsd-arm64': 0.25.5 - '@esbuild/freebsd-x64': 0.25.5 - '@esbuild/linux-arm': 0.25.5 - '@esbuild/linux-arm64': 0.25.5 - '@esbuild/linux-ia32': 0.25.5 - '@esbuild/linux-loong64': 0.25.5 - '@esbuild/linux-mips64el': 0.25.5 - '@esbuild/linux-ppc64': 0.25.5 - '@esbuild/linux-riscv64': 0.25.5 - '@esbuild/linux-s390x': 0.25.5 - '@esbuild/linux-x64': 0.25.5 - '@esbuild/netbsd-arm64': 0.25.5 - '@esbuild/netbsd-x64': 0.25.5 - '@esbuild/openbsd-arm64': 0.25.5 - '@esbuild/openbsd-x64': 0.25.5 - '@esbuild/sunos-x64': 0.25.5 - '@esbuild/win32-arm64': 0.25.5 - '@esbuild/win32-ia32': 0.25.5 - '@esbuild/win32-x64': 0.25.5 + '@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.9: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.9 + '@esbuild/android-arm': 0.25.9 + '@esbuild/android-arm64': 0.25.9 + '@esbuild/android-x64': 0.25.9 + '@esbuild/darwin-arm64': 0.25.9 + '@esbuild/darwin-x64': 0.25.9 + '@esbuild/freebsd-arm64': 0.25.9 + '@esbuild/freebsd-x64': 0.25.9 + '@esbuild/linux-arm': 0.25.9 + '@esbuild/linux-arm64': 0.25.9 + '@esbuild/linux-ia32': 0.25.9 + '@esbuild/linux-loong64': 0.25.9 + '@esbuild/linux-mips64el': 0.25.9 + '@esbuild/linux-ppc64': 0.25.9 + '@esbuild/linux-riscv64': 0.25.9 + '@esbuild/linux-s390x': 0.25.9 + '@esbuild/linux-x64': 0.25.9 + '@esbuild/netbsd-arm64': 0.25.9 + '@esbuild/netbsd-x64': 0.25.9 + '@esbuild/openbsd-arm64': 0.25.9 + '@esbuild/openbsd-x64': 0.25.9 + '@esbuild/openharmony-arm64': 0.25.9 + '@esbuild/sunos-x64': 0.25.9 + '@esbuild/win32-arm64': 0.25.9 + '@esbuild/win32-ia32': 0.25.9 + '@esbuild/win32-x64': 0.25.9 escalade@3.2.0: {} @@ -4946,12 +6911,33 @@ snapshots: exit-hook@2.2.1: {} + expand-template@2.0.3: + optional: true + + expect-type@1.2.2: {} + fast-fifo@1.3.2: {} fdir@6.4.5(picomatch@4.0.2): optionalDependencies: picomatch: 4.0.2 + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + + file-uri-to-path@1.0.0: + optional: true + + focus-trap@7.6.5: + dependencies: + tabbable: 6.2.0 + foreground-child@3.3.0: dependencies: cross-spawn: 7.0.3 @@ -4964,11 +6950,12 @@ snapshots: es-set-tostringtag: 2.1.0 mime-types: 2.1.35 - fs-extra@10.1.0: + formdata-polyfill@4.0.10: dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.1.0 - universalify: 2.0.1 + fetch-blob: 3.2.0 + + fs-constants@1.0.0: + optional: true fsevents@2.3.2: optional: true @@ -5002,6 +6989,9 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 + github-from-package@0.0.0: + optional: true + glob@10.4.5: dependencies: foreground-child: 3.3.0 @@ -5029,7 +7019,27 @@ snapshots: dependencies: function-bind: 1.1.2 - hono@4.7.6: {} + hast-util-to-html@9.0.5: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hono@4.7.10: {} + + hookable@5.5.3: {} hosted-git-info@6.1.3: dependencies: @@ -5037,6 +7047,17 @@ snapshots: hpagent@1.2.0: {} + html-void-elements@3.0.0: {} + + ieee754@1.2.1: + optional: true + + inherits@2.0.4: + optional: true + + ini@1.3.8: + optional: true + intl-messageformat@10.7.16: dependencies: '@formatjs/ecma402-abstract': 2.3.4 @@ -5055,7 +7076,13 @@ snapshots: is-fullwidth-code-point@3.0.0: {} - isbot@5.1.28: {} + is-reference@3.0.3: + dependencies: + '@types/estree': 1.0.8 + + is-what@4.1.16: {} + + isbot@5.1.30: {} isexe@2.0.0: {} @@ -5069,12 +7096,16 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 - jiti@2.4.2: {} + jiti@2.5.1: {} - jose@6.0.11: {} + jose@6.1.0: {} + + js-base64@3.7.7: {} js-tokens@4.0.0: {} + js-tokens@9.0.1: {} + js-yaml@4.1.0: dependencies: argparse: 2.0.1 @@ -5089,12 +7120,6 @@ snapshots: json5@2.2.3: {} - jsonfile@6.1.0: - dependencies: - universalify: 2.0.1 - optionalDependencies: - graceful-fs: 4.2.11 - jsonpath-plus@10.3.0: dependencies: '@jsep-plugin/assignment': 1.3.0(jsep@1.4.0) @@ -5103,48 +7128,65 @@ snapshots: kleur@4.1.5: {} - lefthook-darwin-arm64@1.11.13: + layerr@3.0.0: {} + + lefthook-darwin-arm64@1.12.3: optional: true - lefthook-darwin-x64@1.11.13: + lefthook-darwin-x64@1.12.3: optional: true - lefthook-freebsd-arm64@1.11.13: + lefthook-freebsd-arm64@1.12.3: optional: true - lefthook-freebsd-x64@1.11.13: + lefthook-freebsd-x64@1.12.3: optional: true - lefthook-linux-arm64@1.11.13: + lefthook-linux-arm64@1.12.3: optional: true - lefthook-linux-x64@1.11.13: + lefthook-linux-x64@1.12.3: optional: true - lefthook-openbsd-arm64@1.11.13: + lefthook-openbsd-arm64@1.12.3: optional: true - lefthook-openbsd-x64@1.11.13: + lefthook-openbsd-x64@1.12.3: optional: true - lefthook-windows-arm64@1.11.13: + lefthook-windows-arm64@1.12.3: optional: true - lefthook-windows-x64@1.11.13: + lefthook-windows-x64@1.12.3: optional: true - lefthook@1.11.13: + lefthook@1.12.3: + optionalDependencies: + lefthook-darwin-arm64: 1.12.3 + lefthook-darwin-x64: 1.12.3 + lefthook-freebsd-arm64: 1.12.3 + lefthook-freebsd-x64: 1.12.3 + lefthook-linux-arm64: 1.12.3 + lefthook-linux-x64: 1.12.3 + lefthook-openbsd-arm64: 1.12.3 + lefthook-openbsd-x64: 1.12.3 + lefthook-windows-arm64: 1.12.3 + lefthook-windows-x64: 1.12.3 + + libsql@0.5.17: + dependencies: + '@neon-rs/load': 0.0.4 + detect-libc: 2.0.2 optionalDependencies: - lefthook-darwin-arm64: 1.11.13 - lefthook-darwin-x64: 1.11.13 - lefthook-freebsd-arm64: 1.11.13 - lefthook-freebsd-x64: 1.11.13 - lefthook-linux-arm64: 1.11.13 - lefthook-linux-x64: 1.11.13 - lefthook-openbsd-arm64: 1.11.13 - lefthook-openbsd-x64: 1.11.13 - lefthook-windows-arm64: 1.11.13 - lefthook-windows-x64: 1.11.13 + '@libsql/darwin-arm64': 0.5.17 + '@libsql/darwin-x64': 0.5.17 + '@libsql/linux-arm-gnueabihf': 0.5.17 + '@libsql/linux-arm-musleabihf': 0.5.17 + '@libsql/linux-arm64-gnu': 0.5.17 + '@libsql/linux-arm64-musl': 0.5.17 + '@libsql/linux-x64-gnu': 0.5.17 + '@libsql/linux-x64-musl': 0.5.17 + '@libsql/win32-x64-msvc': 0.5.17 lightningcss-darwin-arm64@1.30.1: optional: true @@ -5195,6 +7237,8 @@ snapshots: lodash@4.17.21: {} + loupe@3.1.4: {} + lru-cache@10.2.2: {} lru-cache@5.1.1: @@ -5203,16 +7247,47 @@ snapshots: lru-cache@7.18.3: {} - lucide-react@0.511.0(react@19.1.0): + lucide-react@0.540.0(react@19.1.1): dependencies: - react: 19.1.0 + react: 19.1.1 magic-string@0.30.17: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 + mark.js@8.11.1: {} + math-intrinsics@1.1.0: {} + mdast-util-to-hast@13.2.0: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.0 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.0.0 + vfile: 6.0.3 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-encode@2.0.1: {} + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + mime-db@1.52.0: {} mime-types@2.1.35: @@ -5221,16 +7296,28 @@ snapshots: mime@4.0.7: {} + mimic-response@3.1.0: + optional: true + minimatch@9.0.5: dependencies: brace-expansion: 2.0.1 + minimist@1.2.8: + optional: true + minipass@7.1.2: {} - minizlib@3.0.1: + minisearch@7.1.2: {} + + minizlib@3.0.2: dependencies: minipass: 7.1.2 - rimraf: 5.0.10 + + mitt@3.0.1: {} + + mkdirp-classic@0.5.3: + optional: true mkdirp@3.0.1: {} @@ -5240,10 +7327,26 @@ snapshots: nanoid@3.3.11: {} + napi-build-utils@2.0.0: + optional: true + + node-abi@3.75.0: + dependencies: + semver: 7.7.2 + optional: true + + node-domexception@1.0.0: {} + node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + node-gyp-build@4.8.4: optional: true @@ -5276,16 +7379,24 @@ snapshots: npm-package-arg: 10.1.0 semver: 7.7.2 - oauth4webapi@3.5.1: {} + oauth4webapi@3.8.0: {} once@1.4.0: dependencies: wrappy: 1.0.2 - openid-client@6.5.0: + oniguruma-parser@0.12.1: {} + + oniguruma-to-es@4.3.3: + dependencies: + oniguruma-parser: 0.12.1 + regex: 6.0.1 + regex-recursion: 6.0.2 + + openid-client@6.7.0: dependencies: - jose: 6.0.11 - oauth4webapi: 3.5.1 + jose: 6.1.0 + oauth4webapi: 3.8.0 package-json-from-dist@1.0.1: {} @@ -5298,222 +7409,288 @@ snapshots: pathe@1.1.2: {} + pathe@2.0.3: {} + + pathval@2.0.1: {} + + perfect-debounce@1.0.0: {} + + periscopic@4.0.2: + dependencies: + '@types/estree': 1.0.8 + is-reference: 3.0.3 + zimmerframe: 1.1.2 + picocolors@1.1.1: {} picomatch@4.0.2: {} - playwright-core@1.52.0: {} + picomatch@4.0.3: {} - playwright@1.52.0: + playwright-core@1.55.0: {} + + playwright@1.55.0: dependencies: - playwright-core: 1.52.0 + playwright-core: 1.55.0 optionalDependencies: fsevents: 2.3.2 - postcss@8.5.4: + postcss@8.5.6: dependencies: nanoid: 3.3.11 picocolors: 1.1.1 source-map-js: 1.2.1 - preact@10.26.7: {} + preact@10.27.1: {} + + prebuild-install@7.1.3: + dependencies: + detect-libc: 2.0.4 + expand-template: 2.0.3 + github-from-package: 0.0.0 + minimist: 1.2.8 + mkdirp-classic: 0.5.3 + napi-build-utils: 2.0.0 + node-abi: 3.75.0 + pump: 3.0.3 + rc: 1.2.8 + simple-get: 4.0.1 + tar-fs: 2.1.3 + tunnel-agent: 0.6.0 + optional: true - prettier@2.8.8: {} + prettier@3.6.2: {} proc-log@3.0.0: {} promise-inflight@1.0.1: {} + promise-limit@2.7.0: {} + promise-retry@2.0.1: dependencies: err-code: 2.0.3 retry: 0.12.0 + property-information@7.1.0: {} + pump@3.0.2: dependencies: end-of-stream: 1.4.4 once: 1.4.0 - react-aria@3.40.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0): - dependencies: - '@internationalized/string': 3.2.6 - '@react-aria/breadcrumbs': 3.5.24(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/button': 3.13.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/calendar': 3.8.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/checkbox': 3.15.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/color': 3.0.7(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/combobox': 3.12.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/datepicker': 3.14.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/dialog': 3.5.25(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/disclosure': 3.0.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/dnd': 3.9.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/focus': 3.20.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/gridlist': 3.13.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/i18n': 3.12.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/interactions': 3.25.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/label': 3.7.18(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/landmark': 3.0.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/link': 3.8.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/listbox': 3.14.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/menu': 3.18.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/meter': 3.4.23(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/numberfield': 3.11.14(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/overlays': 3.27.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/progress': 3.4.23(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/radio': 3.11.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/searchfield': 3.8.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/select': 3.15.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/selection': 3.24.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/separator': 3.4.9(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/slider': 3.7.19(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/ssr': 3.9.8(react@19.1.0) - '@react-aria/switch': 3.7.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/table': 3.17.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/tabs': 3.10.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/tag': 3.6.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/textfield': 3.17.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/toast': 3.0.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/tooltip': 3.8.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/tree': 3.0.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/utils': 3.29.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-aria/visually-hidden': 3.8.23(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - - react-codemirror-merge@4.23.12(@babel/runtime@7.27.3)(@codemirror/autocomplete@6.18.2(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8)(@lezer/common@1.2.3))(@codemirror/language@6.11.0)(@codemirror/lint@6.8.2)(@codemirror/search@6.5.7)(@codemirror/state@6.5.2)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.36.8)(codemirror@6.0.1(@lezer/common@1.2.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + pump@3.0.3: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + optional: true + + rc@1.2.8: + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + optional: true + + react-aria@3.42.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + dependencies: + '@internationalized/string': 3.2.7 + '@react-aria/breadcrumbs': 3.5.27(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/button': 3.14.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/calendar': 3.9.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/checkbox': 3.16.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/color': 3.1.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/combobox': 3.13.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/datepicker': 3.15.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/dialog': 3.5.28(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/disclosure': 3.0.7(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/dnd': 3.11.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/focus': 3.21.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/gridlist': 3.13.3(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/i18n': 3.12.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/interactions': 3.25.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/label': 3.7.20(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/landmark': 3.0.5(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/link': 3.8.4(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/listbox': 3.14.7(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/menu': 3.19.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/meter': 3.4.25(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/numberfield': 3.12.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/overlays': 3.28.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/progress': 3.4.25(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/radio': 3.12.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/searchfield': 3.8.7(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/select': 3.16.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/selection': 3.25.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/separator': 3.4.11(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/slider': 3.8.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/ssr': 3.9.10(react@19.1.1) + '@react-aria/switch': 3.7.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/table': 3.17.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/tabs': 3.10.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/tag': 3.7.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/textfield': 3.18.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/toast': 3.0.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/tooltip': 3.8.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/tree': 3.1.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/utils': 3.30.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-aria/visually-hidden': 3.8.26(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + react-codemirror-merge@4.25.1(@babel/runtime@7.27.3)(@codemirror/autocomplete@6.18.2(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8)(@lezer/common@1.2.3))(@codemirror/language@6.11.0)(@codemirror/lint@6.8.2)(@codemirror/search@6.5.7)(@codemirror/state@6.5.2)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.36.8)(codemirror@6.0.1(@lezer/common@1.2.3))(react-dom@19.1.1(react@19.1.1))(react@19.1.1): dependencies: '@babel/runtime': 7.27.3 '@codemirror/merge': 6.10.1 '@codemirror/state': 6.5.2 '@codemirror/theme-one-dark': 6.1.2 '@codemirror/view': 6.36.8 - '@uiw/react-codemirror': 4.23.12(@babel/runtime@7.27.3)(@codemirror/autocomplete@6.18.2(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8)(@lezer/common@1.2.3))(@codemirror/language@6.11.0)(@codemirror/lint@6.8.2)(@codemirror/search@6.5.7)(@codemirror/state@6.5.2)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.36.8)(codemirror@6.0.1(@lezer/common@1.2.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@uiw/react-codemirror': 4.25.1(@babel/runtime@7.27.3)(@codemirror/autocomplete@6.18.2(@codemirror/language@6.11.0)(@codemirror/state@6.5.2)(@codemirror/view@6.36.8)(@lezer/common@1.2.3))(@codemirror/language@6.11.0)(@codemirror/lint@6.8.2)(@codemirror/search@6.5.7)(@codemirror/state@6.5.2)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.36.8)(codemirror@6.0.1(@lezer/common@1.2.3))(react-dom@19.1.1(react@19.1.1))(react@19.1.1) codemirror: 6.0.1(@lezer/common@1.2.3) - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) transitivePeerDependencies: - '@codemirror/autocomplete' - '@codemirror/language' - '@codemirror/lint' - '@codemirror/search' - react-dom@19.1.0(react@19.1.0): + react-dom@19.1.1(react@19.1.1): dependencies: - react: 19.1.0 + react: 19.1.1 scheduler: 0.26.0 - react-error-boundary@6.0.0(react@19.1.0): + react-error-boundary@6.0.0(react@19.1.1): dependencies: '@babel/runtime': 7.27.3 - react: 19.1.0 + react: 19.1.1 - react-icons@5.5.0(react@19.1.0): + react-icons@5.5.0(react@19.1.1): dependencies: - react: 19.1.0 + react: 19.1.1 react-refresh@0.14.2: {} - react-router-dom@7.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + react-router-dom@7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1): dependencies: - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - react-router: 7.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + react-router: 7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) - react-router-hono-server@2.13.0(patch_hash=6549978df41006e07f1335bfe4ca86224ea36ed40d3f08dfef33143bad54005c)(@react-router/dev@7.6.1(@types/node@22.15.24)(jiti@2.4.2)(lightningcss@1.30.1)(react-router@7.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(terser@5.39.0)(tsx@4.19.4)(typescript@5.8.3)(vite@6.3.5(@types/node@22.15.24)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0))(yaml@2.8.0))(@types/react@19.1.6)(bufferutil@4.0.9)(react-router@7.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(utf-8-validate@5.0.10)(vite@6.3.5(@types/node@22.15.24)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0)): + react-router-hono-server@2.21.0(patch_hash=b68723a36649e2c3bd9e9edcfff3a8bc0fdb48e1cf6d64eba37c04f7bfbb1417)(@hono/node-server@1.19.0(hono@4.7.10))(@react-router/dev@7.8.1(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(react-dom@19.1.1(react@19.1.1))(react-router@7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(rolldown-vite@7.1.4(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1))(terser@5.39.0)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1))(@types/react@19.1.10)(bufferutil@4.0.9)(react-router@7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(rolldown-vite@7.1.4(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1))(utf-8-validate@5.0.10): dependencies: '@drizzle-team/brocli': 0.11.0 - '@hono/node-server': 1.14.0(hono@4.7.6) - '@hono/node-ws': 1.1.1(@hono/node-server@1.14.0(hono@4.7.6))(bufferutil@4.0.9)(hono@4.7.6)(utf-8-validate@5.0.10) - '@hono/vite-dev-server': 0.19.0(hono@4.7.6) - '@react-router/dev': 7.6.1(@types/node@22.15.24)(jiti@2.4.2)(lightningcss@1.30.1)(react-router@7.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(terser@5.39.0)(tsx@4.19.4)(typescript@5.8.3)(vite@6.3.5(@types/node@22.15.24)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0))(yaml@2.8.0) - '@types/react': 19.1.6 - hono: 4.7.6 - react-router: 7.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - vite: 6.3.5(@types/node@22.15.24)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0) + '@hono/node-server': 1.19.0(hono@4.7.10) + '@hono/node-ws': 1.2.0(@hono/node-server@1.19.0(hono@4.7.10))(bufferutil@4.0.9)(hono@4.7.10)(utf-8-validate@5.0.10) + '@hono/vite-dev-server': 0.20.1(hono@4.7.10) + '@react-router/dev': 7.8.1(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(react-dom@19.1.1(react@19.1.1))(react-router@7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(rolldown-vite@7.1.4(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1))(terser@5.39.0)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1) + '@types/react': 19.1.10 + hono: 4.7.10 + react-router: 7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + vite: rolldown-vite@7.1.4(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1) transitivePeerDependencies: - bufferutil - utf-8-validate - react-router@7.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + react-router@7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1): dependencies: cookie: 1.0.2 - react: 19.1.0 + react: 19.1.1 set-cookie-parser: 2.7.1 optionalDependencies: - react-dom: 19.1.0(react@19.1.0) + react-dom: 19.1.1(react@19.1.1) - react-scan@0.3.4(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react-router-dom@7.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-router@7.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(rollup@4.36.0): + react-scan@0.4.3(@types/react@19.1.10)(react-dom@19.1.1(react@19.1.1))(react-router-dom@7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react-router@7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1)(rollup@4.46.3): dependencies: - '@babel/core': 7.27.3 - '@babel/generator': 7.27.3 - '@babel/types': 7.27.3 + '@babel/core': 7.28.3 + '@babel/generator': 7.28.3 + '@babel/types': 7.28.2 '@clack/core': 0.3.5 '@clack/prompts': 0.8.2 - '@pivanov/utils': 0.0.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@preact/signals': 1.3.2(preact@10.26.7) - '@rollup/pluginutils': 5.1.4(rollup@4.36.0) - '@types/node': 20.17.52 - bippy: 0.3.14(@types/react@19.1.6)(react@19.1.0) - esbuild: 0.25.5 + '@pivanov/utils': 0.0.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@preact/signals': 1.3.2(preact@10.27.1) + '@rollup/pluginutils': 5.2.0(rollup@4.46.3) + '@types/node': 20.19.11 + bippy: 0.3.18(@types/react@19.1.10)(react@19.1.1) + esbuild: 0.25.9 estree-walker: 3.0.3 kleur: 4.1.5 mri: 1.2.0 - playwright: 1.52.0 - preact: 10.26.7 - react: 19.1.0 - react-dom: 19.1.0(react@19.1.0) - tsx: 4.19.4 + playwright: 1.55.0 + preact: 10.27.1 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + tsx: 4.20.4 optionalDependencies: - react-router: 7.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - react-router-dom: 7.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react-router: 7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react-router-dom: 7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) unplugin: 2.1.0 transitivePeerDependencies: - '@types/react' - rollup - supports-color - react-stately@3.38.0(react@19.1.0): - dependencies: - '@react-stately/calendar': 3.8.1(react@19.1.0) - '@react-stately/checkbox': 3.6.14(react@19.1.0) - '@react-stately/collections': 3.12.4(react@19.1.0) - '@react-stately/color': 3.8.5(react@19.1.0) - '@react-stately/combobox': 3.10.5(react@19.1.0) - '@react-stately/data': 3.13.0(react@19.1.0) - '@react-stately/datepicker': 3.14.1(react@19.1.0) - '@react-stately/disclosure': 3.0.4(react@19.1.0) - '@react-stately/dnd': 3.5.4(react@19.1.0) - '@react-stately/form': 3.1.4(react@19.1.0) - '@react-stately/list': 3.12.2(react@19.1.0) - '@react-stately/menu': 3.9.4(react@19.1.0) - '@react-stately/numberfield': 3.9.12(react@19.1.0) - '@react-stately/overlays': 3.6.16(react@19.1.0) - '@react-stately/radio': 3.10.13(react@19.1.0) - '@react-stately/searchfield': 3.5.12(react@19.1.0) - '@react-stately/select': 3.6.13(react@19.1.0) - '@react-stately/selection': 3.20.2(react@19.1.0) - '@react-stately/slider': 3.6.4(react@19.1.0) - '@react-stately/table': 3.14.2(react@19.1.0) - '@react-stately/tabs': 3.8.2(react@19.1.0) - '@react-stately/toast': 3.1.0(react@19.1.0) - '@react-stately/toggle': 3.8.4(react@19.1.0) - '@react-stately/tooltip': 3.5.4(react@19.1.0) - '@react-stately/tree': 3.8.10(react@19.1.0) - '@react-types/shared': 3.29.1(react@19.1.0) - react: 19.1.0 - - react@19.1.0: {} + react-stately@3.40.0(react@19.1.1): + dependencies: + '@react-stately/calendar': 3.8.3(react@19.1.1) + '@react-stately/checkbox': 3.7.0(react@19.1.1) + '@react-stately/collections': 3.12.6(react@19.1.1) + '@react-stately/color': 3.9.0(react@19.1.1) + '@react-stately/combobox': 3.11.0(react@19.1.1) + '@react-stately/data': 3.13.2(react@19.1.1) + '@react-stately/datepicker': 3.15.0(react@19.1.1) + '@react-stately/disclosure': 3.0.6(react@19.1.1) + '@react-stately/dnd': 3.6.1(react@19.1.1) + '@react-stately/form': 3.2.0(react@19.1.1) + '@react-stately/list': 3.12.4(react@19.1.1) + '@react-stately/menu': 3.9.6(react@19.1.1) + '@react-stately/numberfield': 3.10.0(react@19.1.1) + '@react-stately/overlays': 3.6.18(react@19.1.1) + '@react-stately/radio': 3.11.0(react@19.1.1) + '@react-stately/searchfield': 3.5.14(react@19.1.1) + '@react-stately/select': 3.7.0(react@19.1.1) + '@react-stately/selection': 3.20.4(react@19.1.1) + '@react-stately/slider': 3.7.0(react@19.1.1) + '@react-stately/table': 3.14.4(react@19.1.1) + '@react-stately/tabs': 3.8.4(react@19.1.1) + '@react-stately/toast': 3.1.2(react@19.1.1) + '@react-stately/toggle': 3.9.0(react@19.1.1) + '@react-stately/tooltip': 3.5.6(react@19.1.1) + '@react-stately/tree': 3.9.1(react@19.1.1) + '@react-types/shared': 3.31.0(react@19.1.1) + react: 19.1.1 + + react@19.1.1: {} + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + optional: true readdirp@4.1.2: {} - remix-utils@8.7.0(react-router@7.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)(zod@3.25.33): + regex-recursion@6.0.2: + dependencies: + regex-utilities: 2.3.0 + + regex-utilities@2.3.0: {} + + regex@6.0.1: + dependencies: + regex-utilities: 2.3.0 + + remix-utils@8.8.0(@oslojs/crypto@1.0.1)(@oslojs/encoding@1.1.0)(react-router@7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1))(react@19.1.1): dependencies: type-fest: 4.41.0 optionalDependencies: - react: 19.1.0 - react-router: 7.6.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - zod: 3.25.33 + '@oslojs/crypto': 1.0.1 + '@oslojs/encoding': 1.1.0 + react: 19.1.1 + react-router: 7.8.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) resolve-pkg-maps@1.0.0: {} @@ -5521,35 +7698,76 @@ snapshots: rfc4648@1.5.4: {} - rimraf@5.0.10: + rfdc@1.4.1: {} + + rolldown-vite@7.1.4(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1): dependencies: - glob: 10.4.5 + fdir: 6.5.0(picomatch@4.0.3) + lightningcss: 1.30.1 + picomatch: 4.0.3 + postcss: 8.5.6 + rolldown: 1.0.0-beta.33 + tinyglobby: 0.2.14 + optionalDependencies: + '@types/node': 24.3.0 + esbuild: 0.25.9 + fsevents: 2.3.3 + jiti: 2.5.1 + terser: 5.39.0 + tsx: 4.20.4 + yaml: 2.8.1 - rollup@4.36.0: + rolldown@1.0.0-beta.33: dependencies: - '@types/estree': 1.0.6 + '@oxc-project/runtime': 0.82.2 + '@oxc-project/types': 0.82.2 + '@rolldown/pluginutils': 1.0.0-beta.33 + ansis: 4.1.0 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.0-beta.33 + '@rolldown/binding-darwin-arm64': 1.0.0-beta.33 + '@rolldown/binding-darwin-x64': 1.0.0-beta.33 + '@rolldown/binding-freebsd-x64': 1.0.0-beta.33 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.33 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.33 + '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.33 + '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.33 + '@rolldown/binding-linux-x64-musl': 1.0.0-beta.33 + '@rolldown/binding-openharmony-arm64': 1.0.0-beta.33 + '@rolldown/binding-wasm32-wasi': 1.0.0-beta.33 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.33 + '@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.33 + '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.33 + + rollup@4.46.3: + dependencies: + '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.36.0 - '@rollup/rollup-android-arm64': 4.36.0 - '@rollup/rollup-darwin-arm64': 4.36.0 - '@rollup/rollup-darwin-x64': 4.36.0 - '@rollup/rollup-freebsd-arm64': 4.36.0 - '@rollup/rollup-freebsd-x64': 4.36.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.36.0 - '@rollup/rollup-linux-arm-musleabihf': 4.36.0 - '@rollup/rollup-linux-arm64-gnu': 4.36.0 - '@rollup/rollup-linux-arm64-musl': 4.36.0 - '@rollup/rollup-linux-loongarch64-gnu': 4.36.0 - '@rollup/rollup-linux-powerpc64le-gnu': 4.36.0 - '@rollup/rollup-linux-riscv64-gnu': 4.36.0 - '@rollup/rollup-linux-s390x-gnu': 4.36.0 - '@rollup/rollup-linux-x64-gnu': 4.36.0 - '@rollup/rollup-linux-x64-musl': 4.36.0 - '@rollup/rollup-win32-arm64-msvc': 4.36.0 - '@rollup/rollup-win32-ia32-msvc': 4.36.0 - '@rollup/rollup-win32-x64-msvc': 4.36.0 + '@rollup/rollup-android-arm-eabi': 4.46.3 + '@rollup/rollup-android-arm64': 4.46.3 + '@rollup/rollup-darwin-arm64': 4.46.3 + '@rollup/rollup-darwin-x64': 4.46.3 + '@rollup/rollup-freebsd-arm64': 4.46.3 + '@rollup/rollup-freebsd-x64': 4.46.3 + '@rollup/rollup-linux-arm-gnueabihf': 4.46.3 + '@rollup/rollup-linux-arm-musleabihf': 4.46.3 + '@rollup/rollup-linux-arm64-gnu': 4.46.3 + '@rollup/rollup-linux-arm64-musl': 4.46.3 + '@rollup/rollup-linux-loongarch64-gnu': 4.46.3 + '@rollup/rollup-linux-ppc64-gnu': 4.46.3 + '@rollup/rollup-linux-riscv64-gnu': 4.46.3 + '@rollup/rollup-linux-riscv64-musl': 4.46.3 + '@rollup/rollup-linux-s390x-gnu': 4.46.3 + '@rollup/rollup-linux-x64-gnu': 4.46.3 + '@rollup/rollup-linux-x64-musl': 4.46.3 + '@rollup/rollup-win32-arm64-msvc': 4.46.3 + '@rollup/rollup-win32-ia32-msvc': 4.46.3 + '@rollup/rollup-win32-x64-msvc': 4.46.3 fsevents: 2.3.3 + safe-buffer@5.2.1: + optional: true + scheduler@0.26.0: {} semver@6.3.1: {} @@ -5564,8 +7782,31 @@ snapshots: shebang-regex@3.0.0: {} + shiki@3.9.2: + dependencies: + '@shikijs/core': 3.9.2 + '@shikijs/engine-javascript': 3.9.2 + '@shikijs/engine-oniguruma': 3.9.2 + '@shikijs/langs': 3.9.2 + '@shikijs/themes': 3.9.2 + '@shikijs/types': 3.9.2 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + siginfo@2.0.0: {} + signal-exit@4.1.0: {} + simple-concat@1.0.1: + optional: true + + simple-get@4.0.1: + dependencies: + decompress-response: 6.0.0 + once: 1.4.0 + simple-concat: 1.0.1 + optional: true + sisteransi@1.0.5: {} smart-buffer@4.2.0: {} @@ -5592,25 +7833,31 @@ snapshots: source-map@0.6.1: {} + space-separated-tokens@2.0.2: {} + spdx-correct@3.2.0: dependencies: spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.21 + spdx-license-ids: 3.0.22 spdx-exceptions@2.5.0: {} spdx-expression-parse@3.0.1: dependencies: spdx-exceptions: 2.5.0 - spdx-license-ids: 3.0.21 + spdx-license-ids: 3.0.22 - spdx-license-ids@3.0.21: {} + spdx-license-ids@3.0.22: {} + + speakingurl@14.0.1: {} sprintf-js@1.1.3: {} - stream-buffers@3.0.3: {} + stackback@0.0.2: {} - stream-slice@0.1.2: {} + std-env@3.9.0: {} + + stream-buffers@3.0.3: {} streamx@2.22.0: dependencies: @@ -5631,6 +7878,16 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.1.0 + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + optional: true + + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -5639,22 +7896,43 @@ snapshots: dependencies: ansi-regex: 6.0.1 + strip-json-comments@2.0.1: + optional: true + + strip-literal@3.0.0: + dependencies: + js-tokens: 9.0.1 + style-mod@4.1.2: {} - tailwind-merge@3.3.0: {} + superjson@2.2.2: + dependencies: + copy-anything: 3.0.5 + + tabbable@6.2.0: {} + + tailwind-merge@3.3.1: {} - tailwindcss-animate@1.0.7(tailwindcss@4.1.8): + tailwindcss-animate@1.0.7(tailwindcss@4.1.12): dependencies: - tailwindcss: 4.1.8 + tailwindcss: 4.1.12 - tailwindcss-react-aria-components@2.0.0(tailwindcss@4.1.8): + tailwindcss-react-aria-components@2.0.0(tailwindcss@4.1.12): dependencies: - tailwindcss: 4.1.8 + tailwindcss: 4.1.12 - tailwindcss@4.1.8: {} + tailwindcss@4.1.12: {} tapable@2.2.2: {} + tar-fs@2.1.3: + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.3 + tar-stream: 2.2.0 + optional: true + tar-fs@3.0.9: dependencies: pump: 3.0.2 @@ -5665,6 +7943,15 @@ snapshots: transitivePeerDependencies: - bare-buffer + tar-stream@2.2.0: + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.5 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + optional: true + tar-stream@3.1.7: dependencies: b4a: 1.6.7 @@ -5676,14 +7963,14 @@ snapshots: '@isaacs/fs-minipass': 4.0.1 chownr: 3.0.0 minipass: 7.1.2 - minizlib: 3.0.1 + minizlib: 3.0.2 mkdirp: 3.0.1 yallist: 5.0.0 terser@5.39.0: dependencies: - '@jridgewell/source-map': 0.3.6 - acorn: 8.14.1 + '@jridgewell/source-map': 0.3.11 + acorn: 8.15.0 commander: 2.20.3 source-map-support: 0.5.21 optional: true @@ -5692,47 +7979,87 @@ snapshots: dependencies: b4a: 1.6.7 + tinybench@2.9.0: {} + + tinyexec@0.3.2: {} + tinyglobby@0.2.14: dependencies: fdir: 6.4.5(picomatch@4.0.2) picomatch: 4.0.2 + tinypool@1.1.1: {} + + tinyrainbow@2.0.0: {} + + tinyspy@4.0.3: {} + tr46@0.0.3: {} - tsconfck@3.1.4(typescript@5.8.3): + trim-lines@3.0.1: {} + + tsconfck@3.1.4(typescript@5.9.2): optionalDependencies: - typescript: 5.8.3 + typescript: 5.9.2 tslib@2.6.2: {} tslib@2.8.1: {} - tsx@4.19.4: + tsx@4.20.4: dependencies: - esbuild: 0.25.5 + esbuild: 0.25.9 get-tsconfig: 4.10.1 optionalDependencies: fsevents: 2.3.3 - type-fest@4.41.0: {} + tunnel-agent@0.6.0: + dependencies: + safe-buffer: 5.2.1 + optional: true + + turbo-stream@3.1.0: {} - typescript@5.8.3: {} + type-fest@4.41.0: {} - undici-types@6.19.8: {} + typescript@5.9.2: {} - undici-types@6.20.0: {} + ulidx@2.4.1: + dependencies: + layerr: 3.0.0 undici-types@6.21.0: {} - undici@6.21.3: {} + undici-types@7.10.0: {} - undici@7.10.0: {} + undici@7.14.0: {} - universalify@2.0.1: {} + unist-util-is@6.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.1: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.0 + + unist-util-visit@5.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.0 + unist-util-visit-parents: 6.0.1 unplugin@2.1.0: dependencies: - acorn: 8.14.1 + acorn: 8.15.0 webpack-virtual-modules: 0.6.2 optional: true @@ -5742,23 +8069,26 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 - use-sync-external-store@1.5.0(react@19.1.0): + use-sync-external-store@1.5.0(react@19.1.1): dependencies: - react: 19.1.0 + react: 19.1.1 - usehooks-ts@3.1.1(react@19.1.0): + usehooks-ts@3.1.1(react@19.1.1): dependencies: lodash.debounce: 4.0.8 - react: 19.1.0 + react: 19.1.1 utf-8-validate@5.0.10: dependencies: node-gyp-build: 4.8.4 optional: true - valibot@0.41.0(typescript@5.8.3): + util-deprecate@1.0.2: + optional: true + + valibot@0.41.0(typescript@5.9.2): optionalDependencies: - typescript: 5.8.3 + typescript: 5.9.2 validate-npm-package-license@3.0.4: dependencies: @@ -5767,13 +8097,23 @@ snapshots: validate-npm-package-name@5.0.1: {} - vite-node@3.0.0-beta.2(@types/node@22.15.24)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0): + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + + vite-node@3.2.4(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1): dependencies: cac: 6.7.14 debug: 4.4.1 es-module-lexer: 1.7.0 - pathe: 1.1.2 - vite: 6.3.5(@types/node@22.15.24)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0) + pathe: 2.0.3 + vite: 7.1.2(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1) transitivePeerDependencies: - '@types/node' - jiti @@ -5788,36 +8128,140 @@ snapshots: - tsx - yaml - vite-tsconfig-paths@5.1.4(typescript@5.8.3)(vite@6.3.5(@types/node@22.15.24)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0)): + vite-tsconfig-paths@5.1.4(rolldown-vite@7.1.4(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1))(typescript@5.9.2): dependencies: debug: 4.4.0 globrex: 0.1.2 - tsconfck: 3.1.4(typescript@5.8.3) + tsconfck: 3.1.4(typescript@5.9.2) optionalDependencies: - vite: 6.3.5(@types/node@22.15.24)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0) + vite: rolldown-vite@7.1.4(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1) transitivePeerDependencies: - supports-color - typescript - vite@6.3.5(@types/node@22.15.24)(jiti@2.4.2)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.19.4)(yaml@2.8.0): + vite@7.1.2(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1): dependencies: - esbuild: 0.25.5 - fdir: 6.4.5(picomatch@4.0.2) - picomatch: 4.0.2 - postcss: 8.5.4 - rollup: 4.36.0 + esbuild: 0.25.9 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.46.3 tinyglobby: 0.2.14 optionalDependencies: - '@types/node': 22.15.24 + '@types/node': 24.3.0 fsevents: 2.3.3 - jiti: 2.4.2 + jiti: 2.5.1 lightningcss: 1.30.1 terser: 5.39.0 - tsx: 4.19.4 - yaml: 2.8.0 + tsx: 4.20.4 + yaml: 2.8.1 + + vitefu@1.1.1(rolldown-vite@7.1.4(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1)): + optionalDependencies: + vite: rolldown-vite@7.1.4(@types/node@24.3.0)(esbuild@0.25.9)(jiti@2.5.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1) + + vitepress@2.0.0-alpha.11(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(postcss@8.5.6)(terser@5.39.0)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1): + dependencies: + '@docsearch/css': 4.0.0-beta.7 + '@docsearch/js': 4.0.0-beta.7 + '@iconify-json/simple-icons': 1.2.48 + '@shikijs/core': 3.9.2 + '@shikijs/transformers': 3.9.2 + '@shikijs/types': 3.9.2 + '@types/markdown-it': 14.1.2 + '@vitejs/plugin-vue': 6.0.1(vite@7.1.2(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1))(vue@3.5.18(typescript@5.9.2)) + '@vue/devtools-api': 8.0.0 + '@vue/shared': 3.5.18 + '@vueuse/core': 13.7.0(vue@3.5.18(typescript@5.9.2)) + '@vueuse/integrations': 13.7.0(focus-trap@7.6.5)(vue@3.5.18(typescript@5.9.2)) + focus-trap: 7.6.5 + mark.js: 8.11.1 + minisearch: 7.1.2 + shiki: 3.9.2 + vite: 7.1.2(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1) + vue: 3.5.18(typescript@5.9.2) + optionalDependencies: + postcss: 8.5.6 + transitivePeerDependencies: + - '@types/node' + - async-validator + - axios + - change-case + - drauu + - fuse.js + - idb-keyval + - jiti + - jwt-decode + - less + - lightningcss + - nprogress + - qrcode + - sass + - sass-embedded + - sortablejs + - stylus + - sugarss + - terser + - tsx + - typescript + - universal-cookie + - yaml + + vitest@3.2.4(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1): + dependencies: + '@types/chai': 5.2.2 + '@vitest/expect': 3.2.4 + '@vitest/mocker': 3.2.4(vite@7.1.2(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1)) + '@vitest/pretty-format': 3.2.4 + '@vitest/runner': 3.2.4 + '@vitest/snapshot': 3.2.4 + '@vitest/spy': 3.2.4 + '@vitest/utils': 3.2.4 + chai: 5.2.1 + debug: 4.4.1 + expect-type: 1.2.2 + magic-string: 0.30.17 + pathe: 2.0.3 + picomatch: 4.0.2 + std-env: 3.9.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.14 + tinypool: 1.1.1 + tinyrainbow: 2.0.0 + vite: 7.1.2(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1) + vite-node: 3.2.4(@types/node@24.3.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.39.0)(tsx@4.20.4)(yaml@2.8.1) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 24.3.0 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + vue@3.5.18(typescript@5.9.2): + dependencies: + '@vue/compiler-dom': 3.5.18 + '@vue/compiler-sfc': 3.5.18 + '@vue/runtime-dom': 3.5.18 + '@vue/server-renderer': 3.5.18(vue@3.5.18(typescript@5.9.2)) + '@vue/shared': 3.5.18 + optionalDependencies: + typescript: 5.9.2 w3c-keyname@2.2.8: {} + web-streams-polyfill@3.3.3: {} + webidl-conversions@3.0.1: {} webpack-virtual-modules@0.6.2: @@ -5836,6 +8280,11 @@ snapshots: dependencies: isexe: 2.0.0 + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -5850,11 +8299,6 @@ snapshots: wrappy@1.0.2: {} - ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10): - optionalDependencies: - bufferutil: 4.0.9 - utf-8-validate: 5.0.10 - ws@8.18.2(bufferutil@4.0.9)(utf-8-validate@5.0.10): optionalDependencies: bufferutil: 4.0.9 @@ -5864,7 +8308,8 @@ snapshots: yallist@5.0.0: {} - yaml@2.8.0: {} + yaml@2.8.1: {} - zod@3.25.33: - optional: true + zimmerframe@1.1.2: {} + + zwitch@2.0.4: {} diff --git a/tests/config.test.js b/tests/config.test.js new file mode 100644 index 00000000..5ee35a40 --- /dev/null +++ b/tests/config.test.js @@ -0,0 +1,353 @@ +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import yaml from 'js-yaml'; +import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest'; +import { overlayFS } from './setupOverlayFs.js'; + +// Get the directory name in ESM +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// Helper to create a temp file with given content, return its path +function writeTempFile(baseName, content) { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'headplane-test-')); + const filePath = path.join(dir, baseName); + fs.writeFileSync(filePath, content); + return filePath; +} + +// Helper to create a temporary YAML config file with minimal required structure +function writeTempYamlConfig(customConfig = {}) { + const defaultConfig = { + debug: false, + server: { + host: '127.0.0.1', + port: 8080, + cookie_secret: '12345678901234567890123456789012', + cookie_secure: false, + agent: { + authkey: 'testagentauthkey', + ttl: 180000, + cache_path: '/tmp/agent_cache.json', + }, + }, + headscale: { url: 'http://localhost:8081', config_strict: false }, + }; + + function deepMerge(target, source) { + let output = { ...target }; + if (isObject(target) && isObject(source)) { + output = { ...target, ...source }; + for (const key of Object.keys(source)) { + if (isObject(source[key]) && key in target && isObject(target[key])) { + output[key] = deepMerge(target[key], source[key]); + } else { + output[key] = source[key]; + } + } + for (const sectionName of ['oidc', 'server', 'headscale']) { + if (output[sectionName] && source[sectionName]) { + const sectionSource = source[sectionName]; + const sectionDefault = target[sectionName] || {}; + const sectionOutput = output[sectionName]; + + for (const baseKey of ['cookie_secret', 'client_secret', 'api_key']) { + const valueKey = baseKey; + const pathKey = `${baseKey}_path`; + const sourceHasValue = Object.hasOwn(sectionSource, valueKey); + const sourceHasPath = Object.hasOwn(sectionSource, pathKey); + const defaultHasValue = Object.hasOwn(sectionDefault, valueKey); + const defaultHasPath = Object.hasOwn(sectionDefault, pathKey); + + if (sourceHasPath && !sourceHasValue && defaultHasValue) { + delete sectionOutput[valueKey]; + } else if (sourceHasValue && !sourceHasPath && defaultHasPath) { + delete sectionOutput[pathKey]; + } + } + } + } + } + return output; + } + + function isObject(item) { + return item && typeof item === 'object' && !Array.isArray(item); + } + + const merged = deepMerge(defaultConfig, customConfig); + const yamlContent = + typeof customConfig === 'string' ? customConfig : yaml.dump(merged); + return writeTempFile('config.yaml', yamlContent); +} + +// Store original process.env to restore after tests +const originalEnv = { ...process.env }; + +describe('Configuration Loading', () => { + let loadConfig; + let ConfigError; + + beforeAll(async () => { + const module = await import('../app/server/config/loader.js'); + loadConfig = module.loadConfig; + ConfigError = module.ConfigError; + }); + + beforeEach(() => { + // biome-ignore lint/performance/noDelete: needed for test cleanup + delete process.env.HEADPLANE_OIDC__CLIENT_SECRET_PATH; + // biome-ignore lint/performance/noDelete: needed for test cleanup + delete process.env.HEADPLANE_SERVER__COOKIE_SECRET_PATH; + // biome-ignore lint/performance/noDelete: needed for test cleanup + delete process.env.HEADPLANE_HEADSCALE__API_KEY_PATH; + // biome-ignore lint/performance/noDelete: needed for test cleanup + delete process.env.TEST_SECRET_DIR; + + // Clear overlayfs + overlayFS.clear(); + + // Create default files that the config expects + overlayFS.createFile( + '/var/lib/headplane/agent_cache.json', + JSON.stringify({}), + ); + overlayFS.createFile( + '/var/lib/headplane/users.json', + `[{"u":"acb3294f89a16b554e06b80d5266a3c8b09a883e1fa78ac459a550bf52a32564","c":65535}]`, + ); + overlayFS.createFile('/tmp/agent_cache.json', JSON.stringify({})); + + // Create test files that some tests expect to exist + overlayFS.createFile('irrelevant', 'irrelevant-content'); + overlayFS.createFile('placeholder', 'placeholder-content'); + }); + + afterAll(() => { + Object.assign(process.env, originalEnv); + overlayFS.clear(); + }); + + describe('OIDC Configuration', () => { + const minimalOidcFields = { + token_endpoint_auth_method: 'client_secret_basic', + disable_api_key_login: false, + headscale_api_key: 'dummyKey', + }; + + it('should load client_secret from file specified in client_secret_path', async () => { + const secretValue = 'yaml-file-oidc-secret'; + const secretPath = writeTempFile('oidc_secret.txt', secretValue); + const tempConfigPath = writeTempYamlConfig({ + oidc: { + issuer: 'https://example.com/oidc', + client_id: 'test', + client_secret_path: secretPath, + ...minimalOidcFields, + }, + }); + const config = await loadConfig({ loadEnv: false, path: tempConfigPath }); + expect(config.oidc.client_secret).toBe(secretValue); + }); + + it('should override YAML client_secret_path with environment variable', async () => { + const envValue = 'env-file-oidc-secret'; + const envPath = writeTempFile('env_oidc_secret.txt', envValue); + process.env.HEADPLANE_OIDC__CLIENT_SECRET_PATH = envPath; + // Instead of 'irrelevant', use a temp file that exists + const irrelevantPath = writeTempFile( + 'irrelevant.txt', + 'irrelevant-content', + ); + const tempConfigPath = writeTempYamlConfig({ + oidc: { + issuer: 'https://example.com/oidc', + client_id: 'test', + client_secret_path: irrelevantPath, + ...minimalOidcFields, + }, + }); + const config = await loadConfig({ loadEnv: true, path: tempConfigPath }); + expect(config.oidc.client_secret).toBe(envValue); + }); + + it('should handle environment variable interpolation in client_secret_path', async () => { + const value = 'interpolated-secret'; + const dir = fs.mkdtempSync( + path.join(os.tmpdir(), 'headplane-secret-dir-'), + ); + const file = path.join(dir, 'secret.txt'); + fs.writeFileSync(file, value); + process.env.TEST_SECRET_DIR = dir; + process.env.HEADPLANE_OIDC__CLIENT_SECRET_PATH = + '${TEST_SECRET_DIR}/secret.txt'; + // Instead of 'placeholder', use a temp file that exists + const placeholderPath = writeTempFile( + 'placeholder.txt', + 'placeholder-content', + ); + const tempConfigPath = writeTempYamlConfig({ + oidc: { + issuer: 'https://example.com/oidc', + client_id: 'test', + client_secret_path: placeholderPath, + ...minimalOidcFields, + }, + }); + const config = await loadConfig({ loadEnv: true, path: tempConfigPath }); + expect(config.oidc.client_secret).toBe(value); + }); + + it('should reject when client_secret_path points to non-existent file', async () => { + const tempConfigPath = writeTempYamlConfig({ + oidc: { + issuer: 'https://example.com/oidc', + client_id: 'test', + client_secret_path: '/no/such/file', + ...minimalOidcFields, + }, + }); + await expect( + loadConfig({ loadEnv: false, path: tempConfigPath }), + ).rejects.toThrow(ConfigError); + }); + + it('should reject when client_secret_path has unresolvable env var interpolation', async () => { + process.env.HEADPLANE_OIDC__CLIENT_SECRET_PATH = + '${MISSING_DIR}/secret.txt'; + const tempConfigPath = writeTempYamlConfig({ + oidc: { + issuer: 'https://example.com/oidc', + client_id: 'test', + client_secret_path: 'placeholder', + ...minimalOidcFields, + }, + }); + await expect( + loadConfig({ loadEnv: true, path: tempConfigPath }), + ).rejects.toThrow(/Environment variable "MISSING_DIR" not found/); + }); + }); + + describe('Server Configuration', () => { + it('should load cookie_secret directly from YAML', async () => { + const valid = 'abcdefghijklmnopqrstuvwxyz123456'; + const tempConfigPath = writeTempYamlConfig({ + server: { cookie_secret: valid }, + }); + const config = await loadConfig({ loadEnv: false, path: tempConfigPath }); + expect(config.server.cookie_secret).toBe(valid); + }); + + it('should load cookie_secret from file', async () => { + const secret = 'a'.repeat(32); + const secretPath = writeTempFile('cookie_secret.txt', secret); + const tempConfigPath = writeTempYamlConfig({ + server: { cookie_secret_path: secretPath }, + }); + const config = await loadConfig({ loadEnv: false, path: tempConfigPath }); + expect(config.server.cookie_secret).toBe(secret); + }); + + it('should reject when both cookie_secret and cookie_secret_path are in YAML', async () => { + const secretPath = writeTempFile('conflict.txt', 'x'.repeat(32)); + const tempConfigPath = writeTempYamlConfig({ + server: { + cookie_secret: '1'.repeat(32), + cookie_secret_path: secretPath, + }, + }); + await expect( + loadConfig({ loadEnv: false, path: tempConfigPath }), + ).rejects.toThrow( + /Only one of \"cookie_secret\" or \"cookie_secret_path\" may be set/, + ); + }); + + it('should reject when neither cookie_secret nor cookie_secret_path is provided', async () => { + const yaml = `debug: false +server: + host: \"127.0.0.1\" + port: 8080 + cookie_secure: false + agent: + authkey: \"key\" + ttl: 180000 + cache_path: \"/tmp/cache.json\" +headscale: + url: \"http://localhost\" + config_strict: false +`; + const tempConfigPath = writeTempYamlConfig(yaml); + await expect( + loadConfig({ loadEnv: false, path: tempConfigPath }), + ).rejects.toThrow( + /Either \"cookie_secret\" or \"cookie_secret_path\" must be provided for cookie_secret/, + ); + }); + }); + + describe('Headscale Configuration', () => { + it('should load headscale_api_key directly from YAML', async () => { + const tempConfigPath = writeTempYamlConfig({ + oidc: { + issuer: 'https://example.com/oidc', + client_id: 'test', + headscale_api_key: 'hs-yaml-key', + token_endpoint_auth_method: 'client_secret_basic', + disable_api_key_login: false, + }, + }); + const config = await loadConfig({ loadEnv: false, path: tempConfigPath }); + expect(config.oidc.headscale_api_key).toBe('hs-yaml-key'); + }); + + it('should load headscale_api_key from file', async () => { + const val = 'hs-file-key'; + const p = writeTempFile('hs_api_key.txt', val); + const tempConfigPath = writeTempYamlConfig({ + oidc: { + issuer: 'https://example.com/oidc', + client_id: 'test', + headscale_api_key_path: p, + token_endpoint_auth_method: 'client_secret_basic', + disable_api_key_login: false, + }, + }); + const config = await loadConfig({ loadEnv: false, path: tempConfigPath }); + expect(config.oidc.headscale_api_key).toBe(val); + }); + + it('should reject when both headscale_api_key and headscale_api_key_path are in YAML', async () => { + const p = writeTempFile('conflict.txt', 'irrelevant'); + const tempConfigPath = writeTempYamlConfig({ + oidc: { + issuer: 'https://example.com/oidc', + client_id: 'test', + headscale_api_key: 'key', + headscale_api_key_path: p, + token_endpoint_auth_method: 'client_secret_basic', + disable_api_key_login: false, + }, + }); + await expect( + loadConfig({ loadEnv: false, path: tempConfigPath }), + ).rejects.toThrow( + /Only one of \"headscale_api_key\" or \"headscale_api_key_path\" may be set/, + ); + }); + + it('should keep config_path string and interpolate env vars', async () => { + process.env.MY_HS_CONFIG_SUBDIR = 'hs-test'; + const cfgVal = '/etc/headscale-${MY_HS_CONFIG_SUBDIR}/config.yaml'; + const exp = '/etc/headscale-hs-test/config.yaml'; + const tempConfigPath = writeTempYamlConfig({ + headscale: { config_path: cfgVal }, + }); + const config = await loadConfig({ loadEnv: true, path: tempConfigPath }); + expect(config.headscale.config_path).toBe(exp); + }); + }); +}); diff --git a/tests/setupOverlayFs.js b/tests/setupOverlayFs.js new file mode 100644 index 00000000..439f02f5 --- /dev/null +++ b/tests/setupOverlayFs.js @@ -0,0 +1,86 @@ +import fs from 'node:fs'; +import fsPromises from 'node:fs/promises'; + +// Simple overlayfs implementation for tests +class OverlayFS { + constructor() { + this.overlays = new Map(); + } + + // Create a virtual file at the given path + createFile(filePath, content) { + this.overlays.set(filePath, content); + } + + // Check if a file exists in our overlay + exists(filePath) { + return this.overlays.has(filePath); + } + + // Read a file from our overlay + readFile(filePath) { + if (this.overlays.has(filePath)) { + return this.overlays.get(filePath); + } + throw new Error(`File not found: ${filePath}`); + } + + // Clean up all overlays + clear() { + this.overlays.clear(); + } +} + +// Global overlayfs instance +export const overlayFS = new OverlayFS(); + +// Monkey patch fs.readFileSync to use our overlay +const originalReadFileSync = fs.readFileSync; +fs.readFileSync = function (filePath, options) { + if (overlayFS.exists(filePath)) { + const content = overlayFS.readFile(filePath); + if (options?.encoding) { + return content; + } + return Buffer.from(content); + } + return originalReadFileSync.call(this, filePath, options); +}; + +// Monkey patch fs.promises.readFile (async) to use our overlay +const originalAsyncReadFile = fsPromises.readFile; +fsPromises.readFile = function (filePath, options) { + if (overlayFS.exists(filePath)) { + const content = overlayFS.readFile(filePath); + if (options?.encoding) { + return Promise.resolve(content); + } + return Promise.resolve(Buffer.from(content)); + } + return originalAsyncReadFile.call(this, filePath, options); +}; + +// Monkey patch fs.access to handle overlayfs directories +const originalAccess = fs.access; +fs.access = function (filePath, mode, callback) { + // Handle directories that should exist in our overlay + if (filePath === '/var/lib/headplane/' || filePath === '/var/lib/headplane') { + if (callback) { + callback(null); + } else { + return Promise.resolve(); + } + return; + } + return originalAccess.call(this, filePath, mode, callback); +}; + +// Monkey patch fs.promises.access to handle overlayfs directories +const originalAsyncAccess = fsPromises.access; +fsPromises.access = function (filePath, mode) { + // Handle directories that should exist in our overlay + if (filePath === '/var/lib/headplane/' || filePath === '/var/lib/headplane') { + return Promise.resolve(); + } + return originalAsyncAccess.call(this, filePath, mode); +}; diff --git a/tsconfig.json b/tsconfig.json index 3e2b7331..3fc47aae 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,11 +1,11 @@ { "include": [ - "**/*.ts", - "**/*.tsx", - "**/.server/**/*.ts", - "**/.server/**/*.tsx", - "**/.client/**/*.ts", - "**/.client/**/*.tsx" + "**/*.ts", + "**/*.tsx", + "**/.server/**/*.ts", + "**/.server/**/*.tsx", + "**/.client/**/*.ts", + "**/.client/**/*.tsx" ], "compilerOptions": { "lib": ["DOM", "DOM.Iterable", "ES2022"], @@ -21,7 +21,6 @@ "allowJs": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, - "baseUrl": ".", "paths": { "~/*": ["./app/*"], "~server/*": ["./server/*"] diff --git a/vite.config.ts b/vite.config.ts index 9a8899e2..77bcc463 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -13,6 +13,7 @@ if (prefix.endsWith('/')) { // Load the version via package.json const pkg = await readFile('package.json', 'utf-8'); +const isNext = process.env.IMAGE_TAG?.includes('next'); const { version } = JSON.parse(pkg); if (!version) { throw new Error('Unable to read version from package.json'); @@ -22,8 +23,8 @@ if (!version) { const config = await readFile('config.example.yaml', 'utf-8'); const { server } = parse(config); -export default defineConfig(({ isSsrBuild }) => ({ - base: isSsrBuild ? `${prefix}/` : undefined, +export default defineConfig(({ command, isSsrBuild }) => ({ + base: command === 'build' ? `${prefix}/` : undefined, plugins: [ reactRouterHonoServer(), reactRouter(), @@ -34,12 +35,18 @@ export default defineConfig(({ isSsrBuild }) => ({ host: server.host, port: server.port, }, + build: { + target: 'esnext', + }, ssr: { target: 'node', - noExternal: isSsrBuild ? true : undefined, + noExternal: isSsrBuild ? ['@libsql/client'] : undefined, + }, + optimizeDeps: { + include: ['@libsql/client'], }, define: { - __VERSION__: JSON.stringify(version), + __VERSION__: JSON.stringify(isNext ? `${version}-next` : version), __PREFIX__: JSON.stringify(prefix), }, })); diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 00000000..a77f53c7 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,16 @@ +import { resolve } from 'node:path'; +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + environment: 'node', + include: ['tests/**/*.test.js'], + exclude: ['node_modules/**', 'build/**'], + setupFiles: ['./tests/setupOverlayFs.js'], + }, + resolve: { + alias: { + '~': resolve(__dirname, './app'), + }, + }, +}); diff --git a/wrangler.toml b/wrangler.toml new file mode 100644 index 00000000..2931343a --- /dev/null +++ b/wrangler.toml @@ -0,0 +1,6 @@ +name = "headplane" +compatibility_date = "2025-08-18" + +[assets] +directory = "docs/.vitepress/dist" +not_found_handling = "404-page"