diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 70158884961..41be9c9ee74 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -14,6 +14,10 @@ updates: open-pull-requests-limit: 20 labels: - "dependencies" + # Dependabot's npm parser reads only dependencies, devDependencies, and + # optionalDependencies — never peerDependencies. It cannot see the + # optional OpenTelemetry peer dependencies in server/package.json, so it + # never bumps their declared versions. ignore: # @types/node describes the APIs available in the supported Node runtime. # Runtime major upgrades are deliberate compatibility changes, so keep diff --git a/.npmrc b/.npmrc index 3e775efb0f4..f301fedf982 100644 --- a/.npmrc +++ b/.npmrc @@ -1 +1 @@ -auto-install-peers=true +auto-install-peers=false diff --git a/README.md b/README.md index 80ce5ce44f5..5541a858b8b 100644 --- a/README.md +++ b/README.md @@ -467,7 +467,7 @@ Find Plugins and more at [awesome-paperclip](https://github.com/gsxdsm/awesome-p ## Observability -Paperclip ships with opt-in OpenTelemetry auto-instrumentation for the server (traces only). It activates when `OTEL_EXPORTER_OTLP_ENDPOINT` is set and supports `grpc`, `http/protobuf`, and `http/json` via the standard `OTEL_EXPORTER_OTLP_PROTOCOL` env var. The `@opentelemetry/*` packages are optional peer dependencies — install them only if you want tracing. See [doc/observability.md](doc/observability.md) for install commands and the full env-var reference. +Paperclip ships with opt-in OpenTelemetry auto-instrumentation for the server (traces only). It activates when `OTEL_EXPORTER_OTLP_ENDPOINT` is set and supports `grpc`, `http/protobuf`, and `http/json` via the standard `OTEL_EXPORTER_OTLP_PROTOCOL` env var. `@opentelemetry/api` is a normal server dependency; the SDK, auto-instrumentation, and exporter packages are optional peer dependencies — install them only if you want tracing. See [doc/observability.md](doc/observability.md) for install commands and the full env-var reference. Paperclip also ships with opt-in Sentry error monitoring for the server and the browser. Set `SENTRY_DSN` to activate it — the server and the browser then report to the same Sentry project. `@sentry/node` is an optional peer dependency for the server; install it only if you want error monitoring. See [doc/observability.md](doc/observability.md#sentry-error-monitoring) for the install command, the privacy settings, and the full default capture set. diff --git a/doc/observability.md b/doc/observability.md index db3d8bea263..2a7865308bd 100644 --- a/doc/observability.md +++ b/doc/observability.md @@ -8,42 +8,62 @@ separate first-party event system. Paperclip ships with **opt-in** OpenTelemetry auto-instrumentation for the server process. When activated it produces **traces only** — no metrics and no -logs are exported by this integration. The OTel packages are *optional peer -dependencies*: they are not in the default lockfile and are loaded dynamically -only when an operator turns the feature on. +logs are exported by this integration. -When `OTEL_EXPORTER_OTLP_ENDPOINT` is unset, none of the `@opentelemetry/*` +`@opentelemetry/api` is a normal dependency of `@paperclipai/server`. Every +install includes it. It stays a no-op interface until an SDK registers a +provider, so it exports no telemetry by itself. + +The SDK, the auto-instrumentation bundle, and the resources and +semantic-conventions helpers are *optional peer dependencies*: they are not in +the default lockfile, and the server loads them dynamically only when an +operator turns the feature on. The three exporters below are mutually +alternative peer dependencies — install exactly **one**, matching +`OTEL_EXPORTER_OTLP_PROTOCOL`. + +When `OTEL_EXPORTER_OTLP_ENDPOINT` is unset, none of the `@opentelemetry/*` SDK packages are imported and there is zero runtime overhead. +`server/package.json` declares each optional package at the exact version the +server tests against; install that exact version. Our Dependabot cannot bump +these versions: its npm parser reads only `dependencies`, `devDependencies`, +and `optionalDependencies`, never `peerDependencies`. A peer version here is a +compatibility claim, not an installed version, so raising it is a human +decision. `@opentelemetry/api` is the one OpenTelemetry package Paperclip +maintains as a dependency; once you install the packages below, they become +normal dependencies of **your own** project, and your own Dependabot updates +them. + ## Enabling tracing ### 1. Install the OTel peer dependencies Install the SDK, the auto-instrumentations bundle, the resources/semconv -helpers, and **one** exporter matching your chosen OTLP protocol. +helpers, and **one** exporter matching your chosen OTLP protocol, at the exact +versions below. Common to every protocol: ```bash pnpm add \ - @opentelemetry/sdk-node \ - @opentelemetry/auto-instrumentations-node \ - @opentelemetry/resources \ - @opentelemetry/semantic-conventions + @opentelemetry/sdk-node@0.221.0 \ + @opentelemetry/auto-instrumentations-node@0.79.0 \ + @opentelemetry/resources@2.10.0 \ + @opentelemetry/semantic-conventions@1.43.0 ``` Then add the exporter for the protocol you intend to use: -| `OTEL_EXPORTER_OTLP_PROTOCOL` | Exporter package | -| ----------------------------- | --------------------------------------------- | -| `grpc` (default if unset) | `@opentelemetry/exporter-trace-otlp-grpc` | -| `http/protobuf` | `@opentelemetry/exporter-trace-otlp-proto` | -| `http/json` | `@opentelemetry/exporter-trace-otlp-http` | +| `OTEL_EXPORTER_OTLP_PROTOCOL` | Exporter package | Version | +| ------------------------------ | ------------------------------------------- | --------- | +| `grpc` (default if unset) | `@opentelemetry/exporter-trace-otlp-grpc` | `0.221.0` | +| `http/protobuf` | `@opentelemetry/exporter-trace-otlp-proto` | `0.221.0` | +| `http/json` | `@opentelemetry/exporter-trace-otlp-http` | `0.221.0` | For example, for the default gRPC path: ```bash -pnpm add @opentelemetry/exporter-trace-otlp-grpc +pnpm add @opentelemetry/exporter-trace-otlp-grpc@0.221.0 ``` ### 2. Set the environment @@ -94,9 +114,11 @@ can confirm the value. If `OTEL_EXPORTER_OTLP_PROTOCOL` is set to an unrecognized value, Paperclip logs a single warning and falls back to gRPC. -If `OTEL_EXPORTER_OTLP_ENDPOINT` is set but the OTel packages are not -installed, the server logs a single diagnostic line on boot and continues -without tracing — your server stays up. +Before it imports any OTel package, the server checks the four common +packages and the selected exporter against the exact versions +`server/package.json` declares. If `OTEL_EXPORTER_OTLP_ENDPOINT` is set and a +package is missing or installed at a different version, the server logs one +diagnostic line on boot and continues without tracing — your server stays up. ## Scope diff --git a/packages/adapter-utils/src/execution-target-stdin-race.test.ts b/packages/adapter-utils/src/execution-target-stdin-race.test.ts index e911258c544..43a47d577e1 100644 --- a/packages/adapter-utils/src/execution-target-stdin-race.test.ts +++ b/packages/adapter-utils/src/execution-target-stdin-race.test.ts @@ -1,5 +1,6 @@ import { execFile as execFileCallback, spawn } from "node:child_process"; -import { chmod, mkdir, mkdtemp, readFile, readdir, rename, rm, writeFile } from "node:fs/promises"; +import { symlinkSync } from "node:fs"; +import { chmod, lstat, mkdir, mkdtemp, readFile, readdir, readlink, rename, rm, writeFile } from "node:fs/promises"; import net from "node:net"; import os from "node:os"; import path from "node:path"; @@ -745,6 +746,109 @@ describe("deterministic remote process-session wrapper shutdown (PAP-5316)", () return fakeBirthtimePreloadPath; } + // A test-only preload for PAP-5355: it deterministically simulates a + // same-sandbox peer that wins the gap between the wrapper's final identity + // check and its removal call. nextProbeFileName() is deterministic (pid + + // call sequence), so this preload can compute the exact probe path the + // wrapper itself will check next. It patches fs.promises.lstat inside the + // wrapper's own process: the first time that call targets the expected + // probe path, it replaces the path with a peer-owned entry before the real + // lstat runs, so the wrapper observes the swapped entry's identity, not its + // own. This is the worst case for the wrapper (the swap always lands + // before the wrapper's very last look at the path), so a wrapper that + // still leaves the peer's entry untouched under this preload proves the + // fix for every less-adversarial timing too. It never runs unless a test + // opts in, and it never touches this test file's own process. + let probeSwapPreloadDir: string | null = null; + afterAll(async () => { + if (probeSwapPreloadDir) await rm(probeSwapPreloadDir, { recursive: true, force: true }).catch(() => undefined); + }); + let probeSwapPreloadPath: Promise | null = null; + async function getProbeSwapPreloadPath(): Promise { + if (!probeSwapPreloadPath) { + probeSwapPreloadPath = (async () => { + const dir = await mkdtemp(path.join(os.tmpdir(), "paperclip-probe-swap-preload-")); + probeSwapPreloadDir = dir; + const preloadPath = path.join(dir, "probe-swap-preload.cjs"); + await writeFile( + preloadPath, + [ + `const fs = require("fs");`, + `const path = require("path");`, + `const mode = process.env.PAPERCLIP_TEST_PROBE_SWAP_MODE;`, + `const seq = process.env.PAPERCLIP_TEST_PROBE_SWAP_SEQ;`, + `const symlinkTarget = process.env.PAPERCLIP_TEST_PROBE_SWAP_SYMLINK_TARGET;`, + `if (mode && seq) {`, + ` const expectedName = ".paperclip-birthtime-probe-" + process.pid + "-" + seq;`, + ` let swapped = false;`, + ` const originalLstat = fs.promises.lstat.bind(fs.promises);`, + ` fs.promises.lstat = async (candidatePath, opts) => {`, + ` if (!swapped && path.basename(String(candidatePath)) === expectedName) {`, + ` swapped = true;`, + ` try { fs.unlinkSync(candidatePath); } catch {}`, + ` if (mode === "file") fs.writeFileSync(candidatePath, "peer-owned-content");`, + ` else if (mode === "dir") fs.mkdirSync(candidatePath);`, + ` else if (mode === "symlink") fs.symlinkSync(symlinkTarget, candidatePath);`, + ` }`, + ` return originalLstat(candidatePath, opts);`, + ` };`, + `}`, + ].join("\n"), + "utf8", + ); + return preloadPath; + })(); + } + return probeSwapPreloadPath; + } + + // A test-only preload for PAP-5374: it simulates fstat() failing on the + // wrapper's own just-opened probe file descriptor, the one signal the real + // filesystem in this sandbox never produces on demand. nextProbeFileName() + // is deterministic (pid + call sequence), so this preload knows which + // fs.promises.open() call is the wrapper's probe write and patches only the + // FileHandle that call returns, leaving every other open() untouched. It + // never runs unless a test opts in, and it never touches this test file's + // own process. + let fstatFailurePreloadDir: string | null = null; + afterAll(async () => { + if (fstatFailurePreloadDir) await rm(fstatFailurePreloadDir, { recursive: true, force: true }).catch(() => undefined); + }); + let fstatFailurePreloadPath: Promise | null = null; + async function getFstatFailurePreloadPath(): Promise { + if (!fstatFailurePreloadPath) { + fstatFailurePreloadPath = (async () => { + const dir = await mkdtemp(path.join(os.tmpdir(), "paperclip-fstat-failure-preload-")); + fstatFailurePreloadDir = dir; + const preloadPath = path.join(dir, "fstat-failure-preload.cjs"); + await writeFile( + preloadPath, + [ + `const fs = require("fs");`, + `const path = require("path");`, + `const seq = process.env.PAPERCLIP_TEST_FSTAT_FAILURE_SEQ;`, + `if (seq) {`, + ` const expectedName = ".paperclip-birthtime-probe-" + process.pid + "-" + seq;`, + ` const originalOpen = fs.promises.open.bind(fs.promises);`, + ` fs.promises.open = async (targetPath, flags, mode) => {`, + ` const handle = await originalOpen(targetPath, flags, mode);`, + ` if (path.basename(String(targetPath)) === expectedName) {`, + ` handle.stat = async () => {`, + ` throw new Error("EIO: simulated fstat failure for test");`, + ` };`, + ` }`, + ` return handle;`, + ` };`, + `}`, + ].join("\n"), + "utf8", + ); + return preloadPath; + })(); + } + return fstatFailurePreloadPath; + } + // Run the real emitted wrapper (either variant) as a node process, with no // sandbox and no bridge in front of it. The test owns the wrapper's node // ChildProcess handle directly, so it can observe the wrapper's own exit @@ -770,6 +874,15 @@ describe("deterministic remote process-session wrapper shutdown (PAP-5316)", () // Used to drive the lease timing overrides directly, with no host bridge // in front of the wrapper. env?: Record; + // Makes the wrapper's own process observe a same-sandbox peer replacing + // its birth-time probe file, through the preload above (PAP-5355). seq 1 + // is sessionDir's probe (the first one captureSessionIdentity() runs). + probeSwap?: { seq: 1 | 2; mode: "file" | "dir" | "symlink"; symlinkTarget?: string }; + // Makes the wrapper's own process observe an fstat() failure on the open + // descriptor for its own birth-time probe file, through the preload above + // (PAP-5374). seq 1 is sessionDir's probe (the first one + // captureSessionIdentity() runs). + fstatFailure?: { seq: 1 | 2 }; }) { const sessionDir = await mkdtemp(path.join(options?.parentDir ?? os.tmpdir(), "paperclip-wrapper-lifecycle-")); cleanupDirs.push(sessionDir); @@ -799,6 +912,16 @@ describe("deterministic remote process-session wrapper shutdown (PAP-5316)", () env.PAPERCLIP_TEST_FAKE_BIRTHTIME_MODE = options.fakeBirthtime.mode; execArgv.push("--require", await getFakeBirthtimePreloadPath()); } + if (options?.probeSwap) { + env.PAPERCLIP_TEST_PROBE_SWAP_SEQ = String(options.probeSwap.seq); + env.PAPERCLIP_TEST_PROBE_SWAP_MODE = options.probeSwap.mode; + if (options.probeSwap.symlinkTarget) env.PAPERCLIP_TEST_PROBE_SWAP_SYMLINK_TARGET = options.probeSwap.symlinkTarget; + execArgv.push("--require", await getProbeSwapPreloadPath()); + } + if (options?.fstatFailure) { + env.PAPERCLIP_TEST_FSTAT_FAILURE_SEQ = String(options.fstatFailure.seq); + execArgv.push("--require", await getFstatFailurePreloadPath()); + } const child = spawn(process.execPath, [...execArgv, wrapperPath], { cwd: sessionDir, @@ -852,6 +975,7 @@ describe("deterministic remote process-session wrapper shutdown (PAP-5316)", () } return { + pid: child.pid, sessionDir, stdinDir, eventsDir, @@ -1832,6 +1956,200 @@ describe("deterministic remote process-session wrapper shutdown (PAP-5316)", () expect(wrapper.stderrText()).toMatch(/Latching on a lost process session identity/); }, 15_000); + it("T20 refuses to write through a probe path a sandbox peer pre-created as a symbolic link, and leaves that link and its target untouched", async () => { + const rootDir = await mkdtemp(path.join(os.tmpdir(), "paperclip-probe-symlink-race-")); + cleanupDirs.push(rootDir); + const pidFile = path.join(rootDir, "t20-child.pid"); + const childPath = path.join(rootDir, "t20-child.mjs"); + await writeFile(childPath, trackedChildSource(pidFile), "utf8"); + + const sessionDir = await mkdtemp(path.join(os.tmpdir(), "paperclip-probe-symlink-session-")); + cleanupDirs.push(sessionDir); + const stdinDir = path.join(sessionDir, "stdin"); + await mkdir(stdinDir, { recursive: true }); + + const wrapperPath = path.join(sessionDir, "wrapper.mjs"); + await writeFile(wrapperPath, getProcessSessionRemoteSource({ outputToStdout: true }), "utf8"); + const config = { command: process.execPath, args: [childPath], cwd: sessionDir, env: {} }; + const commandPayload = Buffer.from(JSON.stringify(config), "utf8").toString("base64"); + + // A file this test owns, standing in for a file a sandbox peer already + // controls. The wrapper's probe write must never reach it. + const probeLinkTarget = path.join(rootDir, "t20-probe-target.txt"); + const knownContent = "t20-untouched-content"; + await writeFile(probeLinkTarget, knownContent, "utf8"); + + const child = spawn(process.execPath, [wrapperPath], { + cwd: sessionDir, + env: { + ...process.env, + PAPERCLIP_PROCESS_SESSION_DIR: sessionDir, + PAPERCLIP_PROCESS_SESSION_COMMAND_B64: commandPayload, + }, + stdio: ["ignore", "pipe", "pipe"], + }); + + // Wins the race to the probe path against the wrapper's own probe write. + // nextProbeFileName() is deterministic: it names + // ".paperclip-birthtime-probe--1" on the wrapper's first probe call, + // which always targets sessionDir. child.pid is available synchronously + // right after spawn() returns, well before the freshly spawned process + // has loaded Node or parsed its own script, so this synchronous + // symlinkSync call lands first. This is the same advantage a real + // sandbox peer racing to pre-create the path would have, so it gives the + // strongest proof: the real wrapper process, under the real race, must + // still refuse to follow the link. + const probePath = path.join(sessionDir, `.paperclip-birthtime-probe-${child.pid}-1`); + symlinkSync(probeLinkTarget, probePath); + + let stderrText = ""; + child.stderr.on("data", (chunk: Buffer) => { + stderrText += chunk.toString("utf8"); + }); + const exited = new Promise((resolve) => child.on("close", () => resolve())); + + await Promise.race([ + exited, + delay(8_000).then(() => { + throw new Error("The wrapper process did not exit."); + }), + ]); + + await expectNoLiveProcessByArgvSubstring(childPath); + expect(stderrText).toMatch(/could not be created exclusively/); + expect((await lstat(probePath)).isSymbolicLink()).toBe(true); + expect(await readFile(probeLinkTarget, "utf8")).toBe(knownContent); + }, 15_000); + + // ---- PAP-5355: identity-aware cleanup after a same-sandbox peer replaces + // the probe file this wrapper just created, in the gap between this + // wrapper's last identity check and its removal call. The probeSwap + // preload (see getProbeSwapPreloadPath above) simulates the worst-case + // timing for that gap deterministically, instead of racing real wall-clock + // time: it swaps the path the instant the wrapper itself looks at it for + // the last time before deciding whether to remove it. + + it("T21 still removes its own probe file normally when no peer ever replaces it", async () => { + const rootDir = await mkdtemp(path.join(os.tmpdir(), "paperclip-probe-no-swap-")); + cleanupDirs.push(rootDir); + const pidFile = path.join(rootDir, "t21-child.pid"); + const childPath = path.join(rootDir, "t21-child.mjs"); + await writeFile(childPath, trackedChildSource(pidFile), "utf8"); + + const wrapper = await startWrapperProcess({ + outputToStdout: false, + command: process.execPath, + args: [childPath], + }); + await waitForTrackedChildPid(pidFile); + + const probePath = path.join(wrapper.sessionDir, `.paperclip-birthtime-probe-${wrapper.pid}-1`); + await waitFor(async () => !(await lstat(probePath).then(() => true).catch(() => false)), 4_000); + await expect(lstat(probePath)).rejects.toThrow(); + }, 15_000); + + it("T22 leaves a peer's replacement file untouched instead of deleting it", async () => { + const rootDir = await mkdtemp(path.join(os.tmpdir(), "paperclip-probe-swap-file-")); + cleanupDirs.push(rootDir); + const pidFile = path.join(rootDir, "t22-child.pid"); + const childPath = path.join(rootDir, "t22-child.mjs"); + await writeFile(childPath, trackedChildSource(pidFile), "utf8"); + + const wrapper = await startWrapperProcess({ + outputToStdout: false, + command: process.execPath, + args: [childPath], + probeSwap: { seq: 1, mode: "file" }, + }); + await waitForTrackedChildPid(pidFile); + + const probePath = path.join(wrapper.sessionDir, `.paperclip-birthtime-probe-${wrapper.pid}-1`); + await waitFor(async () => (await readFile(probePath, "utf8").catch(() => null)) === "peer-owned-content", 4_000); + // The wrapper's own cleanup call already ran (the preload only swaps the + // path the moment the wrapper itself checks it). This delay proves that + // run settled and nothing removes the peer's file afterward. + await delay(200); + expect(await readFile(probePath, "utf8")).toBe("peer-owned-content"); + }, 15_000); + + it("T23 leaves a peer's replacement directory untouched instead of deleting it", async () => { + const rootDir = await mkdtemp(path.join(os.tmpdir(), "paperclip-probe-swap-dir-")); + cleanupDirs.push(rootDir); + const pidFile = path.join(rootDir, "t23-child.pid"); + const childPath = path.join(rootDir, "t23-child.mjs"); + await writeFile(childPath, trackedChildSource(pidFile), "utf8"); + + const wrapper = await startWrapperProcess({ + outputToStdout: false, + command: process.execPath, + args: [childPath], + probeSwap: { seq: 1, mode: "dir" }, + }); + await waitForTrackedChildPid(pidFile); + + const probePath = path.join(wrapper.sessionDir, `.paperclip-birthtime-probe-${wrapper.pid}-1`); + await waitFor(async () => await lstat(probePath).then((stats) => stats.isDirectory()).catch(() => false), 4_000); + await delay(200); + expect((await lstat(probePath)).isDirectory()).toBe(true); + }, 15_000); + + it("T24 leaves a peer's replacement symbolic link and its target untouched instead of deleting or following it", async () => { + const rootDir = await mkdtemp(path.join(os.tmpdir(), "paperclip-probe-swap-symlink-")); + cleanupDirs.push(rootDir); + const pidFile = path.join(rootDir, "t24-child.pid"); + const childPath = path.join(rootDir, "t24-child.mjs"); + await writeFile(childPath, trackedChildSource(pidFile), "utf8"); + + const linkTarget = path.join(rootDir, "t24-probe-target.txt"); + const knownContent = "t24-untouched-content"; + await writeFile(linkTarget, knownContent, "utf8"); + + const wrapper = await startWrapperProcess({ + outputToStdout: false, + command: process.execPath, + args: [childPath], + probeSwap: { seq: 1, mode: "symlink", symlinkTarget: linkTarget }, + }); + await waitForTrackedChildPid(pidFile); + + const probePath = path.join(wrapper.sessionDir, `.paperclip-birthtime-probe-${wrapper.pid}-1`); + await waitFor(async () => await lstat(probePath).then((stats) => stats.isSymbolicLink()).catch(() => false), 4_000); + await delay(200); + expect((await lstat(probePath)).isSymbolicLink()).toBe(true); + expect(await readlink(probePath)).toBe(linkTarget); + expect(await readFile(linkTarget, "utf8")).toBe(knownContent); + }, 15_000); + + it("T25 fails closed at capture when its own probe file's identity cannot be read, so no orphan wrapper or child ever starts polling", async () => { + const rootDir = await mkdtemp(path.join(os.tmpdir(), "paperclip-probe-fstat-failure-")); + cleanupDirs.push(rootDir); + const pidFile = path.join(rootDir, "t25-child.pid"); + const childPath = path.join(rootDir, "t25-child.mjs"); + await writeFile(childPath, trackedChildSource(pidFile), "utf8"); + + const wrapper = await startWrapperProcess({ + outputToStdout: false, + command: process.execPath, + args: [childPath], + fstatFailure: { seq: 1 }, + }); + + await Promise.race([ + wrapper.exited, + delay(8_000).then(() => { + throw new Error("The wrapper process did not exit."); + }), + ]); + expect(wrapper.stderrText()).toMatch(/its own probe file's identity could not be read/); + await expectNoLiveProcessByArgvSubstring(childPath); + + // With no verified identity for the probe file, the wrapper must not + // remove it by path alone: it leaves the file exactly as it created it, + // rather than risking removal of a different entry a peer may have put + // at the same path. + const probePath = path.join(wrapper.sessionDir, `.paperclip-birthtime-probe-${wrapper.pid}-1`); + expect((await lstat(probePath)).isFile()).toBe(true); + }, 15_000); // ---- PAP-5361: a host-refreshed lease bounds the wrapper's own lifetime, // so a host crash cannot orphan it. The host writes and refreshes // ".paperclip-session-lease" under sessionDir; the wrapper reads only its @@ -1840,7 +2158,7 @@ describe("deterministic remote process-session wrapper shutdown (PAP-5316)", () const LEASE_FILE_NAME = ".paperclip-session-lease"; - it("T21 no refresh: the wrapper terminates itself and its child after the lease duration elapses", async () => { + it("T26 no refresh: the wrapper terminates itself and its child after the lease duration elapses", async () => { for (const outputToStdout of [false, true]) { const rootDir = await mkdtemp(path.join(os.tmpdir(), "paperclip-lease-no-refresh-")); cleanupDirs.push(rootDir); @@ -1866,7 +2184,7 @@ describe("deterministic remote process-session wrapper shutdown (PAP-5316)", () } }, 20_000); - it("T22 a valid rename-based refresh resets the deadline, and the wrapper stays alive past the lease duration", async () => { + it("T27 a valid rename-based refresh resets the deadline, and the wrapper stays alive past the lease duration", async () => { for (const outputToStdout of [false, true]) { const wrapper = await startWrapperProcess({ outputToStdout, @@ -1913,7 +2231,7 @@ describe("deterministic remote process-session wrapper shutdown (PAP-5316)", () } }, 20_000); - it("T23 a missing lease never resets the deadline, and ordinary stdin traffic does not substitute for it", async () => { + it("T28 a missing lease never resets the deadline, and ordinary stdin traffic does not substitute for it", async () => { for (const outputToStdout of [false, true]) { const wrapper = await startWrapperProcess({ outputToStdout, @@ -1946,7 +2264,7 @@ describe("deterministic remote process-session wrapper shutdown (PAP-5316)", () } }, 20_000); - it("T24 a symbolic link at the lease path is never followed, its target stays unchanged, and the wrapper expires", async () => { + it("T29 a symbolic link at the lease path is never followed, its target stays unchanged, and the wrapper expires", async () => { const { symlink } = await import("node:fs/promises"); for (const outputToStdout of [false, true]) { const wrapper = await startWrapperProcess({ @@ -1973,7 +2291,7 @@ describe("deterministic remote process-session wrapper shutdown (PAP-5316)", () } }, 20_000); - it("T25 a directory at the lease path is never treated as a valid lease, and the wrapper expires", async () => { + it("T30 a directory at the lease path is never treated as a valid lease, and the wrapper expires", async () => { for (const outputToStdout of [false, true]) { const wrapper = await startWrapperProcess({ outputToStdout, @@ -2000,7 +2318,7 @@ describe("deterministic remote process-session wrapper shutdown (PAP-5316)", () // touches the lease path defers this wrapper's expiry. This is not a // capability the peer lacked -- it can already spawn its own long-lived // work -- so a later change must not silently alter this shape. - it("T26 a peer that keeps touching the lease file defers this wrapper's expiry", async () => { + it("T31 a peer that keeps touching the lease file defers this wrapper's expiry", async () => { const { utimes } = await import("node:fs/promises"); for (const outputToStdout of [false, true]) { const wrapper = await startWrapperProcess({ @@ -2040,7 +2358,7 @@ describe("deterministic remote process-session wrapper shutdown (PAP-5316)", () } }, 20_000); - it("T27 each wrapper source has exactly one lease deadline declaration and one lease check call site, and the lease code adds no kill caller or numeric process identifier", () => { + it("T32 each wrapper source has exactly one lease deadline declaration and one lease check call site, and the lease code adds no kill caller or numeric process identifier", () => { for (const outputToStdout of [true, false]) { const src = getProcessSessionRemoteSource({ outputToStdout }); const code = src @@ -2071,7 +2389,7 @@ describe("deterministic remote process-session wrapper shutdown (PAP-5316)", () } }); - it("T28 an injected slow lease refresh in flight during stop() cannot recreate sessionDir after removal", async () => { + it("T33 an injected slow lease refresh in flight during stop() cannot recreate sessionDir after removal", async () => { const rootDir = await mkdtemp(path.join(os.tmpdir(), "paperclip-lease-host-race-")); cleanupDirs.push(rootDir); const childPath = path.join(rootDir, "quiet-child.mjs"); @@ -2160,7 +2478,7 @@ describe("deterministic remote process-session wrapper shutdown (PAP-5316)", () expect(stillThere).toBeNull(); }, 15_000); - it("T29 the lease refresh command carries bypassSession and contains no mkdir", async () => { + it("T34 the lease refresh command carries bypassSession and contains no mkdir", async () => { const rootDir = await mkdtemp(path.join(os.tmpdir(), "paperclip-lease-command-shape-")); cleanupDirs.push(rootDir); const childPath = path.join(rootDir, "quiet-child.mjs"); @@ -2236,7 +2554,7 @@ describe("deterministic remote process-session wrapper shutdown (PAP-5316)", () } }, 10_000); - it("T30 validation: a zero, a negative, a non-numeric, and a D<=P lease override pair all fall back to the defaults on the host and in the wrapper", async () => { + it("T35 validation: a zero, a negative, a non-numeric, and a D<=P lease override pair all fall back to the defaults on the host and in the wrapper", async () => { const invalidPairs: Array<[string, string]> = [ ["0", "900000"], ["-1000", "900000"], @@ -2320,7 +2638,7 @@ describe("deterministic remote process-session wrapper shutdown (PAP-5316)", () ]); }, 30_000); - it("T31 the lease refresh exec carries its own short timeout, never the run's adapter timeout", async () => { + it("T36 the lease refresh exec carries its own short timeout, never the run's adapter timeout", async () => { const rootDir = await mkdtemp(path.join(os.tmpdir(), "paperclip-lease-refresh-timeout-")); cleanupDirs.push(rootDir); const childPath = path.join(rootDir, "quiet-child.mjs"); diff --git a/packages/adapter-utils/src/execution-target.ts b/packages/adapter-utils/src/execution-target.ts index 5b8022bf72a..e945a319547 100644 --- a/packages/adapter-utils/src/execution-target.ts +++ b/packages/adapter-utils/src/execution-target.ts @@ -2697,31 +2697,104 @@ function nextProbeFileName() { // change-time copy. Creating and removing a file inside a directory changes // that directory's OWN change time but never its true creation time, so a // birthtimeMs that moves across the probe is a change-time copy. Returns -// false both on a detected copy and on a probe that cannot run at all (for -// example a permission error): either way the caller must not trust the -// value. +// null when the value is proven real. Returns a stderr-ready reason string +// on any failure (a detected copy, or a probe that cannot run at all, for +// example a permission error or a pre-created probe path): either way the +// caller must not trust the value. +// +// The open uses the "wx" flag: exclusive create, fail if the path exists. +// A sandbox peer cannot pre-create the probe path as a symbolic link and +// have this call follow it, because "wx" fails closed on an existing path +// instead of following a link to it. +// +// Cleanup checks identity, not only ownership of the initial create. This +// wrapper reads the probe file's identity, (dev, ino, ctimeMs), off the open +// file descriptor itself (fstat), not off the path, so a peer that swaps the +// path in the short gap after create cannot poison the identity this +// wrapper trusts as its own. Right before removal, this wrapper reads the +// path's identity again and removes it only when that identity still +// matches. A same-sandbox peer that deletes the probe file and creates its +// own entry at the same path in between leaves a different identity behind, +// so this wrapper leaves that entry untouched instead of removing it. This +// covers a peer's replacement file, a peer's replacement directory, and a +// peer's replacement symbolic link alike, because all three change the +// identity this wrapper reads back. The identity check includes ctimeMs, +// not only (dev, ino): a filesystem can hand this call's freed inode number +// straight back out to a peer's very next create at the same path, so +// (dev, ino) alone can match a path this call no longer owns; ctimeMs resets +// on every create, so a peer's replacement carries a different one even when +// the inode number repeats. Node's filesystem API has no call that removes a +// path only when its identity still matches an earlier read as one atomic +// step, so a gap remains between this wrapper's final identity read and the +// removal call itself. A peer that wins this gap can put any entry at the +// probe path before the removal call runs. This can include a pre-existing +// file the peer renames into place, not only a file the peer creates fresh. +// The removal call then removes whatever entry sits at the probe path at +// that moment. Two bounds still hold on that removal. The path always +// stays under dirPath. If the entry is a symbolic link, the removal call +// removes the link itself instead of following it to a different target. +// A non-recursive removal call also fails if the entry is a directory. async function birthtimeSurvivesProbe(dirPath) { let before; try { before = (await fs.lstat(dirPath)).birthtimeMs; } catch { - return false; + return "its reported creation time could not be read"; } const probePath = path.posix.join(dirPath, nextProbeFileName()); + let handle; try { - await fs.writeFile(probePath, ""); + handle = await fs.open(probePath, "wx"); } catch { - return false; + return "its probe file could not be created exclusively (the path may already exist)"; + } + // fstat on the open handle names the exact inode this call just created. + // A path-based lstat here instead would be racy against a peer that swaps + // the path in the gap between the create above and the stat: fstat has no + // such gap, because a file descriptor keeps naming the inode it opened no + // matter what a later swap does to the path. + let ownedIdentity = null; + try { + const createdStats = await handle.stat(); + // ctimeMs guards against inode reuse; see the function comment above. + ownedIdentity = { dev: createdStats.dev, ino: createdStats.ino, ctimeMs: createdStats.ctimeMs }; + } catch { + ownedIdentity = null; } finally { + await handle.close().catch(() => undefined); + } + if (!ownedIdentity) { + // fstat on this call's own just-opened descriptor failed. This call then + // has no verified identity for the probe file it created, so it must not + // check or remove that file by path: a peer could already own the entry + // at that path, and a path-based removal here could delete the peer's + // entry instead of this call's own file. Fail closed right here instead + // of falling through to the birthtime comparison below, so a failed + // identity read can never let this probe report success. + return "its own probe file's identity could not be read from the open file descriptor"; + } + // The one gap the fs API cannot close: this lstat and the removal below + // are two separate calls, not one atomic "remove if identity still + // matches" step. A peer that wins this narrow gap can put any entry at + // the probe path, including a pre-existing file it renames into place, + // and the removal call below removes whatever entry is there when it + // runs. + const currentStats = await fs.lstat(probePath).catch(() => null); + const stillOwned = + currentStats !== null && + currentStats.dev === ownedIdentity.dev && + currentStats.ino === ownedIdentity.ino && + currentStats.ctimeMs === ownedIdentity.ctimeMs; + if (stillOwned) { await fs.rm(probePath, { force: true }).catch(() => undefined); } let after; try { after = (await fs.lstat(dirPath)).birthtimeMs; } catch { - return false; + return "its reported creation time could not be read"; } - return before === after; + return before === after ? null : "its reported creation time changed after a probe write"; } async function refuseUnusableCreationTime(label, dirPath, reason) { @@ -2748,12 +2821,14 @@ async function refuseUnusableCreationTime(label, dirPath, reason) { // it, run once here, before either directory's identity is captured. async function captureSessionIdentity() { try { - if (!(await birthtimeSurvivesProbe(sessionDir))) { - await refuseUnusableCreationTime("sessionDir", sessionDir, "its reported creation time changed after a probe write"); + const sessionProbeFailure = await birthtimeSurvivesProbe(sessionDir); + if (sessionProbeFailure) { + await refuseUnusableCreationTime("sessionDir", sessionDir, sessionProbeFailure); return; } - if (!(await birthtimeSurvivesProbe(stdinDir))) { - await refuseUnusableCreationTime("stdinDir", stdinDir, "its reported creation time changed after a probe write"); + const stdinProbeFailure = await birthtimeSurvivesProbe(stdinDir); + if (stdinProbeFailure) { + await refuseUnusableCreationTime("stdinDir", stdinDir, stdinProbeFailure); return; } const session = await statPathIdentity(sessionDir); diff --git a/packages/adapters/claude-local/package.json b/packages/adapters/claude-local/package.json index a645a137099..b6bdb2c895a 100644 --- a/packages/adapters/claude-local/package.json +++ b/packages/adapters/claude-local/package.json @@ -54,6 +54,7 @@ }, "dependencies": { "@agentclientprotocol/claude-agent-acp": "^0.70.0", + "@anthropic-ai/sdk": "0.121.0", "@paperclipai/adapter-utils": "workspace:*", "@paperclipai/shared": "workspace:*", "picocolors": "^1.1.1" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6969138f192..8b0b149369a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,7 +1,7 @@ lockfileVersion: '9.0' settings: - autoInstallPeers: true + autoInstallPeers: false excludeLinksFromLockfile: false overrides: @@ -45,7 +45,7 @@ importers: version: 7.0.2 vitest: specifier: ^4.1.10 - version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@25.2.3)(jsdom@30.0.1(@noble/hashes@2.3.0))(vite@8.2.2(@types/node@25.2.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) + version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(jsdom@30.0.1(@noble/hashes@2.3.0))(tsx@4.23.12) cli: dependencies: @@ -105,7 +105,7 @@ importers: version: 17.4.2 drizzle-orm: specifier: 0.45.2 - version: 0.45.2(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9)(sqlite3@5.1.7) + version: 0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9) embedded-postgres: specifier: ^18.1.0-beta.16 version: 18.1.0-beta.16(patch_hash=55uhvnotpqyiy37rn3pqpukhei) @@ -143,7 +143,10 @@ importers: dependencies: '@agentclientprotocol/claude-agent-acp': specifier: ^0.70.0 - version: 0.70.0(@anthropic-ai/sdk@0.81.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.30.0(zod@4.4.3)) + version: 0.70.0(@anthropic-ai/sdk@0.121.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.30.0(zod@4.4.3)) + '@anthropic-ai/sdk': + specifier: 0.121.0 + version: 0.121.0(zod@4.4.3) '@paperclipai/adapter-utils': specifier: workspace:* version: link:../../adapter-utils @@ -267,7 +270,7 @@ importers: version: 7.0.2 vitest: specifier: ^4.1.10 - version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.3.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) + version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(jsdom@30.0.1(@noble/hashes@2.3.0))(tsx@4.23.12) packages/adapters/hermes-gateway: dependencies: @@ -283,7 +286,7 @@ importers: version: 7.0.2 vitest: specifier: ^4.1.10 - version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.3.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) + version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(jsdom@30.0.1(@noble/hashes@2.3.0))(tsx@4.23.12) packages/adapters/kimi-local: dependencies: @@ -362,7 +365,7 @@ importers: version: link:../shared drizzle-orm: specifier: ^0.45.2 - version: 0.45.2(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9)(sqlite3@5.1.7) + version: 0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9) embedded-postgres: specifier: ^18.1.0-beta.16 version: 18.1.0-beta.16(patch_hash=55uhvnotpqyiy37rn3pqpukhei) @@ -384,7 +387,7 @@ importers: version: 7.0.2 vitest: specifier: ^4.1.10 - version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.3.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) + version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(jsdom@30.0.1(@noble/hashes@2.3.0))(tsx@4.23.12) packages/google-sheets-mcp-server: dependencies: @@ -406,7 +409,7 @@ importers: version: 7.0.2 vitest: specifier: ^4.1.10 - version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.3.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) + version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(jsdom@30.0.1(@noble/hashes@2.3.0))(tsx@4.23.12) packages/kv-demo-mcp-server: dependencies: @@ -425,7 +428,7 @@ importers: version: 7.0.2 vitest: specifier: ^4.1.10 - version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.3.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) + version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(jsdom@30.0.1(@noble/hashes@2.3.0))(tsx@4.23.12) packages/mcp-server: dependencies: @@ -447,7 +450,7 @@ importers: version: 7.0.2 vitest: specifier: ^4.1.10 - version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.3.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) + version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(jsdom@30.0.1(@noble/hashes@2.3.0))(tsx@4.23.12) packages/paperclip-runner: dependencies: @@ -466,7 +469,7 @@ importers: version: 7.0.2 vitest: specifier: ^4.1.10 - version: 4.1.11(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.3.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) + version: 4.1.11(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(jsdom@30.0.1(@noble/hashes@2.3.0))(tsx@4.23.12) packages/plugins/create-paperclip-plugin: dependencies: @@ -486,9 +489,6 @@ importers: '@paperclipai/plugin-sdk': specifier: workspace:* version: link:../../sdk - react: - specifier: ^19.2.8 - version: 19.2.8 devDependencies: '@rollup/plugin-node-resolve': specifier: ^16.0.1 @@ -516,7 +516,7 @@ importers: version: 7.0.2 vitest: specifier: ^4.1.10 - version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.3.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) + version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(jsdom@30.0.1(@noble/hashes@2.3.0))(tsx@4.23.12) packages/plugins/examples/plugin-file-browser-example: dependencies: @@ -634,13 +634,9 @@ importers: version: 7.0.2 vitest: specifier: ^4.1.10 - version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.3.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) + version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(jsdom@30.0.1(@noble/hashes@2.3.0))(tsx@4.23.12) packages/plugins/plugin-llm-wiki: - dependencies: - react: - specifier: ^19.2.8 - version: 19.2.8 devDependencies: '@paperclipai/plugin-sdk': specifier: workspace:* @@ -677,7 +673,7 @@ importers: version: 7.0.2 vitest: specifier: ^4.1.10 - version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.3.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) + version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(jsdom@30.0.1(@noble/hashes@2.3.0))(tsx@4.23.12) packages/plugins/plugin-workspace-diff: dependencies: @@ -711,16 +707,13 @@ importers: version: 7.0.2 vitest: specifier: ^4.1.10 - version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.3.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) + version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(jsdom@30.0.1(@noble/hashes@2.3.0))(tsx@4.23.12) packages/plugins/sdk: dependencies: '@paperclipai/shared': specifier: workspace:* version: link:../../shared - react: - specifier: ^19.2.8 - version: 19.2.8 zod: specifier: ^4.4.3 version: 4.4.3 @@ -768,7 +761,7 @@ importers: version: 7.0.2 vitest: specifier: ^4.1.10 - version: 4.1.11(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.3.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) + version: 4.1.11(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(jsdom@30.0.1(@noble/hashes@2.3.0))(tsx@4.23.12) packages/teams-catalog: devDependencies: @@ -840,7 +833,7 @@ importers: version: 3.0.1(ajv@8.20.0) better-auth: specifier: 1.7.0 - version: 1.7.0(@opentelemetry/api@1.9.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9)(sqlite3@5.1.7))(pg@8.18.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vitest@4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.3.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12))) + version: 1.7.0(@opentelemetry/api@1.9.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9))(pg@8.18.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vitest@4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(jsdom@30.0.1(@noble/hashes@2.3.0))(tsx@4.23.12)) chokidar: specifier: ^5.0.0 version: 5.0.0 @@ -855,7 +848,7 @@ importers: version: 17.4.2 drizzle-orm: specifier: ^0.45.2 - version: 0.45.2(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9)(sqlite3@5.1.7) + version: 0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9) embedded-postgres: specifier: ^18.1.0-beta.16 version: 18.1.0-beta.16(patch_hash=55uhvnotpqyiy37rn3pqpukhei) @@ -937,7 +930,7 @@ importers: version: 8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12) vitest: specifier: ^4.1.10 - version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.3.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) + version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(jsdom@30.0.1(@noble/hashes@2.3.0))(tsx@4.23.12) ui: dependencies: @@ -1067,6 +1060,9 @@ importers: tailwind-merge: specifier: ^3.6.0 version: 3.6.0 + yjs: + specifier: 13.6.29 + version: 13.6.29 devDependencies: '@sentry/browser': specifier: ^10.71.0 @@ -1076,10 +1072,10 @@ importers: version: 10.5.10(storybook@10.5.10(@types/react@19.2.18)(react@19.2.8)) '@storybook/addon-docs': specifier: 10.5.10 - version: 10.5.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(esbuild@0.28.2)(rollup@4.63.0)(storybook@10.5.10(@types/react@19.2.18)(react@19.2.8))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) + version: 10.5.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(esbuild@0.28.2)(rollup@4.62.4)(storybook@10.5.10(@types/react@19.2.18)(react@19.2.8))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) '@storybook/react-vite': specifier: 10.5.10 - version: 10.5.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(esbuild@0.28.2)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(rollup@4.63.0)(storybook@10.5.10(@types/react@19.2.18)(react@19.2.8))(typescript@7.0.2)(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) + version: 10.5.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(esbuild@0.28.2)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(rollup@4.62.4)(storybook@10.5.10(@types/react@19.2.18)(react@19.2.8))(typescript@7.0.2)(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) '@tailwindcss/vite': specifier: ^4.3.3 version: 4.3.3(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) @@ -1109,7 +1105,7 @@ importers: version: 8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12) vitest: specifier: ^4.1.10 - version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.3.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) + version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(jsdom@30.0.1(@noble/hashes@2.3.0))(tsx@4.23.12) packages: @@ -1191,8 +1187,8 @@ packages: '@modelcontextprotocol/sdk': ^1.29.0 zod: ^4.0.0 - '@anthropic-ai/sdk@0.81.0': - resolution: {integrity: sha512-D4K5PvEV6wPiRtVlVsJHIUhHAmOZ6IT/I9rKlTf84gR7GyyAurPJK7z9BOf/AZqC5d1DhYQGJNKRmV+q8dGhgw==} + '@anthropic-ai/sdk@0.121.0': + resolution: {integrity: sha512-WFzwcH8l49CZHv0vQ9QQT51VJ1/DLDQfNSs9awpGlnKBdaSnqtdZa+tw/3cxxosTPIgK8uw1GqsJ2dSbCBD1Lg==} hasBin: true peerDependencies: zod: ^3.25.0 || ^4.0.0 @@ -1767,9 +1763,6 @@ packages: '@drizzle-team/brocli@0.10.2': resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==} - '@electric-sql/pglite@0.3.15': - resolution: {integrity: sha512-Cj++n1Mekf9ETfdc16TlDi+cDDQF0W7EcbyRHYOAeZdsAe8M/FJg18itDTSwyHfar2WIezawM9o0EKaRGVKygQ==} - '@embedded-postgres/darwin-arm64@18.1.0-beta.16': resolution: {integrity: sha512-tU/syLOamFZdXMC+p7AYczmFKIiolFlZ8y3Qb7KonX37O07ezc/OSDiQ641sheV3X0WPf9V10qyK8c81rleDdw==} engines: {node: '>=16'} @@ -2328,9 +2321,6 @@ packages: '@floating-ui/utils@0.2.12': resolution: {integrity: sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==} - '@gar/promisify@1.1.3': - resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} - '@hono/node-server@2.1.0': resolution: {integrity: sha512-XovyyCCnBzW+zKu+z/zq8hwNs4KOR5rEMAOxo2f40Q5xoOI37IMm6MIg2COOUtUApo0i6850MTBKH2u4QLGIqg==} engines: {node: '>=20'} @@ -2849,14 +2839,6 @@ packages: resolution: {integrity: sha512-oN+QwyX7VSHotibwubG3kpzbwKrfnyR6OOO+3Nk/53ADL7FmgHHz4TgrbaYKvvOw09u6QTx0oiH1cNCIOuN0CQ==} engines: {node: '>= 20.19.0'} - '@npmcli/fs@1.1.1': - resolution: {integrity: sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==} - - '@npmcli/move-file@1.1.2': - resolution: {integrity: sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==} - engines: {node: '>=10'} - deprecated: This functionality has been moved to @npmcli/fs - '@openai/codex@0.148.0': resolution: {integrity: sha512-bh5kH9+BMrFaHGmLeoSansPdfRksvr4UXzjQInns/KRO7r8VJ+6AAW+SqUsE8XcG3+OW/mI4EEy8Gpo9UDXGvQ==} engines: {node: '>=16'} @@ -4202,251 +4184,126 @@ packages: cpu: [arm] os: [android] - '@rollup/rollup-android-arm-eabi@4.63.0': - resolution: {integrity: sha512-70TeIFezKKy65LgAVyQh+w94/gjWhvPWaLaGGeMEgVrPkQhuj/M5bAYYZzIFUj9Y69oHyTm5Um/R6gcLh4A8JA==} - cpu: [arm] - os: [android] - '@rollup/rollup-android-arm64@4.62.4': resolution: {integrity: sha512-JKuJc+pnpks2pjy7L/N3v/cAkZxYlnmuZoD840ldbMI5KDbC4iO9NKwPKYdjYFCMAIIlBzYSFHxIJVYzRo2/8A==} cpu: [arm64] os: [android] - '@rollup/rollup-android-arm64@4.63.0': - resolution: {integrity: sha512-YC86tYIHK6M1IV+wbzO+Bxk8RCBr6ZyWYgWxUCzaZD8mc8rrFoIJDNzDrkHBYRc/wKdrsIXmm6/F7NzrAO+OrA==} - cpu: [arm64] - os: [android] - '@rollup/rollup-darwin-arm64@4.62.4': resolution: {integrity: sha512-krw5uS2STmvJ02x0uTXHbqQNuz+9eZ1iw+qXk9dmW2gvV4jV7O2hEoOnuhFrpOPiel1mBFtqbxYZZtC46hXLOw==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-arm64@4.63.0': - resolution: {integrity: sha512-oI+ECtUcli0y0fi4xpW82GdPIXdTkI8G8DSjG2LRuw09fPAGykaWYH/hXxiKuTxiAjiPSTIIuYUqof5Z2hShWw==} - cpu: [arm64] - os: [darwin] - '@rollup/rollup-darwin-x64@4.62.4': resolution: {integrity: sha512-wsTxtgApb4PrOsNJIm0FZ1h3WvCC+k9uxLJ4ad75hgoS4NiRes2SoJFlDAyMwiUY8IssDqGcHbXuN0sx1tfF1A==} cpu: [x64] os: [darwin] - '@rollup/rollup-darwin-x64@4.63.0': - resolution: {integrity: sha512-NwV+1s7TiKrMe4owHyKB/dTLD7ZJD0YEBEhIz+hvav1Cu1GReJjF+rsdNwjzENQeIAbE/CoNiaAc5Vz2h5DPAA==} - cpu: [x64] - os: [darwin] - '@rollup/rollup-freebsd-arm64@4.62.4': resolution: {integrity: sha512-GUOnQlyZe3yAXhWOtOMsn5Qkrv5E5mZXa0thbARWi5Ei2szlVXJFQhddZ4HbAzh8q92w5twp+CQvs/eFanz9YQ==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-arm64@4.63.0': - resolution: {integrity: sha512-tWtHBTu5gOPK4u4Urtk4qAHW3zZ9rQAmbssO8gp7ELvGTGI3aCiq6NqyTQ0PCIg7KbHJF2UkGDDs77YZGxfjCA==} - cpu: [arm64] - os: [freebsd] - '@rollup/rollup-freebsd-x64@4.62.4': resolution: {integrity: sha512-/Y7f3QuxjzPKsjA/rfEDa3+0vXqyjmJ50Ln8dPpCmWkKTrUoWHG1cWhTqaAMLob2m2nESWuC7yGrREz019Ztqg==} cpu: [x64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.63.0': - resolution: {integrity: sha512-2qPoJiwTvtHQ27NnYvTnsgk8laXWYuVmNESG8WFZBcEPKLfZ3I27qBJarjVRQtwGeYyRfq5ZowHXih9lm2BItw==} - cpu: [x64] - os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.62.4': resolution: {integrity: sha512-81wiiX3v7aqy+T+bT61TJ78yJjRquqFFTTbAPt08imfQQzkPIW8t6aJbkTagtCCrXMNc9D66+geqlK7ydLPNqA==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-gnueabihf@4.63.0': - resolution: {integrity: sha512-FQwsTRvLNuHoTdICABJQfbPUSEueISGmnpT06tXTMpfprf5NiKLSXKA0A+w45wJnCmZAnzgqBwbt6ARFuyOi5w==} - cpu: [arm] - os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.62.4': resolution: {integrity: sha512-9kmDIvNZqdoHOBZgNtpTBeLWYO/LVipM3H/j62P8848/l/VPEQL6N3uxU9pvP1oZAsXyC2MEnFP3ovRjo7WYNQ==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.63.0': - resolution: {integrity: sha512-BBVTXziw8mY1a4ZbWME9tZyfzqXCDPqaC7Z3heQ29p5dkvXzwL0NwelO8zLa8c3RBKvl3YTuSnBgsBhYBtwjIw==} - cpu: [arm] - os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.62.4': resolution: {integrity: sha512-CcnXHWnXg69g+DX5VWL3FHts3qMRN2uVEHX+BZvGLdd07/gXkn3ePjYtO1LDJvxkGKVHMclKBRa1QUTH+6toYQ==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.63.0': - resolution: {integrity: sha512-w2Iyy9+RqKwx3d9qWMKsJg0FfRBsY0/pXNv0mCQ3ueRvJI6+QAScfD4nrMlzFLs2HNVW6Ew+mtZfDl9b7Ew5/Q==} - cpu: [arm64] - os: [linux] - '@rollup/rollup-linux-arm64-musl@4.62.4': resolution: {integrity: sha512-iFOibiHnTRuhrWLlRsOQFdZJJIa7S8OwkneJr4ocALP16u5yk6lWLINFwhHaEqBFMsKDUZofLkGos7+CPzGB3g==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.63.0': - resolution: {integrity: sha512-YK++KtrFRHYE0P6/RtYEAy9t8F37znP+K03RrIuLPYOL6SVlObRumf/0OE4V/h63xL9DwkWbNssZfmA9hawuDA==} - cpu: [arm64] - os: [linux] - '@rollup/rollup-linux-loong64-gnu@4.62.4': resolution: {integrity: sha512-XnWYMI7euHlb5a871xPja+Gm7DRCFU+FGRrtS2sMq9N8FvqtpagUy6gD4YOemC5MRk9xbh8+jYMEJbigFQwsgA==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-loong64-gnu@4.63.0': - resolution: {integrity: sha512-aBfOG6fP7YkkPmTqPwufRJeFyz7WPpECv9XNbnsk9+vg7rxdih0lbtEel7jcRng4LZrrmU3FfitCFyEj4BWDWg==} - cpu: [loong64] - os: [linux] - '@rollup/rollup-linux-loong64-musl@4.62.4': resolution: {integrity: sha512-qGDAlO0U8xedCcsdRm9oaoQY8DAx/QT7uIxJWhCdx0ceIWX783UC9QSYkdpzAe29wNiVfp24+bZdQmn49o45SQ==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-loong64-musl@4.63.0': - resolution: {integrity: sha512-LGaHEOeHNAag9VuS1Crs5DFg4RrU9MPi2nVnNJk9DTePx/B6RRYKVmrIXt2h7YOJlwjaFJ6lwtFDliZxScTLrQ==} - cpu: [loong64] - os: [linux] - '@rollup/rollup-linux-ppc64-gnu@4.62.4': resolution: {integrity: sha512-ru4H6ezD7ysA5EiEK6qkkaEb4modH8CTej6kUy/gQi20u3kB3G7Zn8snXXkeJSCOFKG/rbPPtM/+9Wgas1961w==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-ppc64-gnu@4.63.0': - resolution: {integrity: sha512-jClvk+J0FC3b7Udvegiw5/4hErbHtmsNsQgENnKXDWtNCJXsJYZH5WURvu7imDOO38xYml24eeh5x3A04ppwCw==} - cpu: [ppc64] - os: [linux] - '@rollup/rollup-linux-ppc64-musl@4.62.4': resolution: {integrity: sha512-2W4MO5WQVJnbJaZdvDb9rhBDuFU1nKIepPFpJUBsTh2k1YY2g+ODViaWuyOAjQ5cOP7NvrvLzt3wvHOoiAvc7w==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-ppc64-musl@4.63.0': - resolution: {integrity: sha512-0OJlaGK+8+B777Ql5okIpD7ua5Ro9+VB9Ve0OKa28OQJZ1RbuUBVNHK/e3pr4BROqsyPl1JrPO1ZxJseCNffcA==} - cpu: [ppc64] - os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.62.4': resolution: {integrity: sha512-+fxjfuoAmVMCYV5QyjoIpu0cp5DOiOTeqYFk1AVaxGr+/ravWLX89XfQmptsoWcaVy/TGf2hexzbUOrCQIL1CQ==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.63.0': - resolution: {integrity: sha512-Ygsx+HoNH7afwi1bTIXbnTvVnsO+zurPLSYxybV1hHFVU72OWOCl6v05ql/z0hkpAPx+DK7Kn9Bi7MayCcjLTA==} - cpu: [riscv64] - os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.62.4': resolution: {integrity: sha512-jTn8JfHGL4djjFxPuM06LmNUJDsst2jeVlsd9OmIH6zc5sC9K6rIuO4YajXatLUpBmBKl6b35ro1QZocLi+tcA==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.63.0': - resolution: {integrity: sha512-pDQxtMGb+OvG3fLwR2OkZlSd47hW+kWg4BYMG/++sR6RqorQccwPTDsxda5hPwiIeIErAnCF9ma3SAU06bdQtQ==} - cpu: [riscv64] - os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.62.4': resolution: {integrity: sha512-oCJCJL4pXsoDcP2QZ+JVlPTIRc6266zsIaeJJsWImmF7HO0W8nb6HuSgZlMWxJwaPf8ehbSw8yo0EUw925hKsA==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.63.0': - resolution: {integrity: sha512-0BnUG9mS8I4SSHr3XsxVhuCMEiu+rX61xxZF5vujso4LaiAGFZFxvDjg6Xn6tLPNTUAfuCvQYas4LMQMVsKRSQ==} - cpu: [s390x] - os: [linux] - '@rollup/rollup-linux-x64-gnu@4.62.4': resolution: {integrity: sha512-W69hukhZ3KKNRCaMIEzKvcFye42hh0FE1+YoYaf5+Ikacuftoco6yO/xouz0hc5d5W/s3yBro5jRiuEE/Q5vUw==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.63.0': - resolution: {integrity: sha512-Adu/VttB1dpPNW+FEacrZ+xVm9tFty84+RrFzsqlFaPxoJB+9XXyDGtp5dCOoBwGBIEVH0To7lExFXEx0BIF4A==} - cpu: [x64] - os: [linux] - '@rollup/rollup-linux-x64-musl@4.62.4': resolution: {integrity: sha512-qiXbGG2jkjXhzXpsFZSR2Xpb8DN/UaxYsbb/STbuR/6fpaDgRmmaq1B/LmtF2wQFOFOSsK2jdE0RZ3a0zHn4QA==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.63.0': - resolution: {integrity: sha512-NQ3bDvjUbFKmP23671xUlXtKmqVsUBd6M4PQCvbmNtOy06hnQIdKHy8oG/6S3R/S6He1JgPk6A5VT+prAJMYEw==} - cpu: [x64] - os: [linux] - '@rollup/rollup-openbsd-x64@4.62.4': resolution: {integrity: sha512-nWeM//hxv8mIo6jD7Hu4o48DVmV9pbV6gsKaWU+4NFyqHoPKwrkRiZGLKUhOBk8qNmDmpwFtPKg80Bo/Tn4xiQ==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openbsd-x64@4.63.0': - resolution: {integrity: sha512-u2eDAl4+0aFvA13GxlGBtTI3SS3sdgwgtV0HyjZ0QaQVCgNE+jqNGey+GtxWiq+wxr/UycAx/OnfJzApCFamvA==} - cpu: [x64] - os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.62.4': resolution: {integrity: sha512-s62SQ/vgsRSvMwDkOEfTqfgASF0f26ZNaQuTA6Aok5lrikf89yI2W0gFHvZb2Jpgc6N8JnOKZgCK2iciO3CsxQ==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-openharmony-arm64@4.63.0': - resolution: {integrity: sha512-XvRb5vfW3wAZQ+ZUG21AnHHDKtNcw99eigzEhjr//NZ3u7SoBaPP0seSc7FgP7p1epAEdAoZckMW9WY/+4w70w==} - cpu: [arm64] - os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.62.4': resolution: {integrity: sha512-J6wGf8TVGbXJq+HH+ttTvrcfNKPbuZecV6KT1B8I18BC5IURUh5kl4Yl5OEP5eFIUoI5BWxCsyYMhFsDx8kekw==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-arm64-msvc@4.63.0': - resolution: {integrity: sha512-iZPmniy4kNBf5yo2RezbkYNNK5HPbXE9+g+twnbqSng7dtLEJy1SKoxiE/ni4FDacjyuZpEeb9U054N4EoKHYw==} - cpu: [arm64] - os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.62.4': resolution: {integrity: sha512-zmfrQd/0wu6oJs8Vq8KwY/YtsKSsLtKe/HwAP4Wqy8LhWjeT55fHRAkOhYQ12wI3ayS4Tt12d5CDRD7N96SAYQ==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.63.0': - resolution: {integrity: sha512-mFBBd+LF37fnE8JnYUOH+imj0aPFPK30vpar4ehJkgnLj9sZn8ZxiRENmLtgIwxK7TC8klF6N57fxdNBwQoqOA==} - cpu: [ia32] - os: [win32] - '@rollup/rollup-win32-x64-gnu@4.62.4': resolution: {integrity: sha512-qPzHqdj9rfUD+w79dtE07zi/kFwKyCJqplp5K5ygeLTp7jLpAoc16OAH39HSmRC9UpozaecsleI8uAdEj6v2yw==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.63.0': - resolution: {integrity: sha512-ujeqEY3B+zbGn3Z4Q03cUBG/LGWnBJncVT36WER31LcOsQk9+1dmINKKtvmmfChUvRbK1G0R8OhMWFgHgaZtAw==} - cpu: [x64] - os: [win32] - '@rollup/rollup-win32-x64-msvc@4.62.4': resolution: {integrity: sha512-zD6NdeWEByGE9QF9vCrlJ5YQB4oq9q91kPZS37Jwj5hOkvR1lTBSpsKhKDw4IJtbQ35LsTS1HD9DZYGKIshU1Q==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.63.0': - resolution: {integrity: sha512-hncn90N4sOky0L2LKE5oESKLbxCPeVo4eLA2LSMoDzM+879ml4WSr+Rr4DWknNIVVvS1Hirkc9hx02W6YxS8rQ==} - cpu: [x64] - os: [win32] - '@sentry/browser-utils@10.71.0': resolution: {integrity: sha512-Djhb+RdEwSdYTlDaMzc2uRCA+bYDIFsFCtZzKEtB9UR7lJNV/bJ0k3el3ifaVGTRELO8WBll/X0elty1Dk5tTw==} engines: {node: '>=18'} @@ -4534,6 +4391,9 @@ packages: resolution: {integrity: sha512-FOKpVZob9MPTn2znRzGrnsMHv7BOsKVw3XiP/cOyYLDVZ9qKp4nifIiSCuUU/fIj5Vu0UOAxCFr+qRAtG0NUkA==} engines: {node: '>=18.0.0'} + '@stablelib/base64@1.0.1': + resolution: {integrity: sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==} + '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} @@ -4749,10 +4609,6 @@ packages: peerDependencies: '@testing-library/dom': '>=7.21.4' - '@tootallnate/once@1.1.2': - resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==} - engines: {node: '>= 6'} - '@tybys/wasm-util@0.10.3': resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} @@ -4930,9 +4786,6 @@ packages: '@types/node@24.13.3': resolution: {integrity: sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==} - '@types/node@25.2.3': - resolution: {integrity: sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==} - '@types/qs@6.15.1': resolution: {integrity: sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==} @@ -5196,9 +5049,6 @@ packages: '@xterm/xterm@6.0.0': resolution: {integrity: sha512-TQwDdQGtwwDt+2cgKDLn0IRaSxYu1tSUjgKarSDkUM0ZNiSRXFpjxEsvc/Zgc5kq5omJ+V0a8/kIM2WD3sMOYg==} - abbrev@1.1.1: - resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} - accepts@2.0.0: resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} engines: {node: '>= 0.6'} @@ -5222,22 +5072,10 @@ packages: resolution: {integrity: sha512-XNAb/a6TCqou+TufU8/u11HCu9x1gYvOoxLwtlXgIqmkrYQADVv6ljyW2zwiPhHz9R1gItAWpuDrdJMmrOBFEA==} engines: {node: '>= 16.0.0'} - agent-base@6.0.2: - resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} - engines: {node: '>= 6.0.0'} - agent-base@7.1.4: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} - agentkeepalive@4.6.0: - resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} - engines: {node: '>= 8.0.0'} - - aggregate-error@3.1.0: - resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} - engines: {node: '>=8'} - ajv-formats@3.0.1: resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} peerDependencies: @@ -5272,14 +5110,6 @@ packages: append-field@1.0.0: resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==} - aproba@2.1.0: - resolution: {integrity: sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==} - - are-we-there-yet@3.0.1: - resolution: {integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - deprecated: This package is no longer supported. - argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -5479,12 +5309,6 @@ packages: bignumber.js@9.3.1: resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} - bindings@1.5.0: - resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} - - bl@4.1.0: - resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - body-parser@2.2.2: resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} engines: {node: '>=18'} @@ -5492,9 +5316,6 @@ packages: bowser@2.14.1: resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==} - brace-expansion@1.1.18: - resolution: {integrity: sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==} - brace-expansion@2.1.4: resolution: {integrity: sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==} @@ -5513,9 +5334,6 @@ packages: buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - buffer@5.7.1: - resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - buildcheck@0.0.7: resolution: {integrity: sha512-lHblz4ahamxpTmnsk+MNTRWsjYKv965MwOrSJyeD588rR3Jcu7swE+0wN5F+PbL5cjgu/9ObkhfzEPuofEMwLA==} engines: {node: '>=10.0.0'} @@ -5532,10 +5350,6 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} - cacache@15.3.0: - resolution: {integrity: sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==} - engines: {node: '>= 10'} - call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -5578,23 +5392,12 @@ packages: resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} engines: {node: '>= 20.19.0'} - chownr@1.1.4: - resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} - - chownr@2.0.0: - resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} - engines: {node: '>=10'} - class-variance-authority@0.7.1: resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} classnames@2.5.1: resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} - clean-stack@2.2.0: - resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} - engines: {node: '>=6'} - clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} @@ -5623,10 +5426,6 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - color-support@1.1.3: - resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} - hasBin: true - colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} @@ -5655,16 +5454,10 @@ packages: compute-scroll-into-view@2.0.4: resolution: {integrity: sha512-y/ZA3BGnxoM/QHHQ2Uy49CLtnWPbt4tTPpEEZiEmmiWBFKjej7nEyH8Ryz54jH0MLXflUYA3Er2zUxPSJu5R+g==} - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - concat-stream@2.0.0: resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==} engines: {'0': node >= 6.0} - console-control-strings@1.1.0: - resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} - content-disposition@1.0.1: resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} engines: {node: '>=18'} @@ -5917,18 +5710,10 @@ packages: decode-named-character-reference@1.3.0: resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} - decompress-response@6.0.0: - resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} - engines: {node: '>=10'} - deep-eql@5.0.2: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} - deep-extend@0.6.0: - resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} - engines: {node: '>=4.0.0'} - deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} @@ -5955,9 +5740,6 @@ packages: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} - delegates@1.0.0: - resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} - depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} @@ -6144,9 +5926,6 @@ packages: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} - encoding@0.1.13: - resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} - end-of-stream@1.4.5: resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} @@ -6158,13 +5937,6 @@ packages: resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==} engines: {node: '>=20.19.0'} - env-paths@2.2.1: - resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} - engines: {node: '>=6'} - - err-code@2.0.3: - resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} - es-define-property@1.0.1: resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} @@ -6252,10 +6024,6 @@ packages: resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} engines: {node: '>=18.0.0'} - expand-template@2.0.3: - resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} - engines: {node: '>=6'} - expect-type@1.4.0: resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} engines: {node: '>=12.0.0'} @@ -6285,6 +6053,9 @@ packages: fast-safe-stringify@2.1.1: resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + fast-sha256@1.3.0: + resolution: {integrity: sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==} + fast-string-truncated-width@3.0.3: resolution: {integrity: sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==} @@ -6313,9 +6084,6 @@ packages: resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} engines: {node: ^12.20 || >= 14.13} - file-uri-to-path@1.0.0: - resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} - finalhandler@2.1.1: resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} engines: {node: '>= 18.0.0'} @@ -6366,16 +6134,6 @@ packages: resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} engines: {node: '>= 0.8'} - fs-constants@1.0.0: - resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} - - fs-minipass@2.1.0: - resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} - engines: {node: '>= 8'} - - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - fsevents@2.3.2: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -6389,11 +6147,6 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - gauge@4.0.4: - resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - deprecated: This package is no longer supported. - gaxios@7.1.3: resolution: {integrity: sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ==} engines: {node: '>=18'} @@ -6429,9 +6182,6 @@ packages: get-tsconfig@4.14.0: resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} - github-from-package@0.0.0: - resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} - glob@10.5.0: resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me @@ -6441,10 +6191,6 @@ packages: resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} engines: {node: 18 || 20 || >=22} - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - google-auth-library@10.5.0: resolution: {integrity: sha512-7ABviyMOlX5hIVD60YOfHw4/CxOfBhyduaYB+wbFWCWoni4N7SLcV46hrVRktuBbZjFC9ONyqamZITN7q3n32w==} engines: {node: '>=18'} @@ -6487,9 +6233,6 @@ packages: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} - has-unicode@2.0.1: - resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} - hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} @@ -6527,28 +6270,14 @@ packages: html-void-elements@3.0.0: resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} - http-cache-semantics@4.2.0: - resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} - http-errors@2.0.1: resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} engines: {node: '>= 0.8'} - http-proxy-agent@4.0.1: - resolution: {integrity: sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==} - engines: {node: '>= 6'} - - https-proxy-agent@5.0.1: - resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} - engines: {node: '>= 6'} - https-proxy-agent@7.0.6: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} - humanize-ms@1.2.1: - resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} - i18next@26.3.6: resolution: {integrity: sha512-Bu5Z2nAXgfVyM8xvW3jk9EKRIuX37PudsrBViThNFx7CR7aaYTpP01cxNB/E4c4UUzTDiAZRstEhsRfPOL/8xA==} peerDependencies: @@ -6569,33 +6298,16 @@ packages: resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==} engines: {node: '>=0.10.0'} - ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - import-meta-resolve@4.2.0: resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==} - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - indent-string@4.0.0: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} - infer-owner@1.0.4: - resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==} - - inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. - inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - ini@1.3.8: - resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - inline-style-parser@0.2.7: resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} @@ -6652,9 +6364,6 @@ packages: engines: {node: '>=14.16'} hasBin: true - is-lambda@1.0.1: - resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==} - is-module@1.0.0: resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} @@ -6940,10 +6649,6 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} - lru_map@0.4.1: resolution: {integrity: sha512-I+lBvqMMFfqaV8CJCISjI3wbjmwVu/VyOoU7+qtu9d7ioW5klMgsTTiUOUp+DJvfTTzKXoPbyC6YfgkNcyPSOg==} @@ -6959,10 +6664,6 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - make-fetch-happen@9.1.0: - resolution: {integrity: sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==} - engines: {node: '>= 10'} - markdown-table@3.0.4: resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} @@ -7189,10 +6890,6 @@ packages: engines: {node: '>=4.0.0'} hasBin: true - mimic-response@3.1.0: - resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} - engines: {node: '>=10'} - min-indent@1.0.1: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} @@ -7201,9 +6898,6 @@ packages: resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} engines: {node: 18 || 20 || >=22} - minimatch@3.1.5: - resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} - minimatch@9.0.9: resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} engines: {node: '>=16 || 14 >=14.17'} @@ -7211,50 +6905,10 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - minipass-collect@1.0.2: - resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==} - engines: {node: '>= 8'} - - minipass-fetch@1.4.1: - resolution: {integrity: sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==} - engines: {node: '>=8'} - - minipass-flush@1.0.7: - resolution: {integrity: sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA==} - engines: {node: '>= 8'} - - minipass-pipeline@1.2.4: - resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==} - engines: {node: '>=8'} - - minipass-sized@1.0.3: - resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==} - engines: {node: '>=8'} - - minipass@3.3.6: - resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} - engines: {node: '>=8'} - - minipass@5.0.0: - resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} - engines: {node: '>=8'} - minipass@7.1.3: resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} - minizlib@2.1.2: - resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} - engines: {node: '>= 8'} - - mkdirp-classic@0.5.3: - resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} - - mkdirp@1.0.4: - resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} - engines: {node: '>=10'} - hasBin: true - motion-dom@12.43.0: resolution: {integrity: sha512-azKON4d9S65PEoFUiQTMTgPheEmzf2QngdRc50AKfJp9Q9mmcBVw22c8eMq9k8kxOFHdL7+WZY7N/5F/lwiDag==} @@ -7303,24 +6957,10 @@ packages: resolution: {integrity: sha512-B0UbxzK1s0CN8Xht6r+7iT5+xV8PTaRERR1nATeplRv1Rw5YLWfVAid0hkqY3EceqpG4RjTk8GAwIxQY39Rnwg==} engines: {node: ^20.0.0 || >=22.0.0} - napi-build-utils@2.0.0: - resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} - - negotiator@0.6.4: - resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} - engines: {node: '>= 0.6'} - negotiator@1.0.0: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} - node-abi@3.95.0: - resolution: {integrity: sha512-T9iGctuocf0qIWFFOTxPzjT5q0SILqaBYXt272tlBHvTKC5+3JnkMirLxNJNkXHtFyBjU2Jx+NL4Zipr0B/c6Q==} - engines: {node: '>=10'} - - node-addon-api@7.1.1: - resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} - node-domexception@1.0.0: resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} engines: {node: '>=10.5.0'} @@ -7330,25 +6970,10 @@ packages: resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - node-gyp@8.4.1: - resolution: {integrity: sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==} - engines: {node: '>= 10.12.0'} - hasBin: true - node-releases@2.0.53: resolution: {integrity: sha512-D9UOmYG3UH1V+ENW56t5QXBwJw1YEY18ruVeus89Rw+SyIgjPkCO84bRzO3uNIYosJbNwiabWVn48o3uJLjxFQ==} engines: {node: '>=18'} - nopt@5.0.0: - resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==} - engines: {node: '>=6'} - hasBin: true - - npmlog@6.0.2: - resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - deprecated: This package is no longer supported. - object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -7393,10 +7018,6 @@ packages: oxc-resolver@11.21.2: resolution: {integrity: sha512-w5tLwYN3Zo24w5EeWJjJWZOwhYqTtC8PS2B1tIt7BZUuqTIcU07sQValbDw+rq7+AuAGzOHklgK+ifsy4lpXfw==} - p-map@4.0.0: - resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} - engines: {node: '>=10'} - package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} @@ -7416,10 +7037,6 @@ packages: path-data-parser@0.1.0: resolution: {integrity: sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==} - path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -7563,12 +7180,6 @@ packages: resolution: {integrity: sha512-ZlsFlG7MtSFCoc5xreOvBAozCJ6Pf06opgJjh9ONEv418xpZSAzNjstD36C6+JwOnfSqOW/9uDkqKjezTdxZhw==} engines: {node: '>=20'} - prebuild-install@7.1.3: - resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} - engines: {node: '>=10'} - deprecated: No longer maintained. Please contact the author of the relevant native addon; alternatives are available. - hasBin: true - pretty-format@27.5.1: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -7576,18 +7187,6 @@ packages: process-warning@5.1.0: resolution: {integrity: sha512-jQSaVHsPgtyw60e1rQ/A+/ArPEj/S8pS/vFnyGa/gYFXrKk/6RuDkoqVDQ5NI5MmS01698ltlAk0NoDBNLujRw==} - promise-inflight@1.0.1: - resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} - peerDependencies: - bluebird: '*' - peerDependenciesMeta: - bluebird: - optional: true - - promise-retry@2.0.1: - resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} - engines: {node: '>=10'} - prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} @@ -7604,9 +7203,6 @@ packages: pump@3.0.3: resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} - pump@3.0.4: - resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} - punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -7643,10 +7239,6 @@ packages: resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} engines: {node: '>= 0.10'} - rc@1.2.8: - resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} - hasBin: true - react-docgen-typescript@2.4.0: resolution: {integrity: sha512-ZtAp5XTO5HRzQctjPU0ybY0RRCQO19X/8fxn3w7y2VVTUbGHDKULPTL4ky3vB05euSgG5NpALhEhDPvQ56wvXg==} peerDependencies: @@ -7826,15 +7418,6 @@ packages: engines: {node: '>= 0.4'} hasBin: true - retry@0.12.0: - resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} - engines: {node: '>= 4'} - - rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - rimraf@5.0.10: resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==} hasBin: true @@ -7852,11 +7435,6 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true - rollup@4.63.0: - resolution: {integrity: sha512-T5vnZ2y4QqC3/4P+w2+JO+Q/OVdnPsv4XcSYJYMEn0R9/jjl5AgLwO9LAZMzP2lN71O6pypn91rB7lDstUkfrQ==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - rou3@0.9.2: resolution: {integrity: sha512-3SOzvaAg8rkHrXtRjpCvCvbyO5to9oOO27Z/XqHEYXfMRVSw/qMIVdmaOk9W2lcRLtR6dlqTjo9hDeJk70QBYQ==} @@ -7918,9 +7496,6 @@ packages: resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} engines: {node: '>= 18'} - set-blocking@2.0.0: - resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - set-cookie-parser@2.7.2: resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} @@ -7978,19 +7553,10 @@ packages: siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - simple-concat@1.0.1: - resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} - - simple-get@4.0.1: - resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} - sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} @@ -7999,18 +7565,6 @@ packages: engines: {node: '>=18'} hasBin: true - smart-buffer@4.2.0: - resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} - engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} - - socks-proxy-agent@6.2.1: - resolution: {integrity: sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==} - engines: {node: '>= 10'} - - socks@2.8.9: - resolution: {integrity: sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==} - engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} - sonic-boom@4.2.1: resolution: {integrity: sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==} @@ -8032,20 +7586,16 @@ packages: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} - sqlite3@5.1.7: - resolution: {integrity: sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog==} - ssh2@1.17.0: resolution: {integrity: sha512-wPldCk3asibAjQ/kziWQQt1Wh3PgDFpC0XpwclzKcdT1vql6KeYxf5LIt4nlFkUeR8WuphYMKqUA56X4rjbfgQ==} engines: {node: '>=10.16.0'} - ssri@8.0.1: - resolution: {integrity: sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==} - engines: {node: '>= 8'} - stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + standardwebhooks@1.0.0: + resolution: {integrity: sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg==} + statuses@2.0.2: resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} engines: {node: '>= 0.8'} @@ -8109,10 +7659,6 @@ packages: resolution: {integrity: sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==} engines: {node: '>=12'} - strip-json-comments@2.0.1: - resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} - engines: {node: '>=0.10.0'} - strip-json-comments@5.0.3: resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==} engines: {node: '>=14.16'} @@ -8157,21 +7703,9 @@ packages: resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} engines: {node: '>=6'} - tar-fs@2.1.5: - resolution: {integrity: sha512-OboTd8mmMhZDNPV+UjQcK9yKAatXu2aJ+r1w4im1Otd4M4fl2hwvdoXUxIYHFTHWK/3y3FarBP70v3vwmGlOxw==} - - tar-stream@2.2.0: - resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} - engines: {node: '>=6'} - tar-stream@3.2.0: resolution: {integrity: sha512-ojzvCvVaNp6aOTFmG7jaRD0meowIAuPc3cMMhSgKiVWws1GyHbGd/xvnyuRKcKlMpt3qvxx6r0hreCNITP9hIg==} - tar@6.2.1: - resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} - engines: {node: '>=10'} - deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - teex@1.0.1: resolution: {integrity: sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==} @@ -8260,9 +7794,6 @@ packages: engines: {node: '>=18.0.0'} hasBin: true - tunnel-agent@0.6.0: - resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} - tweetnacl@0.14.5: resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} @@ -8282,9 +7813,6 @@ packages: engines: {node: '>=16.20.0'} hasBin: true - undici-types@7.16.0: - resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - undici-types@7.18.2: resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} @@ -8305,12 +7833,6 @@ packages: unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} - unique-filename@1.1.1: - resolution: {integrity: sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==} - - unique-slug@2.0.2: - resolution: {integrity: sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==} - unist-util-is@6.0.1: resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} @@ -8479,7 +8001,6 @@ packages: '@vitest/ui': 4.1.10 happy-dom: '*' jsdom: '*' - vite: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: '@edge-runtime/vm': optional: true @@ -8520,7 +8041,6 @@ packages: '@vitest/ui': 4.1.11 happy-dom: '*' jsdom: '*' - vite: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: '@edge-runtime/vm': optional: true @@ -8589,9 +8109,6 @@ packages: engines: {node: '>=8'} hasBin: true - wide-align@1.1.5: - resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} - wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -8637,9 +8154,6 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - yjs@13.6.29: resolution: {integrity: sha512-kHqDPdltoXH+X4w1lVmMtddE3Oeqq48nM40FD5ojTd8xYhQpzIDcfE2keMSU5bAgRPJBe225WTUdyUgj1DtbiQ==} engines: {node: '>=16.0.0', npm: '>=8.0.0'} @@ -8680,10 +8194,10 @@ snapshots: '@adobe/css-tools@4.5.0': {} - '@agentclientprotocol/claude-agent-acp@0.70.0(@anthropic-ai/sdk@0.81.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.30.0(zod@4.4.3))': + '@agentclientprotocol/claude-agent-acp@0.70.0(@anthropic-ai/sdk@0.121.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.30.0(zod@4.4.3))': dependencies: '@agentclientprotocol/sdk': 1.3.0(zod@4.4.3) - '@anthropic-ai/claude-agent-sdk': 0.3.232(@anthropic-ai/sdk@0.81.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.30.0(zod@4.4.3))(zod@4.4.3) + '@anthropic-ai/claude-agent-sdk': 0.3.232(@anthropic-ai/sdk@0.121.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.30.0(zod@4.4.3))(zod@4.4.3) zod: 4.4.3 transitivePeerDependencies: - '@anthropic-ai/sdk' @@ -8739,9 +8253,9 @@ snapshots: '@anthropic-ai/claude-agent-sdk-win32-x64@0.3.232': optional: true - '@anthropic-ai/claude-agent-sdk@0.3.232(@anthropic-ai/sdk@0.81.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.30.0(zod@4.4.3))(zod@4.4.3)': + '@anthropic-ai/claude-agent-sdk@0.3.232(@anthropic-ai/sdk@0.121.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.30.0(zod@4.4.3))(zod@4.4.3)': dependencies: - '@anthropic-ai/sdk': 0.81.0(zod@4.4.3) + '@anthropic-ai/sdk': 0.121.0(zod@4.4.3) '@modelcontextprotocol/sdk': 1.30.0(zod@4.4.3) zod: 4.4.3 optionalDependencies: @@ -8754,9 +8268,10 @@ snapshots: '@anthropic-ai/claude-agent-sdk-win32-arm64': 0.3.232 '@anthropic-ai/claude-agent-sdk-win32-x64': 0.3.232 - '@anthropic-ai/sdk@0.81.0(zod@4.4.3)': + '@anthropic-ai/sdk@0.121.0(zod@4.4.3)': dependencies: json-schema-to-ts: 3.1.1 + standardwebhooks: 1.0.0 optionalDependencies: zod: 4.4.3 @@ -9149,12 +8664,12 @@ snapshots: optionalDependencies: '@opentelemetry/api': 1.9.1 - '@better-auth/drizzle-adapter@1.7.0(@better-auth/core@1.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.4.3))(jose@6.2.9)(kysely@0.29.5)(nanostores@1.5.2))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9)(sqlite3@5.1.7))': + '@better-auth/drizzle-adapter@1.7.0(@better-auth/core@1.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.4.3))(jose@6.2.9)(kysely@0.29.5)(nanostores@1.5.2))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9))': dependencies: '@better-auth/core': 1.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.4.3))(jose@6.2.9)(kysely@0.29.5)(nanostores@1.5.2) '@better-auth/utils': 0.4.2 optionalDependencies: - drizzle-orm: 0.45.2(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9)(sqlite3@5.1.7) + drizzle-orm: 0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9) '@better-auth/kysely-adapter@1.7.0(@better-auth/core@1.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.4.3))(jose@6.2.9)(kysely@0.29.5)(nanostores@1.5.2))(@better-auth/utils@0.4.2)(kysely@0.29.5)': dependencies: @@ -9591,9 +9106,6 @@ snapshots: '@drizzle-team/brocli@0.10.2': {} - '@electric-sql/pglite@0.3.15': - optional: true - '@embedded-postgres/darwin-arm64@18.1.0-beta.16': optional: true @@ -9920,9 +9432,6 @@ snapshots: '@floating-ui/utils@0.2.12': {} - '@gar/promisify@1.1.3': - optional: true - '@hono/node-server@2.1.0(hono@4.13.2)': dependencies: hono: 4.13.2 @@ -10555,18 +10064,6 @@ snapshots: '@noble/hashes@2.3.0': {} - '@npmcli/fs@1.1.1': - dependencies: - '@gar/promisify': 1.1.3 - semver: 7.8.5 - optional: true - - '@npmcli/move-file@1.1.2': - dependencies: - mkdirp: 1.0.4 - rimraf: 3.0.2 - optional: true - '@openai/codex@0.148.0': optionalDependencies: '@openai/codex-darwin-arm64': '@openai/codex@0.148.0-darwin-arm64' @@ -11751,164 +11248,89 @@ snapshots: optionalDependencies: rollup: 4.62.4 - '@rollup/pluginutils@5.4.0(rollup@4.63.0)': + '@rollup/pluginutils@5.4.0(rollup@4.62.4)': dependencies: '@types/estree': 1.0.9 estree-walker: 2.0.2 picomatch: 4.0.7 optionalDependencies: - rollup: 4.63.0 + rollup: 4.62.4 '@rollup/rollup-android-arm-eabi@4.62.4': optional: true - '@rollup/rollup-android-arm-eabi@4.63.0': - optional: true - '@rollup/rollup-android-arm64@4.62.4': optional: true - '@rollup/rollup-android-arm64@4.63.0': - optional: true - '@rollup/rollup-darwin-arm64@4.62.4': optional: true - '@rollup/rollup-darwin-arm64@4.63.0': - optional: true - '@rollup/rollup-darwin-x64@4.62.4': optional: true - '@rollup/rollup-darwin-x64@4.63.0': - optional: true - '@rollup/rollup-freebsd-arm64@4.62.4': optional: true - '@rollup/rollup-freebsd-arm64@4.63.0': - optional: true - '@rollup/rollup-freebsd-x64@4.62.4': optional: true - '@rollup/rollup-freebsd-x64@4.63.0': - optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.62.4': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.63.0': - optional: true - '@rollup/rollup-linux-arm-musleabihf@4.62.4': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.63.0': - optional: true - '@rollup/rollup-linux-arm64-gnu@4.62.4': optional: true - '@rollup/rollup-linux-arm64-gnu@4.63.0': - optional: true - '@rollup/rollup-linux-arm64-musl@4.62.4': optional: true - '@rollup/rollup-linux-arm64-musl@4.63.0': - optional: true - '@rollup/rollup-linux-loong64-gnu@4.62.4': optional: true - '@rollup/rollup-linux-loong64-gnu@4.63.0': - optional: true - '@rollup/rollup-linux-loong64-musl@4.62.4': optional: true - '@rollup/rollup-linux-loong64-musl@4.63.0': - optional: true - '@rollup/rollup-linux-ppc64-gnu@4.62.4': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.63.0': - optional: true - '@rollup/rollup-linux-ppc64-musl@4.62.4': optional: true - '@rollup/rollup-linux-ppc64-musl@4.63.0': - optional: true - '@rollup/rollup-linux-riscv64-gnu@4.62.4': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.63.0': - optional: true - '@rollup/rollup-linux-riscv64-musl@4.62.4': optional: true - '@rollup/rollup-linux-riscv64-musl@4.63.0': - optional: true - '@rollup/rollup-linux-s390x-gnu@4.62.4': optional: true - '@rollup/rollup-linux-s390x-gnu@4.63.0': - optional: true - '@rollup/rollup-linux-x64-gnu@4.62.4': optional: true - '@rollup/rollup-linux-x64-gnu@4.63.0': - optional: true - '@rollup/rollup-linux-x64-musl@4.62.4': optional: true - '@rollup/rollup-linux-x64-musl@4.63.0': - optional: true - '@rollup/rollup-openbsd-x64@4.62.4': optional: true - '@rollup/rollup-openbsd-x64@4.63.0': - optional: true - '@rollup/rollup-openharmony-arm64@4.62.4': optional: true - '@rollup/rollup-openharmony-arm64@4.63.0': - optional: true - '@rollup/rollup-win32-arm64-msvc@4.62.4': optional: true - '@rollup/rollup-win32-arm64-msvc@4.63.0': - optional: true - '@rollup/rollup-win32-ia32-msvc@4.62.4': optional: true - '@rollup/rollup-win32-ia32-msvc@4.63.0': - optional: true - '@rollup/rollup-win32-x64-gnu@4.62.4': optional: true - '@rollup/rollup-win32-x64-gnu@4.63.0': - optional: true - '@rollup/rollup-win32-x64-msvc@4.62.4': optional: true - '@rollup/rollup-win32-x64-msvc@4.63.0': - optional: true - '@sentry/browser-utils@10.71.0': dependencies: '@sentry/conventions': 0.16.0 @@ -12021,6 +11443,8 @@ snapshots: dependencies: tslib: 2.8.1 + '@stablelib/base64@1.0.1': {} + '@standard-schema/spec@1.1.0': {} '@statsig/client-core@3.31.0': {} @@ -12035,10 +11459,10 @@ snapshots: axe-core: 4.13.0 storybook: 10.5.10(@types/react@19.2.18)(react@19.2.8) - '@storybook/addon-docs@10.5.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(esbuild@0.28.2)(rollup@4.63.0)(storybook@10.5.10(@types/react@19.2.18)(react@19.2.8))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12))': + '@storybook/addon-docs@10.5.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(esbuild@0.28.2)(rollup@4.62.4)(storybook@10.5.10(@types/react@19.2.18)(react@19.2.8))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12))': dependencies: '@mdx-js/react': 3.1.1(@types/react@19.2.18)(react@19.2.8) - '@storybook/csf-plugin': 10.5.10(esbuild@0.28.2)(rollup@4.63.0)(storybook@10.5.10(@types/react@19.2.18)(react@19.2.8))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) + '@storybook/csf-plugin': 10.5.10(esbuild@0.28.2)(rollup@4.62.4)(storybook@10.5.10(@types/react@19.2.18)(react@19.2.8))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) '@storybook/icons': 2.1.0(react@19.2.8) '@storybook/react-dom-shim': 10.5.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(storybook@10.5.10(@types/react@19.2.18)(react@19.2.8)) react: 19.2.8 @@ -12054,9 +11478,9 @@ snapshots: - vite - webpack - '@storybook/builder-vite@10.5.10(esbuild@0.28.2)(rollup@4.63.0)(storybook@10.5.10(@types/react@19.2.18)(react@19.2.8))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12))': + '@storybook/builder-vite@10.5.10(esbuild@0.28.2)(rollup@4.62.4)(storybook@10.5.10(@types/react@19.2.18)(react@19.2.8))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12))': dependencies: - '@storybook/csf-plugin': 10.5.10(esbuild@0.28.2)(rollup@4.63.0)(storybook@10.5.10(@types/react@19.2.18)(react@19.2.8))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) + '@storybook/csf-plugin': 10.5.10(esbuild@0.28.2)(rollup@4.62.4)(storybook@10.5.10(@types/react@19.2.18)(react@19.2.8))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) storybook: 10.5.10(@types/react@19.2.18)(react@19.2.8) ts-dedent: 2.3.0 vite: 8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12) @@ -12065,13 +11489,13 @@ snapshots: - rollup - webpack - '@storybook/csf-plugin@10.5.10(esbuild@0.28.2)(rollup@4.63.0)(storybook@10.5.10(@types/react@19.2.18)(react@19.2.8))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12))': + '@storybook/csf-plugin@10.5.10(esbuild@0.28.2)(rollup@4.62.4)(storybook@10.5.10(@types/react@19.2.18)(react@19.2.8))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12))': dependencies: storybook: 10.5.10(@types/react@19.2.18)(react@19.2.8) unplugin: 2.3.11 optionalDependencies: esbuild: 0.28.2 - rollup: 4.63.0 + rollup: 4.62.4 vite: 8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12) '@storybook/global@5.0.0': {} @@ -12089,11 +11513,11 @@ snapshots: '@types/react': 19.2.18 '@types/react-dom': 19.2.4(@types/react@19.2.18) - '@storybook/react-vite@10.5.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(esbuild@0.28.2)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(rollup@4.63.0)(storybook@10.5.10(@types/react@19.2.18)(react@19.2.8))(typescript@7.0.2)(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12))': + '@storybook/react-vite@10.5.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(esbuild@0.28.2)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(rollup@4.62.4)(storybook@10.5.10(@types/react@19.2.18)(react@19.2.8))(typescript@7.0.2)(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12))': dependencies: '@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(typescript@7.0.2)(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) - '@rollup/pluginutils': 5.4.0(rollup@4.63.0) - '@storybook/builder-vite': 10.5.10(esbuild@0.28.2)(rollup@4.63.0)(storybook@10.5.10(@types/react@19.2.18)(react@19.2.8))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) + '@rollup/pluginutils': 5.4.0(rollup@4.62.4) + '@storybook/builder-vite': 10.5.10(esbuild@0.28.2)(rollup@4.62.4)(storybook@10.5.10(@types/react@19.2.18)(react@19.2.8))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) '@storybook/react': 10.5.10(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(storybook@10.5.10(@types/react@19.2.18)(react@19.2.8))(typescript@7.0.2) empathic: 2.0.1 magic-string: 0.30.21 @@ -12234,9 +11658,6 @@ snapshots: dependencies: '@testing-library/dom': 10.4.1 - '@tootallnate/once@1.1.2': - optional: true - '@tybys/wasm-util@0.10.3': dependencies: tslib: 2.8.1 @@ -12462,11 +11883,6 @@ snapshots: dependencies: undici-types: 7.18.2 - '@types/node@25.2.3': - dependencies: - undici-types: 7.16.0 - optional: true - '@types/qs@6.15.1': {} '@types/range-parser@1.2.7': {} @@ -12635,14 +12051,6 @@ snapshots: optionalDependencies: vite: 8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12) - '@vitest/mocker@4.1.10(vite@8.2.2(@types/node@25.2.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12))': - dependencies: - '@vitest/spy': 4.1.10 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 8.2.2(@types/node@25.2.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12) - '@vitest/mocker@4.1.11(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12))': dependencies: '@vitest/spy': 4.1.11 @@ -12719,9 +12127,6 @@ snapshots: '@xterm/xterm@6.0.0': {} - abbrev@1.1.1: - optional: true - accepts@2.0.0: dependencies: mime-types: 3.0.2 @@ -12747,26 +12152,8 @@ snapshots: address@2.0.3: {} - agent-base@6.0.2: - dependencies: - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - optional: true - agent-base@7.1.4: {} - agentkeepalive@4.6.0: - dependencies: - humanize-ms: 1.2.1 - optional: true - - aggregate-error@3.1.0: - dependencies: - clean-stack: 2.2.0 - indent-string: 4.0.0 - optional: true - ajv-formats@3.0.1(ajv@8.20.0): optionalDependencies: ajv: 8.20.0 @@ -12792,15 +12179,6 @@ snapshots: append-field@1.0.0: {} - aproba@2.1.0: - optional: true - - are-we-there-yet@3.0.1: - dependencies: - delegates: 1.0.0 - readable-stream: 3.6.2 - optional: true - argparse@2.0.1: {} aria-hidden@1.2.6: @@ -12891,10 +12269,10 @@ snapshots: dependencies: tweetnacl: 0.14.5 - better-auth@1.7.0(@opentelemetry/api@1.9.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9)(sqlite3@5.1.7))(pg@8.18.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vitest@4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.3.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12))): + better-auth@1.7.0(@opentelemetry/api@1.9.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9))(pg@8.18.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(vitest@4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(jsdom@30.0.1(@noble/hashes@2.3.0))(tsx@4.23.12)): dependencies: '@better-auth/core': 1.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.4.3))(jose@6.2.9)(kysely@0.29.5)(nanostores@1.5.2) - '@better-auth/drizzle-adapter': 1.7.0(@better-auth/core@1.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.4.3))(jose@6.2.9)(kysely@0.29.5)(nanostores@1.5.2))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9)(sqlite3@5.1.7)) + '@better-auth/drizzle-adapter': 1.7.0(@better-auth/core@1.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.4.3))(jose@6.2.9)(kysely@0.29.5)(nanostores@1.5.2))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9)) '@better-auth/kysely-adapter': 1.7.0(@better-auth/core@1.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.4.3))(jose@6.2.9)(kysely@0.29.5)(nanostores@1.5.2))(@better-auth/utils@0.4.2)(kysely@0.29.5) '@better-auth/memory-adapter': 1.7.0(@better-auth/core@1.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.4.3))(jose@6.2.9)(kysely@0.29.5)(nanostores@1.5.2))(@better-auth/utils@0.4.2) '@better-auth/mongo-adapter': 1.7.0(@better-auth/core@1.7.0(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.1)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.4.3))(jose@6.2.9)(kysely@0.29.5)(nanostores@1.5.2))(@better-auth/utils@0.4.2) @@ -12912,11 +12290,11 @@ snapshots: zod: 4.4.3 optionalDependencies: drizzle-kit: 0.31.10 - drizzle-orm: 0.45.2(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9)(sqlite3@5.1.7) + drizzle-orm: 0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9) pg: 8.18.0 react: 19.2.8 react-dom: 19.2.8(react@19.2.8) - vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.3.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) + vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(jsdom@30.0.1(@noble/hashes@2.3.0))(tsx@4.23.12) transitivePeerDependencies: - '@cloudflare/workers-types' - '@opentelemetry/api' @@ -12936,18 +12314,6 @@ snapshots: bignumber.js@9.3.1: {} - bindings@1.5.0: - dependencies: - file-uri-to-path: 1.0.0 - optional: true - - bl@4.1.0: - dependencies: - buffer: 5.7.1 - inherits: 2.0.4 - readable-stream: 3.6.2 - optional: true - body-parser@2.2.2: dependencies: bytes: 3.1.2 @@ -12964,12 +12330,6 @@ snapshots: bowser@2.14.1: {} - brace-expansion@1.1.18: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - optional: true - brace-expansion@2.1.4: dependencies: balanced-match: 1.0.2 @@ -12990,12 +12350,6 @@ snapshots: buffer-from@1.1.2: {} - buffer@5.7.1: - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - optional: true - buildcheck@0.0.7: optional: true @@ -13009,30 +12363,6 @@ snapshots: bytes@3.1.2: {} - cacache@15.3.0: - dependencies: - '@npmcli/fs': 1.1.1 - '@npmcli/move-file': 1.1.2 - chownr: 2.0.0 - fs-minipass: 2.1.0 - glob: 7.2.3 - infer-owner: 1.0.4 - lru-cache: 6.0.0 - minipass: 3.3.6 - minipass-collect: 1.0.2 - minipass-flush: 1.0.7 - minipass-pipeline: 1.2.4 - mkdirp: 1.0.4 - p-map: 4.0.0 - promise-inflight: 1.0.1 - rimraf: 3.0.2 - ssri: 8.0.1 - tar: 6.2.1 - unique-filename: 1.1.1 - transitivePeerDependencies: - - bluebird - optional: true - call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -13071,21 +12401,12 @@ snapshots: dependencies: readdirp: 5.1.1 - chownr@1.1.4: - optional: true - - chownr@2.0.0: - optional: true - class-variance-authority@0.7.1: dependencies: clsx: 2.1.1 classnames@2.5.1: {} - clean-stack@2.2.0: - optional: true - clsx@2.1.1: {} cm6-theme-basic-light@0.2.0(@codemirror/language@6.12.4)(@codemirror/state@6.7.1)(@codemirror/view@6.43.9)(@lezer/highlight@1.2.3): @@ -13123,9 +12444,6 @@ snapshots: color-name@1.1.4: {} - color-support@1.1.3: - optional: true - colorette@2.0.20: {} combined-stream@1.0.8: @@ -13144,9 +12462,6 @@ snapshots: compute-scroll-into-view@2.0.4: {} - concat-map@0.0.1: - optional: true - concat-stream@2.0.0: dependencies: buffer-from: 1.1.2 @@ -13154,9 +12469,6 @@ snapshots: readable-stream: 3.6.2 typedarray: 0.0.6 - console-control-strings@1.1.0: - optional: true - content-disposition@1.0.1: {} content-type@1.0.5: {} @@ -13421,16 +12733,8 @@ snapshots: dependencies: character-entities: 2.0.2 - decompress-response@6.0.0: - dependencies: - mimic-response: 3.1.0 - optional: true - deep-eql@5.0.2: {} - deep-extend@0.6.0: - optional: true - deepmerge@4.3.1: {} default-browser-id@5.0.1: {} @@ -13450,9 +12754,6 @@ snapshots: delayed-stream@1.0.0: {} - delegates@1.0.0: - optional: true - depd@2.0.0: {} dequal@2.0.3: {} @@ -13508,14 +12809,12 @@ snapshots: esbuild: 0.25.12 tsx: 4.23.12 - drizzle-orm@0.45.2(@electric-sql/pglite@0.3.15)(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9)(sqlite3@5.1.7): + drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(kysely@0.29.5)(pg@8.18.0)(postgres@3.4.9): optionalDependencies: - '@electric-sql/pglite': 0.3.15 '@opentelemetry/api': 1.9.1 kysely: 0.29.5 pg: 8.18.0 postgres: 3.4.9 - sqlite3: 5.1.7 dunder-proto@1.0.1: dependencies: @@ -13557,11 +12856,6 @@ snapshots: encodeurl@2.0.0: {} - encoding@0.1.13: - dependencies: - iconv-lite: 0.6.3 - optional: true - end-of-stream@1.4.5: dependencies: once: 1.4.0 @@ -13573,12 +12867,6 @@ snapshots: entities@8.0.0: {} - env-paths@2.2.1: - optional: true - - err-code@2.0.3: - optional: true - es-define-property@1.0.1: {} es-errors@1.3.0: {} @@ -13720,9 +13008,6 @@ snapshots: dependencies: eventsource-parser: 3.1.1 - expand-template@2.0.3: - optional: true - expect-type@1.4.0: {} express-rate-limit@8.6.2(express@5.2.1): @@ -13776,6 +13061,8 @@ snapshots: fast-safe-stringify@2.1.1: {} + fast-sha256@1.3.0: {} + fast-string-truncated-width@3.0.3: {} fast-string-width@3.0.2: @@ -13801,9 +13088,6 @@ snapshots: node-domexception: 1.0.0 web-streams-polyfill: 3.3.3 - file-uri-to-path@1.0.0: - optional: true - finalhandler@2.1.1: dependencies: debug: 4.4.3 @@ -13861,17 +13145,6 @@ snapshots: fresh@2.0.0: {} - fs-constants@1.0.0: - optional: true - - fs-minipass@2.1.0: - dependencies: - minipass: 3.3.6 - optional: true - - fs.realpath@1.0.0: - optional: true - fsevents@2.3.2: optional: true @@ -13880,18 +13153,6 @@ snapshots: function-bind@1.1.2: {} - gauge@4.0.4: - dependencies: - aproba: 2.1.0 - color-support: 1.1.3 - console-control-strings: 1.1.0 - has-unicode: 2.0.1 - signal-exit: 3.0.7 - string-width: 4.2.3 - strip-ansi: 6.0.1 - wide-align: 1.1.5 - optional: true - gaxios@7.1.3: dependencies: extend: 3.0.2 @@ -13945,9 +13206,6 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 - github-from-package@0.0.0: - optional: true - glob@10.5.0: dependencies: foreground-child: 3.3.1 @@ -13963,16 +13221,6 @@ snapshots: minipass: 7.1.3 path-scurry: 2.0.2 - glob@7.2.3: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.5 - once: 1.4.0 - path-is-absolute: 1.0.1 - optional: true - google-auth-library@10.5.0: dependencies: base64-js: 1.5.1 @@ -14026,9 +13274,6 @@ snapshots: dependencies: has-symbols: 1.1.0 - has-unicode@2.0.1: - optional: true - hasown@2.0.2: dependencies: function-bind: 1.1.2 @@ -14091,9 +13336,6 @@ snapshots: html-void-elements@3.0.0: {} - http-cache-semantics@4.2.0: - optional: true - http-errors@2.0.1: dependencies: depd: 2.0.0 @@ -14102,23 +13344,6 @@ snapshots: statuses: 2.0.2 toidentifier: 1.0.1 - http-proxy-agent@4.0.1: - dependencies: - '@tootallnate/once': 1.1.2 - agent-base: 6.0.2 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - optional: true - - https-proxy-agent@5.0.1: - dependencies: - agent-base: 6.0.2 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - optional: true - https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.4 @@ -14126,11 +13351,6 @@ snapshots: transitivePeerDependencies: - supports-color - humanize-ms@1.2.1: - dependencies: - ms: 2.1.3 - optional: true - i18next@26.3.6(typescript@7.0.2): optionalDependencies: typescript: 7.0.2 @@ -14147,30 +13367,12 @@ snapshots: dependencies: safer-buffer: 2.1.2 - ieee754@1.2.1: - optional: true - import-meta-resolve@4.2.0: {} - imurmurhash@0.1.4: - optional: true - indent-string@4.0.0: {} - infer-owner@1.0.4: - optional: true - - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - optional: true - inherits@2.0.4: {} - ini@1.3.8: - optional: true - inline-style-parser@0.2.7: {} internmap@1.0.1: {} @@ -14210,9 +13412,6 @@ snapshots: dependencies: is-docker: 3.0.0 - is-lambda@1.0.1: - optional: true - is-module@1.0.0: {} is-plain-obj@4.1.0: {} @@ -14445,11 +13644,6 @@ snapshots: dependencies: yallist: 3.1.1 - lru-cache@6.0.0: - dependencies: - yallist: 4.0.0 - optional: true - lru_map@0.4.1: {} lucide-react@1.32.0(react@19.2.8): @@ -14462,29 +13656,6 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 - make-fetch-happen@9.1.0: - dependencies: - agentkeepalive: 4.6.0 - cacache: 15.3.0 - http-cache-semantics: 4.2.0 - http-proxy-agent: 4.0.1 - https-proxy-agent: 5.0.1 - is-lambda: 1.0.1 - lru-cache: 6.0.0 - minipass: 3.3.6 - minipass-collect: 1.0.2 - minipass-fetch: 1.4.1 - minipass-flush: 1.0.7 - minipass-pipeline: 1.2.4 - negotiator: 0.6.4 - promise-retry: 2.0.1 - socks-proxy-agent: 6.2.1 - ssri: 8.0.1 - transitivePeerDependencies: - - bluebird - - supports-color - optional: true - markdown-table@3.0.4: {} marked@16.4.2: {} @@ -15021,77 +14192,20 @@ snapshots: mime@2.6.0: {} - mimic-response@3.1.0: - optional: true - min-indent@1.0.1: {} minimatch@10.2.6: dependencies: brace-expansion: 5.0.9 - minimatch@3.1.5: - dependencies: - brace-expansion: 1.1.18 - optional: true - minimatch@9.0.9: dependencies: brace-expansion: 2.1.4 minimist@1.2.8: {} - minipass-collect@1.0.2: - dependencies: - minipass: 3.3.6 - optional: true - - minipass-fetch@1.4.1: - dependencies: - minipass: 3.3.6 - minipass-sized: 1.0.3 - minizlib: 2.1.2 - optionalDependencies: - encoding: 0.1.13 - optional: true - - minipass-flush@1.0.7: - dependencies: - minipass: 3.3.6 - optional: true - - minipass-pipeline@1.2.4: - dependencies: - minipass: 3.3.6 - optional: true - - minipass-sized@1.0.3: - dependencies: - minipass: 3.3.6 - optional: true - - minipass@3.3.6: - dependencies: - yallist: 4.0.0 - optional: true - - minipass@5.0.0: - optional: true - minipass@7.1.3: {} - minizlib@2.1.2: - dependencies: - minipass: 3.3.6 - yallist: 4.0.0 - optional: true - - mkdirp-classic@0.5.3: - optional: true - - mkdirp@1.0.4: - optional: true - motion-dom@12.43.0: dependencies: motion-utils: 12.39.0 @@ -15126,22 +14240,8 @@ snapshots: nanostores@1.5.2: {} - napi-build-utils@2.0.0: - optional: true - - negotiator@0.6.4: - optional: true - negotiator@1.0.0: {} - node-abi@3.95.0: - dependencies: - semver: 7.8.5 - optional: true - - node-addon-api@7.1.1: - optional: true - node-domexception@1.0.0: {} node-fetch@3.3.2: @@ -15150,38 +14250,8 @@ snapshots: fetch-blob: 3.2.0 formdata-polyfill: 4.0.10 - node-gyp@8.4.1: - dependencies: - env-paths: 2.2.1 - glob: 7.2.3 - graceful-fs: 4.2.11 - make-fetch-happen: 9.1.0 - nopt: 5.0.0 - npmlog: 6.0.2 - rimraf: 3.0.2 - semver: 7.8.5 - tar: 6.2.1 - which: 2.0.2 - transitivePeerDependencies: - - bluebird - - supports-color - optional: true - node-releases@2.0.53: {} - nopt@5.0.0: - dependencies: - abbrev: 1.1.1 - optional: true - - npmlog@6.0.2: - dependencies: - are-we-there-yet: 3.0.1 - console-control-strings: 1.1.0 - gauge: 4.0.4 - set-blocking: 2.0.0 - optional: true - object-assign@4.1.1: {} object-inspect@1.13.4: {} @@ -15269,11 +14339,6 @@ snapshots: '@oxc-resolver/binding-win32-arm64-msvc': 11.21.2 '@oxc-resolver/binding-win32-x64-msvc': 11.21.2 - p-map@4.0.0: - dependencies: - aggregate-error: 3.1.0 - optional: true - package-json-from-dist@1.0.1: {} package-manager-detector@1.8.0: {} @@ -15296,9 +14361,6 @@ snapshots: path-data-parser@0.1.0: {} - path-is-absolute@1.0.1: - optional: true - path-key@3.1.1: {} path-parse@1.0.7: {} @@ -15447,22 +14509,6 @@ snapshots: powershell-utils@0.2.0: {} - prebuild-install@7.1.3: - dependencies: - detect-libc: 2.1.2 - expand-template: 2.0.3 - github-from-package: 0.0.0 - minimist: 1.2.8 - mkdirp-classic: 0.5.3 - napi-build-utils: 2.0.0 - node-abi: 3.95.0 - pump: 3.0.4 - rc: 1.2.8 - simple-get: 4.0.1 - tar-fs: 2.1.5 - tunnel-agent: 0.6.0 - optional: true - pretty-format@27.5.1: dependencies: ansi-regex: 5.0.1 @@ -15471,15 +14517,6 @@ snapshots: process-warning@5.1.0: {} - promise-inflight@1.0.1: - optional: true - - promise-retry@2.0.1: - dependencies: - err-code: 2.0.3 - retry: 0.12.0 - optional: true - prop-types@15.8.1: dependencies: loose-envify: 1.4.0 @@ -15500,12 +14537,6 @@ snapshots: end-of-stream: 1.4.5 once: 1.4.0 - pump@3.0.4: - dependencies: - end-of-stream: 1.4.5 - once: 1.4.0 - optional: true - punycode@2.3.1: {} qs@6.15.0: @@ -15591,14 +14622,6 @@ snapshots: iconv-lite: 0.7.3 unpipe: 1.0.0 - rc@1.2.8: - dependencies: - deep-extend: 0.6.0 - ini: 1.3.8 - minimist: 1.2.8 - strip-json-comments: 2.0.1 - optional: true - react-docgen-typescript@2.4.0(typescript@7.0.2): dependencies: typescript: 7.0.2 @@ -15807,14 +14830,6 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - retry@0.12.0: - optional: true - - rimraf@3.0.2: - dependencies: - glob: 7.2.3 - optional: true - rimraf@5.0.10: dependencies: glob: 10.5.0 @@ -15874,39 +14889,6 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.62.4 fsevents: 2.3.3 - rollup@4.63.0: - dependencies: - '@types/estree': 1.0.9 - optionalDependencies: - '@napi-rs/lzma-linux-x64-gnu': 1.5.1 - '@rollup/rollup-android-arm-eabi': 4.63.0 - '@rollup/rollup-android-arm64': 4.63.0 - '@rollup/rollup-darwin-arm64': 4.63.0 - '@rollup/rollup-darwin-x64': 4.63.0 - '@rollup/rollup-freebsd-arm64': 4.63.0 - '@rollup/rollup-freebsd-x64': 4.63.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.63.0 - '@rollup/rollup-linux-arm-musleabihf': 4.63.0 - '@rollup/rollup-linux-arm64-gnu': 4.63.0 - '@rollup/rollup-linux-arm64-musl': 4.63.0 - '@rollup/rollup-linux-loong64-gnu': 4.63.0 - '@rollup/rollup-linux-loong64-musl': 4.63.0 - '@rollup/rollup-linux-ppc64-gnu': 4.63.0 - '@rollup/rollup-linux-ppc64-musl': 4.63.0 - '@rollup/rollup-linux-riscv64-gnu': 4.63.0 - '@rollup/rollup-linux-riscv64-musl': 4.63.0 - '@rollup/rollup-linux-s390x-gnu': 4.63.0 - '@rollup/rollup-linux-x64-gnu': 4.63.0 - '@rollup/rollup-linux-x64-musl': 4.63.0 - '@rollup/rollup-openbsd-x64': 4.63.0 - '@rollup/rollup-openharmony-arm64': 4.63.0 - '@rollup/rollup-win32-arm64-msvc': 4.63.0 - '@rollup/rollup-win32-ia32-msvc': 4.63.0 - '@rollup/rollup-win32-x64-gnu': 4.63.0 - '@rollup/rollup-win32-x64-msvc': 4.63.0 - fsevents: 2.3.3 - optional: true - rou3@0.9.2: {} roughjs@4.6.6: @@ -15979,9 +14961,6 @@ snapshots: transitivePeerDependencies: - supports-color - set-blocking@2.0.0: - optional: true - set-cookie-parser@2.7.2: {} set-cookie-parser@3.1.2: {} @@ -16081,21 +15060,8 @@ snapshots: siginfo@2.0.0: {} - signal-exit@3.0.7: - optional: true - signal-exit@4.1.0: {} - simple-concat@1.0.1: - optional: true - - simple-get@4.0.1: - dependencies: - decompress-response: 6.0.0 - once: 1.4.0 - simple-concat: 1.0.1 - optional: true - sisteransi@1.0.5: {} skillflag@0.2.0: @@ -16107,24 +15073,6 @@ snapshots: - bare-buffer - react-native-b4a - smart-buffer@4.2.0: - optional: true - - socks-proxy-agent@6.2.1: - dependencies: - agent-base: 6.0.2 - debug: 4.4.3 - socks: 2.8.9 - transitivePeerDependencies: - - supports-color - optional: true - - socks@2.8.9: - dependencies: - ip-address: 10.5.0 - smart-buffer: 4.2.0 - optional: true - sonic-boom@4.2.1: dependencies: atomic-sleep: 1.0.0 @@ -16142,19 +15090,6 @@ snapshots: split2@4.2.0: {} - sqlite3@5.1.7: - dependencies: - bindings: 1.5.0 - node-addon-api: 7.1.1 - prebuild-install: 7.1.3 - tar: 6.2.1 - optionalDependencies: - node-gyp: 8.4.1 - transitivePeerDependencies: - - bluebird - - supports-color - optional: true - ssh2@1.17.0: dependencies: asn1: 0.2.6 @@ -16163,13 +15098,13 @@ snapshots: cpu-features: 0.0.10 nan: 2.28.0 - ssri@8.0.1: - dependencies: - minipass: 3.3.6 - optional: true - stackback@0.0.2: {} + standardwebhooks@1.0.0: + dependencies: + '@stablelib/base64': 1.0.1 + fast-sha256: 1.3.0 + statuses@2.0.2: {} std-env@4.2.0: {} @@ -16248,9 +15183,6 @@ snapshots: strip-indent@4.1.1: {} - strip-json-comments@2.0.1: - optional: true - strip-json-comments@5.0.3: {} style-mod@4.1.3: {} @@ -16299,23 +15231,6 @@ snapshots: tapable@2.3.3: {} - tar-fs@2.1.5: - dependencies: - chownr: 1.1.4 - mkdirp-classic: 0.5.3 - pump: 3.0.4 - tar-stream: 2.2.0 - optional: true - - tar-stream@2.2.0: - dependencies: - bl: 4.1.0 - end-of-stream: 1.4.5 - fs-constants: 1.0.0 - inherits: 2.0.4 - readable-stream: 3.6.2 - optional: true - tar-stream@3.2.0: dependencies: b4a: 1.8.1 @@ -16327,16 +15242,6 @@ snapshots: - bare-buffer - react-native-b4a - tar@6.2.1: - dependencies: - chownr: 2.0.0 - fs-minipass: 2.1.0 - minipass: 5.0.0 - minizlib: 2.1.2 - mkdirp: 1.0.4 - yallist: 4.0.0 - optional: true - teex@1.0.1: dependencies: streamx: 2.28.0 @@ -16413,11 +15318,6 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - tunnel-agent@0.6.0: - dependencies: - safe-buffer: 5.2.1 - optional: true - tweetnacl@0.14.5: {} type-is@1.6.18: @@ -16456,9 +15356,6 @@ snapshots: '@typescript/typescript-win32-arm64': 7.0.2 '@typescript/typescript-win32-x64': 7.0.2 - undici-types@7.16.0: - optional: true - undici-types@7.18.2: {} undici-types@8.10.0: {} @@ -16483,16 +15380,6 @@ snapshots: trough: 2.2.0 vfile: 6.0.3 - unique-filename@1.1.1: - dependencies: - unique-slug: 2.0.2 - optional: true - - unique-slug@2.0.2: - dependencies: - imurmurhash: 0.1.4 - optional: true - unist-util-is@6.0.1: dependencies: '@types/unist': 3.0.3 @@ -16612,21 +15499,7 @@ snapshots: jiti: 2.7.0 tsx: 4.23.12 - vite@8.2.2(@types/node@25.2.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12): - dependencies: - lightningcss: 1.33.0 - picomatch: 4.0.7 - postcss: 8.5.26 - rolldown: 1.2.5 - tinyglobby: 0.2.17 - optionalDependencies: - '@types/node': 25.2.3 - esbuild: 0.28.2 - fsevents: 2.3.3 - jiti: 2.7.0 - tsx: 4.23.12 - - vitest@4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.3.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)): + vitest@4.1.10(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(jsdom@30.0.1(@noble/hashes@2.3.0))(tsx@4.23.12): dependencies: '@vitest/expect': 4.1.10 '@vitest/mocker': 4.1.10(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) @@ -16653,38 +15526,20 @@ snapshots: '@types/node': 24.13.3 jsdom: 30.0.1(@noble/hashes@2.3.0) transitivePeerDependencies: + - '@vitejs/devtools' + - esbuild + - jiti + - less - msw + - sass + - sass-embedded + - stylus + - sugarss + - terser + - tsx + - yaml - vitest@4.1.10(@opentelemetry/api@1.9.1)(@types/node@25.2.3)(jsdom@30.0.1(@noble/hashes@2.3.0))(vite@8.2.2(@types/node@25.2.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)): - dependencies: - '@vitest/expect': 4.1.10 - '@vitest/mocker': 4.1.10(vite@8.2.2(@types/node@25.2.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) - '@vitest/pretty-format': 4.1.10 - '@vitest/runner': 4.1.10 - '@vitest/snapshot': 4.1.10 - '@vitest/spy': 4.1.10 - '@vitest/utils': 4.1.10 - es-module-lexer: 2.3.1 - expect-type: 1.4.0 - magic-string: 0.30.21 - obug: 2.1.4 - pathe: 2.0.3 - picomatch: 4.0.5 - std-env: 4.2.0 - tinybench: 2.9.0 - tinyexec: 1.2.4 - tinyglobby: 0.2.17 - tinyrainbow: 3.1.0 - vite: 8.2.2(@types/node@25.2.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12) - why-is-node-running: 2.3.0 - optionalDependencies: - '@opentelemetry/api': 1.9.1 - '@types/node': 25.2.3 - jsdom: 30.0.1(@noble/hashes@2.3.0) - transitivePeerDependencies: - - msw - - vitest@4.1.11(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(jsdom@30.0.1(@noble/hashes@2.3.0))(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)): + vitest@4.1.11(@opentelemetry/api@1.9.1)(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(jsdom@30.0.1(@noble/hashes@2.3.0))(tsx@4.23.12): dependencies: '@vitest/expect': 4.1.11 '@vitest/mocker': 4.1.11(vite@8.2.2(@types/node@24.13.3)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.12)) @@ -16711,7 +15566,18 @@ snapshots: '@types/node': 24.13.3 jsdom: 30.0.1(@noble/hashes@2.3.0) transitivePeerDependencies: + - '@vitejs/devtools' + - esbuild + - jiti + - less - msw + - sass + - sass-embedded + - stylus + - sugarss + - terser + - tsx + - yaml vscode-jsonrpc@9.0.1: {} @@ -16754,11 +15620,6 @@ snapshots: siginfo: 2.0.0 stackback: 0.0.2 - wide-align@1.1.5: - dependencies: - string-width: 4.2.3 - optional: true - wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -16792,9 +15653,6 @@ snapshots: yallist@3.1.1: {} - yallist@4.0.0: - optional: true - yjs@13.6.29: dependencies: lib0: 0.2.117 diff --git a/server/package.json b/server/package.json index 75d2b88cbec..f3a057cd4e9 100644 --- a/server/package.json +++ b/server/package.json @@ -100,6 +100,38 @@ "vite": "^8.2.2", "vitest": "^4.1.10" }, + "peerDependencies": { + "@opentelemetry/auto-instrumentations-node": "0.79.0", + "@opentelemetry/exporter-trace-otlp-grpc": "0.221.0", + "@opentelemetry/exporter-trace-otlp-http": "0.221.0", + "@opentelemetry/exporter-trace-otlp-proto": "0.221.0", + "@opentelemetry/resources": "2.10.0", + "@opentelemetry/sdk-node": "0.221.0", + "@opentelemetry/semantic-conventions": "1.43.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/auto-instrumentations-node": { + "optional": true + }, + "@opentelemetry/exporter-trace-otlp-grpc": { + "optional": true + }, + "@opentelemetry/exporter-trace-otlp-http": { + "optional": true + }, + "@opentelemetry/exporter-trace-otlp-proto": { + "optional": true + }, + "@opentelemetry/resources": { + "optional": true + }, + "@opentelemetry/sdk-node": { + "optional": true + }, + "@opentelemetry/semantic-conventions": { + "optional": true + } + }, "engines": { "node": ">=24.11.0" } diff --git a/server/src/__tests__/instrumentation.test.ts b/server/src/__tests__/instrumentation.test.ts index e2a3937ceb8..475dc770355 100644 --- a/server/src/__tests__/instrumentation.test.ts +++ b/server/src/__tests__/instrumentation.test.ts @@ -88,6 +88,157 @@ describe("instrumentationReady", () => { }); }); +describe("checkExactPeerVersions", () => { + it("passes when the installed version matches the declared version exactly", async () => { + const { checkExactPeerVersions } = await importFreshInstrumentation(); + const require = createRequire(import.meta.url); + const vitestVersion = (require("vitest/package.json") as { version: string }).version; + + const result = checkExactPeerVersions(["vitest"], { vitest: vitestVersion }); + + expect(result).toEqual({ ok: true }); + }); + + it("reports a package as missing when it cannot be resolved", async () => { + const { checkExactPeerVersions } = await importFreshInstrumentation(); + + const result = checkExactPeerVersions(["@paperclipai/does-not-exist-anywhere"], { + "@paperclipai/does-not-exist-anywhere": "1.0.0", + }); + + expect(result.ok).toBe(false); + if (!result.ok) { + expect(result.diagnostic).toContain("@opentelemetry/* packages are not installed"); + expect(result.diagnostic).toContain("@paperclipai/does-not-exist-anywhere"); + } + }); + + it("reports a package as mismatched when the installed version differs from the declared version", async () => { + const { checkExactPeerVersions } = await importFreshInstrumentation(); + const require = createRequire(import.meta.url); + const vitestVersion = (require("vitest/package.json") as { version: string }).version; + + const result = checkExactPeerVersions(["vitest"], { + vitest: "0.0.0-not-the-installed-version", + }); + + expect(result.ok).toBe(false); + if (!result.ok) { + expect(result.diagnostic).toContain("a package is installed at an unsupported version"); + expect(result.diagnostic).toContain(`vitest@${vitestVersion}`); + expect(result.diagnostic).toContain("expected 0.0.0-not-the-installed-version"); + } + }); +}); + +describe("bootstrapOtel exact-version gate", () => { + it("does not mention the two exporters OTEL_EXPORTER_OTLP_PROTOCOL did not select", async () => { + process.env[ENDPOINT_ENV] = "http://collector:4318"; + process.env[PROTOCOL_ENV] = "http/json"; + const warn = vi.spyOn(console, "warn").mockImplementation(() => {}); + + const { instrumentationReady } = await importFreshInstrumentation(); + await instrumentationReady; + + // The OTel packages are absent in this test environment, so the gate + // reports every checked package as missing. It must have checked the + // selected exporter (http/json → exporter-trace-otlp-http) and skipped + // the two the protocol did not select. + const diagnosticCall = warn.mock.calls.find((call) => + String(call[0]).includes("@opentelemetry/* packages are not installed"), + ); + expect(diagnosticCall).toBeDefined(); + const message = String(diagnosticCall![0]); + expect(message).toContain("@opentelemetry/exporter-trace-otlp-http"); + expect(message).not.toContain("@opentelemetry/exporter-trace-otlp-grpc"); + expect(message).not.toContain("@opentelemetry/exporter-trace-otlp-proto"); + }); + + it("emits exactly one diagnostic when the endpoint is set and packages are absent", async () => { + process.env[ENDPOINT_ENV] = "http://collector:4318"; + const warn = vi.spyOn(console, "warn").mockImplementation(() => {}); + + const { instrumentationReady } = await importFreshInstrumentation(); + await instrumentationReady; + + const diagnosticCalls = warn.mock.calls.filter((call) => + String(call[0]).includes("@opentelemetry/* packages are not installed"), + ); + expect(diagnosticCalls).toHaveLength(1); + }); +}); + +describe("bootstrapOtel post-gate load failure", () => { + it("logs a load-failure diagnostic, not the missing-package message, when a package passes the gate but its dynamic import fails", async () => { + process.env[ENDPOINT_ENV] = "http://collector:4318"; + const warn = vi.spyOn(console, "warn").mockImplementation(() => {}); + + // Fake the resolution steps the exact-version gate uses, so every checked + // package reports as installed at its declared version. The dynamic + // `import(...)` calls in bootstrapOtel are untouched, so they still fail + // for real — the packages are not actually installed in this test run. + // That forces the one path the catch block now must describe: a package + // that passed the gate but failed to load. + const FAKE_ROOT = "/fake-otel-pkg"; + const require = createRequire(import.meta.url); + const peerDependencies = ( + require("../../package.json") as { peerDependencies?: Record } + ).peerDependencies ?? {}; + + vi.resetModules(); + vi.doMock("node:fs", async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + existsSync: (path: unknown) => + String(path).startsWith(FAKE_ROOT) ? true : actual.existsSync(path as never), + readFileSync: (path: unknown, options?: unknown) => { + const asString = String(path); + if (asString.startsWith(FAKE_ROOT) && asString.endsWith("package.json")) { + const name = decodeURIComponent( + asString.slice(FAKE_ROOT.length + 1, -"/package.json".length), + ); + return JSON.stringify({ name, version: peerDependencies[name] }); + } + return actual.readFileSync(path as never, options as never); + }, + }; + }); + vi.doMock("node:module", async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + createRequire: (...args: Parameters) => { + const real = actual.createRequire(...args); + const fake = ((id: string) => real(id)) as typeof real; + fake.resolve = ((id: string, options?: unknown) => + id in peerDependencies + ? `${FAKE_ROOT}/${encodeURIComponent(id)}/index.js` + : real.resolve(id, options as never)) as typeof real.resolve; + return fake; + }, + }; + }); + + try { + const { instrumentationReady } = await import("../instrumentation.js"); + await instrumentationReady; + } finally { + vi.doUnmock("node:fs"); + vi.doUnmock("node:module"); + } + + for (const call of warn.mock.calls) { + expect(String(call[0])).not.toContain("packages are not installed"); + expect(String(call[0])).not.toContain("Install @opentelemetry/sdk-node"); + } + expect(warn).toHaveBeenCalledWith( + expect.stringContaining("passed the version check"), + expect.anything(), + ); + }); +}); + describe("getStartupTracer", () => { it("returns a usable tracer-shaped object when OTEL_EXPORTER_OTLP_ENDPOINT is unset", async () => { const { getStartupTracer } = await importFreshInstrumentation(); diff --git a/server/src/__tests__/plugin-worker-manager-duplex.test.ts b/server/src/__tests__/plugin-worker-manager-duplex.test.ts index 40d9c3f5525..57384a7ab0c 100644 --- a/server/src/__tests__/plugin-worker-manager-duplex.test.ts +++ b/server/src/__tests__/plugin-worker-manager-duplex.test.ts @@ -656,6 +656,33 @@ describe("plugin worker manager duplex channel route", () => { } }); + it("carries the transport-close discriminator through a pre-bind exit hold and replay", async () => { + // Regression test: an exit notification that batches with the open reply + // arrives before the bind, so the host holds it in the single pre-bind exit + // slot and replays it after the bind. The hold must keep the transport-close + // discriminator, or the replay reports a plain exit instead of a transport + // close. + const handle = makeDuplexHandle(); + try { + await handle.start(); + const session = await handle.openDuplexChannel( + duplexOpenInput({ + batchWithOpenReply: true, + workerSessionId: "ws-A", + data: [{ chunk: "one" }], + transportClosed: true, + }), + ); + const chunks: string[] = []; + session.onData((chunk) => chunks.push(new TextDecoder().decode(chunk))); + await expect(session.wait()).resolves.toEqual({ exitCode: null, transportClosed: true }); + expect(chunks).toEqual(["one"]); + await session.close(); + } finally { + await handle.stop().catch(() => undefined); + } + }); + it("ends the route when a batched frame passes the per-chunk limit before the bind", async () => { const handle = makeDuplexHandle({ duplexChannelLimits: { maxChunkChars: 4 }, diff --git a/server/src/__tests__/server-package-otel-peer-metadata.test.ts b/server/src/__tests__/server-package-otel-peer-metadata.test.ts new file mode 100644 index 00000000000..1473622d0b6 --- /dev/null +++ b/server/src/__tests__/server-package-otel-peer-metadata.test.ts @@ -0,0 +1,53 @@ +import { readFileSync } from "node:fs"; +import { fileURLToPath } from "node:url"; +import { describe, expect, it } from "vitest"; + +/** + * The seven OpenTelemetry packages `server/src/instrumentation.ts` loads + * through a dynamic import. Each one must be an optional peer dependency, not + * a normal dependency, so a default install never pulls in the SDK. This test + * guards the manifest half of that contract; `instrumentation.test.ts` guards + * the runtime half (the bootstrap fails open when a package is absent). + */ + +const OPTIONAL_OTEL_PACKAGES = [ + "@opentelemetry/sdk-node", + "@opentelemetry/auto-instrumentations-node", + "@opentelemetry/resources", + "@opentelemetry/semantic-conventions", + "@opentelemetry/exporter-trace-otlp-grpc", + "@opentelemetry/exporter-trace-otlp-proto", + "@opentelemetry/exporter-trace-otlp-http", +] as const; + +const packageJsonPath = fileURLToPath(new URL("../../package.json", import.meta.url)); + +describe("server package OpenTelemetry peer metadata", () => { + const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8")) as { + dependencies?: Record; + devDependencies?: Record; + peerDependencies?: Record; + peerDependenciesMeta?: Record; + }; + + it.each(OPTIONAL_OTEL_PACKAGES)( + "declares %s as an optional peer dependency", + (packageName) => { + expect(packageJson.peerDependencies?.[packageName]).toBeDefined(); + expect(packageJson.peerDependenciesMeta?.[packageName]?.optional).toBe(true); + }, + ); + + it.each(OPTIONAL_OTEL_PACKAGES)( + "does not list %s in dependencies or devDependencies", + (packageName) => { + expect(packageJson.dependencies?.[packageName]).toBeUndefined(); + expect(packageJson.devDependencies?.[packageName]).toBeUndefined(); + }, + ); + + it("keeps @opentelemetry/api as a normal dependency", () => { + expect(packageJson.dependencies?.["@opentelemetry/api"]).toBeDefined(); + expect(packageJson.peerDependencies?.["@opentelemetry/api"]).toBeUndefined(); + }); +}); diff --git a/server/src/instrumentation.ts b/server/src/instrumentation.ts index 5f7a31bc967..4b2d7444588 100644 --- a/server/src/instrumentation.ts +++ b/server/src/instrumentation.ts @@ -15,6 +15,12 @@ // - `http/json` → @opentelemetry/exporter-trace-otlp-http // Any other value logs a warning and falls back to grpc. // +// Before it imports any package, the bootstrap checks the four common +// packages and the selected exporter against the exact versions this +// manifest's `peerDependencies` declare. A missing or a mismatched version +// logs one diagnostic and leaves the server running without tracing; it +// never throws. +// // Timing guarantee: the bootstrap is async (dynamic imports), so it cannot // patch modules "before they are evaluated" — by the time the first await // yields, index.ts's static imports (http, express, pg) are already loaded. @@ -27,8 +33,9 @@ // handler before `process.exit`. import { execFileSync } from "node:child_process"; -import { readFileSync } from "node:fs"; +import { existsSync, readFileSync } from "node:fs"; import { createRequire } from "node:module"; +import { dirname, join } from "node:path"; const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT; @@ -273,6 +280,20 @@ export function recordProviderPluginSpan(input: { } } +/** + * The four OTel packages that every protocol needs, regardless of which + * exporter `OTEL_EXPORTER_OTLP_PROTOCOL` selects. `bootstrapOtel` reads this + * synchronously (before its first `await`), so it must be declared above + * `instrumentationReady`: that export calls `bootstrapOtel` at module-init + * time, and a `const` declared below it is not yet initialized then. + */ +const OTEL_COMMON_PACKAGES = [ + "@opentelemetry/sdk-node", + "@opentelemetry/auto-instrumentations-node", + "@opentelemetry/resources", + "@opentelemetry/semantic-conventions", +] as const; + /** * Resolves once the OTel SDK has started (or once bootstrap has failed and * logged, or immediately when the feature is off). Await before constructing @@ -340,6 +361,112 @@ export function resolveProtocol(): { } } +/** + * Read this package's own `peerDependencies`, so the exact-version gate + * compares an installed package against the same version this manifest + * declares — one source of truth, not a second hardcoded copy. Returns an + * empty map on any read or parse failure (fail open: an unreadable manifest + * skips the version check rather than blocking startup). + */ +function readOwnPeerDependencies(): Record { + try { + const pkgUrl = new URL("../package.json", import.meta.url); + const raw = readFileSync(pkgUrl, "utf8"); + const parsed = JSON.parse(raw) as { peerDependencies?: Record }; + return parsed.peerDependencies ?? {}; + } catch { + return {}; + } +} + +/** + * Read an installed package's own declared `version`, without importing or + * executing the package. Resolves the package's main entry point (which + * respects its `exports` map) and then walks up the filesystem to the + * nearest `package.json` whose `name` matches — a direct + * `require.resolve(\`${packageName}/package.json\`)` throws for a package + * whose `exports` map does not expose `./package.json` as a subpath, which + * several `@opentelemetry/*` packages do not, even though the package is + * correctly installed. Returns null when the package cannot be resolved or no + * matching `package.json` is found. + */ +function readInstalledPackageVersion(packageName: string): string | null { + try { + const require = createRequire(import.meta.url); + let dir = dirname(require.resolve(packageName)); + for (;;) { + const candidate = join(dir, "package.json"); + if (existsSync(candidate)) { + const parsed = JSON.parse(readFileSync(candidate, "utf8")) as { + name?: unknown; + version?: unknown; + }; + if (parsed.name === packageName) { + return typeof parsed.version === "string" ? parsed.version : null; + } + } + const parent = dirname(dir); + if (parent === dir) return null; + dir = parent; + } + } catch { + return null; + } +} + +/** + * Verify that every package in `packageNames` is installed at the exact + * version `peerDependencies` declares. Checks only the packages the caller + * passes in — the bootstrap passes the four common packages plus the one + * exporter `OTEL_EXPORTER_OTLP_PROTOCOL` selected, never the two unselected + * exporters. Never throws: a missing manifest, a missing package, or an + * unreadable `package.json` all resolve to a reported issue, not an + * exception. + * + * `peerDependencies` defaults to this manifest's own declared versions + * (`readOwnPeerDependencies()`), which is what the bootstrap uses. A test + * passes an explicit map instead, so it can check the comparison logic + * against a package it controls without writing into `node_modules`. + */ +export function checkExactPeerVersions( + packageNames: readonly string[], + peerDependencies: Record = readOwnPeerDependencies(), +): { ok: true } | { ok: false; diagnostic: string; detail: unknown } { + const missing: string[] = []; + const mismatched: { name: string; installed: string; expected: string }[] = []; + + for (const name of packageNames) { + const expected = peerDependencies[name]; + const installed = readInstalledPackageVersion(name); + if (installed === null) { + missing.push(name); + } else if (expected && installed !== expected) { + mismatched.push({ name, installed, expected }); + } + } + + if (missing.length === 0 && mismatched.length === 0) return { ok: true }; + + const parts: string[] = []; + if (missing.length > 0) { + parts.push(`the @opentelemetry/* packages are not installed: ${missing.join(", ")}`); + } + if (mismatched.length > 0) { + const detail = mismatched + .map((m) => `${m.name}@${m.installed} (expected ${m.expected})`) + .join(", "); + parts.push(`a package is installed at an unsupported version: ${detail}`); + } + + return { + ok: false, + diagnostic: + `[paperclip] OTEL_EXPORTER_OTLP_ENDPOINT is set but ${parts.join("; and ")}. ` + + "Continuing without tracing.", + detail: { missing, mismatched }, + }; +} + async function importExporter(protocol: ExporterProtocol): Promise<{ OTLPTraceExporter: new (config?: Record) => unknown; }> { @@ -425,6 +552,17 @@ export function resolveServiceVersion( async function bootstrapOtel(endpoint: string): Promise { const { protocol, packageName: exporterPackage } = resolveProtocol(); + // Gate on exact peer versions before touching a single dynamic import: a + // package installed at the wrong version can still load and start, then + // fail in a way the operator only sees in the collector, not the server + // log. Checking first turns that into one precise, fail-open diagnostic. + const versionCheck = checkExactPeerVersions([...OTEL_COMMON_PACKAGES, exporterPackage]); + if (!versionCheck.ok) { + // eslint-disable-next-line no-console + console.warn(versionCheck.diagnostic, versionCheck.detail); + return; + } + try { // Dynamic imports so type-resolution doesn't require the packages to // be installed unless the operator actually opts in. @@ -517,14 +655,16 @@ async function bootstrapOtel(endpoint: string): Promise { process.once("SIGTERM", () => void shutdownInstrumentation()); process.once("SIGINT", () => void shutdownInstrumentation()); } catch (err) { - // OTel packages not installed, or dynamic import failed. Fall through - // with a single diagnostic so the opt-in path is self-documenting. + // The exact-version gate above already confirmed every checked package is + // installed at the declared version, so only a load failure after that + // point reaches this block: a bad build, a broken native binding, or a + // package that throws during its own module init. Fall through with a + // single diagnostic so the opt-in path is self-documenting. // eslint-disable-next-line no-console console.warn( - "[paperclip] OTEL_EXPORTER_OTLP_ENDPOINT is set but the @opentelemetry/* " + - `packages are not installed. Install @opentelemetry/sdk-node, ` + - `@opentelemetry/auto-instrumentations-node, ${exporterPackage}, ` + - `@opentelemetry/resources, and @opentelemetry/semantic-conventions to enable tracing.`, + "[paperclip] OTEL_EXPORTER_OTLP_ENDPOINT is set and the @opentelemetry/* " + + "packages passed the version check, but one of them failed to load. " + + "Continuing without tracing.", err, ); } diff --git a/server/src/services/plugin-worker-manager.ts b/server/src/services/plugin-worker-manager.ts index 0b533a3385c..f4c03ade2e9 100644 --- a/server/src/services/plugin-worker-manager.ts +++ b/server/src/services/plugin-worker-manager.ts @@ -1804,6 +1804,9 @@ export function createPluginWorkerHandle( interface HeldDuplexExitEvent { workerSessionId: string; exitCode: number | null; + // A reason-less transport close carries this discriminator. The hold must + // keep it, or a replay reports a real exit for what was a transport close. + transportClosed: boolean; token: ReservationToken | null; } @@ -2334,6 +2337,7 @@ export function createPluginWorkerHandle( route.preBindExit = { workerSessionId, exitCode, + transportClosed: params.transportClosed === true, token: reserved === "no-ledger" ? null : reserved, }; return; @@ -2414,6 +2418,7 @@ export function createPluginWorkerHandle( hostRouteId: route.hostRouteId, workerSessionId: heldExit.workerSessionId, exitCode: heldExit.exitCode, + ...(heldExit.transportClosed ? { transportClosed: true } : {}), }, }); } diff --git a/ui/package.json b/ui/package.json index ec0e14d9f02..49e04bf2838 100644 --- a/ui/package.json +++ b/ui/package.json @@ -69,7 +69,8 @@ "react-resizable-panels": "^4.12.3", "react-router-dom": "^7.18.2", "remark-gfm": "^4.0.1", - "tailwind-merge": "^3.6.0" + "tailwind-merge": "^3.6.0", + "yjs": "13.6.29" }, "devDependencies": { "@sentry/browser": "^10.71.0",