From 29afac60f6f4e5d0b19fb941518ac896dc6b17f0 Mon Sep 17 00:00:00 2001 From: Aarnav Tale Date: Thu, 27 Aug 2026 14:59:47 -0700 Subject: [PATCH] feat(ssh): bump restty and follow upstream tailscale ssh --- Dockerfile | 2 +- app/routes/ssh/ghostty.client.tsx | 99 +- app/routes/ssh/page.tsx | 61 +- app/routes/ssh/wasm.client.ts | 95 +- app/routes/ssh/wasm_js.d.ts | 116 +++ build.sh | 20 +- cmd/hp_ssh/build-tags.txt | 1 + cmd/hp_ssh/hp_ssh.go | 94 -- cmd/hp_ssh/wasm_js.go | 718 +++++++++++++ compose.yaml | 2 +- flake.nix | 23 +- go.mod | 84 +- go.sum | 254 ++--- internal/hp_ipn/ipnserver.go | 134 --- internal/hp_ipn/jsfunc.go | 43 - internal/hp_ipn/jsmap.go | 118 --- internal/hp_ipn/notify.go | 41 - internal/hp_ipn/ssh.go | 186 ---- mise.toml | 2 +- nix/agent.nix | 2 +- nix/package.nix | 2 +- nix/ssh-wasm.nix | 16 +- package.json | 4 +- patches/tailscale-derp-port.patch | 46 - patches/tailscale-netcheck-derp-port.patch | 25 + patches/tsconnect-term-type.patch | 26 + patches/tsconnect-types.patch | 38 + pnpm-lock.yaml | 1095 ++++++-------------- runtime/http.ts | 25 +- scripts/sync-tsconnect.sh | 64 ++ scripts/wasm-tags.go | 31 + 31 files changed, 1653 insertions(+), 1814 deletions(-) create mode 100644 app/routes/ssh/wasm_js.d.ts create mode 100644 cmd/hp_ssh/build-tags.txt delete mode 100644 cmd/hp_ssh/hp_ssh.go create mode 100644 cmd/hp_ssh/wasm_js.go delete mode 100644 internal/hp_ipn/ipnserver.go delete mode 100644 internal/hp_ipn/jsfunc.go delete mode 100644 internal/hp_ipn/jsmap.go delete mode 100644 internal/hp_ipn/notify.go delete mode 100644 internal/hp_ipn/ssh.go delete mode 100644 patches/tailscale-derp-port.patch create mode 100644 patches/tailscale-netcheck-derp-port.patch create mode 100644 patches/tsconnect-term-type.patch create mode 100644 patches/tsconnect-types.patch create mode 100755 scripts/sync-tsconnect.sh create mode 100644 scripts/wasm-tags.go diff --git a/Dockerfile b/Dockerfile index 336a7ad..bb42048 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM --platform=$BUILDPLATFORM golang:1.25.1 AS go-base +FROM --platform=$BUILDPLATFORM golang:1.26.6 AS go-base WORKDIR /run RUN apt-get update && apt-get install -y --no-install-recommends patch && rm -rf /var/lib/apt/lists/* diff --git a/app/routes/ssh/ghostty.client.tsx b/app/routes/ssh/ghostty.client.tsx index 661a944..bacb541 100644 --- a/app/routes/ssh/ghostty.client.tsx +++ b/app/routes/ssh/ghostty.client.tsx @@ -3,8 +3,6 @@ import { Restty } from "restty"; import type { GhosttyTheme } from "restty"; import type { PtyTransport } from "restty/internal"; -import type { HeadplaneSSH, TunnelSession } from "./wasm.client"; - const FONT_BASE = `${__PREFIX__}/fonts`; // Ghostty's default canvas background is rgb(20,23,26) — a dark gray, not black. @@ -18,36 +16,50 @@ const HEADPLANE_THEME: GhosttyTheme = { raw: {}, }; -function createSSHTransport(ssh: HeadplaneSSH, ipAddress: string, username: string): PtyTransport { - let session: TunnelSession | null = null; +function createSSHTransport( + ipn: IPN, + ipAddress: string, + username: string, + onConnected: () => void, +): PtyTransport { + let session: IPNSSHSession | null = null; + let writeInput: ((data: string) => void) | null = null; return { connect(options) { - session = ssh.openTunnel({ - ipAddress, - username, - onData: (data) => options.callbacks.onData?.(data), - onConnect: () => options.callbacks.onConnect?.(), - onDisconnect: () => { + session = ipn.ssh(ipAddress, username, { + writeFn: (data) => options.callbacks.onData?.(data), + writeErrorFn: (error) => options.callbacks.onData?.(error), + setReadFn: (readFn) => { + writeInput = readFn; + }, + rows: options.rows ?? 24, + cols: options.cols ?? 80, + termType: "xterm-256color", + timeoutSeconds: 30, + onConnectionProgress: () => {}, + onConnected: () => { + options.callbacks.onConnect?.(); + onConnected(); + }, + onDone: () => { options.callbacks.onDisconnect?.(); session = null; + writeInput = null; }, }); - - if (options.cols && options.rows) { - session.resize(options.cols, options.rows); - } }, disconnect() { session?.close(); session = null; }, sendInput(data) { - session?.writeInput(data); + writeInput?.(data); return session != null; }, + // Restty passes cols first, the Tailscale session takes rows first. resize(cols, rows) { - session?.resize(cols, rows); + session?.resize(rows, cols); return session != null; }, isConnected() { @@ -61,66 +73,63 @@ function createSSHTransport(ssh: HeadplaneSSH, ipAddress: string, username: stri } interface GhosttyProps { - ssh: HeadplaneSSH; + ipn: IPN; ipAddress: string; username: string; onConnected: () => void; } -export default function Ghostty({ ssh, ipAddress, username, onConnected }: GhosttyProps) { +export default function Ghostty({ ipn, ipAddress, username, onConnected }: GhosttyProps) { const divRef = useRef(null); useEffect(() => { if (!divRef.current) return; - const transport = createSSHTransport(ssh, ipAddress, username); + const transport = createSSHTransport(ipn, ipAddress, username, onConnected); const restty = new Restty({ root: divRef.current, - createInitialPane: true, - defaultContextMenu: false, - shortcuts: false, - searchUi: false, - paneStyles: { - inactivePaneOpacity: 1, - activePaneOpacity: 1, + surface: { + createInitialPane: true, + defaultContextMenu: false, + shortcuts: false, + searchUi: false, + paneStyles: { + inactivePaneOpacity: 1, + activePaneOpacity: 1, + }, }, - appOptions: { + terminal: { fontSize: 20, ligatures: true, - fontPreset: "none", - fontSources: [ + fonts: [ { - type: "url", url: `${FONT_BASE}/JetBrainsMonoNLNerdFontMono-Regular.ttf`, - label: "JetBrains Mono Nerd Font", + name: "JetBrains Mono Nerd Font", }, { - type: "url", url: `${FONT_BASE}/JetBrainsMonoNLNerdFontMono-Bold.ttf`, - label: "JetBrains Mono Nerd Font Bold", + name: "JetBrains Mono Nerd Font Bold", + weight: 700, }, { - type: "url", url: `${FONT_BASE}/JetBrainsMonoNLNerdFontMono-Italic.ttf`, - label: "JetBrains Mono Nerd Font Italic", + name: "JetBrains Mono Nerd Font Italic", + style: "italic", }, { - type: "url", url: `${FONT_BASE}/JetBrainsMonoNLNerdFontMono-BoldItalic.ttf`, - label: "JetBrains Mono Nerd Font Bold Italic", + name: "JetBrains Mono Nerd Font Bold Italic", + weight: 700, + style: "italic", }, { - type: "url", url: `${FONT_BASE}/SymbolsNerdFontMono-Regular.ttf`, - label: "Symbols Nerd Font", + name: "Symbols Nerd Font", }, ], + }, + services: { ptyTransport: transport, - callbacks: { - onPtyStatus: (status) => { - if (status === "connected") onConnected(); - }, - }, }, }); @@ -131,7 +140,7 @@ export default function Ghostty({ ssh, ipAddress, username, onConnected }: Ghost return () => { restty.destroy(); }; - }, [ssh, ipAddress, username]); + }, [ipn, ipAddress, username, onConnected]); return
; } diff --git a/app/routes/ssh/page.tsx b/app/routes/ssh/page.tsx index 1f9e9b8..fe782d1 100644 --- a/app/routes/ssh/page.tsx +++ b/app/routes/ssh/page.tsx @@ -18,8 +18,7 @@ import type { Route } from "./+types/page"; import { isSSHError, SSHErrorBoundary, sshErrors } from "./errors"; import Ghostty from "./ghostty.client"; import UserPrompt from "./user-prompt"; -import type { HeadplaneSSH } from "./wasm.client"; -import { loadHeadplaneWASM } from "./wasm.client"; +import { connectTailnet } from "./wasm.client"; const WASM_MODULE_URL = `${__PREFIX__}/hp_ssh.wasm`; const WASM_HELPER_URL = `${__PREFIX__}/wasm_exec.js`; @@ -217,48 +216,36 @@ function SSHConsole({ username: string; node: { ipAddress: string; controlURL: string; preAuthKey: string; ephemeralHostname: string }; }) { - const [ssh, setSsh] = useState(null); + const [ipn, setIpn] = useState(null); const [connected, setConnected] = useState(false); - const [status, setStatus] = useState("Starting tunnel…"); + const [status, setStatus] = useState("Joining Tailnet…"); useEffect(() => { let cancelled = false; - console.log("[ssh] Loading WASM factory"); - loadHeadplaneWASM().then((create) => { - console.log("[ssh] Factory loaded, creating IPN", create); - - if (cancelled) { - return; - } - - setStatus("Joining Tailnet…"); - const instance = create({ - controlURL: node.controlURL, - preAuthKey: node.preAuthKey, - hostname: node.ephemeralHostname, - onReady: () => { - console.log("[ssh] IPN ready (Running)"); - if (!cancelled) { - setStatus(`Connecting to ${hostname}…`); - setSsh(instance); - } - }, - onError: (msg) => { - console.error("[ssh] IPN error:", msg); - if (!cancelled) { - setStatus(`Failed to join Tailnet: ${msg}`); - } - }, - }); - - console.log("[ssh] IPN instance created", instance); - }); + connectTailnet({ + controlURL: node.controlURL, + authKey: node.preAuthKey, + hostname: node.ephemeralHostname, + onPanic: (error) => { + if (!cancelled) setStatus(`Tailnet node stopped: ${error}`); + }, + }).then( + (instance) => { + if (cancelled) return; + setStatus(`Connecting to ${hostname}…`); + setIpn(instance); + }, + (error: unknown) => { + if (cancelled) return; + setStatus(`Failed to join Tailnet: ${error instanceof Error ? error.message : error}`); + }, + ); return () => { cancelled = true; }; - }, [node]); + }, [node, hostname]); return (
@@ -271,9 +258,9 @@ function SSHConsole({
)} - {ssh && ( + {ipn && ( setConnected(true)} diff --git a/app/routes/ssh/wasm.client.ts b/app/routes/ssh/wasm.client.ts index e656a1c..8afb022 100644 --- a/app/routes/ssh/wasm.client.ts +++ b/app/routes/ssh/wasm.client.ts @@ -1,56 +1,21 @@ const WASM_MODULE_URL = `${__PREFIX__}/hp_ssh.wasm`; const WASM_HELPER_URL = `${__PREFIX__}/wasm_exec.js`; -declare global { - type HeadplaneSSHFactory = (config: HeadplaneSSHConfig) => HeadplaneSSH; - var __hp_ssh_resolve: ((factory: HeadplaneSSHFactory) => void) | undefined; - - var Go: { - new (): { - importObject: WebAssembly.Imports; - run(instance: WebAssembly.Instance): Promise; - argv?: string[]; - env?: Record; - exit?: (code: number) => void; - }; - }; -} - -interface HeadplaneSSHConfig { +export interface TailnetConfig { controlURL: string; - preAuthKey: string; + authKey: string; hostname: string; - onReady: () => void; - onError?: (message: string) => void; + onPanic: (error: string) => void; } -export interface HeadplaneSSH { - openTunnel(config: TunnelConfig): TunnelSession; -} - -interface TunnelConfig { - ipAddress: string; - username: string; - timeout?: number; - onData: (data: string) => void; - onConnect: () => void; - onDisconnect: () => void; -} - -export interface TunnelSession { - writeInput(data: string): void; - resize(cols: number, rows: number): void; - close(): void; -} - -let resolvedFactory: Promise | null = null; +let goHelper: Promise | null = null; function loadGoHelper(): Promise { if (typeof globalThis.Go !== "undefined") { return Promise.resolve(); } - return new Promise((resolve, reject) => { + goHelper ??= new Promise((resolve, reject) => { const script = document.createElement("script"); script.src = WASM_HELPER_URL; script.crossOrigin = "anonymous"; @@ -58,25 +23,47 @@ function loadGoHelper(): Promise { script.onerror = () => reject(new Error("Failed to load Go WASM helper")); document.head.appendChild(script); }); + + return goHelper; } /** - * One-shot function that loads the Go WASM binary and returns the SSH factory. - * Automatically loads the Go JS helper if it hasn't been loaded yet. + * Boots the Tailscale WASM node and resolves once it has joined the Tailnet. + * Rejects if the pre-auth key is refused or the Go runtime panics. */ -export async function loadHeadplaneWASM(): Promise { - if (!resolvedFactory) { - await loadGoHelper(); +export async function connectTailnet(config: TailnetConfig): Promise { + await loadGoHelper(); - const go = new Go(); - const result = await WebAssembly.instantiateStreaming(fetch(WASM_MODULE_URL), go.importObject); + const go = new Go(); + const module = await WebAssembly.instantiateStreaming(fetch(WASM_MODULE_URL), go.importObject); - resolvedFactory = new Promise((resolve) => { - globalThis.__hp_ssh_resolve = resolve; + // The Go process parks on a channel forever, so returning means it died. + go.run(module.instance).then(() => config.onPanic("Unexpected shutdown")); + + const ipn = newIPN({ + controlURL: config.controlURL, + authKey: config.authKey, + hostname: config.hostname, + }); + + let loginStarted = false; + + return new Promise((resolve, reject) => { + ipn.run({ + notifyState: (state) => { + if (state === "Running") resolve(ipn); + + // The backend parks at NeedsLogin until login starts. With an auth key + // set this consumes it rather than opening an interactive flow. + if (state === "NeedsLogin" && !loginStarted) { + loginStarted = true; + ipn.login(); + } + }, + notifyNetMap: () => {}, + // Only reached when the auth key was refused and the node wants a human. + notifyBrowseToURL: () => reject(new Error("Headscale rejected the pre-auth key")), + notifyPanicRecover: (error) => reject(new Error(error)), }); - - go.run(result.instance); - } - - return resolvedFactory; + }); } diff --git a/app/routes/ssh/wasm_js.d.ts b/app/routes/ssh/wasm_js.d.ts new file mode 100644 index 0000000..8ab0342 --- /dev/null +++ b/app/routes/ssh/wasm_js.d.ts @@ -0,0 +1,116 @@ +// Copyright (c) Tailscale Inc & contributors +// SPDX-License-Identifier: BSD-3-Clause + +/** + * @fileoverview Type definitions for types exported by the wasm_js.go Go + * module. + * + * Vendored from tailscale.com/cmd/tsconnect/src/types/wasm_js.d.ts; see + * cmd/hp_ssh/wasm_js.go for the upstream ref. Local changes live in + * patches/tsconnect-types.patch and are already applied here. + */ + +declare global { + function newIPN(config: IPNConfig): IPN; + + var Go: { + new (): { + importObject: WebAssembly.Imports; + run(instance: WebAssembly.Instance): Promise; + }; + }; + + interface IPN { + run(callbacks: IPNCallbacks): void; + login(): void; + logout(): void; + ssh( + host: string, + username: string, + termConfig: { + writeFn: (data: string) => void; + writeErrorFn: (err: string) => void; + setReadFn: (readFn: (data: string) => void) => void; + rows: number; + cols: number; + /** Defaults to "xterm" */ + termType?: string; + /** Defaults to 5 seconds */ + timeoutSeconds?: number; + onConnectionProgress: (message: string) => void; + onConnected: () => void; + onDone: () => void; + }, + ): IPNSSHSession; + fetch(url: string): Promise<{ + status: number; + statusText: string; + text: () => Promise; + }>; + } + + interface IPNSSHSession { + resize(rows: number, cols: number): boolean; + close(): boolean; + } + + interface IPNStateStorage { + setState(id: string, value: string): void; + getState(id: string): string; + } + + type IPNConfig = { + stateStorage?: IPNStateStorage; + authKey?: string; + controlURL?: string; + hostname?: string; + }; + + type IPNCallbacks = { + notifyState: (state: IPNState) => void; + notifyNetMap: (netMapStr: string) => void; + notifyBrowseToURL: (url: string) => void; + notifyPanicRecover: (err: string) => void; + }; + + type IPNNetMap = { + self: IPNNetMapSelfNode; + peers: IPNNetMapPeerNode[]; + lockedOut: boolean; + }; + + type IPNNetMapNode = { + name: string; + addresses: string[]; + machineKey: string; + nodeKey: string; + }; + + type IPNNetMapSelfNode = IPNNetMapNode & { + machineStatus: IPNMachineStatus; + }; + + type IPNNetMapPeerNode = IPNNetMapNode & { + online?: boolean; + tailscaleSSHEnabled: boolean; + }; + + /** Mirrors values from ipn/backend.go */ + type IPNState = + | "NoState" + | "InUseOtherUser" + | "NeedsLogin" + | "NeedsMachineAuth" + | "Stopped" + | "Starting" + | "Running"; + + /** Mirrors values from MachineStatus in tailcfg.go */ + type IPNMachineStatus = + | "MachineUnknown" + | "MachineUnauthorized" + | "MachineAuthorized" + | "MachineInvalid"; +} + +export {}; diff --git a/build.sh b/build.sh index d96c9ad..9a628ad 100755 --- a/build.sh +++ b/build.sh @@ -137,20 +137,20 @@ build_wasm() { cat "$(go env GOROOT)/lib/wasm/wasm_exec.js" >> \ "$(dirname "$WASM_OUTPUT")/wasm_exec.js" - # Vendor dependencies and apply the DERP port patch. - # Tailscale's browser WebSocket and netcheck URL builders ignore - # DERPPort, which breaks WASM connections to non-443 DERP servers. + WASM_TAGS=$(cat "$ROOT_DIR/cmd/hp_ssh/build-tags.txt") || die "missing wasm build tags" + + # Tailscale's netcheck still builds its browser DERP probe URL from the + # hostname alone, so a DERP server on a non-443 port never gets a home + # relay. Vendor the tree so we can patch it before building. echo "==> Vendoring Go dependencies for WASM patch" go mod vendor - DERP_PATCH="$ROOT_DIR/patches/tailscale-derp-port.patch" - if [ -f "$DERP_PATCH" ]; then - echo "==> Applying DERP port patch" - patch -d vendor/tailscale.com -p1 < "$DERP_PATCH" || \ - die "failed to apply DERP port patch" - fi + echo "==> Applying netcheck DERP port patch" + patch -d vendor/tailscale.com -p1 < "$ROOT_DIR/patches/tailscale-netcheck-derp-port.patch" || \ + die "failed to apply netcheck DERP port patch" - GOOS=js GOARCH=wasm go build -mod=vendor -o "$WASM_OUTPUT" ./cmd/hp_ssh + GOOS=js GOARCH=wasm go build -mod=vendor -tags "$WASM_TAGS" \ + -trimpath -ldflags "-s -w" -o "$WASM_OUTPUT" ./cmd/hp_ssh rm -rf vendor } diff --git a/cmd/hp_ssh/build-tags.txt b/cmd/hp_ssh/build-tags.txt new file mode 100644 index 0000000..ea5b7ed --- /dev/null +++ b/cmd/hp_ssh/build-tags.txt @@ -0,0 +1 @@ +netgo,omitidna,omitpemdecrypt,osusergo,ts_omit_ace,ts_omit_acme,ts_omit_advertiseexitnode,ts_omit_advertiseroutes,ts_omit_appconnectors,ts_omit_aws,ts_omit_bakedroots,ts_omit_bird,ts_omit_cachenetmap,ts_omit_captiveportal,ts_omit_capture,ts_omit_cliconndiag,ts_omit_clientmetrics,ts_omit_clientupdate,ts_omit_cloud,ts_omit_colorable,ts_omit_completion,ts_omit_completion_scripts,ts_omit_conn25,ts_omit_dbus,ts_omit_debug,ts_omit_debugeventbus,ts_omit_debugportmapper,ts_omit_desktop_sessions,ts_omit_doctor,ts_omit_drive,ts_omit_flashappliance,ts_omit_gro,ts_omit_hujsonconf,ts_omit_identityfederation,ts_omit_iptables,ts_omit_kube,ts_omit_linkspeed,ts_omit_linuxdnsfight,ts_omit_listenrawdisco,ts_omit_netlog,ts_omit_networkmanager,ts_omit_oauthkey,ts_omit_osrouter,ts_omit_outboundproxy,ts_omit_peerapiclient,ts_omit_peerapiserver,ts_omit_portlist,ts_omit_portmapper,ts_omit_posture,ts_omit_qrcodes,ts_omit_relayserver,ts_omit_remoteconfig,ts_omit_resolved,ts_omit_routecheck,ts_omit_runtimemetrics,ts_omit_sdnotify,ts_omit_serve,ts_omit_serviceclientprefs,ts_omit_ssh,ts_omit_synology,ts_omit_syslog,ts_omit_syspolicy,ts_omit_systray,ts_omit_taildrop,ts_omit_tailnetlock,ts_omit_tap,ts_omit_tpm,ts_omit_tundevstats,ts_omit_unixsocketidentity,ts_omit_useexitnode,ts_omit_useproxy,ts_omit_usermetrics,ts_omit_useroutes,ts_omit_wakeonlan,ts_omit_webbrowser,ts_omit_webclient diff --git a/cmd/hp_ssh/hp_ssh.go b/cmd/hp_ssh/hp_ssh.go deleted file mode 100644 index 3fd3ce9..0000000 --- a/cmd/hp_ssh/hp_ssh.go +++ /dev/null @@ -1,94 +0,0 @@ -//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") - - factory := js.FuncOf(func(this js.Value, args []js.Value) any { - if len(args) != 1 { - log.Printf("Usage: create(config)") - return nil - } - - config, err := hp_ipn.ParseIPNConfig(args[0]) - if err != nil { - log.Printf("Error parsing config: %v", err) - return nil - } - - callbacks := hp_ipn.ParseIPNCallbacks(args[0]) - - ipn, err := hp_ipn.NewTsWasmIpn(config, callbacks) - if err != nil { - callbacks.OnError(err.Error()) - return nil - } - - go func() { - if err := ipn.Start(context.Background()); err != nil { - callbacks.OnError(err.Error()) - } - }() - - return map[string]any{ - "openTunnel": js.FuncOf(func(this js.Value, args []js.Value) any { - if len(args) != 1 { - log.Printf("Usage: openTunnel(config)") - return nil - } - - tunnelConfig, err := hp_ipn.ParseTunnelConfig(args[0]) - if err != nil { - log.Printf("Error parsing tunnel config: %v", err) - return nil - } - - session := ipn.NewSSHSession(tunnelConfig) - go session.ConnectAndRun() - - return map[string]any{ - "writeInput": js.FuncOf(func(this js.Value, args []js.Value) any { - if len(args) == 1 { - session.WriteInput(args[0].String()) - } - return nil - }), - - "resize": js.FuncOf(func(this js.Value, args []js.Value) any { - if len(args) != 2 { - return nil - } - session.Resize(args[0].Int(), args[1].Int()) - return nil - }), - - "close": js.FuncOf(func(this js.Value, args []js.Value) any { - session.Close() - return nil - }), - } - }), - } - }) - - resolve := js.Global().Get("__hp_ssh_resolve") - if resolve.Type() != js.TypeFunction { - log.Printf("__hp_ssh_resolve is not set, cannot initialize") - return - } - - resolve.Invoke(factory) - js.Global().Delete("__hp_ssh_resolve") - - log.Printf("WASM Headplane SSH module loaded successfully") - <-make(chan bool) -} diff --git a/cmd/hp_ssh/wasm_js.go b/cmd/hp_ssh/wasm_js.go new file mode 100644 index 0000000..e7f50dc --- /dev/null +++ b/cmd/hp_ssh/wasm_js.go @@ -0,0 +1,718 @@ +// Copyright (c) Tailscale Inc & contributors +// SPDX-License-Identifier: BSD-3-Clause + +// Vendored from tailscale.com/cmd/tsconnect/wasm/wasm_js.go. +// Upstream ref: fb27d87e02c7358e44a063668902a183216b72ae +// +// Local changes live in patches/tsconnect-term-type.patch and are already +// applied here. Run scripts/sync-tsconnect.sh to move to a newer upstream. + +// The wasm package builds a WebAssembly module that provides a subset of +// Tailscale APIs to JavaScript. +// +// When run in the browser, a newIPN(config) function is added to the global JS +// namespace. When called it returns an ipn object with the methods +// run(callbacks), login(), logout(), and ssh(...). +package main + +import ( + "bytes" + "context" + "encoding/hex" + "encoding/json" + "fmt" + "log" + "math/rand/v2" + "net" + "net/http" + "net/netip" + "strings" + "syscall/js" + "time" + + "golang.org/x/crypto/ssh" + "tailscale.com/control/controlclient" + "tailscale.com/ipn" + "tailscale.com/ipn/ipnauth" + "tailscale.com/ipn/ipnlocal" + "tailscale.com/ipn/ipnserver" + "tailscale.com/ipn/store/mem" + "tailscale.com/logpolicy" + "tailscale.com/logtail" + "tailscale.com/net/netns" + "tailscale.com/net/tsdial" + "tailscale.com/safesocket" + "tailscale.com/tailcfg" + "tailscale.com/tsd" + "tailscale.com/types/views" + "tailscale.com/wgengine" + "tailscale.com/wgengine/netstack" + "tailscale.com/words" +) + +// ControlURL defines the URL to be used for connection to Control. +var ControlURL = ipn.DefaultControlURL + +func main() { + js.Global().Set("newIPN", js.FuncOf(func(this js.Value, args []js.Value) any { + if len(args) != 1 { + log.Fatal("Usage: newIPN(config)") + return nil + } + return newIPN(args[0]) + })) + // Keep Go runtime alive, otherwise it will be shut down before newIPN gets + // called. + <-make(chan bool) +} + +func newIPN(jsConfig js.Value) map[string]any { + netns.SetEnabled(false) + + var store ipn.StateStore + if jsStateStorage := jsConfig.Get("stateStorage"); !jsStateStorage.IsUndefined() { + store = &jsStateStore{jsStateStorage} + } else { + store = new(mem.Store) + } + + controlURL := ControlURL + if jsControlURL := jsConfig.Get("controlURL"); jsControlURL.Type() == js.TypeString { + controlURL = jsControlURL.String() + } + + var authKey string + if jsAuthKey := jsConfig.Get("authKey"); jsAuthKey.Type() == js.TypeString { + authKey = jsAuthKey.String() + } + + var hostname string + if jsHostname := jsConfig.Get("hostname"); jsHostname.Type() == js.TypeString { + hostname = jsHostname.String() + } else { + hostname = generateHostname() + } + + lpc := getOrCreateLogPolicyConfig(store) + c := logtail.Config{ + Collection: lpc.Collection, + PrivateID: lpc.PrivateID, + + // Compressed requests set HTTP headers that are not supported by the + // no-cors fetching mode: + CompressLogs: false, + + HTTPC: &http.Client{Transport: &noCORSTransport{http.DefaultTransport}}, + } + logtail := logtail.NewLogger(c, log.Printf) + logf := logtail.Logf + + sys := tsd.NewSystem() + sys.Set(store) + dialer := &tsdial.Dialer{Logf: logf} + dialer.SetBus(sys.Bus.Get()) + eng, err := wgengine.NewUserspaceEngine(logf, wgengine.Config{ + Dialer: dialer, + SetSubsystem: sys.Set, + ControlKnobs: sys.ControlKnobs(), + HealthTracker: sys.HealthTracker.Get(), + ExtraRootCAs: sys.ExtraRootCAs, + Metrics: sys.UserMetricsRegistry(), + EventBus: sys.Bus.Get(), + }) + if err != nil { + log.Fatal(err) + } + sys.Set(eng) + + ns, err := netstack.Create(logf, sys.Tun.Get(), eng, sys.MagicSock.Get(), dialer, sys.DNSManager.Get(), sys.ProxyMapper()) + if err != nil { + log.Fatalf("netstack.Create: %v", err) + } + sys.Set(ns) + ns.ProcessLocalIPs = true + ns.ProcessSubnets = true + + dialer.UseNetstackForIP = func(ip netip.Addr) bool { + return true + } + dialer.NetstackDialTCP = func(ctx context.Context, dst netip.AddrPort) (net.Conn, error) { + // Note: don't just return ns.DialContextTCP or we'll return + // *gonet.TCPConn(nil) instead of a nil interface which trips up + // callers. + tcpConn, err := ns.DialContextTCP(ctx, dst) + if err != nil { + return nil, err + } + return tcpConn, nil + } + dialer.NetstackDialUDP = func(ctx context.Context, dst netip.AddrPort) (net.Conn, error) { + // Note: don't just return ns.DialContextUDP or we'll return + // *gonet.UDPConn(nil) instead of a nil interface which trips up + // callers. + udpConn, err := ns.DialContextUDP(ctx, dst) + if err != nil { + return nil, err + } + return udpConn, nil + } + sys.NetstackRouter.Set(true) + sys.Tun.Get().Start() + + logid := lpc.PublicID + srv := ipnserver.New(logf, logid, sys.Bus.Get(), sys.NetMon.Get()) + lb, err := ipnlocal.NewLocalBackend(logf, logid, sys, controlclient.LoginEphemeral) + if err != nil { + log.Fatalf("ipnlocal.NewLocalBackend: %v", err) + } + if err := ns.Start(lb); err != nil { + log.Fatalf("failed to start netstack: %v", err) + } + srv.SetLocalBackend(lb) + + jsIPN := &jsIPN{ + dialer: dialer, + srv: srv, + lb: lb, + controlURL: controlURL, + authKey: authKey, + hostname: hostname, + } + + return map[string]any{ + "run": js.FuncOf(func(this js.Value, args []js.Value) any { + if len(args) != 1 { + log.Fatal(`Usage: run({ + notifyState(state: int): void, + notifyNetMap(netMap: object): void, + notifyBrowseToURL(url: string): void, + notifyPanicRecover(err: string): void, + })`) + return nil + } + jsIPN.run(args[0]) + return nil + }), + "login": js.FuncOf(func(this js.Value, args []js.Value) any { + if len(args) != 0 { + log.Printf("Usage: login()") + return nil + } + jsIPN.login() + return nil + }), + "logout": js.FuncOf(func(this js.Value, args []js.Value) any { + if len(args) != 0 { + log.Printf("Usage: logout()") + return nil + } + jsIPN.logout() + return nil + }), + "ssh": js.FuncOf(func(this js.Value, args []js.Value) any { + if len(args) != 3 { + log.Printf("Usage: ssh(hostname, userName, termConfig)") + return nil + } + return jsIPN.ssh( + args[0].String(), + args[1].String(), + args[2]) + }), + "fetch": js.FuncOf(func(this js.Value, args []js.Value) any { + if len(args) != 1 { + log.Printf("Usage: fetch(url)") + return nil + } + + url := args[0].String() + return jsIPN.fetch(url) + }), + } +} + +type jsIPN struct { + dialer *tsdial.Dialer + srv *ipnserver.Server + lb *ipnlocal.LocalBackend + controlURL string + authKey string + hostname string +} + +var jsIPNState = map[ipn.State]string{ + ipn.NoState: "NoState", + ipn.InUseOtherUser: "InUseOtherUser", + ipn.NeedsLogin: "NeedsLogin", + ipn.NeedsMachineAuth: "NeedsMachineAuth", + ipn.Stopped: "Stopped", + ipn.Starting: "Starting", + ipn.Running: "Running", +} + +var jsMachineStatus = map[tailcfg.MachineStatus]string{ + tailcfg.MachineUnknown: "MachineUnknown", + tailcfg.MachineUnauthorized: "MachineUnauthorized", + tailcfg.MachineAuthorized: "MachineAuthorized", + tailcfg.MachineInvalid: "MachineInvalid", +} + +func (i *jsIPN) run(jsCallbacks js.Value) { + notifyState := func(state ipn.State) { + jsCallbacks.Call("notifyState", jsIPNState[state]) + } + notifyState(ipn.NoState) + + i.lb.SetNotifyCallback(func(n ipn.Notify) { + // Panics in the notify callback are likely due to be due to bugs in + // this bridging module (as opposed to actual bugs in Tailscale) and + // thus may be recoverable. Let the UI know, and allow the user to + // choose if they want to reload the page. + defer func() { + if r := recover(); r != nil { + fmt.Println("Panic recovered:", r) + jsCallbacks.Call("notifyPanicRecover", fmt.Sprint(r)) + } + }() + log.Printf("NOTIFY: %+v", n) + if n.State != nil { + notifyState(*n.State) + } + if n.SelfChange != nil { + // Self changed: rebuild the JS-side NetMap snapshot. Peers + // don't ride on the bus anymore, so fetch them on demand + // from LocalBackend. + nm := i.lb.NetMapWithPeers() + if nm != nil { + jsNetMap := jsNetMap{ + Self: jsNetMapSelfNode{ + jsNetMapNode: jsNetMapNode{ + Name: nm.SelfName(), + 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) + } + }) + + go func() { + err := i.lb.Start(ipn.Options{ + UpdatePrefs: &ipn.Prefs{ + ControlURL: i.controlURL, + RouteAll: false, + WantRunning: true, + Hostname: i.hostname, + }, + AuthKey: i.authKey, + }) + if err != nil { + log.Printf("Start error: %v", err) + } + }() + + go func() { + ln, err := safesocket.Listen("") + if err != nil { + log.Fatalf("safesocket.Listen: %v", err) + } + + err = i.srv.Run(context.Background(), ln) + log.Fatalf("ipnserver.Run exited: %v", err) + }() +} + +func (i *jsIPN) login() { + go i.lb.StartLoginInteractive(context.Background()) +} + +func (i *jsIPN) logout() { + if i.lb.State() == ipn.NoState { + log.Printf("Backend not running") + } + go func() { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + i.lb.Logout(ctx, ipnauth.Self) + }() +} + +func (i *jsIPN) ssh(host, username string, termConfig js.Value) map[string]any { + jsSSHSession := &jsSSHSession{ + jsIPN: i, + host: host, + username: username, + termConfig: termConfig, + } + + go jsSSHSession.Run() + + return map[string]any{ + "close": js.FuncOf(func(this js.Value, args []js.Value) any { + return jsSSHSession.Close() != nil + }), + "resize": js.FuncOf(func(this js.Value, args []js.Value) any { + rows := args[0].Int() + cols := args[1].Int() + return jsSSHSession.Resize(rows, cols) != nil + }), + } +} + +type jsSSHSession struct { + jsIPN *jsIPN + host string + username string + termConfig js.Value + session *ssh.Session + + pendingResizeRows int + pendingResizeCols int +} + +func (s *jsSSHSession) Run() { + writeFn := s.termConfig.Get("writeFn") + writeErrorFn := s.termConfig.Get("writeErrorFn") + setReadFn := s.termConfig.Get("setReadFn") + rows := s.termConfig.Get("rows").Int() + cols := s.termConfig.Get("cols").Int() + timeoutSeconds := 5.0 + if jsTimeoutSeconds := s.termConfig.Get("timeoutSeconds"); jsTimeoutSeconds.Type() == js.TypeNumber { + timeoutSeconds = jsTimeoutSeconds.Float() + } + onConnectionProgress := s.termConfig.Get("onConnectionProgress") + onConnected := s.termConfig.Get("onConnected") + onDone := s.termConfig.Get("onDone") + defer onDone.Invoke() + + writeError := func(label string, err error) { + writeErrorFn.Invoke(fmt.Sprintf("%s Error: %v\r\n", label, err)) + } + reportProgress := func(message string) { + onConnectionProgress.Invoke(message) + } + + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeoutSeconds*float64(time.Second))) + defer cancel() + reportProgress(fmt.Sprintf("Connecting to %s…", strings.Split(s.host, ".")[0])) + c, err := s.jsIPN.dialer.UserDial(ctx, "tcp", net.JoinHostPort(s.host, "22")) + if err != nil { + writeError("Dial", err) + return + } + defer c.Close() + + config := &ssh.ClientConfig{ + HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { + // Host keys are not used with Tailscale SSH, but we can use this + // callback to know that the connection has been established. + reportProgress("SSH connection established…") + return nil + }, + User: s.username, + } + + reportProgress("Starting SSH client…") + sshConn, _, _, err := ssh.NewClientConn(c, s.host, config) + if err != nil { + writeError("SSH Connection", err) + return + } + defer sshConn.Close() + + sshClient := ssh.NewClient(sshConn, nil, nil) + defer sshClient.Close() + + session, err := sshClient.NewSession() + if err != nil { + writeError("SSH Session", err) + return + } + s.session = session + defer session.Close() + + stdin, err := session.StdinPipe() + if err != nil { + writeError("SSH Stdin", err) + return + } + + session.Stdout = termWriter{writeFn} + session.Stderr = termWriter{writeFn} + + setReadFn.Invoke(js.FuncOf(func(this js.Value, args []js.Value) any { + input := args[0].String() + _, err := stdin.Write([]byte(input)) + if err != nil { + writeError("Write Input", err) + } + return nil + })) + + // We might have gotten a resize notification since we started opening the + // session, pick up the latest size. + if s.pendingResizeRows != 0 { + rows = s.pendingResizeRows + } + if s.pendingResizeCols != 0 { + cols = s.pendingResizeCols + } + termType := "xterm" + if v := s.termConfig.Get("termType"); v.Type() == js.TypeString { + termType = v.String() + } + err = session.RequestPty(termType, rows, cols, ssh.TerminalModes{ + ssh.ECHO: 1, ssh.ICANON: 1, ssh.ISIG: 1, ssh.ICRNL: 1, ssh.IUTF8: 1, + ssh.TTY_OP_ISPEED: 14400, ssh.TTY_OP_OSPEED: 14400, + }) + if err != nil { + writeError("Pseudo Terminal", err) + return + } + + err = session.Shell() + if err != nil { + writeError("Shell", err) + return + } + + onConnected.Invoke() + err = session.Wait() + if err != nil { + writeError("Wait", err) + return + } +} + +func (s *jsSSHSession) Close() error { + if s.session == nil { + // We never had a chance to open the session, ignore the close request. + return nil + } + return s.session.Close() +} + +func (s *jsSSHSession) Resize(rows, cols int) error { + if s.session == nil { + s.pendingResizeRows = rows + s.pendingResizeCols = cols + return nil + } + return s.session.WindowChange(rows, cols) +} + +func (i *jsIPN) fetch(url string) js.Value { + return makePromise(func() (any, error) { + c := &http.Client{ + Transport: &http.Transport{ + DialContext: i.dialer.UserDial, + }, + } + res, err := c.Get(url) + if err != nil { + return nil, err + } + + return map[string]any{ + "status": res.StatusCode, + "statusText": res.Status, + "text": js.FuncOf(func(this js.Value, args []js.Value) any { + return makePromise(func() (any, error) { + defer res.Body.Close() + buf := new(bytes.Buffer) + if _, err := buf.ReadFrom(res.Body); err != nil { + return nil, err + } + return buf.String(), nil + }) + }), + // TODO: populate a more complete JS Response object + }, nil + }) +} + +type termWriter struct { + f js.Value +} + +func (w termWriter) Write(p []byte) (n int, err error) { + r := bytes.Replace(p, []byte("\n"), []byte("\n\r"), -1) + w.f.Invoke(string(r)) + return len(p), nil +} + +type jsNetMap struct { + Self jsNetMapSelfNode `json:"self"` + Peers []jsNetMapPeerNode `json:"peers"` + LockedOut bool `json:"lockedOut"` +} + +type jsNetMapNode struct { + Name string `json:"name"` + Addresses []string `json:"addresses"` + MachineKey string `json:"machineKey"` + NodeKey string `json:"nodeKey"` +} + +type jsNetMapSelfNode struct { + jsNetMapNode + MachineStatus string `json:"machineStatus"` +} + +type jsNetMapPeerNode struct { + jsNetMapNode + Online *bool `json:"online,omitempty"` + TailscaleSSHEnabled bool `json:"tailscaleSSHEnabled"` +} + +type jsStateStore struct { + jsStateStorage js.Value +} + +func (s *jsStateStore) ReadState(id ipn.StateKey) ([]byte, error) { + jsValue := s.jsStateStorage.Call("getState", string(id)) + if jsValue.String() == "" { + return nil, ipn.ErrStateNotExist + } + return hex.DecodeString(jsValue.String()) +} + +func (s *jsStateStore) WriteState(id ipn.StateKey, bs []byte) error { + s.jsStateStorage.Call("setState", string(id), hex.EncodeToString(bs)) + return nil +} + +func mapSlice[T any, M any](a []T, f func(T) M) []M { + n := make([]M, len(a)) + for i, e := range a { + n[i] = f(e) + } + return n +} + +func mapSliceView[T any, M any](a views.Slice[T], f func(T) M) []M { + n := make([]M, a.Len()) + for i, v := range a.All() { + n[i] = f(v) + } + return n +} + +func filterSlice[T any](a []T, f func(T) bool) []T { + n := make([]T, 0, len(a)) + for _, e := range a { + if f(e) { + n = append(n, e) + } + } + return n +} + +func generateHostname() string { + tails := words.Tails() + scales := words.Scales() + if rand.IntN(2) == 0 { + // JavaScript + tails = filterSlice(tails, func(s string) bool { return strings.HasPrefix(s, "j") }) + scales = filterSlice(scales, func(s string) bool { return strings.HasPrefix(s, "s") }) + } else { + // WebAssembly + tails = filterSlice(tails, func(s string) bool { return strings.HasPrefix(s, "w") }) + scales = filterSlice(scales, func(s string) bool { return strings.HasPrefix(s, "a") }) + } + + tail := tails[rand.IntN(len(tails))] + scale := scales[rand.IntN(len(scales))] + return fmt.Sprintf("%s-%s", tail, scale) +} + +// makePromise handles the boilerplate of wrapping goroutines with JS promises. +// f is run on a goroutine and its return value is used to resolve the promise +// (or reject it if an error is returned). +func makePromise(f func() (any, error)) js.Value { + handler := js.FuncOf(func(this js.Value, args []js.Value) any { + resolve := args[0] + reject := args[1] + go func() { + if res, err := f(); err == nil { + resolve.Invoke(res) + } else { + reject.Invoke(err.Error()) + } + }() + return nil + }) + + promiseConstructor := js.Global().Get("Promise") + return promiseConstructor.New(handler) +} + +const logPolicyStateKey = "log-policy" + +func getOrCreateLogPolicyConfig(state ipn.StateStore) *logpolicy.Config { + if configBytes, err := state.ReadState(logPolicyStateKey); err == nil { + if config, err := logpolicy.ConfigFromBytes(configBytes); err == nil { + return config + } else { + log.Printf("Could not parse log policy config: %v", err) + } + } else if err != ipn.ErrStateNotExist { + log.Printf("Could not get log policy config from state store: %v", err) + } + config := logpolicy.NewConfig(logtail.CollectionNode) + if err := state.WriteState(logPolicyStateKey, config.ToBytes()); err != nil { + log.Printf("Could not save log policy config to state store: %v", err) + } + return config +} + +// noCORSTransport wraps a RoundTripper and forces the no-cors mode on requests, +// so that we can use it with non-CORS-aware servers. +type noCORSTransport struct { + http.RoundTripper +} + +func (t *noCORSTransport) RoundTrip(req *http.Request) (*http.Response, error) { + req.Header.Set("js.fetch:mode", "no-cors") + resp, err := t.RoundTripper.RoundTrip(req) + if err == nil { + // In no-cors mode no response properties are returned. Populate just + // the status so that callers do not think this was an error. + resp.StatusCode = http.StatusOK + resp.Status = http.StatusText(http.StatusOK) + } + return resp, err +} diff --git a/compose.yaml b/compose.yaml index b3be156..88809f8 100644 --- a/compose.yaml +++ b/compose.yaml @@ -24,7 +24,7 @@ services: - "./test/caddy/config:/config" - "./test/caddy/certs:/certs" headscale: - image: "headscale/headscale:0.29.0" + image: "headscale/headscale:0.29.2" container_name: "headscale" labels: me.tale.headplane.target: headscale diff --git a/flake.nix b/flake.nix index c66e15d..b03171b 100644 --- a/flake.nix +++ b/flake.nix @@ -26,13 +26,19 @@ rec { inherit system; overlays = [ devshell.overlays.default ]; }; + + # nixpkgs' default go is 1.26.5; go.mod (via tailscale) needs >= 1.26.6. + buildGoModule = pkgs.buildGoModule.override {go = pkgs.go_1_27;}; in rec { formatter = pkgs.alejandra; packages = { headplane = pkgs.callPackage ./nix/package.nix {headplane-ssh-wasm = packages.headplane-ssh-wasm;}; - headplane-agent = pkgs.callPackage ./nix/agent.nix {}; + headplane-agent = pkgs.callPackage ./nix/agent.nix {inherit buildGoModule;}; headplane-nixos-docs = pkgs.callPackage ./nix/docs.nix {}; - headplane-ssh-wasm = pkgs.callPackage ./nix/ssh-wasm.nix {}; + headplane-ssh-wasm = pkgs.callPackage ./nix/ssh-wasm.nix { + inherit buildGoModule; + go = pkgs.go_1_27; + }; }; checks.default = pkgs.symlinkJoin { name = "headplane-with-agent"; @@ -53,7 +59,7 @@ rec { ${providedPackages} ''; packages = [ - pkgs.go + pkgs.go_1_27 pkgs.nodejs-slim_24 pkgs.pnpm_10 pkgs.typescript-language-server @@ -64,11 +70,16 @@ rec { }; }) // { - overlays.default = final: prev: { + overlays.default = final: prev: let + buildGoModule = final.buildGoModule.override {go = final.go_1_27;}; + in { headplane = final.callPackage ./nix/package.nix {headplane-ssh-wasm = final.headplane-ssh-wasm;}; - headplane-agent = final.callPackage ./nix/agent.nix {}; + headplane-agent = final.callPackage ./nix/agent.nix {inherit buildGoModule;}; headplane-nixos-docs = final.callPackage ./nix/docs.nix {}; - headplane-ssh-wasm = final.callPackage ./nix/ssh-wasm.nix {}; + headplane-ssh-wasm = final.callPackage ./nix/ssh-wasm.nix { + inherit buildGoModule; + go = final.go_1_27; + }; }; nixosModules.headplane = import ./nix/module.nix; }; diff --git a/go.mod b/go.mod index f46a9bb..ce49517 100644 --- a/go.mod +++ b/go.mod @@ -1,79 +1,53 @@ module github.com/tale/headplane -go 1.25.1 +go 1.26.6 require ( go4.org/mem v0.0.0-20240501181205-ae6ca9944745 - golang.org/x/crypto v0.41.0 - tailscale.com v1.88.2 + golang.org/x/crypto v0.54.0 + tailscale.com v1.102.3 ) require ( - filippo.io/edwards25519 v1.1.0 // indirect + filippo.io/edwards25519 v1.2.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.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.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/coder/websocket v1.8.14 // indirect + github.com/creachadair/msync v0.8.1 // 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.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 - github.com/google/btree v1.1.2 // indirect - 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/fxamacker/cbor/v2 v2.9.0 // indirect + github.com/gaissmai/bart v0.26.1 // indirect + github.com/go-json-experiment/json v0.0.0-20260214004413-d219187c3433 // indirect + github.com/godbus/dbus/v5 v5.2.2 // indirect + github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect + github.com/google/btree v1.1.3 // indirect + github.com/google/go-cmp v0.7.0 // indirect github.com/hdevalence/ed25519consensus v0.2.0 // indirect - github.com/illarion/gonotify/v3 v3.0.2 // indirect - github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/jsimonetti/rtnetlink v1.4.0 // indirect - github.com/klauspost/compress v1.17.11 // indirect - github.com/mdlayher/genetlink v1.3.2 // indirect + github.com/huin/goupnp v1.3.0 // indirect + github.com/jsimonetti/rtnetlink v1.4.1 // indirect + github.com/klauspost/compress v1.19.1 // 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/prometheus-community/pro-bing v0.4.0 // indirect + github.com/pires/go-proxyproto v0.8.1 // indirect github.com/safchain/ethtool v0.3.0 // indirect - github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e // indirect + github.com/tailscale/certstore v0.1.1-0.20260409135935-3638fb84b77d // indirect github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 // 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/hujson v0.0.0-20260302212456-ecc657c15afd // 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/tailscale/wireguard-go v0.0.0-20260715223240-2e01ba5b00f0 // indirect github.com/x448/float16 v0.8.4 // indirect go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // 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.org/x/exp v0.0.0-20260410095643-746e56fc9e2f // indirect + golang.org/x/net v0.56.0 // indirect + golang.org/x/oauth2 v0.36.0 // indirect + golang.org/x/sync v0.22.0 // indirect + golang.org/x/sys v0.47.0 // indirect + golang.org/x/term v0.45.0 // indirect + golang.org/x/text v0.40.0 // indirect + golang.org/x/time v0.15.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-20250205023644-9414b50a5633 // indirect + gvisor.dev/gvisor v0.0.0-20260224225140-573d5e7127a8 // indirect ) diff --git a/go.sum b/go.sum index 92ac417..87b8c47 100644 --- a/go.sum +++ b/go.sum @@ -1,86 +1,95 @@ 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/edwards25519 v1.2.0 h1:crnVqOiS4jqYleHd9vaKZ+HKtHfllngJIiOpNpoJsjo= +filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc= filippo.io/mkcert v1.4.4 h1:8eVbbwfVlaqUM7OwuftKc2nuYOoTDQWqsoXmzoXZdbc= filippo.io/mkcert v1.4.4/go.mod h1:VyvOchVuAye3BoUsPUOOofKygVwLV2KQMVFJNRq+1dA= -github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs= -github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= +github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/akutz/memconn v0.1.0 h1:NawI0TORU4hcOMsMr11g7vwlCdkYeLKXBcxWu2W/P8A= github.com/akutz/memconn v0.1.0/go.mod h1:Jo8rI7m0NieZyLI5e2CDlRdRqRRB4S7Xp77ukDjH+Fw= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= 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.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.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/aws/aws-sdk-go-v2 v1.42.1 h1:9eOTgu1z/dVtYpNZ3/8/XbbaX0x/BqE3HUzAzs6K0ek= +github.com/aws/aws-sdk-go-v2 v1.42.1/go.mod h1:5pKeft2eJj+gElQ38Jqg4ibCqh+/AK33/0X3hip7IjM= +github.com/aws/aws-sdk-go-v2/config v1.32.17 h1:FpL4/758/diKwqbytU0prpuiu60fgXKUWCpDJtApclU= +github.com/aws/aws-sdk-go-v2/config v1.32.17/go.mod h1:OXqUMzgXytfoF9JaKkhrOYsyh72t9G+MJH8mMRaexOE= +github.com/aws/aws-sdk-go-v2/credentials v1.19.16 h1:r3RJBuU7X9ibt8RHbMjWE6y60QbKBiII6wSrXnapxSU= +github.com/aws/aws-sdk-go-v2/credentials v1.19.16/go.mod h1:6cx7zqDENJDbBIIWX6P8s0h6hqHC8Avbjh9Dseo27ug= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23 h1:UuSfcORqNSz/ey3VPRS8TcVH2Ikf0/sC+Hdj400QI6U= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23/go.mod h1:+G/OSGiOFnSOkYloKj/9M35s74LgVAdJBSD5lsFfqKg= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.30 h1:xM/Is9cKMHa8Jj8zkvWhvrFkZsXJV9E+BB4g0HW0duQ= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.30/go.mod h1:WueJeNDZvK1fMYEWJIkcivBfEzUkTpBhzlrUKKY8EuA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.30 h1:jn46zC9LdsVR/ZpMIJqMqb8hHv31BlLx3ulVqNspUOk= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.30/go.mod h1:1hTMsAgbdS/AtUi4bw8+gUuh1pceo+eXRLfpSuSQj3M= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24 h1:OQqn11BtaYv1WLUowvcA30MpzIu8Ti4pcLPIIyoKZrA= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24/go.mod h1:X5ZJyfwVrWA96GzPmUCWFQaEARPR7gCrpq2E92PJwAE= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.13 h1:mbRIur/BiHK6SKPjoBIXSE/hJ6g6JGRLuxQy1jGjlN4= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.13/go.mod h1:ITg9em2KbJx1s0y4aqRX5OYWG6HBZ5TVR//OdpEZ2CQ= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.30 h1:/Z5jmNrKsSD7EmDjzAPsm/3L9IuOkzaynklJZ1qX7S4= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.30/go.mod h1:lEzEZnOosE7zi8Z6royW1cFJTD9fpab4Ul1SBrllewk= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.11 h1:TdJ+HdzOBhU8+iVAOGUTU63VXopcumCOF1paFulHWZc= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.11/go.mod h1:R82ZRExE/nheo0N+T8zHPcLRTcH8MGsnR3BiVGX0TwI= +github.com/aws/aws-sdk-go-v2/service/ssm v1.45.0 h1:IOdss+igJDFdic9w3WKwxGCmHqUxydvIhJOm9LJ32Dk= +github.com/aws/aws-sdk-go-v2/service/ssm v1.45.0/go.mod h1:Q7XIWsMo0JcMpI/6TGD6XXcXcV1DbTj6e9BKNntIMIM= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.17 h1:7byT8HUWrgoRp6sXjxtZwgOKfhss5fW6SkLBtqzgRoE= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.17/go.mod h1:xNWknVi4Ezm1vg1QsB/5EWpAJURq22uqd38U8qKvOJc= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.21 h1:+1Kl1zx6bWi4X7cKi3VYh29h8BvsCoHQEQ6ST9X8w7w= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.21/go.mod h1:4vIRDq+CJB2xFAXZ+YgGUTiEft7oAQlhIs71xcSeuVg= +github.com/aws/aws-sdk-go-v2/service/sts v1.42.1 h1:F/M5Y9I3nwr2IEpshZgh1GeHpOItExNM9L1euNuh/fk= +github.com/aws/aws-sdk-go-v2/service/sts v1.42.1/go.mod h1:mTNxImtovCOEEuD65mKW7DCsL+2gjEH+RPEAexAzAio= +github.com/aws/smithy-go v1.27.3 h1:F3Zb497UhhskkfpJmfkXswyo+t0sh9OTBnIHjogWbVY= +github.com/aws/smithy-go v1.27.3/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= +github.com/axiomhq/hyperloglog v0.0.0-20240319100328-84253e514e02 h1:bXAPYSbdYbS5VTy92NIUbeDI1qyggi+JYh5op9IFlcQ= +github.com/axiomhq/hyperloglog v0.0.0-20240319100328-84253e514e02/go.mod h1:k08r+Yj1PRAmuayFiRK6MYuR5Ve4IuZtTfxErMIh0+c= +github.com/cilium/ebpf v0.16.0 h1:+BiEnHL6Z7lXnlGUsXQPPAE7+kenAd4ES8MQ5min0Ok= +github.com/cilium/ebpf v0.16.0/go.mod h1:L7u2Blt2jMM/vLAVgjxluxtBKlz3/GWjB0dMOEngfwE= +github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g= +github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= 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/mds v0.25.13 h1:PsSUHV6zsfPd29k4kvm1rMoee1YFia7JyNGeMPmDcPM= +github.com/creachadair/mds v0.25.13/go.mod h1:4hatI3hRM+qhzuAmqPRFvaBM8mONkS7nsLxkcuTYUIs= +github.com/creachadair/msync v0.8.1 h1:QRd8si3qZ2Q4TaDL7tS/MG/lFE3YND7U7J9fy42eAFM= +github.com/creachadair/msync v0.8.1/go.mod h1:dt0bscS09J8Ie3AdccK9JpCb7LfStaDGlAmDLukOlY4= 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= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= +github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa h1:h8TfIT1xc8FWbwwpmHn1J5i43Y0uZP97GqasGCzSRJk= github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa/go.mod h1:Nx87SkVqTKd8UtT+xu7sM/l+LgXs6c0aHrlKusR+2EQ= +github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc h1:8WFBn63wegobsYAX0YjD+8suexZDga5CctH4CCTx2+8= +github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw= github.com/digitalocean/go-smbios v0.0.0-20180907143718-390a4f403a8e h1:vUmf0yezR0y7jJ5pceLHthLaYf4bA5T14B6q39S4q2Q= 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/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.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/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= +github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/gaissmai/bart v0.26.1 h1:+w4rnLGNlA2GDVn382Tfe3jOsK5vOr5n4KmigJ9lbTo= +github.com/gaissmai/bart v0.26.1/go.mod h1:GREWQfTLRWz/c5FTOsIw+KkscuFkIV5t8Rp7Nd1Td5c= 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-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-json-experiment/json v0.0.0-20260214004413-d219187c3433 h1:vymEbVwYFP/L05h5TKQxvkXoKxNvTpjxYKdF1Nlwuao= +github.com/go-json-experiment/json v0.0.0-20260214004413-d219187c3433/go.mod h1:tphK2c80bpPhMOI4v6bIc2xWywPfbqi1Z06+RcrMkDg= 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/hashtriemap v0.0.0-20251130024219-545ba229f689 h1:0psnKZ+N2IP43/SZC8SKx6OpFJwLmQb9m9QyV9BC2f8= +github.com/go4org/hashtriemap v0.0.0-20251130024219-545ba229f689/go.mod h1:OGmRfY/9QEK2P5zCRtmqfbCF283xPkU2dvVA4MvbvpI= 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= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -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/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ= +github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= +github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= +github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= 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= @@ -89,20 +98,20 @@ 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/hdevalence/ed25519consensus v0.2.0 h1:37ICyZqdyj0lAZ8P4D1d1id3HqbbG1N3iBb1Tb4rdcU= github.com/hdevalence/ed25519consensus v0.2.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= +github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= 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/insomniacslk/dhcp v0.0.0-20240129002554-15c9b8791914 h1:kD8PseueGeYiid/Mmcv17Q0Qqicc4F46jcX22L/e/Hs= +github.com/insomniacslk/dhcp v0.0.0-20240129002554-15c9b8791914/go.mod h1:3A9PQ1cunSDF/1rbTq99Ts4pVnycWg+vlPkfeD2NLFI= github.com/jellydator/ttlcache/v3 v3.1.0 h1:0gPFG0IHHP6xyUyXq+JaD8fwkDCqgqwohXNJBcYE71g= github.com/jellydator/ttlcache/v3 v3.1.0/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= 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/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= -github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/jsimonetti/rtnetlink v1.4.1 h1:JfD4jthWBqZMEffc5RjgmlzpYttAVw1sdnmiNaPO3hE= +github.com/jsimonetti/rtnetlink v1.4.1/go.mod h1:xJjT7t59UIZ62GLZbv6PLLo8VFrostJMPBAheR6OM8w= +github.com/klauspost/compress v1.19.1 h1:VsB4HPswih7mmZ8WleSFQ75c/Ui1M4trX5oAsJnhSlk= +github.com/klauspost/compress v1.19.1/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a h1:+RR6SqnTkDLWyICxS1xpjCi/3dhyV+TgZwA6Ww3KncQ= github.com/kortschak/wol v0.0.0-20200729010619-da482cc4850a/go.mod h1:YTtCCM3ryyfiu4F7t8HQ1mxvp1UBdWM2r6Xa+nGWvDk= github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= @@ -127,34 +136,32 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq 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.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= -github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pierrec/lz4/v4 v4.1.26 h1:GrpZw1gZttORinvzBdXPUXATeqlJjqUG/D87TKMnhjY= +github.com/pierrec/lz4/v4 v4.1.26/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4= +github.com/pires/go-proxyproto v0.8.1 h1:9KEixbdJfhrbtjpz/ZwCdWDD2Xem0NZ38qMYaASJgp0= +github.com/pires/go-proxyproto v0.8.1/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU= github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo= github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -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.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/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.69.0 h1:OA85nJQS/T/MaYh/Q2CcgDKSGWqNIgrBDvDH85CuiNk= +github.com/prometheus/common v0.69.0/go.mod h1:ZzL3f6u94qUxh9p+tJTrF+FvBS1XXbbRAZCQkytAL0Y= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= 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/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/studio-b12/gowebdav v0.13.0 h1:OcwSg6IQHOFNdYHn3bPOHwSE8looG8N56Y5xTT1asqQ= +github.com/studio-b12/gowebdav v0.13.0/go.mod h1:bHA7t77X/QFExdeAnDzK6vKM34kEZAcE1OX4MfiwjkE= +github.com/tailscale/certstore v0.1.1-0.20260409135935-3638fb84b77d h1:JcGKBZAL7ePLwOhUdN8qGQZlP5GueEiIZwY7R62pejE= +github.com/tailscale/certstore v0.1.1-0.20260409135935-3638fb84b77d/go.mod h1:XrBNfAFN+pwoWuksbFS9Ccxnopa15zJGgXRFN90l3K4= +github.com/tailscale/gliderssh v0.3.4-0.20260716005906-1a0f895faf28 h1:Azz5ILxxVsHN/KjIu3wkJPAmmtiijucZw4Ax5Ye8n+s= +github.com/tailscale/gliderssh v0.3.4-0.20260716005906-1a0f895faf28/go.mod h1:wn16Km1EZOX4UEAyaZa3dBwfFGOJ7neck40NcwosJUw= 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-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/golang-x-crypto v0.0.0-20260720153645-2ba0bf7866ed h1:uyvHhX1FQada0vVk8CSHa4tJT96EEAkTypaYz8Tq5Nc= +github.com/tailscale/golang-x-crypto v0.0.0-20260720153645-2ba0bf7866ed/go.mod h1:NC3xRCu4UR+m4n6ix8b6oLLbHa820Y0StbOQEdWTDo0= +github.com/tailscale/hujson v0.0.0-20260302212456-ecc657c15afd h1:Rf9uhF1+VJ7ZHqxrG8pJ6YacmHvVCmByDmGbAWCc/gA= +github.com/tailscale/hujson v0.0.0-20260302212456-ecc657c15afd/go.mod h1:EbW0wDK/qEUYI0A5bqq0C2kF8JTQwWONmGDBbzsxxHo= 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-20250107143737-35a0c7bd7edc h1:24heQPtnFR+yfntqhI3oAu9i27nEojcQ4NuBQOo5ZFA= @@ -163,8 +170,8 @@ github.com/tailscale/web-client-prebuilt v0.0.0-20250124233751-d4cd19a26976 h1:U 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-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/wireguard-go v0.0.0-20260715223240-2e01ba5b00f0 h1:CnIEL2n7Xql6Ux1k+Vu5S5ubDHCT/kxFgkKCY8FjefU= +github.com/tailscale/wireguard-go v0.0.0-20260715223240-2e01ba5b00f0/go.mod h1:6SerzcvHWQchKO2BfNdmquA77CHSECZuFl+D9fp4RnI= 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= @@ -173,7 +180,6 @@ 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.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= @@ -182,53 +188,49 @@ go4.org/mem v0.0.0-20240501181205-ae6ca9944745 h1:Tl++JLUCe4sxGu8cTpDzRLd3tN7US4 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.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/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw= +golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk= +golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM= +golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80= 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.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/image v0.41.0 h1:8wS72eGJMJaBxK6okTzd4WaXumUlTVlb753MlsSvTCo= +golang.org/x/image v0.41.0/go.mod h1:uIc348UZMSvS5Z65CVZ7iDPaNobNFEPeJ4kbqTOszmA= +golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= +golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= +golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= +golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= +golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= +golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -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-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= +golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -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.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= +golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0= +golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w= +golang.org/x/text v0.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs= +golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY= +golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= +golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= +golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q= +golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA= 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 v0.0.0-20260522210424-ecfc5a8d5446 h1:cqHQ3AycTHvM2R7ikgyX57D+XvtcSnGylsLkOVhta/w= +golang.zx2c4.com/wireguard v0.0.0-20260522210424-ecfc5a8d5446/go.mod h1:rpwXGsirqLqN2L0JDJQlwOboGHmptD5ZD6T2VmcqhTw= 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.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= -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= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gvisor.dev/gvisor v0.0.0-20260224225140-573d5e7127a8 h1:Zy8IV/+FMLxy6j6p87vk/vQGKcdnbprwjTxc8UiUtsA= +gvisor.dev/gvisor v0.0.0-20260224225140-573d5e7127a8/go.mod h1:QkHjoMIBaYtpVufgwv3keYAbln78mBoCuShZrPrer1Q= +honnef.co/go/tools v0.7.0 h1:w6WUp1VbkqPEgLz4rkBzH/CSU6HkoqNLp6GstyTx3lU= +honnef.co/go/tools v0.7.0/go.mod h1:pm29oPxeP3P82ISxZDgIYeOaf9ta6Pi0EWvCFoLG2vc= 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.88.2 h1:S8S+gt/Vx4KDlVjNHk7spcyGihTcJflKMroSnwjp5kQ= -tailscale.com v1.88.2/go.mod h1:LHaTiwRgzebPDLgZ6RQQVzX+1SR5fbNl51fzm7UtMaw= +tailscale.com v1.102.3 h1:M1czCAtMuIcg+2Z+FBPbJyAk3ZEQGEFKnvHthtE1c6M= +tailscale.com v1.102.3/go.mod h1:47bv91Xbg4K1p5wti7F1dmKvUVWV5BXF78d9EWJ+d6c= diff --git a/internal/hp_ipn/ipnserver.go b/internal/hp_ipn/ipnserver.go deleted file mode 100644 index 7c378d8..0000000 --- a/internal/hp_ipn/ipnserver.go +++ /dev/null @@ -1,134 +0,0 @@ -//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/netns" - "tailscale.com/net/tsdial" - "tailscale.com/safesocket" - "tailscale.com/tsd" - "tailscale.com/types/logid" - "tailscale.com/wgengine" - "tailscale.com/wgengine/netstack" -) - -type TsWasmIpn struct { - options *IPNConfig - dialer *tsdial.Dialer - server *ipnserver.Server - backend *ipnlocal.LocalBackend -} - -func NewTsWasmIpn(options *IPNConfig, callbacks *IPNCallbacks) (*TsWasmIpn, error) { - logf := log.Printf - netns.SetEnabled(false) - - sys := tsd.NewSystem() - sys.Set(new(mem.Store)) - - dialer := &tsdial.Dialer{Logf: logf} - - engine, err := wgengine.NewUserspaceEngine(logf, wgengine.Config{ - Dialer: dialer, - SetSubsystem: sys.Set, - ControlKnobs: sys.ControlKnobs(), - HealthTracker: sys.HealthTracker(), - Metrics: sys.UserMetricsRegistry(), - EventBus: sys.Bus.Get(), - }) - if err != nil { - return nil, fmt.Errorf("failed to create userspace engine: %w", 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) - if err != nil { - return nil, fmt.Errorf("failed to create netstack: %w", err) - } - - sys.Set(wgstack) - - 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) - } - - logID := logid.PublicID{} - sys.NetstackRouter.Set(true) - sys.Tun.Get().Start() - - server := ipnserver.New(logf, logID, sys.NetMon.Get()) - - backend, err := ipnlocal.NewLocalBackend(logf, logID, sys, controlclient.LoginEphemeral) - if err != nil { - return nil, fmt.Errorf("failed to create local backend: %w", err) - } - - if err := wgstack.Start(backend); err != nil { - return nil, fmt.Errorf("failed to start netstack: %w", err) - } - - server.SetLocalBackend(backend) - registerNotifyCallback(callbacks, backend) - - return &TsWasmIpn{ - options: options, - dialer: dialer, - server: server, - backend: backend, - }, nil -} - -func (t *TsWasmIpn) Start(ctx context.Context) error { - listener, err := safesocket.Listen("") - if err != nil { - return fmt.Errorf("failed to create safesocket listener: %w", err) - } - - go func() { - if err := t.server.Run(ctx, listener); err != nil { - log.Printf("Tailscale server exited: %v", err) - } - }() - - 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) - } - - return nil -} diff --git a/internal/hp_ipn/jsfunc.go b/internal/hp_ipn/jsfunc.go deleted file mode 100644 index 691b903..0000000 --- a/internal/hp_ipn/jsfunc.go +++ /dev/null @@ -1,43 +0,0 @@ -//go:build js && wasm - -package hp_ipn - -import ( - "syscall/js" - - "tailscale.com/ipn" -) - -type IPNCallbacks struct { - OnReady func() - OnError func(string) -} - -func ParseIPNCallbacks(obj js.Value) *IPNCallbacks { - cb := &IPNCallbacks{ - OnReady: func() {}, - OnError: func(string) {}, - } - - onReady := obj.Get("onReady") - if onReady.Type() == js.TypeFunction { - cb.OnReady = func() { onReady.Invoke() } - } - - onError := obj.Get("onError") - if onError.Type() == js.TypeFunction { - cb.OnError = func(msg string) { onError.Invoke(msg) } - } - - return cb -} - -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", -} diff --git a/internal/hp_ipn/jsmap.go b/internal/hp_ipn/jsmap.go deleted file mode 100644 index 9914332..0000000 --- a/internal/hp_ipn/jsmap.go +++ /dev/null @@ -1,118 +0,0 @@ -//go:build js && wasm - -package hp_ipn - -import ( - "errors" - "syscall/js" -) - -type IPNConfig struct { - ControlURL string - PreAuthKey string - Hostname string -} - -func ParseIPNConfig(obj js.Value) (*IPNConfig, error) { - if obj.IsUndefined() || obj.IsNull() { - return nil, errors.New("config cannot be undefined or null") - } - - controlURL := safeString("controlURL", obj) - preAuthKey := safeString("preAuthKey", obj) - hostname := safeString("hostname", obj) - - if controlURL == "" || preAuthKey == "" || hostname == "" { - return nil, errors.New("missing required fields: controlURL, preAuthKey, hostname") - } - - return &IPNConfig{ - ControlURL: controlURL, - PreAuthKey: preAuthKey, - Hostname: hostname, - }, nil -} - -type TunnelConfig struct { - IPAddress string - Username string - Timeout int - OnData func(data string) - OnConnect func() - OnDisconnect func() -} - -func ParseTunnelConfig(obj js.Value) (*TunnelConfig, error) { - if obj.IsUndefined() || obj.IsNull() { - return nil, errors.New("tunnel config cannot be undefined or null") - } - - ipAddress := safeString("ipAddress", obj) - username := safeString("username", obj) - if ipAddress == "" || username == "" { - return nil, errors.New("missing required fields: ipAddress, username") - } - - timeout := safeInt("timeout", obj) - if timeout <= 0 { - timeout = 30 - } - - config := &TunnelConfig{ - IPAddress: ipAddress, - Username: username, - Timeout: timeout, - } - - onData := obj.Get("onData") - if onData.IsUndefined() || onData.IsNull() || onData.Type() != js.TypeFunction { - return nil, errors.New("`onData` is required and must be a function") - } - config.OnData = func(data string) { - onData.Invoke(data) - } - - 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 -} - -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() -} - -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 deleted file mode 100644 index 7121d9f..0000000 --- a/internal/hp_ipn/notify.go +++ /dev/null @@ -1,41 +0,0 @@ -//go:build js && wasm - -package hp_ipn - -import ( - "context" - "fmt" - "log" - "sync" - - "tailscale.com/ipn" - "tailscale.com/ipn/ipnlocal" -) - -func registerNotifyCallback(callbacks *IPNCallbacks, lb *ipnlocal.LocalBackend) { - var readyOnce sync.Once - - lb.SetNotifyCallback(func(n ipn.Notify) { - defer func() { - if rec := recover(); rec != nil { - callbacks.OnError(fmt.Sprint(rec)) - } - }() - - if n.State != nil { - if *n.State == ipn.Running { - readyOnce.Do(callbacks.OnReady) - } - - if *n.State == ipn.NeedsLogin { - go forceInteractiveLogin(lb) - } - } - }) -} - -func forceInteractiveLogin(lb *ipnlocal.LocalBackend) { - if err := lb.StartLoginInteractive(context.Background()); err != nil { - log.Printf("Error starting interactive login: %v", err) - } -} diff --git a/internal/hp_ipn/ssh.go b/internal/hp_ipn/ssh.go deleted file mode 100644 index e1caf2f..0000000 --- a/internal/hp_ipn/ssh.go +++ /dev/null @@ -1,186 +0,0 @@ -//go:build js && wasm - -package hp_ipn - -import ( - "context" - "fmt" - "io" - "log" - "net" - "time" - - "golang.org/x/crypto/ssh" -) - -type SSHSession struct { - IPAddress string - Username string - Config *TunnelConfig - Ipn *TsWasmIpn - Pty *ssh.Session - - stdin io.Writer - resizeCols int - resizeRows int - cancel context.CancelFunc -} - -func (i *TsWasmIpn) NewSSHSession(config *TunnelConfig) *SSHSession { - return &SSHSession{ - IPAddress: config.IPAddress, - Username: config.Username, - Config: config, - Ipn: i, - } -} - -func (s *SSHSession) ConnectAndRun() { - defer s.Config.OnDisconnect() - - ctx, cancel := context.WithTimeout(context.Background(), time.Duration(s.Config.Timeout)*time.Second) - s.cancel = cancel - defer cancel() - - conn, err := s.Ipn.dialer.UserDial(ctx, "tcp", net.JoinHostPort(s.IPAddress, "22")) - if err != nil { - s.writeError("Dial", err) - return - } - defer conn.Close() - - // In Go WASM, gVisor's netstack conn.Read blocks indefinitely without - // a deadline because the single-threaded goroutine scheduler needs the - // deadline machinery to yield to the browser event loop and process - // inbound WireGuard packets. We set a deadline that covers the entire - // SSH handshake and clear it once the session is established. - conn.SetReadDeadline(time.Now().Add(30 * time.Second)) - - sshConf := &ssh.ClientConfig{ - User: s.Username, - HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error { - return nil - }, - } - - sshConn, chans, reqs, err := ssh.NewClientConn(conn, s.IPAddress, sshConf) - if err != nil { - s.writeError("SSH", err) - return - } - defer sshConn.Close() - - conn.SetReadDeadline(time.Time{}) - - sshClient := ssh.NewClient(sshConn, chans, reqs) - defer sshClient.Close() - - pty, err := sshClient.NewSession() - if err != nil { - s.writeError("SSH", err) - return - } - defer pty.Close() - s.Pty = pty - - rows := 24 - if s.resizeRows != 0 { - rows = s.resizeRows - } - - cols := 80 - if s.resizeCols != 0 { - cols = s.resizeCols - } - - err = pty.RequestPty("xterm-256color", rows, cols, ssh.TerminalModes{ - ssh.ECHO: 1, - ssh.ICANON: 1, - ssh.ISIG: 1, - ssh.ICRNL: 1, - ssh.IUTF8: 1, - ssh.TTY_OP_ISPEED: 14400, - ssh.TTY_OP_OSPEED: 14400, - }) - if err != nil { - s.writeError("SSH", err) - return - } - - stdin, err := pty.StdinPipe() - if err != nil { - s.writeError("SSH", err) - return - } - s.stdin = 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(DataPipe{s.Config.OnData}, stdout) - go io.Copy(DataPipe{s.Config.OnData}, stderr) - - err = pty.Shell() - if err != nil { - s.writeError("SSH", err) - return - } - - s.Config.OnConnect() - if err := pty.Wait(); err != nil { - log.Printf("SSH session ended: %v", err) - } -} - -func (s *SSHSession) WriteInput(data string) { - if s.stdin != nil { - s.stdin.Write([]byte(data)) - } -} - -// Resize takes cols and rows (JS convention: cols first, rows second) -// and translates to SSH's WindowChange(rows, cols) order. -func (s *SSHSession) Resize(cols, rows int) error { - if s.Pty == nil { - s.resizeCols = cols - s.resizeRows = rows - return nil - } - - return s.Pty.WindowChange(rows, cols) -} - -func (s *SSHSession) Close() error { - if s.cancel != nil { - s.cancel() - s.cancel = nil - } - - if s.Pty != nil { - return s.Pty.Close() - } - - return nil -} - -func (s *SSHSession) writeError(label string, err error) { - s.Config.OnData(fmt.Sprintf("%s error: %v\r\n", label, err)) -} - -type DataPipe struct { - Send func(data string) -} - -func (p DataPipe) Write(data []byte) (int, error) { - p.Send(string(data)) - return len(data), nil -} diff --git a/mise.toml b/mise.toml index 7d25a79..4d160e8 100644 --- a/mise.toml +++ b/mise.toml @@ -1,5 +1,5 @@ [tools] -go = "1.25.1" +go = "1.26.6" pnpm = "10.4.0" node = "24.2" diff --git a/nix/agent.nix b/nix/agent.nix index d9d7697..e611e3a 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-MvrqKMD+A+qBZmzQv+T9920U5uJop+pjfJpZdm2ZqEA="; + vendorHash = "sha256-Q5lRDbx7bg3WsrF+ukVPl7rTSJcqKFhYM9lWtqfiIw4="; ldflags = ["-s" "-w"]; env.CGO_ENABLED = 0; } diff --git a/nix/package.nix b/nix/package.nix index 84ff401..5e96e0c 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -33,7 +33,7 @@ in inherit (finalAttrs) pname version src; fetcherVersion = 3; pnpm = pnpm_10; - hash = "sha256-2F7DplZ+PAMkDepsoeUxS04+IefWy3ARgE8G6Fz+YnQ="; + hash = "sha256-+J36edYqr+qt6C0fU8Q8visrEH5+R6Ww3VuRcykHgZY="; }; buildPhase = '' diff --git a/nix/ssh-wasm.nix b/nix/ssh-wasm.nix index a7b0586..59a499b 100644 --- a/nix/ssh-wasm.nix +++ b/nix/ssh-wasm.nix @@ -14,7 +14,7 @@ in version = (builtins.fromJSON (builtins.readFile ../package.json)).version; src = ../.; subPackages = ["cmd/hp_ssh"]; - vendorHash = "sha256-MvrqKMD+A+qBZmzQv+T9920U5uJop+pjfJpZdm2ZqEA="; + vendorHash = "sha256-Q5lRDbx7bg3WsrF+ukVPl7rTSJcqKFhYM9lWtqfiIw4="; env.CGO_ENABLED = 0; nativeBuildInputs = [go]; @@ -23,14 +23,14 @@ in export GOOS=js export GOARCH=wasm - # Patch Tailscale's derphttp to include DERPPort in WebSocket URLs. - # Without this, DERP servers on non-443 ports fail in WASM builds. - if [ -f patches/tailscale-derp-port.patch ]; then - chmod -R +w vendor/tailscale.com - patch -d vendor/tailscale.com -p1 < patches/tailscale-derp-port.patch - fi + # Tailscale's netcheck builds its browser DERP probe URL from the + # hostname alone, so a DERP server on a non-443 port never gets a + # home relay. + chmod -R +w vendor/tailscale.com + patch -d vendor/tailscale.com -p1 < patches/tailscale-netcheck-derp-port.patch - go build -mod=vendor -o hp_ssh.wasm ./cmd/hp_ssh + go build -mod=vendor -tags "$(cat cmd/hp_ssh/build-tags.txt)" \ + -trimpath -ldflags "-s -w" -o hp_ssh.wasm ./cmd/hp_ssh ''; installPhase = '' diff --git a/package.json b/package.json index 187cde8..ab196c9 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "@dnd-kit/utilities": "^3.2.2", "@fontsource-variable/inter": "^5.3.0", "@iconify/react": "^6.0.2", - "@kubernetes/client-node": "^1.4.0", + "@kubernetes/client-node": "^2.0.0", "@lezer/highlight": "^1.2.3", "@react-router/node": "^8.3.0", "@uiw/react-codemirror": "4.25.11", @@ -48,7 +48,7 @@ "react-dom": "19.2.8", "react-error-boundary": "^6.1.3", "react-router": "^8.3.0", - "restty": "^0.1.35", + "restty": "0.2.6", "tailwind-merge": "3.6.0", "ulidx": "2.4.1", "undici": "8.10.0", diff --git a/patches/tailscale-derp-port.patch b/patches/tailscale-derp-port.patch deleted file mode 100644 index 5c23f9d..0000000 --- a/patches/tailscale-derp-port.patch +++ /dev/null @@ -1,46 +0,0 @@ -Fix DERP browser URLs to include non-standard ports. - -Tailscale's browser DERP paths ignore DERPPort when building WebSocket -and HTTP-only netcheck probe URLs, causing connections to fail when DERP -servers run on non-443 ports (e.g. :8443). The TCP dial path correctly -handles DERPPort but the browser paths used by WASM builds do not. - ---- a/derp/derphttp/derphttp_client.go -+++ b/derp/derphttp/derphttp_client.go -@@ -279,10 +279,19 @@ - return c.url.String() - } - proto := "https" -+ var port string - if debugUseDERPHTTP() { - proto = "http" -+ port = "3340" - } -- return fmt.Sprintf("%s://%s/derp", proto, node.HostName) -+ if node != nil && node.DERPPort != 0 { -+ port = fmt.Sprint(node.DERPPort) -+ } -+ host := node.HostName -+ if port != "" { -+ host = net.JoinHostPort(node.HostName, port) -+ } -+ return fmt.Sprintf("%s://%s/derp", proto, host) - } - - // AddressFamilySelector decides whether IPv6 is preferred for - ---- a/net/netcheck/netcheck.go -+++ b/net/netcheck/netcheck.go -@@ -1103,7 +1103,11 @@ - go func() { - defer wg.Done() - node := rg.Nodes[0] -- req, _ := http.NewRequestWithContext(ctx, "HEAD", "https://"+node.HostName+"/derp/probe", nil) -+ host := node.HostName -+ if node.DERPPort != 0 { -+ host = net.JoinHostPort(node.HostName, fmt.Sprint(node.DERPPort)) -+ } -+ req, _ := http.NewRequestWithContext(ctx, "HEAD", "https://"+host+"/derp/probe", nil) - // One warm-up one to get HTTP connection set - // up and get a connection from the browser's - // pool. diff --git a/patches/tailscale-netcheck-derp-port.patch b/patches/tailscale-netcheck-derp-port.patch new file mode 100644 index 0000000..ccd35cd --- /dev/null +++ b/patches/tailscale-netcheck-derp-port.patch @@ -0,0 +1,25 @@ +netcheck: include DERPPort in the browser HTTPS probe URL + +The js/wasm netcheck path probes each DERP region over HTTPS to measure +latency and pick a home relay. It builds that URL from HostName alone, so +a DERP server on a non-443 port is never reachable and the client ends up +with no home DERP. + +derphttp's urlString already handles DERPPort; this is the same fix for +the one remaining browser path that does not. + +--- a/net/netcheck/netcheck.go ++++ b/net/netcheck/netcheck.go +@@ -1075,7 +1075,11 @@ + } + wg.Go(func() { + node := rg.Nodes[0] +- req, _ := http.NewRequestWithContext(ctx, "HEAD", "https://"+node.HostName+"/derp/probe", nil) ++ host := node.HostName ++ if node.DERPPort != 0 && node.DERPPort != 443 { ++ host = net.JoinHostPort(host, fmt.Sprint(node.DERPPort)) ++ } ++ req, _ := http.NewRequestWithContext(ctx, "HEAD", "https://"+host+"/derp/probe", nil) + // One warm-up one to get HTTP connection set + // up and get a connection from the browser's + // pool. diff --git a/patches/tsconnect-term-type.patch b/patches/tsconnect-term-type.patch new file mode 100644 index 0000000..1651a5e --- /dev/null +++ b/patches/tsconnect-term-type.patch @@ -0,0 +1,26 @@ +tsconnect: let the caller choose the PTY terminal type and modes + +Upstream requests a bare "xterm" PTY with no terminal modes. Headplane +renders with Ghostty and ships a Nerd Font, so it needs xterm-256color +and sane modes for anything colour-aware on the far side. + +Applied to cmd/hp_ssh/wasm_js.go by scripts/sync-tsconnect.sh. + +--- a/wasm/wasm_js.go ++++ b/wasm/wasm_js.go +@@ -484,7 +484,14 @@ + if s.pendingResizeCols != 0 { + cols = s.pendingResizeCols + } +- err = session.RequestPty("xterm", rows, cols, ssh.TerminalModes{}) ++ termType := "xterm" ++ if v := s.termConfig.Get("termType"); v.Type() == js.TypeString { ++ termType = v.String() ++ } ++ err = session.RequestPty(termType, rows, cols, ssh.TerminalModes{ ++ ssh.ECHO: 1, ssh.ICANON: 1, ssh.ISIG: 1, ssh.ICRNL: 1, ssh.IUTF8: 1, ++ ssh.TTY_OP_ISPEED: 14400, ssh.TTY_OP_OSPEED: 14400, ++ }) + if err != nil { + writeError("Pseudo Terminal", err) + return diff --git a/patches/tsconnect-types.patch b/patches/tsconnect-types.patch new file mode 100644 index 0000000..0ef2033 --- /dev/null +++ b/patches/tsconnect-types.patch @@ -0,0 +1,38 @@ +tsconnect: type the termType option and the wasm_exec Go global + +termType matches patches/tsconnect-term-type.patch. Go is declared by the +wasm_exec.js helper the Go toolchain ships, which we load ourselves rather +than through @tailscale/connect. + +@@ -4,11 +4,22 @@ + /** + * @fileoverview Type definitions for types exported by the wasm_js.go Go + * module. ++ * ++ * Vendored from tailscale.com/cmd/tsconnect/src/types/wasm_js.d.ts; see ++ * cmd/hp_ssh/wasm_js.go for the upstream ref. Local changes live in ++ * patches/tsconnect-types.patch and are already applied here. + */ + + declare global { + function newIPN(config: IPNConfig): IPN + ++ var Go: { ++ new (): { ++ importObject: WebAssembly.Imports ++ run(instance: WebAssembly.Instance): Promise ++ } ++ } ++ + interface IPN { + run(callbacks: IPNCallbacks): void + login(): void +@@ -22,6 +33,8 @@ + setReadFn: (readFn: (data: string) => void) => void + rows: number + cols: number ++ /** Defaults to "xterm" */ ++ termType?: string + /** Defaults to 5 seconds */ + timeoutSeconds?: number + onConnectionProgress: (message: string) => void diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9aac98c..eae8493 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -46,8 +46,8 @@ importers: specifier: ^6.0.2 version: 6.0.2(react@19.2.8) '@kubernetes/client-node': - specifier: ^1.4.0 - version: 1.4.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + specifier: ^2.0.0 + version: 2.0.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@lezer/highlight': specifier: ^1.2.3 version: 1.2.3 @@ -100,8 +100,8 @@ importers: specifier: ^8.3.0 version: 8.3.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) restty: - specifier: ^0.1.35 - version: 0.1.35(typescript@7.0.2) + specifier: 0.2.6 + version: 0.2.6 tailwind-merge: specifier: 3.6.0 version: 3.6.0 @@ -177,7 +177,7 @@ importers: version: 8.2.2(@types/node@26.3.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.39.0)(tsx@4.23.12)(yaml@2.9.0) vitepress: specifier: next - version: 2.0.0-alpha.12(@types/node@26.3.0)(jiti@2.7.0)(lightningcss@1.33.0)(postcss@8.5.26)(terser@5.39.0)(tsx@4.23.12)(typescript@7.0.2)(yaml@2.9.0) + version: 2.0.0-alpha.19(@types/node@26.3.0)(esbuild@0.28.2)(jiti@2.7.0)(postcss@8.5.26)(terser@5.39.0)(tsx@4.23.12)(typescript@7.0.2)(yaml@2.9.0) vitest: specifier: ^4.1.11 version: 4.1.11(@types/node@26.3.0)(vite@8.2.2(@types/node@26.3.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.39.0)(tsx@4.23.12)(yaml@2.9.0)) @@ -481,11 +481,14 @@ packages: peerDependencies: react: '>=16.8.0' - '@docsearch/css@4.0.0-beta.7': - resolution: {integrity: sha512-hBIwf14yLasrUcDNS7jrneM1ibFD/JFJVDjdxd1h/LUHx7eyLrS726pKHVr3cTdToNXP/7jrTbnC1MAuDHPoow==} + '@docsearch/css@4.7.0': + resolution: {integrity: sha512-Sk5xkdRFeE7PeWjG9l4AfTwdvMfr9wHiwNNCpHXT4v4SNyNMKdHGvEILc31BgaVFGDDNbv5u/a73tofRiwbEZw==} - '@docsearch/js@4.0.0-beta.7': - resolution: {integrity: sha512-0RJALbDpLMuFy3H/26rjms/qwi5KjsGMN8Lu4k/bs6kBfOWHUN6Dzg/ybj8qB2OLdT2UegsavRIDZKW3QrzQ4Q==} + '@docsearch/js@4.7.0': + resolution: {integrity: sha512-x5lCqu1tetgsJFkjQ6VSocbHldsRkGEgwg5N98Vx21sq/V5wcmj4u226PY9k+TEpIgQ772zlYbPLTPicWyGnpA==} + + '@docsearch/sidepanel-js@4.7.0': + resolution: {integrity: sha512-A8r34jCU8kcIk2viECEn2msA28ojUF1BLi/3v5OWWc5G2N3jOuuumBXoeYjfr8dA0UxgFSy5R2bt12dnFJQSyA==} '@drizzle-team/brocli@0.11.0': resolution: {integrity: sha512-hD3pekGiPg0WPCCGAZmusBBJsDqGUR66Y452YgQsZOnkdQ7ViEPKuyP4huUGEZQefp8g34RRodXYmJ2TbCH+tg==} @@ -834,8 +837,8 @@ packages: engines: {node: '>=6'} hasBin: true - '@iconify-json/simple-icons@1.2.48': - resolution: {integrity: sha512-EACOtZMoPJtERiAbX1De0asrrCtlwI27+03c9OJlYWsly9w1O5vcD8rTzh+kDPjo+K8FOVnq2Qy+h/CzljSKDA==} + '@iconify-json/simple-icons@1.2.93': + resolution: {integrity: sha512-/XhANjfGYOuqvSR3TmUnkQkINvQ4GVjVuukvymRbxtVFBvIq/yiXJqCDycKcQPT401OYT9H2vIY6ihAlz1QIAw==} '@iconify/react@6.0.2': resolution: {integrity: sha512-SMmC2sactfpJD427WJEDN6PMyznTFMhByK9yLW0gOTtnjzzbsi/Ke/XqsumsavFPwNiXs8jSiYeZTmLCLwO+Fg==} @@ -893,8 +896,8 @@ packages: peerDependencies: jsep: ^0.4.0||^1.0.0 - '@kubernetes/client-node@1.4.0': - resolution: {integrity: sha512-Zge3YvF7DJi264dU1b3wb/GmzR99JhUpqTvp+VGHfwZT+g7EOOYNScDJNZwXy9cszyIGPIs0VHr+kk8e95qqrA==} + '@kubernetes/client-node@2.0.0': + resolution: {integrity: sha512-Jx2cRxEVb4XkDNiR/cg8SX9dH6ZHdMhKmZdQcfhn2vdBWHdb2ldwM0P3I0dK4msYhFmC6TCODsNHH144IpA06w==} '@kwsites/file-exists@1.1.1': resolution: {integrity: sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==} @@ -1399,157 +1402,40 @@ packages: cpu: [x64] os: [win32] - '@rolldown/pluginutils@1.0.0-beta.29': - resolution: {integrity: sha512-NIJgOsMjbxAXvoGq/X0gD7VPMQ8j9g0BiDaNjVNVjvl+iKXxL3Jre0v31RmBYeLEmkbj2s02v8vFTbUXi5XS2Q==} - '@rolldown/pluginutils@1.0.1': resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} - '@rollup/rollup-android-arm-eabi@4.62.2': - resolution: {integrity: sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==} - cpu: [arm] - os: [android] + '@shikijs/core@4.4.3': + resolution: {integrity: sha512-QCR4q2ZO/ILJEuwiBMel4wdcTDb1JGwfjKTxPDF6x8ixOaluPrVqIn06C99AcRPhmYlBR56d/Fb+GN58GzExpg==} + engines: {node: '>=20'} - '@rollup/rollup-android-arm64@4.62.2': - resolution: {integrity: sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==} - cpu: [arm64] - os: [android] + '@shikijs/engine-javascript@4.4.3': + resolution: {integrity: sha512-FbOjFJp9VLdo1Wevs10BBtVxiTWwNLqZh5Gkhjgda/ioL15YOgeSl9n+6XMa3qRlPQzfhFNe641SrynFHYG0nQ==} + engines: {node: '>=20'} - '@rollup/rollup-darwin-arm64@4.62.2': - resolution: {integrity: sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==} - cpu: [arm64] - os: [darwin] + '@shikijs/engine-oniguruma@4.4.3': + resolution: {integrity: sha512-EcOQkxdxGQrc1Row/cC2c96/v1dbZqGnEVu1qTuT/MJmp6+cXCvQussowVmCv5Tqr3KuY3c7IbM6HTW3LJ1k9w==} + engines: {node: '>=20'} - '@rollup/rollup-darwin-x64@4.62.2': - resolution: {integrity: sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==} - cpu: [x64] - os: [darwin] + '@shikijs/langs@4.4.3': + resolution: {integrity: sha512-ePic0yfAJGOF83D5wBHK/00EjK65oahBYxFk5epgq33WRv7X9UuxLEV8PtR0szC0z8dl7INIpIodB99JRFlR+A==} + engines: {node: '>=20'} - '@rollup/rollup-freebsd-arm64@4.62.2': - resolution: {integrity: sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==} - cpu: [arm64] - os: [freebsd] + '@shikijs/primitive@4.4.3': + resolution: {integrity: sha512-m0wBeLDQDeIxRdUmrCPdQqfuUamDwRL5isCfYbguKD6NiaKpVbsv+3J81DyIKgNW5h4WAIIr8T4EkgQrBBxvaQ==} + engines: {node: '>=20'} - '@rollup/rollup-freebsd-x64@4.62.2': - resolution: {integrity: sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==} - cpu: [x64] - os: [freebsd] + '@shikijs/themes@4.4.3': + resolution: {integrity: sha512-w8UHjeUnIR965KMWJHUPXOc2mNJUnK3vpVLYLvw5IYU2mnTTJ89E24OrJDBNiJDQ0qzb0tc4l7mrIXx5cFeIyw==} + engines: {node: '>=20'} - '@rollup/rollup-linux-arm-gnueabihf@4.62.2': - resolution: {integrity: sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==} - cpu: [arm] - os: [linux] + '@shikijs/transformers@4.4.3': + resolution: {integrity: sha512-oJSARV6NaWd+rnNJbtnpAdj3Zg0ZVyzsnMgb3vi3HA+35y8lBWUCpOnWsmyiXZIikY+x1BDqrQUgmxfzWh7Jvw==} + engines: {node: '>=20'} - '@rollup/rollup-linux-arm-musleabihf@4.62.2': - resolution: {integrity: sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm64-gnu@4.62.2': - resolution: {integrity: sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-arm64-musl@4.62.2': - resolution: {integrity: sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-loong64-gnu@4.62.2': - resolution: {integrity: sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-loong64-musl@4.62.2': - resolution: {integrity: sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-ppc64-gnu@4.62.2': - resolution: {integrity: sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-ppc64-musl@4.62.2': - resolution: {integrity: sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-riscv64-gnu@4.62.2': - resolution: {integrity: sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-riscv64-musl@4.62.2': - resolution: {integrity: sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.62.2': - resolution: {integrity: sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==} - cpu: [s390x] - os: [linux] - - '@rollup/rollup-linux-x64-gnu@4.62.2': - resolution: {integrity: sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-linux-x64-musl@4.62.2': - resolution: {integrity: sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-openbsd-x64@4.62.2': - resolution: {integrity: sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==} - cpu: [x64] - os: [openbsd] - - '@rollup/rollup-openharmony-arm64@4.62.2': - resolution: {integrity: sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==} - cpu: [arm64] - os: [openharmony] - - '@rollup/rollup-win32-arm64-msvc@4.62.2': - resolution: {integrity: sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.62.2': - resolution: {integrity: sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-gnu@4.62.2': - resolution: {integrity: sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==} - cpu: [x64] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.62.2': - resolution: {integrity: sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==} - 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/types@4.4.3': + resolution: {integrity: sha512-UEJxmRR++MAGR6hugn0vgVS2W/6lWAts84FFSrnlH9sP0LNol7E5+NQ792pH8liWUhyMyjhTgSUH3k7iD7tc5g==} + engines: {node: '>=20'} '@shikijs/vscode-textmate@10.0.2': resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} @@ -1671,8 +1557,8 @@ packages: '@types/estree@1.0.9': resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} - '@types/hast@3.0.4': - resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + '@types/hast@3.0.5': + resolution: {integrity: sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==} '@types/js-yaml@4.0.9': resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==} @@ -1692,15 +1578,9 @@ packages: '@types/mssql@9.1.9': resolution: {integrity: sha512-P0nCgw6vzY23UxZMnbI4N7fnLGANt4LI4yvxze1paPj+LuN28cFv5EI+QidP8udnId/BKhkcRhm/BleNsjK65A==} - '@types/node-fetch@2.6.13': - resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==} - '@types/node@18.19.130': resolution: {integrity: sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==} - '@types/node@24.13.3': - resolution: {integrity: sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==} - '@types/node@26.3.0': resolution: {integrity: sha512-L3fgrnchriRC2ExBflb8j4uZZURHZfQsmQeyVzhjcHW4kkwVyo8/0h1B2MVzMTrYUJYu6G7EWs14hW/L9putqw==} @@ -1886,11 +1766,11 @@ packages: resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} deprecated: Potential CWE-502 - Update to 1.3.1 or higher - '@vitejs/plugin-vue@6.0.1': - resolution: {integrity: sha512-+MaE752hU0wfPFJEUAIxqw18+20euHHdxVtMvbFcOEpjEyfqXH/5DCoTHiVJ0J29EhTJdoTkjEv5YBKU9dnoTw==} + '@vitejs/plugin-vue@6.0.8': + resolution: {integrity: sha512-0ZjgOg7oO6farnNGup7yvoM/YXZV84OZxHAwtflItNa/6zzQyVb5LNxyea3FEKEX2XlagIKzrlH7wwxkKgtiew==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: - vite: ^5.0.0 || ^6.0.0 || ^7.0.0 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 vue: ^3.2.25 '@vitest/expect@4.1.11': @@ -1922,57 +1802,55 @@ packages: '@vitest/utils@4.1.11': resolution: {integrity: sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==} - '@vue/compiler-core@3.5.18': - resolution: {integrity: sha512-3slwjQrrV1TO8MoXgy3aynDQ7lslj5UqDxuHnrzHtpON5CBinhWjJETciPngpin/T3OuW3tXUf86tEurusnztw==} + '@vue/compiler-core@3.5.42': + resolution: {integrity: sha512-2Ye1ilMtKXxl8qZUrQ5j0CdgenFp/HFQmta6rfRyfEsTG69L6Wk+tWuNoHYHMx9E8tF2Slvdg1FuwDvAXdy1LQ==} - '@vue/compiler-dom@3.5.18': - resolution: {integrity: sha512-RMbU6NTU70++B1JyVJbNbeFkK+A+Q7y9XKE2EM4NLGm2WFR8x9MbAtWxPPLdm0wUkuZv9trpwfSlL6tjdIa1+A==} + '@vue/compiler-dom@3.5.42': + resolution: {integrity: sha512-qbhQZEFmycr+ni/qyuccS4sucNN7VAbDfbkvNxWOX2VfgFm90MNs3/UhRNKoPMEIVn0F8gdlYjLPvqxHwHeQOA==} - '@vue/compiler-sfc@3.5.18': - resolution: {integrity: sha512-5aBjvGqsWs+MoxswZPoTB9nSDb3dhd1x30xrrltKujlCxo48j8HGDNj3QPhF4VIS0VQDUrA1xUfp2hEa+FNyXA==} + '@vue/compiler-sfc@3.5.42': + resolution: {integrity: sha512-fkCAFB4okcAANGMThboWnScp/gzWjU0ZSkVnjTIiplmMDq2uq0tIB3j+xVu4rhv5rvOgBySCysudmbMd6xRRqw==} - '@vue/compiler-ssr@3.5.18': - resolution: {integrity: sha512-xM16Ak7rSWHkM3m22NlmcdIM+K4BMyFARAfV9hYFl+SFuRzrZ3uGMNW05kA5pmeMa0X9X963Kgou7ufdbpOP9g==} + '@vue/compiler-ssr@3.5.42': + resolution: {integrity: sha512-xmLk3wLkbizPAiLyomjgFFosf2ys9b5Ghb+oh/k2tnvipNz8OFrQOiTcWCzyK7MpBp9KkyGtfvgfLUivbmuGYA==} - '@vue/devtools-api@8.0.0': - resolution: {integrity: sha512-I2jF/knesMU36zTw1hnExjoixDZvDoantiWKVrHpLd2J160zqqe8vp3vrGfjWdfuHmPJwSXe/YNG3rYOYiwy1Q==} + '@vue/devtools-api@8.2.1': + resolution: {integrity: sha512-6u4vXBlIBAC1wMplIZgpyPn7uh/s4Bf6F5bMzvLv+EdJ0aHs/+4B7Ygv864EStQSjRbsRzTko/kUG1A1IejQ3A==} - '@vue/devtools-kit@8.0.0': - resolution: {integrity: sha512-b11OeQODkE0bctdT0RhL684pEV2DPXJ80bjpywVCbFn1PxuL3bmMPDoJKjbMnnoWbrnUYXYzFfmMWBZAMhORkQ==} + '@vue/devtools-kit@8.2.1': + resolution: {integrity: sha512-FIGIuq3AWReEpbAHY/cRGeHDfI0qOb8OCQ3YjbEAX04uaxIDbGc9rhkbVcG7rnfHPXE3RsU5KrWOu9V/okd8AQ==} - '@vue/devtools-shared@8.0.0': - resolution: {integrity: sha512-jrKnbjshQCiOAJanoeJjTU7WaCg0Dz2BUal6SaR6VM/P3hiFdX5Q6Pxl73ZMnrhCxNK9nAg5hvvRGqs+6dtU1g==} + '@vue/devtools-shared@8.2.1': + resolution: {integrity: sha512-Fkac7lUdGReh6pVOi3AYPRGe82LQqRmAfThW7RRligOAP0ZA/Z1z9XLHDM9dv34pV2HRc79DK8uKPeG2fLnA/g==} - '@vue/reactivity@3.5.18': - resolution: {integrity: sha512-x0vPO5Imw+3sChLM5Y+B6G1zPjwdOri9e8V21NnTnlEvkxatHEH5B5KEAJcjuzQ7BsjGrKtfzuQ5eQwXh8HXBg==} + '@vue/reactivity@3.5.42': + resolution: {integrity: sha512-TzNNfKpb7hDxbQltwAut8VDQA5YP+BuRlxntHUuRjyKwlMvmAPbs3unhCvieijifY6vFfVBwsS7wG/C7uq+bEQ==} - '@vue/runtime-core@3.5.18': - resolution: {integrity: sha512-DUpHa1HpeOQEt6+3nheUfqVXRog2kivkXHUhoqJiKR33SO4x+a5uNOMkV487WPerQkL0vUuRvq/7JhRgLW3S+w==} + '@vue/runtime-core@3.5.42': + resolution: {integrity: sha512-9uACtuHs7vJGkm5Bp3xu4xRDLFTIYy5DgxpToVjqGIAhAEKwQfsaLvKINhM6nFVp6bZPRFGdDqd1g52MqKsotA==} - '@vue/runtime-dom@3.5.18': - resolution: {integrity: sha512-YwDj71iV05j4RnzZnZtGaXwPoUWeRsqinblgVJwR8XTXYZ9D5PbahHQgsbmzUvCWNF6x7siQ89HgnX5eWkr3mw==} + '@vue/runtime-dom@3.5.42': + resolution: {integrity: sha512-rsCmhiWLaRxGltLwhlCWyYkFn7WAbKRh0q17eZ1A6Dq6eqc2ACQ61IIryxz0LrsvCzHSilLA9JHovVwM8CNE2g==} - '@vue/server-renderer@3.5.18': - resolution: {integrity: sha512-PvIHLUoWgSbDG7zLHqSqaCoZvHi6NNmfVFOqO+OnwvqMz/tqQr3FuGWS8ufluNddk7ZLBJYMrjcw1c6XzR12mA==} - peerDependencies: - vue: 3.5.18 + '@vue/server-renderer@3.5.42': + resolution: {integrity: sha512-2++5dUyYS4gvo7xQXSECUDhB7TS0aOl5SeVfC5qSq1Jgfhjvegw1zqhwTIR3imZ+QYPJQw9gfcFvXGAjGZ7ajQ==} - '@vue/shared@3.5.18': - resolution: {integrity: sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA==} + '@vue/shared@3.5.42': + resolution: {integrity: sha512-2rPxex1jQf4jvl9MOHl6YaXCPcrNqz/FstMOEh3QWY+/OME9nQTvl9WYeCwhW7AFjaR0SnngZGlp/wkR6rkI6g==} - '@vueuse/core@13.7.0': - resolution: {integrity: sha512-myagn09+c6BmS6yHc1gTwwsdZilAovHslMjyykmZH3JNyzI5HoWhv114IIdytXiPipdHJ2gDUx0PB93jRduJYg==} + '@vueuse/core@14.4.0': + resolution: {integrity: sha512-X4WHz1HlCzCBoYXesUkifzzWBAcZgXG8Fi5iNPQg/epdzOB3gu8Fawj3hvuwYR1nGcXGnvxwYYcUC/71++svtQ==} peerDependencies: vue: ^3.5.0 - '@vueuse/integrations@13.7.0': - resolution: {integrity: sha512-Na5p0ONLepNV/xCBi8vBMuzCOZh9CFT/OHnrUlABWXgWTWSHM3wrVaLS1xvAijPLU5B1ysyJDDW/hKak80oLGA==} + '@vueuse/integrations@14.4.0': + resolution: {integrity: sha512-oJz9qTgczvA7L1nXQFRU7h8tQbOCoiceqvMMhT9XYMyOGTqLJ2rEa09PON+nD2t48sZUfeOmg4eaWJXV4sZb/w==} peerDependencies: async-validator: ^4 axios: ^1 change-case: ^5 drauu: ^0.4 - focus-trap: ^7 + focus-trap: ^7 || ^8 fuse.js: ^7 idb-keyval: ^6 jwt-decode: ^4 @@ -2007,11 +1885,11 @@ packages: universal-cookie: optional: true - '@vueuse/metadata@13.7.0': - resolution: {integrity: sha512-8okFhS/1ite8EwUdZZfvTYowNTfXmVCOrBFlA31O0HD8HKXhY+WtTRyF0LwbpJfoFPc+s9anNJIXMVrvP7UTZg==} + '@vueuse/metadata@14.4.0': + resolution: {integrity: sha512-swx/255R6JyHZFJhx845iz5CRWDZdCfvkZOpACWc5+c5WHcG24mv8gUT1WIdFQaHt6dq79rvILd9QnCWiyVm9g==} - '@vueuse/shared@13.7.0': - resolution: {integrity: sha512-Wi2LpJi4UA9kM0OZ0FCZslACp92HlVNw1KPaDY6RAzvQ+J1s7seOtcOpmkfbD5aBSmMn9NvOakc8ZxMxmDXTIg==} + '@vueuse/shared@14.4.0': + resolution: {integrity: sha512-JRgY90Sz8DDtPMsaDflvPMp9xYk69JZAmbuDvAquUVXKr2gEjqtzGNTTthLfckH0BzBqvnu31gb4a8TGLRe79g==} peerDependencies: vue: ^3.5.0 @@ -2028,6 +1906,10 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} + agent-base@9.0.0: + resolution: {integrity: sha512-TQf59BsZnytt8GdJKLPfUZ54g/iaUL2OWDSFCCvMOhsHduDQxO8xC4PNeyIkVcA5KwL2phPSv0douC0fgWzmnA==} + engines: {node: '>= 20'} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -2081,14 +1963,6 @@ packages: resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} engines: {node: '>=8.0.0'} - b4a@1.7.3: - resolution: {integrity: sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==} - peerDependencies: - react-native-b4a: '*' - peerDependenciesMeta: - react-native-b4a: - optional: true - b4a@1.8.1: resolution: {integrity: sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==} peerDependencies: @@ -2119,15 +1993,6 @@ packages: bare-abort-controller: optional: true - bare-fs@4.5.1: - resolution: {integrity: sha512-zGUCsm3yv/ePt2PHNbVxjjn0nNB1MkIaR4wOCxJ2ig5pCf5cCVAYJXVhQg/3OhhJV6DB1ts7Hv0oUaElc2TPQg==} - engines: {bare: '>=1.16.0'} - peerDependencies: - bare-buffer: '*' - peerDependenciesMeta: - bare-buffer: - optional: true - bare-fs@4.8.1: resolution: {integrity: sha512-N1nnXdHZAOSstz0XiHikGS4HGMH4CnSwhqWdGQQMqqdvp4Jybm9sE3R1WVnpWVd4SFkc8ryPDBLViNLwiEqECg==} engines: {bare: '>=1.28.0'} @@ -2137,13 +2002,6 @@ packages: bare-buffer: optional: true - bare-os@3.8.7: - resolution: {integrity: sha512-G4Gr1UsGeEy2qtDTZwL7JFLo2wapUarz7iTMcYcMFdS89AIQuBoyjgXZz0Utv7uHs3xA9LckhVbeBi8lEQrC+w==} - engines: {bare: '>=1.14.0'} - - bare-path@3.0.0: - resolution: {integrity: sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==} - bare-path@3.1.1: resolution: {integrity: sha512-JprUlveX3QjApC1cTpsUOiscADftCGVWkzitbHsRqv84hzYwYHw2mbluddsq5TvI8mH/8Ov1f4BiMAdcB0oYnQ==} @@ -2161,20 +2019,6 @@ packages: bare-events: optional: true - bare-stream@2.7.0: - resolution: {integrity: sha512-oyXQNicV1y8nc2aKffH+BUHFRXmx6VrPzlnaEvMhram0nPBrKcEdcyBg5r08D0i8VxngHFAiVyn1QKXpSG0B8A==} - peerDependencies: - bare-buffer: '*' - bare-events: '*' - peerDependenciesMeta: - bare-buffer: - optional: true - bare-events: - optional: true - - bare-url@2.3.2: - resolution: {integrity: sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw==} - bare-url@2.5.2: resolution: {integrity: sha512-L13PCJzKG8RGvx8V1/DdMi12ERhC3tprr7/8a94BxpmnRsFqxh5XZNdhtMxu5HPkRshYOOWRGY8lDP7ZhpG9Cg==} @@ -2195,8 +2039,8 @@ packages: bindings@1.5.0: resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} - birpc@2.5.0: - resolution: {integrity: sha512-VSWO/W6nNQdyP520F1mhf+Lc2f8pjGQOtoHHm7Ze8Go1kX7akpVIrtTa0fn+HB0QJEDVacl6aO08YE0PgXfdnQ==} + birpc@2.9.0: + resolution: {integrity: sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==} bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -2319,10 +2163,6 @@ packages: cookie-es@3.1.1: resolution: {integrity: sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==} - copy-anything@3.0.5: - resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} - engines: {node: '>=12.13'} - core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} @@ -2349,9 +2189,6 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - csstype@3.1.3: - resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} - csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} @@ -2432,10 +2269,12 @@ packages: drizzle-kit@1.0.0-beta.21: resolution: {integrity: sha512-qG1vkkXPhz9GJ6RZhM/DvzL5jeDNYn35cyGeFA0+8iZQ6GTP4FhbOltNDHh/8XNmcI89b40lXJuH1PdxaA7zdQ==} + deprecated: The 1.0.0-beta line is superseded by the 1.0 release candidate. Install drizzle-kit@rc instead. hasBin: true drizzle-orm@1.0.0-beta.21: resolution: {integrity: sha512-HZcIbVn5J9T/Z91Wj12Pn7Pi8/1aykS/GPJf2lXeZnEuPjxaBfQ+YAt0Sl+XI+9R/D1BpK+2fdIqbpuaTbcvqA==} + deprecated: The 1.0.0-beta line is superseded by the 1.0 release candidate. Install drizzle-orm@rc instead. peerDependencies: '@aws-sdk/client-rds-data': '>=3' '@cloudflare/workers-types': '>=4' @@ -2575,8 +2414,8 @@ packages: resolution: {integrity: sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A==} engines: {node: '>=10.13.0'} - entities@4.5.0: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} engines: {node: '>=0.12'} es-define-property@1.0.1: @@ -2590,8 +2429,8 @@ packages: es-module-lexer@2.3.2: resolution: {integrity: sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==} - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} engines: {node: '>= 0.4'} es-set-tostringtag@2.1.0: @@ -2669,8 +2508,8 @@ packages: 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==} + focus-trap@8.2.2: + resolution: {integrity: sha512-qV0g8hRYBqgACcFOH3f9wXc4zPKhr/0z9RI2a6ZijZ72EeBi4g8oBy8zAWuUR1TsMpOzwpUMFvjdasrC41Joug==} foreground-child@3.3.1: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} @@ -2789,8 +2628,8 @@ packages: ini@1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - ip-address@10.2.0: - resolution: {integrity: sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==} + ip-address@10.5.0: + resolution: {integrity: sha512-R5SnVLJmgYYvf2F2ZgwSBnelz5G4q5AxIC277GDfUaNbrZKNANcBC7RHqYYePlszf4kBolVkJauG0ZjHHFh55g==} engines: {node: '>= 12'} is-docker@3.0.0: @@ -2811,10 +2650,6 @@ packages: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} - is-what@4.1.16: - resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} - engines: {node: '>=12.13'} - is-wsl@3.1.1: resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} engines: {node: '>=16'} @@ -2861,10 +2696,6 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-yaml@4.3.1: - resolution: {integrity: sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==} - hasBin: true - js-yaml@5.4.0: resolution: {integrity: sha512-jE7vUJIebKzYQI5xu4co5CRBDlDEYnHrdzsxs4O2giCz4v2SbVMYKpmt1D9L38OKQAeCWmrOTRiCV93u0UkaJA==} hasBin: true @@ -2886,8 +2717,8 @@ packages: engines: {node: '>=6'} hasBin: true - jsonpath-plus@10.3.0: - resolution: {integrity: sha512-8TNmfeTCk2Le33A3vRRwtuworG/L5RrgMvdjhKZxvyShO+mBu2fP50OWUjRLNtvw344DdDarFh9buFAZs5ujeA==} + jsonpath-plus@10.4.0: + resolution: {integrity: sha512-T92WWatJXmhBbKsgH/0hl+jxjdXrifi5IKeMY02DWggRxX0UElcbVzPlmgLTbvsPeW1PasQ6xE2Q75stkhGbsA==} engines: {node: '>=18.0.0'} hasBin: true @@ -3148,9 +2979,6 @@ packages: 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==} - magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} @@ -3211,11 +3039,8 @@ packages: resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} - minisearch@7.1.2: - resolution: {integrity: sha512-R1Pd9eF+MD5JYDDSPAp/q1ougKglm14uEkPMvQ/05RGmx6G9wvmLTrTI/Q5iPNJLYqNdsDQ7qTGIcNWR+FrHmA==} - - mitt@3.0.1: - resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + minisearch@7.2.0: + resolution: {integrity: sha512-dqT2XBYUOZOiC5t2HRnwADjhNS2cecp9u+TJRiJ1Qp/f5qjkeT5APcGPjHw+bz89Ms8Jp+cG4AlE+QZ/QnDglg==} mkdirp-classic@0.5.3: resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} @@ -3281,8 +3106,8 @@ packages: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - oauth4webapi@3.8.5: - resolution: {integrity: sha512-A8jmyUckVhRJj5lspguklcl90Ydqk61H3dcU0oLhH3Yv13KpAliKTt5hknpGGPZSSfOwGyraNEFmofDYH+1kSg==} + oauth4webapi@3.8.7: + resolution: {integrity: sha512-4RxcKxXjuItDFZ20RRPf4YTw3kpeXJyCgJFxVzJ068A7PNJ18st2Dg90tlC1LkSDS0GecroagCLHYEIVUhCAkw==} obug@2.1.4: resolution: {integrity: sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==} @@ -3295,18 +3120,18 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - oniguruma-parser@0.12.1: - resolution: {integrity: sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==} + oniguruma-parser@0.12.2: + resolution: {integrity: sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==} - oniguruma-to-es@4.3.3: - resolution: {integrity: sha512-rPiZhzC3wXwE59YQMRDodUwwT9FZ9nNBwQQfsd1wfdtlKEyCdRV0avrTcSZ5xlIvGRVPd/cx6ZN45ECmS39xvg==} + oniguruma-to-es@4.3.6: + resolution: {integrity: sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==} open@10.2.0: resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} engines: {node: '>=18'} - openid-client@6.8.2: - resolution: {integrity: sha512-uOvTCndr4udZsKihJ68H9bUICrriHdUVJ6Az+4Ns6cW55rwM5h0bjVIzDz2SxgOI84LKjFyjOFvERLzdTUROGA==} + openid-client@6.8.7: + resolution: {integrity: sha512-gtKthNu7evSBvTdrrlHb4F3Fi9dcwlb5QaITlCs+9mfpvuOi0Q3qtBf5+iY4sEP8hy1qCoAdxBNPDcmZeVSDzQ==} oxfmt@0.65.0: resolution: {integrity: sha512-SgS5VgnP42T0zl3zWD+xoH8FCqg1SAFnSRoOT/qeoa6gxcYIqrDMOmcXIg/EWSN92Du4ogB4riuKhKd6Y4CGhw==} @@ -3356,8 +3181,8 @@ packages: pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - perfect-debounce@1.0.0: - resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + perfect-debounce@2.1.0: + resolution: {integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==} picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -3425,9 +3250,6 @@ packages: resolution: {integrity: sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw==} engines: {node: '>=12.0.0'} - pump@3.0.3: - resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} - pump@3.0.4: resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} @@ -3512,8 +3334,8 @@ packages: regex-utilities@2.3.0: resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} - regex@6.0.1: - resolution: {integrity: sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==} + regex@6.1.0: + resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==} require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} @@ -3525,8 +3347,8 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - restty@0.1.35: - resolution: {integrity: sha512-IUr4NsdYCTErKBxuAd0eu/KdiGZhADBxA0ddSPEEIxAz8np3RT1bLiL9iIH+wglmUeSmHRmJzkPN7hGJJ+E/Yw==} + restty@0.2.6: + resolution: {integrity: sha512-wFMXIJ6RqADBnyEN7jc9+v9qcNatFt18IFiqgyBngVPd4VvdOh93f+Nlr1RvOi4agq4T9BUKwYjIRkhmga9+4w==} engines: {bun: '>=1.2.0'} retry@0.12.0: @@ -3544,11 +3366,6 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - rollup@4.62.2: - resolution: {integrity: sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - run-applescript@7.1.0: resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} engines: {node: '>=18'} @@ -3589,8 +3406,9 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - shiki@3.9.2: - resolution: {integrity: sha512-t6NKl5e/zGTvw/IyftLcumolgOczhuroqwXngDeMqJ3h3EQiTY/7wmfgPlsmloD8oYfqkEDqxiaH37Pjm1zUhQ==} + shiki@4.4.3: + resolution: {integrity: sha512-Mb/GvXPHBAXdgGIcnfU5L3ldpn1XcxrGkPHwqgRx17/I2XRfqlFKk2vGkHWINn1kdXvzJZeuO3is6I9KLPFm0g==} + engines: {node: '>=20'} siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} @@ -3612,12 +3430,12 @@ packages: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} - socks-proxy-agent@8.0.5: - resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==} - engines: {node: '>= 14'} + socks-proxy-agent@10.1.0: + resolution: {integrity: sha512-WlMj/67cEJ6MDI1OcsnjuYKDNDoyPCCYZ249kuuXPiMDw9F8PXkVaQ7YWu3siTydfQ/4BEZcvGzu+aYvz7dDCQ==} + engines: {node: '>= 20'} - socks@2.8.7: - resolution: {integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==} + socks@2.8.9: + resolution: {integrity: sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==} engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} sonic-boom@4.2.1: @@ -3637,10 +3455,6 @@ packages: space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} - speakingurl@14.0.1: - resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} - engines: {node: '>=0.10.0'} - split-ca@1.0.1: resolution: {integrity: sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ==} @@ -3668,9 +3482,6 @@ packages: resolution: {integrity: sha512-pqMqwQCso0PBJt2PQmDO0cFj0lyqmiwOMiMSkVtRokl7e+ZTRYgDHKnuZNbqjiJXgsg4nuqtD/zxuo9KqTp0Yw==} engines: {node: '>= 0.10.0'} - streamx@2.23.0: - resolution: {integrity: sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==} - streamx@2.28.1: resolution: {integrity: sha512-zEzXb0s5Cds7tqMH6rhZ05lcJydCWiQPEwiNngVqzsxCc962vLY4Uw+mW7od8kDH258k2Uz/JrOkdIAAhSh9VA==} @@ -3710,12 +3521,8 @@ packages: style-mod@4.1.3: resolution: {integrity: sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==} - superjson@2.2.2: - resolution: {integrity: sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==} - engines: {node: '>=16'} - - tabbable@6.2.0: - resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} + tabbable@6.5.0: + resolution: {integrity: sha512-wieBHXygIm7OyQOu5hQlkk62/WyCFYGlWg7L6/ZCUZwx0o398Zkn4pVmMyfYhfMG8kGrj/Krt8eIk6UKC6VzwA==} tailwind-merge@3.6.0: resolution: {integrity: sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==} @@ -3735,9 +3542,6 @@ packages: tar-fs@2.1.5: resolution: {integrity: sha512-OboTd8mmMhZDNPV+UjQcK9yKAatXu2aJ+r1w4im1Otd4M4fl2hwvdoXUxIYHFTHWK/3y3FarBP70v3vwmGlOxw==} - tar-fs@3.1.1: - resolution: {integrity: sha512-LZA0oaPOc2fVo82Txf3gw+AkEd38szODlptMYejQUhndHMLQ9M059uXR+AfS7DNo0NpINvSqDsvyaCrBVkptWg==} - tar-fs@3.1.3: resolution: {integrity: sha512-/hU4AXnIdZu+Gvl1pk0oI5f5HxWsCJRtY2aFaJdk9VvyL48DWU6iU5WAIPG+wIi1YvWA6eTJvIviP/tMAZZNwQ==} @@ -3745,9 +3549,6 @@ packages: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} engines: {node: '>=6'} - tar-stream@3.1.7: - resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} - tar-stream@3.2.1: resolution: {integrity: sha512-nqsEO8zLZJvrOMdEwkA0QdCLFbetHMn95Zqu4fKwX+hkaTWJPZZOrxx/PwtxoK0MMGQmBQNRW3CPs8IFYQz4cQ==} @@ -3775,16 +3576,11 @@ packages: resolution: {integrity: sha512-YjDLqIITuhGLMnM10yhg3oV6lIG5IMpz1R1DPBZoOOks83q7i7IVpeSWRTiyl7roozjiyLmwIoLK/KY8OnZmIA==} engines: {node: '>= 22.22'} - text-decoder@1.2.3: - resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==} - text-decoder@1.2.7: resolution: {integrity: sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==} - text-shaper@0.1.22: - resolution: {integrity: sha512-OYxqPcNEox3tlXilxZVPNub8EU/A6Lxy9vlCAe362fiGI9f3pMav497wL7cecX0CPq1yVtiBn/lii/ZZUUk9bQ==} - peerDependencies: - typescript: ^5 + text-shaper@0.1.28: + resolution: {integrity: sha512-uwm6+tkgYJ4hsTV0wZVHkZeoXR1/mthLxDiJvfU9o/FiibNinpFRC8PAMTNx8SaOjaK/5ZjDG1XAkPbKlIe2Jg==} thread-stream@4.2.0: resolution: {integrity: sha512-e2zZ96wSChazBsbENf/Pcm/4swHt2cEKQ92rhUjkL9GCKiTDJIaTBenjE/m9DXi0QBmTMDkFDdOomUy20A1tDQ==} @@ -3845,9 +3641,6 @@ packages: undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - undici-types@7.18.2: - resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} - undici-types@8.3.0: resolution: {integrity: sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==} @@ -3902,46 +3695,6 @@ packages: vfile@6.0.3: resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} - vite@7.3.6: - resolution: {integrity: sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - jiti: '>=1.21.0' - less: ^4.0.0 - lightningcss: ^1.21.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 - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - vite@8.2.2: resolution: {integrity: sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3985,18 +3738,15 @@ packages: yaml: optional: true - vitepress@2.0.0-alpha.12: - resolution: {integrity: sha512-yZwCwRRepcpN5QeAhwSnEJxS3I6zJcVixqL1dnm6km4cnriLpQyy2sXQDsE5Ti3pxGPbhU51nTMwI+XC1KNnJg==} + vitepress@2.0.0-alpha.19: + resolution: {integrity: sha512-WnBsb0Bwr43kXKyiis+lld/7ri3hnMbthS8N3hpFtjjwsdLO4IRmiAE08D7aud4q6oMDf9uwRowxzNqRFe/amw==} hasBin: true peerDependencies: markdown-it-mathjax3: ^4 - oxc-minify: ^0.82.1 postcss: ^8 peerDependenciesMeta: markdown-it-mathjax3: optional: true - oxc-minify: - optional: true postcss: optional: true @@ -4041,8 +3791,8 @@ packages: jsdom: optional: true - vue@3.5.18: - resolution: {integrity: sha512-7W4Y4ZbMiQ3SEo+m9lnoNpV9xG7QVMLa+/0RFwwiAVkeYoyGXqWE85jabU4pllJNUzqfLShJ5YLptewhCWUgNA==} + vue@3.5.42: + resolution: {integrity: sha512-4RyHQTbQvOPs3MfvUO1Sg0YRrKNnA0mAVtvpd12Tg1fKDN7OHBUl1IqSn8zGJjK9nI3NkNp8cgTpVrSZC5TTcA==} peerDependencies: typescript: '*' peerDependenciesMeta: @@ -4083,18 +3833,6 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - ws@8.21.0: - resolution: {integrity: sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==} - 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.21.3: resolution: {integrity: sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==} engines: {node: '>=10.0.0'} @@ -4590,9 +4328,11 @@ snapshots: react: 19.2.8 tslib: 2.8.1 - '@docsearch/css@4.0.0-beta.7': {} + '@docsearch/css@4.7.0': {} - '@docsearch/js@4.0.0-beta.7': {} + '@docsearch/js@4.7.0': {} + + '@docsearch/sidepanel-js@4.7.0': {} '@drizzle-team/brocli@0.11.0': {} @@ -4790,7 +4530,7 @@ snapshots: protobufjs: 7.6.5 yargs: 17.7.3 - '@iconify-json/simple-icons@1.2.48': + '@iconify-json/simple-icons@1.2.93': dependencies: '@iconify/types': 2.0.0 @@ -4853,29 +4593,28 @@ snapshots: dependencies: jsep: 1.4.0 - '@kubernetes/client-node@1.4.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + '@kubernetes/client-node@2.0.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': dependencies: '@types/js-yaml': 4.0.9 - '@types/node': 24.13.3 - '@types/node-fetch': 2.6.13 + '@types/node': 26.3.0 '@types/stream-buffers': 3.0.8 form-data: 4.0.6 hpagent: 1.2.0 - isomorphic-ws: 5.0.0(ws@8.21.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - js-yaml: 4.3.1 - jsonpath-plus: 10.3.0 - node-fetch: 2.7.0 - openid-client: 6.8.2 + isomorphic-ws: 5.0.0(ws@8.21.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + js-yaml: 5.4.0 + jsonpath-plus: 10.4.0 + openid-client: 6.8.7 rfc4648: 1.5.4 - socks-proxy-agent: 8.0.5 + socks: 2.8.9 + socks-proxy-agent: 10.1.0 stream-buffers: 3.0.3 - tar-fs: 3.1.1 - ws: 8.21.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + tar-fs: 3.1.3 + undici: 8.10.0 + ws: 8.21.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) transitivePeerDependencies: - bare-abort-controller - bare-buffer - bufferutil - - encoding - react-native-b4a - supports-color - utf-8-validate @@ -5222,120 +4961,50 @@ snapshots: '@rolldown/binding-win32-x64-msvc@1.2.5': optional: true - '@rolldown/pluginutils@1.0.0-beta.29': {} - '@rolldown/pluginutils@1.0.1': {} - '@rollup/rollup-android-arm-eabi@4.62.2': - optional: true - - '@rollup/rollup-android-arm64@4.62.2': - optional: true - - '@rollup/rollup-darwin-arm64@4.62.2': - optional: true - - '@rollup/rollup-darwin-x64@4.62.2': - optional: true - - '@rollup/rollup-freebsd-arm64@4.62.2': - optional: true - - '@rollup/rollup-freebsd-x64@4.62.2': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.62.2': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.62.2': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.62.2': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.62.2': - optional: true - - '@rollup/rollup-linux-loong64-gnu@4.62.2': - optional: true - - '@rollup/rollup-linux-loong64-musl@4.62.2': - optional: true - - '@rollup/rollup-linux-ppc64-gnu@4.62.2': - optional: true - - '@rollup/rollup-linux-ppc64-musl@4.62.2': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.62.2': - optional: true - - '@rollup/rollup-linux-riscv64-musl@4.62.2': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.62.2': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.62.2': - optional: true - - '@rollup/rollup-linux-x64-musl@4.62.2': - optional: true - - '@rollup/rollup-openbsd-x64@4.62.2': - optional: true - - '@rollup/rollup-openharmony-arm64@4.62.2': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.62.2': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.62.2': - optional: true - - '@rollup/rollup-win32-x64-gnu@4.62.2': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.62.2': - optional: true - - '@shikijs/core@3.9.2': + '@shikijs/core@4.4.3': dependencies: - '@shikijs/types': 3.9.2 + '@shikijs/primitive': 4.4.3 + '@shikijs/types': 4.4.3 '@shikijs/vscode-textmate': 10.0.2 - '@types/hast': 3.0.4 + '@types/hast': 3.0.5 hast-util-to-html: 9.0.5 - '@shikijs/engine-javascript@3.9.2': + '@shikijs/engine-javascript@4.4.3': dependencies: - '@shikijs/types': 3.9.2 + '@shikijs/types': 4.4.3 '@shikijs/vscode-textmate': 10.0.2 - oniguruma-to-es: 4.3.3 + oniguruma-to-es: 4.3.6 - '@shikijs/engine-oniguruma@3.9.2': + '@shikijs/engine-oniguruma@4.4.3': dependencies: - '@shikijs/types': 3.9.2 + '@shikijs/types': 4.4.3 '@shikijs/vscode-textmate': 10.0.2 - '@shikijs/langs@3.9.2': + '@shikijs/langs@4.4.3': dependencies: - '@shikijs/types': 3.9.2 + '@shikijs/types': 4.4.3 - '@shikijs/themes@3.9.2': + '@shikijs/primitive@4.4.3': dependencies: - '@shikijs/types': 3.9.2 + '@shikijs/types': 4.4.3 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.5 - '@shikijs/transformers@3.9.2': + '@shikijs/themes@4.4.3': dependencies: - '@shikijs/core': 3.9.2 - '@shikijs/types': 3.9.2 + '@shikijs/types': 4.4.3 - '@shikijs/types@3.9.2': + '@shikijs/transformers@4.4.3': + dependencies: + '@shikijs/core': 4.4.3 + '@shikijs/types': 4.4.3 + + '@shikijs/types@4.4.3': dependencies: '@shikijs/vscode-textmate': 10.0.2 - '@types/hast': 3.0.4 + '@types/hast': 3.0.5 '@shikijs/vscode-textmate@10.0.2': {} @@ -5441,7 +5110,7 @@ snapshots: '@types/estree@1.0.9': {} - '@types/hast@3.0.4': + '@types/hast@3.0.5': dependencies: '@types/unist': 3.0.3 @@ -5468,19 +5137,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@types/node-fetch@2.6.13': - dependencies: - '@types/node': 26.3.0 - form-data: 4.0.6 - '@types/node@18.19.130': dependencies: undici-types: 5.26.5 - '@types/node@24.13.3': - dependencies: - undici-types: 7.18.2 - '@types/node@26.3.0': dependencies: undici-types: 8.3.0 @@ -5620,11 +5280,11 @@ snapshots: '@ungap/structured-clone@1.3.0': {} - '@vitejs/plugin-vue@6.0.1(vite@7.3.6(@types/node@26.3.0)(jiti@2.7.0)(lightningcss@1.33.0)(terser@5.39.0)(tsx@4.23.12)(yaml@2.9.0))(vue@3.5.18(typescript@7.0.2))': + '@vitejs/plugin-vue@6.0.8(vite@8.2.2(@types/node@26.3.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.39.0)(tsx@4.23.12)(yaml@2.9.0))(vue@3.5.42(typescript@7.0.2))': dependencies: - '@rolldown/pluginutils': 1.0.0-beta.29 - vite: 7.3.6(@types/node@26.3.0)(jiti@2.7.0)(lightningcss@1.33.0)(terser@5.39.0)(tsx@4.23.12)(yaml@2.9.0) - vue: 3.5.18(typescript@7.0.2) + '@rolldown/pluginutils': 1.0.1 + vite: 8.2.2(@types/node@26.3.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.39.0)(tsx@4.23.12)(yaml@2.9.0) + vue: 3.5.42(typescript@7.0.2) '@vitest/expect@4.1.11': dependencies: @@ -5667,98 +5327,93 @@ snapshots: convert-source-map: 2.0.0 tinyrainbow: 3.1.1 - '@vue/compiler-core@3.5.18': + '@vue/compiler-core@3.5.42': dependencies: '@babel/parser': 7.29.8 - '@vue/shared': 3.5.18 - entities: 4.5.0 + '@vue/shared': 3.5.42 + entities: 7.0.1 estree-walker: 2.0.2 source-map-js: 1.2.1 - '@vue/compiler-dom@3.5.18': + '@vue/compiler-dom@3.5.42': dependencies: - '@vue/compiler-core': 3.5.18 - '@vue/shared': 3.5.18 + '@vue/compiler-core': 3.5.42 + '@vue/shared': 3.5.42 - '@vue/compiler-sfc@3.5.18': + '@vue/compiler-sfc@3.5.42': dependencies: '@babel/parser': 7.29.8 - '@vue/compiler-core': 3.5.18 - '@vue/compiler-dom': 3.5.18 - '@vue/compiler-ssr': 3.5.18 - '@vue/shared': 3.5.18 + '@vue/compiler-core': 3.5.42 + '@vue/compiler-dom': 3.5.42 + '@vue/compiler-ssr': 3.5.42 + '@vue/shared': 3.5.42 estree-walker: 2.0.2 - magic-string: 0.30.17 + magic-string: 0.30.21 postcss: 8.5.26 source-map-js: 1.2.1 - '@vue/compiler-ssr@3.5.18': + '@vue/compiler-ssr@3.5.42': dependencies: - '@vue/compiler-dom': 3.5.18 - '@vue/shared': 3.5.18 + '@vue/compiler-dom': 3.5.42 + '@vue/shared': 3.5.42 - '@vue/devtools-api@8.0.0': + '@vue/devtools-api@8.2.1': dependencies: - '@vue/devtools-kit': 8.0.0 + '@vue/devtools-kit': 8.2.1 - '@vue/devtools-kit@8.0.0': + '@vue/devtools-kit@8.2.1': dependencies: - '@vue/devtools-shared': 8.0.0 - birpc: 2.5.0 + '@vue/devtools-shared': 8.2.1 + birpc: 2.9.0 hookable: 5.5.3 - mitt: 3.0.1 - perfect-debounce: 1.0.0 - speakingurl: 14.0.1 - superjson: 2.2.2 + perfect-debounce: 2.1.0 - '@vue/devtools-shared@8.0.0': + '@vue/devtools-shared@8.2.1': {} + + '@vue/reactivity@3.5.42': dependencies: - rfdc: 1.4.1 + '@vue/shared': 3.5.42 - '@vue/reactivity@3.5.18': + '@vue/runtime-core@3.5.42': dependencies: - '@vue/shared': 3.5.18 + '@vue/reactivity': 3.5.42 + '@vue/shared': 3.5.42 - '@vue/runtime-core@3.5.18': + '@vue/runtime-dom@3.5.42': dependencies: - '@vue/reactivity': 3.5.18 - '@vue/shared': 3.5.18 + '@vue/reactivity': 3.5.42 + '@vue/runtime-core': 3.5.42 + '@vue/shared': 3.5.42 + csstype: 3.2.3 - '@vue/runtime-dom@3.5.18': + '@vue/server-renderer@3.5.42': dependencies: - '@vue/reactivity': 3.5.18 - '@vue/runtime-core': 3.5.18 - '@vue/shared': 3.5.18 - csstype: 3.1.3 + '@vue/compiler-ssr': 3.5.42 + '@vue/runtime-dom': 3.5.42 + '@vue/shared': 3.5.42 - '@vue/server-renderer@3.5.18(vue@3.5.18(typescript@7.0.2))': - dependencies: - '@vue/compiler-ssr': 3.5.18 - '@vue/shared': 3.5.18 - vue: 3.5.18(typescript@7.0.2) + '@vue/shared@3.5.42': {} - '@vue/shared@3.5.18': {} - - '@vueuse/core@13.7.0(vue@3.5.18(typescript@7.0.2))': + '@vueuse/core@14.4.0(vue@3.5.42(typescript@7.0.2))': dependencies: '@types/web-bluetooth': 0.0.21 - '@vueuse/metadata': 13.7.0 - '@vueuse/shared': 13.7.0(vue@3.5.18(typescript@7.0.2)) - vue: 3.5.18(typescript@7.0.2) + '@vueuse/metadata': 14.4.0 + '@vueuse/shared': 14.4.0(vue@3.5.42(typescript@7.0.2)) + vue: 3.5.42(typescript@7.0.2) - '@vueuse/integrations@13.7.0(focus-trap@7.6.5)(vue@3.5.18(typescript@7.0.2))': + '@vueuse/integrations@14.4.0(focus-trap@8.2.2)(vue@3.5.42(typescript@7.0.2))': dependencies: - '@vueuse/core': 13.7.0(vue@3.5.18(typescript@7.0.2)) - '@vueuse/shared': 13.7.0(vue@3.5.18(typescript@7.0.2)) - vue: 3.5.18(typescript@7.0.2) + '@vueuse/core': 14.4.0(vue@3.5.42(typescript@7.0.2)) + '@vueuse/shared': 14.4.0(vue@3.5.42(typescript@7.0.2)) + vue: 3.5.42(typescript@7.0.2) optionalDependencies: - focus-trap: 7.6.5 + focus-trap: 8.2.2 - '@vueuse/metadata@13.7.0': {} + '@vueuse/metadata@14.4.0': {} - '@vueuse/shared@13.7.0(vue@3.5.18(typescript@7.0.2))': + '@vueuse/shared@14.4.0(vue@3.5.42(typescript@7.0.2))': dependencies: - vue: 3.5.18(typescript@7.0.2) + vue: 3.5.42(typescript@7.0.2) abort-controller@3.0.0: dependencies: @@ -5769,6 +5424,8 @@ snapshots: agent-base@7.1.4: {} + agent-base@9.0.0: {} + ansi-regex@5.0.1: {} ansi-regex@6.3.0: {} @@ -5829,8 +5486,6 @@ snapshots: atomic-sleep@1.0.0: {} - b4a@1.7.3: {} - b4a@1.8.1: {} babel-dead-code-elimination@1.0.12: @@ -5848,18 +5503,6 @@ snapshots: bare-events@2.9.1: {} - bare-fs@4.5.1: - dependencies: - bare-events: 2.8.2 - bare-path: 3.0.0 - bare-stream: 2.7.0(bare-events@2.8.2) - bare-url: 2.3.2 - fast-fifo: 1.3.2 - transitivePeerDependencies: - - bare-abort-controller - - react-native-b4a - optional: true - bare-fs@4.8.1: dependencies: bare-events: 2.9.1 @@ -5871,14 +5514,6 @@ snapshots: - bare-abort-controller - react-native-b4a - bare-os@3.8.7: - optional: true - - bare-path@3.0.0: - dependencies: - bare-os: 3.8.7 - optional: true - bare-path@3.1.1: {} bare-stream@2.13.3(bare-events@2.9.1): @@ -5891,21 +5526,6 @@ snapshots: transitivePeerDependencies: - react-native-b4a - bare-stream@2.7.0(bare-events@2.8.2): - dependencies: - streamx: 2.28.1 - optionalDependencies: - bare-events: 2.8.2 - transitivePeerDependencies: - - bare-abort-controller - - react-native-b4a - optional: true - - bare-url@2.3.2: - dependencies: - bare-path: 3.0.0 - optional: true - bare-url@2.5.2: dependencies: bare-path: 3.1.1 @@ -5929,7 +5549,7 @@ snapshots: file-uri-to-path: 1.0.0 optional: true - birpc@2.5.0: {} + birpc@2.9.0: {} bl@4.1.0: dependencies: @@ -6061,10 +5681,6 @@ snapshots: cookie-es@3.1.1: {} - copy-anything@3.0.5: - dependencies: - is-what: 4.1.16 - core-util-is@1.0.3: {} cpu-features@0.0.10: @@ -6095,8 +5711,6 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - csstype@3.1.3: {} - csstype@3.2.3: {} data-uri-to-buffer@4.0.1: @@ -6210,7 +5824,7 @@ snapshots: graceful-fs: 4.2.11 tapable: 2.3.3 - entities@4.5.0: {} + entities@7.0.1: {} es-define-property@1.0.1: {} @@ -6218,7 +5832,7 @@ snapshots: es-module-lexer@2.3.2: {} - es-object-atoms@1.1.1: + es-object-atoms@1.1.2: dependencies: es-errors: 1.3.0 @@ -6333,9 +5947,9 @@ snapshots: file-uri-to-path@1.0.0: optional: true - focus-trap@7.6.5: + focus-trap@8.2.2: dependencies: - tabbable: 6.2.0 + tabbable: 6.5.0 foreground-child@3.3.1: dependencies: @@ -6371,7 +5985,7 @@ snapshots: call-bind-apply-helpers: 1.0.2 es-define-property: 1.0.1 es-errors: 1.3.0 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 function-bind: 1.1.2 get-proto: 1.0.1 gopd: 1.2.0 @@ -6384,7 +5998,7 @@ snapshots: get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 get-tsconfig@4.13.7: dependencies: @@ -6418,7 +6032,7 @@ snapshots: hast-util-to-html@9.0.5: dependencies: - '@types/hast': 3.0.4 + '@types/hast': 3.0.5 '@types/unist': 3.0.3 ccount: 2.0.1 comma-separated-tokens: 2.0.3 @@ -6432,7 +6046,7 @@ snapshots: hast-util-whitespace@3.0.0: dependencies: - '@types/hast': 3.0.4 + '@types/hast': 3.0.5 help-me@5.0.0: {} @@ -6471,7 +6085,7 @@ snapshots: ini@1.3.8: optional: true - ip-address@10.2.0: {} + ip-address@10.5.0: {} is-docker@3.0.0: {} @@ -6483,8 +6097,6 @@ snapshots: is-stream@2.0.1: {} - is-what@4.1.16: {} - is-wsl@3.1.1: dependencies: is-inside-container: 1.0.0 @@ -6495,9 +6107,9 @@ snapshots: isexe@2.0.0: {} - isomorphic-ws@5.0.0(ws@8.21.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)): + isomorphic-ws@5.0.0(ws@8.21.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)): dependencies: - ws: 8.21.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ws: 8.21.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) jackspeak@3.4.3: dependencies: @@ -6520,10 +6132,6 @@ snapshots: js-tokens@4.0.0: {} - js-yaml@4.3.1: - dependencies: - argparse: 2.0.1 - js-yaml@5.4.0: dependencies: argparse: 2.0.1 @@ -6536,7 +6144,7 @@ snapshots: json5@2.2.3: {} - jsonpath-plus@10.3.0: + jsonpath-plus@10.4.0: dependencies: '@jsep-plugin/assignment': 1.3.0(jsep@1.4.0) '@jsep-plugin/regex': 1.0.4(jsep@1.4.0) @@ -6759,10 +6367,6 @@ snapshots: dependencies: react: 19.2.8 - magic-string@0.30.17: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -6773,7 +6377,7 @@ snapshots: mdast-util-to-hast@13.2.1: dependencies: - '@types/hast': 3.0.4 + '@types/hast': 3.0.5 '@types/mdast': 4.0.4 '@ungap/structured-clone': 1.3.0 devlop: 1.1.0 @@ -6823,9 +6427,7 @@ snapshots: minipass@7.1.3: {} - minisearch@7.1.2: {} - - mitt@3.0.1: {} + minisearch@7.2.0: {} mkdirp-classic@0.5.3: {} @@ -6865,6 +6467,7 @@ snapshots: node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 + optional: true node-fetch@3.3.2: dependencies: @@ -6880,7 +6483,7 @@ snapshots: normalize-path@3.0.0: {} - oauth4webapi@3.8.5: {} + oauth4webapi@3.8.7: {} obug@2.1.4: {} @@ -6890,12 +6493,12 @@ snapshots: dependencies: wrappy: 1.0.2 - oniguruma-parser@0.12.1: {} + oniguruma-parser@0.12.2: {} - oniguruma-to-es@4.3.3: + oniguruma-to-es@4.3.6: dependencies: - oniguruma-parser: 0.12.1 - regex: 6.0.1 + oniguruma-parser: 0.12.2 + regex: 6.1.0 regex-recursion: 6.0.2 open@10.2.0: @@ -6905,10 +6508,10 @@ snapshots: is-inside-container: 1.0.0 wsl-utils: 0.1.0 - openid-client@6.8.2: + openid-client@6.8.7: dependencies: jose: 6.2.10 - oauth4webapi: 3.8.5 + oauth4webapi: 3.8.7 oxfmt@0.65.0: dependencies: @@ -6979,7 +6582,7 @@ snapshots: pathe@2.0.3: {} - perfect-debounce@1.0.0: {} + perfect-debounce@2.1.0: {} picocolors@1.1.1: {} @@ -7089,11 +6692,6 @@ snapshots: '@types/node': 26.3.0 long: 5.3.2 - pump@3.0.3: - dependencies: - end-of-stream: 1.4.5 - once: 1.4.0 - pump@3.0.4: dependencies: end-of-stream: 1.4.5 @@ -7188,7 +6786,7 @@ snapshots: regex-utilities@2.3.0: {} - regex@6.0.1: + regex@6.1.0: dependencies: regex-utilities: 2.3.0 @@ -7198,11 +6796,9 @@ snapshots: resolve-pkg-maps@1.0.0: {} - restty@0.1.35(typescript@7.0.2): + restty@0.2.6: dependencies: - text-shaper: 0.1.22(typescript@7.0.2) - transitivePeerDependencies: - - typescript + text-shaper: 0.1.28 retry@0.12.0: {} @@ -7231,37 +6827,6 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.2.5 '@rolldown/binding-win32-x64-msvc': 1.2.5 - rollup@4.62.2: - dependencies: - '@types/estree': 1.0.9 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.62.2 - '@rollup/rollup-android-arm64': 4.62.2 - '@rollup/rollup-darwin-arm64': 4.62.2 - '@rollup/rollup-darwin-x64': 4.62.2 - '@rollup/rollup-freebsd-arm64': 4.62.2 - '@rollup/rollup-freebsd-x64': 4.62.2 - '@rollup/rollup-linux-arm-gnueabihf': 4.62.2 - '@rollup/rollup-linux-arm-musleabihf': 4.62.2 - '@rollup/rollup-linux-arm64-gnu': 4.62.2 - '@rollup/rollup-linux-arm64-musl': 4.62.2 - '@rollup/rollup-linux-loong64-gnu': 4.62.2 - '@rollup/rollup-linux-loong64-musl': 4.62.2 - '@rollup/rollup-linux-ppc64-gnu': 4.62.2 - '@rollup/rollup-linux-ppc64-musl': 4.62.2 - '@rollup/rollup-linux-riscv64-gnu': 4.62.2 - '@rollup/rollup-linux-riscv64-musl': 4.62.2 - '@rollup/rollup-linux-s390x-gnu': 4.62.2 - '@rollup/rollup-linux-x64-gnu': 4.62.2 - '@rollup/rollup-linux-x64-musl': 4.62.2 - '@rollup/rollup-openbsd-x64': 4.62.2 - '@rollup/rollup-openharmony-arm64': 4.62.2 - '@rollup/rollup-win32-arm64-msvc': 4.62.2 - '@rollup/rollup-win32-ia32-msvc': 4.62.2 - '@rollup/rollup-win32-x64-gnu': 4.62.2 - '@rollup/rollup-win32-x64-msvc': 4.62.2 - fsevents: 2.3.3 - run-applescript@7.1.0: {} safe-buffer@5.1.2: {} @@ -7286,16 +6851,16 @@ snapshots: shebang-regex@3.0.0: {} - shiki@3.9.2: + shiki@4.4.3: 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/core': 4.4.3 + '@shikijs/engine-javascript': 4.4.3 + '@shikijs/engine-oniguruma': 4.4.3 + '@shikijs/langs': 4.4.3 + '@shikijs/themes': 4.4.3 + '@shikijs/types': 4.4.3 '@shikijs/vscode-textmate': 10.0.2 - '@types/hast': 3.0.4 + '@types/hast': 3.0.5 siginfo@2.0.0: {} @@ -7315,17 +6880,17 @@ snapshots: smart-buffer@4.2.0: {} - socks-proxy-agent@8.0.5: + socks-proxy-agent@10.1.0: dependencies: - agent-base: 7.1.4 + agent-base: 9.0.0 debug: 4.4.3 - socks: 2.8.7 + socks: 2.8.9 transitivePeerDependencies: - supports-color - socks@2.8.7: + socks@2.8.9: dependencies: - ip-address: 10.2.0 + ip-address: 10.5.0 smart-buffer: 4.2.0 sonic-boom@4.2.1: @@ -7345,8 +6910,6 @@ snapshots: space-separated-tokens@2.0.2: {} - speakingurl@14.0.1: {} - split-ca@1.0.1: {} split2@4.2.0: {} @@ -7372,15 +6935,6 @@ snapshots: stream-buffers@3.0.3: {} - streamx@2.23.0: - dependencies: - events-universal: 1.0.1 - fast-fifo: 1.3.2 - text-decoder: 1.2.3 - transitivePeerDependencies: - - bare-abort-controller - - react-native-b4a - streamx@2.28.1: dependencies: events-universal: 1.0.1 @@ -7430,11 +6984,7 @@ snapshots: style-mod@4.1.3: {} - superjson@2.2.2: - dependencies: - copy-anything: 3.0.5 - - tabbable@6.2.0: {} + tabbable@6.5.0: {} tailwind-merge@3.6.0: {} @@ -7453,18 +7003,6 @@ snapshots: pump: 3.0.4 tar-stream: 2.2.0 - tar-fs@3.1.1: - dependencies: - pump: 3.0.3 - tar-stream: 3.1.7 - optionalDependencies: - bare-fs: 4.5.1 - bare-path: 3.0.0 - transitivePeerDependencies: - - bare-abort-controller - - bare-buffer - - react-native-b4a - tar-fs@3.1.3: dependencies: pump: 3.0.4 @@ -7485,15 +7023,6 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 - tar-stream@3.1.7: - dependencies: - b4a: 1.7.3 - fast-fifo: 1.3.2 - streamx: 2.23.0 - transitivePeerDependencies: - - bare-abort-controller - - react-native-b4a - tar-stream@3.2.1: dependencies: b4a: 1.8.1 @@ -7575,21 +7104,13 @@ snapshots: - react-native-b4a - supports-color - text-decoder@1.2.3: - dependencies: - b4a: 1.7.3 - transitivePeerDependencies: - - react-native-b4a - text-decoder@1.2.7: dependencies: b4a: 1.8.1 transitivePeerDependencies: - react-native-b4a - text-shaper@0.1.22(typescript@7.0.2): - dependencies: - typescript: 7.0.2 + text-shaper@0.1.28: {} thread-stream@4.2.0: dependencies: @@ -7610,7 +7131,8 @@ snapshots: tmp@0.2.7: {} - tr46@0.0.3: {} + tr46@0.0.3: + optional: true trim-lines@3.0.1: {} @@ -7658,8 +7180,6 @@ snapshots: undici-types@5.26.5: {} - undici-types@7.18.2: {} - undici-types@8.3.0: {} undici@8.10.0: {} @@ -7718,23 +7238,6 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vite@7.3.6(@types/node@26.3.0)(jiti@2.7.0)(lightningcss@1.33.0)(terser@5.39.0)(tsx@4.23.12)(yaml@2.9.0): - dependencies: - esbuild: 0.28.2 - fdir: 6.5.0(picomatch@4.0.7) - picomatch: 4.0.7 - postcss: 8.5.26 - rollup: 4.62.2 - tinyglobby: 0.2.17 - optionalDependencies: - '@types/node': 26.3.0 - fsevents: 2.3.3 - jiti: 2.7.0 - lightningcss: 1.33.0 - terser: 5.39.0 - tsx: 4.23.12 - yaml: 2.9.0 - vite@8.2.2(@types/node@26.3.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.39.0)(tsx@4.23.12)(yaml@2.9.0): dependencies: lightningcss: 1.33.0 @@ -7751,40 +7254,42 @@ snapshots: tsx: 4.23.12 yaml: 2.9.0 - vitepress@2.0.0-alpha.12(@types/node@26.3.0)(jiti@2.7.0)(lightningcss@1.33.0)(postcss@8.5.26)(terser@5.39.0)(tsx@4.23.12)(typescript@7.0.2)(yaml@2.9.0): + vitepress@2.0.0-alpha.19(@types/node@26.3.0)(esbuild@0.28.2)(jiti@2.7.0)(postcss@8.5.26)(terser@5.39.0)(tsx@4.23.12)(typescript@7.0.2)(yaml@2.9.0): 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 + '@docsearch/css': 4.7.0 + '@docsearch/js': 4.7.0 + '@docsearch/sidepanel-js': 4.7.0 + '@iconify-json/simple-icons': 1.2.93 + '@shikijs/core': 4.4.3 + '@shikijs/transformers': 4.4.3 + '@shikijs/types': 4.4.3 '@types/markdown-it': 14.1.2 - '@vitejs/plugin-vue': 6.0.1(vite@7.3.6(@types/node@26.3.0)(jiti@2.7.0)(lightningcss@1.33.0)(terser@5.39.0)(tsx@4.23.12)(yaml@2.9.0))(vue@3.5.18(typescript@7.0.2)) - '@vue/devtools-api': 8.0.0 - '@vue/shared': 3.5.18 - '@vueuse/core': 13.7.0(vue@3.5.18(typescript@7.0.2)) - '@vueuse/integrations': 13.7.0(focus-trap@7.6.5)(vue@3.5.18(typescript@7.0.2)) - focus-trap: 7.6.5 + '@vitejs/plugin-vue': 6.0.8(vite@8.2.2(@types/node@26.3.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.39.0)(tsx@4.23.12)(yaml@2.9.0))(vue@3.5.42(typescript@7.0.2)) + '@vue/devtools-api': 8.2.1 + '@vue/shared': 3.5.42 + '@vueuse/core': 14.4.0(vue@3.5.42(typescript@7.0.2)) + '@vueuse/integrations': 14.4.0(focus-trap@8.2.2)(vue@3.5.42(typescript@7.0.2)) + focus-trap: 8.2.2 mark.js: 8.11.1 - minisearch: 7.1.2 - shiki: 3.9.2 - vite: 7.3.6(@types/node@26.3.0)(jiti@2.7.0)(lightningcss@1.33.0)(terser@5.39.0)(tsx@4.23.12)(yaml@2.9.0) - vue: 3.5.18(typescript@7.0.2) + minisearch: 7.2.0 + shiki: 4.4.3 + vite: 8.2.2(@types/node@26.3.0)(esbuild@0.28.2)(jiti@2.7.0)(terser@5.39.0)(tsx@4.23.12)(yaml@2.9.0) + vue: 3.5.42(typescript@7.0.2) optionalDependencies: postcss: 8.5.26 transitivePeerDependencies: - '@types/node' + - '@vitejs/devtools' - async-validator - axios - change-case - drauu + - esbuild - fuse.js - idb-keyval - jiti - jwt-decode - less - - lightningcss - nprogress - qrcode - sass @@ -7825,13 +7330,13 @@ snapshots: transitivePeerDependencies: - msw - vue@3.5.18(typescript@7.0.2): + vue@3.5.42(typescript@7.0.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@7.0.2)) - '@vue/shared': 3.5.18 + '@vue/compiler-dom': 3.5.42 + '@vue/compiler-sfc': 3.5.42 + '@vue/runtime-dom': 3.5.42 + '@vue/server-renderer': 3.5.42 + '@vue/shared': 3.5.42 optionalDependencies: typescript: 7.0.2 @@ -7840,12 +7345,14 @@ snapshots: web-streams-polyfill@3.3.3: optional: true - webidl-conversions@3.0.1: {} + webidl-conversions@3.0.1: + optional: true whatwg-url@5.0.0: dependencies: tr46: 0.0.3 webidl-conversions: 3.0.1 + optional: true which@2.0.2: dependencies: @@ -7870,16 +7377,10 @@ snapshots: wrappy@1.0.2: {} - ws@8.21.0(bufferutil@4.0.9)(utf-8-validate@5.0.10): - optionalDependencies: - bufferutil: 4.0.9 - utf-8-validate: 5.0.10 - ws@8.21.3(bufferutil@4.0.9)(utf-8-validate@5.0.10): optionalDependencies: bufferutil: 4.0.9 utf-8-validate: 5.0.10 - optional: true wsl-utils@0.1.0: dependencies: diff --git a/runtime/http.ts b/runtime/http.ts index cbfa4e7..a3d350e 100644 --- a/runtime/http.ts +++ b/runtime/http.ts @@ -91,17 +91,28 @@ function createStaticHandler(opts: StaticOptions) { if (!st.isFile()) return false; const isAsset = pathname.startsWith(assetsPrefix); - res.setHeader( - "Cache-Control", - isAsset && opts.immutableAssets - ? "public, max-age=31536000, immutable" - : "public, max-age=3600", - ); + + // Dev serves unhashed files that are rewritten in place, so a rebuild is + // invisible to anything holding a copy. Revalidate instead of pinning. + let cacheControl = "no-cache"; + if (opts.immutableAssets) { + cacheControl = isAsset ? "public, max-age=31536000, immutable" : "public, max-age=3600"; + } + + res.setHeader("Cache-Control", cacheControl); + res.setHeader("Last-Modified", st.mtime.toUTCString()); + + // HTTP dates carry one-second resolution, so floor mtime before comparing. + const modifiedSince = Date.parse(req.headers["if-modified-since"] ?? ""); + if (!Number.isNaN(modifiedSince) && Math.floor(st.mtimeMs / 1000) * 1000 <= modifiedSince) { + res.statusCode = 304; + res.end(); + return true; + } const mimeType = mime.getType(extname(file)) ?? "application/octet-stream"; res.setHeader("Content-Type", mimeType); res.setHeader("Content-Length", String(st.size)); - res.setHeader("Last-Modified", st.mtime.toUTCString()); res.statusCode = 200; if (req.method === "HEAD") { diff --git a/scripts/sync-tsconnect.sh b/scripts/sync-tsconnect.sh new file mode 100755 index 0000000..6c38e8f --- /dev/null +++ b/scripts/sync-tsconnect.sh @@ -0,0 +1,64 @@ +#!/bin/sh +# Resyncs cmd/hp_ssh/wasm_js.go with tailscale.com/cmd/tsconnect and reapplies +# the local patch. Pass the upstream ref to move to; defaults to the ref the +# vendored file currently records. +# +# After a successful sync, bump tailscale.com in go.mod to a release that +# contains the ref, or the file will not compile. + +set -eu + +ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)" +cd "$ROOT_DIR" || exit 1 + +TARGET="cmd/hp_ssh/wasm_js.go" +TYPES="app/routes/ssh/wasm_js.d.ts" +PATCH="patches/tsconnect-term-type.patch" +TYPES_PATCH="patches/tsconnect-types.patch" +RAW="https://raw.githubusercontent.com/tailscale/tailscale" + +die() { echo "error: $*" >&2; exit 1; } + +REF=${1:-$(sed -n 's/^\/\/ Upstream ref: //p' "$TARGET")} +[ -n "$REF" ] || die "no upstream ref given and none recorded in $TARGET" + +echo "==> Syncing tsconnect at $REF" +command -v go >/dev/null 2>&1 || die "go not installed" + +HEADER=$(mktemp) +trap 'rm -f "$HEADER" "$HEADER.go"' EXIT + +cat > "$HEADER" < "$HEADER.go" || + die "failed to fetch wasm_js.go at $REF" + +# Upstream's first three lines are the license header we replace. +cat "$HEADER" > "$TARGET" +tail -n +4 "$HEADER.go" >> "$TARGET" + +echo "==> Applying $PATCH" +patch --no-backup-if-mismatch "$TARGET" < "$PATCH" || die "patch conflict — resolve by hand, then rewrite $PATCH" + +echo "==> Refreshing $TYPES" +curl -fsSL "$RAW/$REF/cmd/tsconnect/src/types/wasm_js.d.ts" > "$TYPES" || + die "failed to fetch wasm_js.d.ts at $REF" + +echo "==> Applying $TYPES_PATCH" +patch --no-backup-if-mismatch "$TYPES" < "$TYPES_PATCH" || die "patch conflict — resolve by hand, then rewrite $TYPES_PATCH" + +echo "==> Regenerating build tags" +GOFLAGS=-mod=mod go run scripts/wasm-tags.go > cmd/hp_ssh/build-tags.txt + +gofmt -w "$TARGET" +echo "==> Done. Rebuild with ./build.sh --wasm" diff --git a/scripts/wasm-tags.go b/scripts/wasm-tags.go new file mode 100644 index 0000000..81e5bbb --- /dev/null +++ b/scripts/wasm-tags.go @@ -0,0 +1,31 @@ +//go:build ignore + +// Regenerates cmd/hp_ssh/build-tags.txt, the -tags value for the SSH WASM +// build. Run via scripts/sync-tsconnect.sh, not at build time: wasmbuild is +// not an import of this module, so it is absent from a vendored tree. +// +// Tailscale computes this list from its own feature registry, so it tracks +// upstream automatically. We drop tailscale_go because it needs Tailscale's +// forked Go toolchain (runtime.TailscaleCurrentP); everything else is a +// ts_omit_* tag that strips server-only features from the browser bundle. +package main + +import ( + "fmt" + "strings" + + "tailscale.com/cmd/tsconnect/wasmbuild" +) + +func main() { + tagList := strings.Split(wasmbuild.Tags(), ",") + keptList := make([]string, 0, len(tagList)) + + for _, tag := range tagList { + if tag != "tailscale_go" { + keptList = append(keptList, tag) + } + } + + fmt.Println(strings.Join(keptList, ",")) +}