From a032eb4194a18af48d716f4f54380cde03b357a3 Mon Sep 17 00:00:00 2001 From: Sudharsan Date: Sat, 25 Jul 2026 04:39:25 +0530 Subject: [PATCH] chore: update dependencies and streamline docs --- .github/workflows/ci.yml | 10 +- .gitignore | 29 +- README.md | 110 +- _legacy/v1/README.md | 36 +- biome.json | 2 +- docs/architecture.md | 253 +-- docs/learnings/README.md | 22 +- .../compat-is-the-auth-slot-not-the-sdk.md | 42 +- .../cors-preflight-and-upload-passthrough.md | 13 +- docs/learnings/kv-free-tier-write-quota.md | 22 +- docs/learnings/openai-egress-geo-block.md | 40 +- .../provider-routing-by-auth-header.md | 30 - docs/learnings/proxy-token-security.md | 20 - .../rate-limit-binding-free-and-loose.md | 18 +- .../token-expiry-check-at-validate.md | 25 +- docs/learnings/websocket-proxy-auth-slots.md | 22 +- lefthook.yml | 2 +- nub.lock | 1813 +++++++++-------- package.json | 48 +- test/ws.test.ts | 85 +- wrangler.toml | 4 +- 21 files changed, 1235 insertions(+), 1411 deletions(-) delete mode 100644 docs/learnings/provider-routing-by-auth-header.md delete mode 100644 docs/learnings/proxy-token-security.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7d879db..da60ba9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,8 +14,8 @@ jobs: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 - uses: nubjs/setup-nub@47e5e7393d50f4e9544ddaf756aa277972afba2d # v0 with: - nub-version: 0.4.7 - node-version: 24 + nub-version: 0.5.0 + node-version: 26 cache-dependency-path: nub.lock - uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b with: @@ -25,8 +25,8 @@ jobs: - run: | uv venv --python 3.14 uv pip install -r test/requirements.txt - - run: nubx --no-install tsc --noEmit - - run: nubx --no-install biome check . + - run: nub exec tsc --noEmit + - run: nub exec biome check . - run: nub audit --prod - - run: nubx --no-install wrangler deploy --dry-run + - run: nub exec wrangler deploy --dry-run - run: nub run test diff --git a/.gitignore b/.gitignore index a35f69f..7bd20eb 100644 --- a/.gitignore +++ b/.gitignore @@ -6,30 +6,14 @@ out dist *.tgz -# code coverage -coverage -*.lcov - # logs logs _.log -report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json - -# dotenv environment variable files -.env -.env.development.local -.env.test.local -.env.production.local -.env.local - -# caches -.eslintcache -.cache -*.tsbuildinfo +report.*.json -# local experiments / scratch -.tmp-* -HANDOFF.md +# secrets +.env* +!.env.example # wrangler local state / build cache .wrangler @@ -44,11 +28,6 @@ HANDOFF.md # Finder (MacOS) folder config .DS_Store -CLAUDE.md - -# claude local settings -.claude/settings.local.json - # python venv for the separate-runner compat tests + caches .venv/ __pycache__/ diff --git a/README.md b/README.md index b4f97c7..849e2c4 100644 --- a/README.md +++ b/README.md @@ -1,121 +1,99 @@ # api-proxy -A single Cloudflare Worker that reverse-proxies the OpenAI, Anthropic, and Google Gemini APIs - over **HTTP and WebSocket** - behind **revocable proxy tokens**. You issue tokens from an admin dashboard and hand them out; each token is validated server-side and swapped for the real provider key before the request is forwarded. Consumers never see your real keys, and you can scope or revoke any token at any time. +A Cloudflare Worker that proxies OpenAI, Anthropic, and Google Gemini over HTTP and WebSocket. Clients use revocable proxy tokens; the Worker validates each token and replaces it with the provider key before forwarding. ## Use it -Works with the official **OpenAI**, **Anthropic**, and **Google GenAI** SDKs (Python and Node) - and, since the worker routes by auth header and forwards everything else verbatim, with anything that speaks those APIs: the Vercel AI SDK, LangChain, LiteLLM, OpenAI-compatible tools, or raw `curl`. A client changes only **two things**: the base URL and the API key (a proxy token). +Clients normally change only their base URL and API key. The compatibility suite covers the official SDKs and selected AI frameworks in `test/sdk-compat/`; other HTTP clients should work when they expose a base-URL override and use a supported credential slot, but are not automatically tested. -| Client | base URL | API key | -|---|---|---| -| OpenAI SDK (Python / Node) | `https:///v1` | proxy token | -| Anthropic SDK (Python / Node) | `https://` (no `/v1`) | proxy token | -| Google `@google/genai` (Node) | `httpOptions.baseUrl = https://` | proxy token | -| Gemini via the OpenAI SDK | `https:///v1beta/openai` | proxy token | +| Client | Base URL | API key | +| ----------------------------- | ---------------------------------------- | ----------- | +| OpenAI SDK | `https:///v1` | proxy token | +| Anthropic SDK | `https://` | proxy token | +| Google `@google/genai` | `httpOptions.baseUrl = https://` | proxy token | +| Gemini through the OpenAI SDK | `https:///v1beta/openai` | proxy token | ```python -# OpenAI SDK (Python); Node is identical from openai import OpenAI + client = OpenAI(base_url="https:///v1", api_key="") client.chat.completions.create( - model="gpt-5.4", messages=[{"role": "user", "content": "Hello"}]) -``` - -Or raw HTTP: - -```bash -curl https:///v1/chat/completions \ - -H "authorization: Bearer " -H "content-type: application/json" \ - -d '{"model":"gpt-5.4","messages":[{"role":"user","content":"Hello"}]}' + model="gpt-5.6", messages=[{"role": "user", "content": "Hello"}]) ``` -Browser apps work too - the worker answers the CORS preflight and reflects the request Origin (provider browser opt-ins still apply, e.g. Anthropic's `dangerouslyAllowBrowser`). +Browser requests are supported through CORS. Provider-specific browser opt-ins still apply, such as Anthropic's `dangerouslyAllowBrowser`. -### WebSocket / realtime +### WebSocket APIs -Realtime sockets proxy the same way - point the WebSocket at the worker and use a proxy token. The worker swaps the token for the real key on the upgrade handshake. +| API | URL | Proxy-token slot | +| ---------------- | ---------------------------------------------------- | --------------------------------------------------------------------------- | +| OpenAI Realtime | `wss:///v1/realtime?model=…` | Bearer header, or `openai-insecure-api-key.` subprotocol in browsers | +| OpenAI Responses | `wss:///v1/responses` | Bearer header | +| Gemini Live | `wss:///ws/…BidiGenerateContent?key=` | `?key=` query | -| WebSocket API | URL | token slot | -|---|---|---| -| OpenAI Realtime (server) | `wss:///v1/realtime?model=…` | `Authorization: Bearer ` | -| OpenAI Realtime (browser) | `wss:///v1/realtime?model=…` | `Sec-WebSocket-Protocol: realtime, openai-insecure-api-key.` | -| OpenAI Responses (WebSocket mode) | `wss:///v1/responses` | `Authorization: Bearer ` | -| Gemini Live | `wss:///ws/…BidiGenerateContent?key=` | `?key=` query | +A socket is authorized and rate-limited when it connects. Revocation affects the next connection, not an open stream. -A browser can't set the `Authorization` header on a WebSocket, so OpenAI places the key in the `openai-insecure-api-key.` subprotocol; the worker rewrites it to a Bearer header upstream. `x-api-key` upgrades route to Anthropic too. A long-lived socket is rate-limited and validated **once at connect**, so a revoke applies to the next connection, not an open stream. - -## How it works - -The proxy token rides in the SDK's normal auth slot. The worker validates its scope, strips the HTTP header/query auth slots, sets one provider key, and forwards the path, remaining query, body, and stream. WebSocket handshakes add OpenAI's browser subprotocol slot. See [docs/architecture.md](docs/architecture.md) for the routing table and design. +See [the architecture](docs/architecture.md) for routing, credential replacement, and consistency rules. ## Setup -Requires Node 24+ and Nub 0.4.7. +Requires Node 26+ and Nub 0.5.x. ```bash nub install -nubx wrangler login -nubx wrangler kv namespace create api-proxy-tokens # paste the id into wrangler.toml +nub exec wrangler login +nub exec wrangler kv namespace create api-proxy-tokens ``` -Set the secrets (only these four; never committed): +Put the namespace ID in `wrangler.toml`, then configure the secrets and deploy: ```bash -nubx wrangler secret put OPENAI_API_KEY -nubx wrangler secret put ANTHROPIC_API_KEY -nubx wrangler secret put GEMINI_API_KEY -nubx wrangler secret put ADMIN_SECRET # password for the admin dashboard -nubx wrangler deploy +nub exec wrangler secret put OPENAI_API_KEY +nub exec wrangler secret put ANTHROPIC_API_KEY +nub exec wrangler secret put GEMINI_API_KEY +nub exec wrangler secret put ADMIN_SECRET +nub exec wrangler deploy ``` -Optional plain vars (NOT secrets) override the upstreams; they default to the real hosts and only need setting for testing: `OPENAI_UPSTREAM`, `ANTHROPIC_UPSTREAM`, `GEMINI_UPSTREAM`. - -## Admin dashboard +`OPENAI_UPSTREAM`, `ANTHROPIC_UPSTREAM`, and `GEMINI_UPSTREAM` are optional plain variables used mainly to point tests at a mock upstream. -Visit `https:///admin`, sign in with `ADMIN_SECRET`, and create tokens with a label, provider scope, optional expiry, and either a custom value (minimum 12 characters) or a generated value. The plaintext is shown **once**. KV stores its SHA-256 hash plus metadata (`label`, `last4`, scope, status, creation/expiry), with `lastUsed` in a side key. The admin route checks for an existing custom-token hash, but KV's read-then-write is not transactional, so do not race identical creations. +## Admin and token controls -## Per-token controls +Visit `https:///admin` and sign in with `ADMIN_SECRET`. -- **Expiry** - optionally set or edit an expiry; past it the token is rejected and the dashboard shows it as `expired`. -- **Rate limit** - each token is capped at 100 requests / 60s (`429` + `Retry-After` over the limit). Tune `[[ratelimits]]` in `wrangler.toml`. It is a per-location, loose ceiling for abuse protection, not a strict quota. -- **Scope & revoke** - a token only reaches the providers you check; disable or delete to revoke (KV changes can take 60 seconds or more to reach other locations). +- Create a generated or custom token with a label, provider scope, and optional expiry. Plaintext is shown once. +- Edit expiry, disable a token, or delete it. KV changes may take 60 seconds or more to reach another Cloudflare location. +- Each token is checked against the default 100 requests per 60 seconds threshold, configured under `[[ratelimits]]` in `wrangler.toml`. This is loose per-location abuse control, not a strict quota. -## Security +Provider keys stay in Cloudflare secrets. KV stores token hashes and metadata, never usable token plaintext. Before forwarding, the Worker removes every recognized inbound credential slot and sets exactly one provider credential. -- Real provider keys are Cloudflare secrets, injected only into outbound requests - never in KV, never returned to callers. -- Token plaintext is not persisted; KV stores hashes, metadata, and separate last-used timestamps. -- The worker strips HTTP header/query auth slots and the WebSocket key subprotocol before setting the provider credential, so a proxy token is not forwarded upstream. -- Do not host the worker on a `*.openai.azure.com` / `*.cognitiveservices.azure.com` domain (the OpenAI SDK switches to Azure auth on those hostnames). +Do not host the Worker on an `*.openai.azure.com` or `*.cognitiveservices.azure.com` domain because OpenAI clients may switch to Azure authentication on those hostnames. ## Testing ```bash -nub run test:unit # tier 1: proxy logic in workerd (vitest-pool-workers), fast CI gate -nub run test:compat # tier 2: real client libs (official SDKs, Vercel AI SDK, LangChain, Genkit) + raw fetch + a real wss round-trip vs a mock upstream -nub run test:py # tier 2 (Python): LiteLLM, LlamaIndex, instructor, Pydantic AI through the worker (needs the venv below) -nub run test # all of the above +nub run test:unit +nub run test:compat +nub run test:py +nub run test ``` -**Each client-named compatibility case doubles as a usage example.** Keep every client: shared auth-slot routing is only one invariant, while separate cases catch base-URL options, default endpoints, implicit headers, transport choices, and streaming behavior. Copy the wiring from the matching file, `fetch.ts`, or `websocket.ts`. The coverage rationale is [docs/learnings/compat-is-the-auth-slot-not-the-sdk.md](docs/learnings/compat-is-the-auth-slot-not-the-sdk.md); the harness is [docs/architecture.md](docs/architecture.md) §14. - -Two gotchas: use Anthropic's normal API-key mode (its OAuth `authToken` mode sends `Bearer`, which would route to OpenAI), and the legacy `google-generativeai` Python SDK needs `transport="rest"` (it defaults to gRPC and won't traverse an HTTP proxy otherwise). - -The Python runner uses a local venv. One-time setup with [uv](https://docs.astral.sh/uv/): +Python compatibility tests need a local environment: ```bash uv venv uv pip install -r test/requirements.txt ``` -> **Gemini is untested with the actual API.** No test hits a live provider - all three run against a mock upstream. OpenAI and Anthropic are additionally verified live in deployment. A `GEMINI_API_KEY` secret is configured, but its validity and the Gemini route have not been verified against the real Google Generative Language API. Treat it as built-but-unproven until that live check passes. +The Python tier exits with an error when `.venv` is absent. All automated tests use fake credentials and mock upstreams; Gemini has not been verified against its live API. Client-specific setup and caveats are in [`test/sdk-compat/`](test/sdk-compat/) and the [compatibility learning](docs/learnings/compat-is-the-auth-slot-not-the-sdk.md). ## Cost -The Worker and SQLite Durable Object have separate allowances. Cloudflare's Free Durable Object tier lists **100,000 requests/day** and **13,000 GB-s/day** (pricing page updated 2026-06-19). Each OpenAI geo-block fallback consumes one DO request, and its execution contributes to active duration; each admin token edit or delete adds one `TokenWriter` DO request. See [Durable Objects pricing](https://developers.cloudflare.com/durable-objects/platform/pricing/); upstream API usage is billed by the provider. +The OpenAI geo-block fallback and every admin token create, edit, or delete use a Durable Object request in addition to the Worker request. See [Cloudflare Durable Objects pricing](https://developers.cloudflare.com/durable-objects/platform/pricing/). Provider API usage is billed separately. ## Contributing -Issues are welcome. External PRs are not accepted and will be auto-closed. +Issues are welcome. External pull requests are auto-closed. ## License diff --git a/_legacy/v1/README.md b/_legacy/v1/README.md index ecf38bb..13af3bc 100644 --- a/_legacy/v1/README.md +++ b/_legacy/v1/README.md @@ -1,35 +1,19 @@ -# v1 - one worker per provider (archived) +# v1 - one worker per provider -The original proxy: **three separate Workers**, one per provider, each a thin pass-through -that swaps the hostname and injects the real key from its own secret. +The original design used three unauthenticated Workers, one for each provider. Each Worker rewrote the host and injected its own provider secret. -``` -client ──▶ openai-proxy ──(Bearer OPENAI_API_KEY)──▶ api.openai.com -client ──▶ claude-proxy ──(x-api-key ANTHROPIC_KEY)─▶ api.anthropic.com -client ──▶ gemini-proxy ──(x-goog-api-key GEMINI)──▶ generativelanguage.googleapis.com -``` - -| File | Worker | Upstream | Key slot it sets | -|---|---|---|---| -| `openai.ts` / `wrangler.openai.toml` | `openai-proxy` | api.openai.com | `Authorization: Bearer` | -| `claude.ts` / `wrangler.claude.toml` | `claude-proxy` | api.anthropic.com | `x-api-key` | -| `gemini.ts` / `wrangler.gemini.toml` | `gemini-proxy` | generativelanguage.googleapis.com | `x-goog-api-key` (and strips `?key=`) | +| Worker | Upstream | Credential set | +|---|---|---| +| `openai-proxy` | api.openai.com | Bearer | +| `claude-proxy` | api.anthropic.com | `x-api-key` | +| `gemini-proxy` | generativelanguage.googleapis.com | `x-goog-api-key` | ## Why it was replaced -- **No auth.** Each worker injected the real upstream key for *any* caller. Anyone who knew - the URL spent the key. There were no shareable, revocable tokens. -- **Three deploys, three URLs.** Clients had to know which worker maps to which provider, and - each needed its own secret and deploy. +Anyone who knew a Worker URL could spend its shared provider key. There were no per-user scopes, revocation, or usage controls, and each provider needed a separate URL and deployment. -v2 (the active root worker) collapses all three into **one** worker that routes by auth header, -gates every request behind a hashed [proxy token](../../docs/learnings/proxy-token-security.md), -and adds the [OpenAI geo-403 egress fix](../../docs/learnings/openai-egress-geo-block.md). See -[provider routing by auth header](../../docs/learnings/provider-routing-by-auth-header.md) for how -one base URL serves all three. +The current root Worker adds hashed proxy tokens, one routing surface, and the OpenAI geo-block fallback. See the active [architecture](../../docs/architecture.md). ## Status -Reference only - **not deployed, not built, not tested.** Kept to document where the project -started. The `main` paths in these tomls point at files in this folder, so each could still be -deployed standalone (`wrangler deploy -c _legacy/v1/wrangler.openai.toml`) if ever needed. +Historical reference only. This directory is excluded from builds and tests and is not maintained as deployable code. diff --git a/biome.json b/biome.json index c60a6ea..f4e63e8 100644 --- a/biome.json +++ b/biome.json @@ -1,5 +1,5 @@ { - "$schema": "https://biomejs.dev/schemas/2.5.3/schema.json", + "$schema": "https://biomejs.dev/schemas/2.5.5/schema.json", "vcs": { "enabled": true, "clientKind": "git", diff --git a/docs/architecture.md b/docs/architecture.md index 36470a5..2119508 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -1,235 +1,92 @@ -# api-proxy architecture +# Architecture -A Cloudflare Worker that reverse-proxies **OpenAI, Anthropic, and Google Gemini** behind revocable **proxy tokens**. Clients receive no provider key: it is absent from KV and responses, application log statements do not include it, and it is sent only from the Worker or its Durable Object to the selected provider. +`api-proxy` is one Cloudflare Worker for OpenAI, Anthropic, and Google Gemini traffic. It handles HTTP, WebSocket upgrades, and the admin dashboard. -This document is the current design. Topic deep-dives with the "why" live in [`docs/learnings/`](learnings/); the retired one-worker-per-provider v1 lives in [`_legacy/v1/`](../_legacy/v1/). +This document describes the current design. [`learnings/`](learnings/) keeps evidence and the reasons behind non-obvious decisions. [`_legacy/v1/`](../_legacy/v1/) is historical reference only. ---- +## Invariants -## 1. Problem +- Provider keys stay in Cloudflare secrets and are read only after authorization. +- Proxy-token plaintext is shown once and never persisted. +- Every recognized inbound credential slot is removed before exactly one provider credential is set. +- Except for CORS preflight, provider traffic requires an active, unexpired token with the requested provider in scope. +- Automated tests use fake credentials and mock upstreams, never live providers. -v1 was three unauthenticated workers (one per provider), each injecting a shared real key for **anyone** who knew the URL - no per-user access, no revocation. v2 collapses them into one token-gated worker. +## Request flow -## 2. Topology +`src/index.ts` sends WebSocket upgrades to `src/ws.ts`, `/admin` traffic to the Hono admin app, and other requests to `src/proxy.ts`. -One worker, dispatched in `src/index.ts`: - -```mermaid -flowchart LR - R[request] --> U{"Upgrade: websocket?"} - U -- yes --> WS["handleWsProxy - wss hot path (§10)"] - U -- no --> AD{"path /admin/*?"} - AD -- yes --> H["Hono admin sub-app (§11)"] - AD -- no --> P["handleProxy - HTTP hot path (§3)"] -``` - -- The **WebSocket upgrade** is checked first so a realtime client never falls through to the HTTP branch. -- The **admin sub-app** leans on Hono's default error handler (`console.error` + 500), so an admin bug still answers cleanly and never touches the proxy branch. -- The **HTTP hot path** is framework-free; `src/proxy.ts` never imports Hono or admin code. - -## 3. Request flow (proxy hot path) +An HTTP request follows this path: -`handleProxy` is a thin wrapper: it answers an `OPTIONS` preflight directly, otherwise runs `proxyRequest` and reflects CORS headers onto the result (§8). `proxyRequest`: - -1. **Extract** the token from whichever auth slot it arrived in and **route** the provider from that slot (+ path); missing either → **401**. (§4) -2. **Validate** `SHA-256(token)` against KV - a miss or a disabled token → **401**; an expired one → **401 `token expired`** (distinct message, the most common self-inflicted failure); a KV read failure (outage, exhausted quota) → **503**. (§6) -3. Requested provider not in the token's scope → **403**. (§4) -4. **Rate-limit** on the hash - over the cap → **429** + `Retry-After` (fail-open). (§7) -5. **Rewrite** the URL to the upstream - protocol/host/port only. (§13) -6. **Swap auth** - strip every HTTP header/query auth slot through `stripAuthSlots`, then set one provider key. (§5) -7. **Fetch** the upstream (OpenAI adds a geo-403 fallback, §9), stream the response, and stamp `lastUsed` fire-and-forget. (§6) +1. Identify the provider and extract the proxy token from the client's normal credential slot. +2. Hash the token and read its metadata from KV. +3. Check status, expiry, provider scope, and the loose per-location rate-limit threshold. +4. Rewrite only the upstream origin, remove all recognized credential slots, and set the selected provider key. +5. Stream the upstream response and schedule a best-effort `lastUsed` stamp. -Steps 2-4 are one shared `authorize()` call - the same spine the WS path runs (§10), so a new check lands in both pipelines by construction. Infrastructure failures log their cause (`console.error`/`warn`) for §13's Workers Logs; auth rejections (401/403/429) deliberately do not - logging every stranger's bad token would let unauthenticated spam burn the log quota. +Missing or invalid tokens return 401, a scope mismatch returns 403, and a rate-limit denial returns 429. A token-store failure returns 503. Rate-limiter failures are fail-open so that the abuse-control layer cannot disable the proxy. Expected 401, 403, and 429 responses are not logged, preventing request-driven log spam. -```mermaid -flowchart TD - A[request] --> B{"token + provider from auth slot? (§4)"} - B -- no --> E1[401] - B -- yes --> C{"SHA-256 valid + active + unexpired in KV? (§6)"} - C -- no --> E2[401] - C -- "KV read fails" --> E5["503"] - C -- yes --> D{"provider in token scope?"} - D -- no --> E3[403] - D -- yes --> F{"under the rate limit? (§7)"} - F -- no --> E4["429 + Retry-After"] - F -- yes --> G["rewrite URL to upstream + swap auth (§13, §5)"] - G --> H["fetch upstream (OpenAI: geo-403 DO fallback, §9)"] - H --> I["stream back unbuffered; stamp lastUsed in waitUntil (§6)"] -``` +## Provider identification and credential replacement -## 4. Provider routing (by auth slot) +Routing uses the credential slot already chosen by the client. This keeps each provider's native path and avoids a proxy-specific path prefix. -The client adds no path prefix and no custom header - routing reads **which auth slot the SDK populated** (`identify`): +| Inbound signal, in precedence order | Provider | +|---|---| +| `x-api-key` | Anthropic | +| `x-goog-api-key` | Gemini | +| Bearer plus `/v1beta/openai/*` | Gemini's OpenAI-compatible API | +| Bearer | OpenAI | +| `?key=` when no earlier slot matched | Gemini | -| Inbound signal | Provider | Upstream | -|---|---|---| -| `x-api-key` | `anthropic` | api.anthropic.com | -| `x-goog-api-key` or `?key=` | `gemini` | generativelanguage.googleapis.com | -| `Authorization: Bearer` + path `/v1beta/openai/*` | `gemini-openai` | generativelanguage.googleapis.com | -| `Authorization: Bearer` (else) | `openai` | api.openai.com | -| none | - | 401 | +The OpenAI-compatible Gemini route uses the same token scope as native Gemini. -Auth slots are checked **before** `?key=`, so a request carrying `Authorization: Bearer` routes to openai / gemini-openai even when it also has `?key=`; the `x-goog-api-key or ?key=` equivalence holds only when no Bearer header is present. +Before forwarding, the Worker removes Bearer, `x-api-key`, `x-goog-api-key`, and `?key=` credentials, then sets one real provider credential. WebSocket handling also removes OpenAI's key-bearing subprotocol entry. Removing every slot prevents an extra client credential from leaking upstream. -`gemini-openai` (the OpenAI-compatible Gemini endpoint) collapses to the `gemini` scope via `coarse()`; the distinction only selects the auth-swap branch. Why no path prefix: [`provider-routing-by-auth-header.md`](learnings/provider-routing-by-auth-header.md). +## Tokens and consistency -## 5. Auth swap (security linchpin) +KV stores token metadata under `SHA-256(token)`. Metadata includes the label, last four characters, provider scope, status, creation time, and optional UTC expiry. Expiry is checked during validation rather than with KV TTL, so expired rows remain visible and the separate usage key is not orphaned. See [the expiry decision](learnings/token-expiry-check-at-validate.md). -Before forwarding HTTP, `swapAuth` deletes every header/query auth slot and sets one provider credential: +`lastUsed` lives in `:lu`, not in the token record. Updating activity can therefore never rewrite an older token record over a revocation. Stamps are intentionally coarse to stay within the Free-plan KV write budget. See [the KV quota learning](learnings/kv-free-tier-write-quota.md). -```ts -stripAuthSlots(headers, url); // shared HTTP/header-query slot list -switch (provider) { - case "openai": case "gemini-openai": headers.set("authorization", `Bearer ${realKey}`); break; - case "anthropic": headers.set("x-api-key", realKey); break; - case "gemini": headers.set("x-goog-api-key", realKey); break; -} -``` +KV does not provide the atomic read-modify-write behavior needed by admin edits. A per-token `TokenWriter` Durable Object serializes create, patch, and delete operations and keeps the latest merge base in its own storage. KV remains the read store used by request authorization. A deletion marker prevents stale KV data from reviving a removed token; creating the same token again clears that marker. -Strip-all-then-set-one prevents dual-slot leaks: `?key=` is deleted for every provider, not only Gemini. `stripAuthSlots` owns the HTTP header/query list and is reused by WebSocket handling; `ws.ts` additionally removes OpenAI's key-bearing subprotocol entry. Tests scan outbound headers and URLs for the proxy token. See [`proxy-token-security.md`](learnings/proxy-token-security.md). +KV changes can take 60 seconds or more to appear in another Cloudflare location. If access must end globally without that delay, rotate the provider credential. -## 6. Token model & lifecycle +## Protocol-specific behavior -KV namespace `TOKENS`, keyed by `SHA-256(token)` (hex). The plaintext is shown **once** at creation and never persisted (`src/tokens.ts`, `src/types.ts`): +### CORS and Gemini uploads -```ts -type TokenMetadata = { - label: string; - last4: string; // for display - providers: ("openai"|"anthropic"|"gemini")[]; // coarse scope - status: "active" | "disabled"; - createdAt: string; // ISO - expiresAt?: string; // ISO (UTC); absent = never expires -}; -``` +`OPTIONS` is answered before authorization because browser preflight does not include the later request's credential headers. The actual request still follows normal authorization and credential replacement. -- **Tokens** are opaque: `ptk_` + 32 url-safe chars (24 random bytes). Custom admin-typed tokens are allowed; validation is by hash of the full string. -- **Validation** (`getValidatedByHash`): returns the record only if `status === "active"` AND, when `expiresAt` is set, it parses to a future timestamp - malformed or past expiry is rejected **fail-closed**. Not KV `expirationTtl` - why: [`token-expiry-check-at-validate.md`](learnings/token-expiry-check-at-validate.md). -- **`lastUsed`** is a separate `:lu` key. The first qualifying use per token/day/isolate schedules a stamp: either an authorized HTTP request that receives any upstream response or a successful WebSocket upgrade. The dashboard localizes the stored ISO timestamp. See [`proxy-token-security.md`](learnings/proxy-token-security.md) and [`kv-free-tier-write-quota.md`](learnings/kv-free-tier-write-quota.md). -- **Lifecycle:** admin creation uses `mintToken` + `TokenWriter.create`; `listTokens` performs one `kv.list` page plus batched multi-key reads; `TokenWriter.patch`/`.remove` handle status, expiry, and deletion (record + `:lu`). Changes can take 60 seconds or more to become visible in other locations. +Gemini's upload-start response contains an absolute, self-authenticating continuation URL. It is returned unchanged, allowing the client to upload directly to Google without the Worker's body-size limit. See [the CORS and upload learning](learnings/cors-preflight-and-upload-passthrough.md). -```mermaid -stateDiagram-v2 - [*] --> active: createToken (plaintext shown once) - active --> disabled: PUT status=disabled - disabled --> active: PUT status=active - active --> expired: expiresAt passes (derived at validate, record kept) - expired --> active: PUT expiresAt (future or cleared) - active --> [*]: DELETE (record + lu key) - disabled --> [*]: DELETE - expired --> [*]: DELETE -``` +### WebSockets -## 7. Per-token rate limiting +WebSockets share the HTTP authorization path, then connect upstream through `fetch()` with an upgrade request and bridge both sockets. Supported token slots are Bearer, Anthropic's `x-api-key`, Gemini's `?key=`, and OpenAI's browser subprotocol entry. -After validation, `RATE_LIMITER.limit({ key: hash })` (the Workers Rate Limiting binding) caps each token. Over the limit → `429` + `Retry-After: 60`. Wrapped in try/catch and **fail-open**: a missing or erroring binding must never brick the proxy. +Authorization and rate limiting happen once during the upgrade. Open frames are not revalidated after revocation. The fetched-socket design and close coordination are explained in [the WebSocket learning](learnings/websocket-proxy-auth-slots.md). -```toml -[[ratelimits]] -name = "RATE_LIMITER" -namespace_id = "1001" +### OpenAI geo-block fallback - [ratelimits.simple] - limit = 100 # one shared ceiling for all tokens; tune freely - period = 60 # must be 10 or 60 -``` +OpenAI requests use the direct edge first. Only an `unsupported_country_region_territory` 403 is retried through a US-jurisdiction Durable Object. The same fallback handles HTTP and WebSocket upgrades. It keeps the provider key inside Cloudflare and avoids charging every request for a Durable Object hop. Evidence and rejected alternatives are in [the geo-block learning](learnings/openai-egress-geo-block.md). -It is in-process (not a subrequest), keyed on the hash, and **per-location + eventually consistent** - a loose ceiling for abuse protection, not a strict quota. Verified to run on the Free plan. `/admin/login` throttling is a separate, tighter `LOGIN_LIMITER` ruleset (§11, §13), so tuning the proxy ceiling never loosens brute-force protection. See [`rate-limit-binding-free-and-loose.md`](learnings/rate-limit-binding-free-and-loose.md). +## Admin dashboard -## 8. CORS & browser support +The server-rendered Hono app lives under `/admin`. The browser submits the admin password, but never receives the `ADMIN_SECRET` binding. Login compares the password in constant time, applies a separate per-IP rate-limit threshold, and issues a signed, server-expired cookie. HTMX is loaded at a pinned version with a matching SRI hash. -`handleProxy` answers `OPTIONS` with `204` **before** token checks because preflight omits credential headers (why: [`cors-preflight-and-upload-passthrough.md`](learnings/cors-preflight-and-upload-passthrough.md)). The URL remains intact, so Gemini's `?key=` may still be present, but the Worker neither validates nor forwards it. The response reflects `Origin` and requested headers, allows `GET, POST, PUT, DELETE, OPTIONS`, and sets `Access-Control-Max-Age: 86400`. An actual cross-origin request runs normal authorization and its outbound provider request carries the real provider key. `withCors` only adds response headers: reflected origin, `Vary: Origin`, and exposed Gemini upload headers. No `Origin` means no CORS headers; cookie credentials are not enabled. +The dashboard creates, lists, edits, disables, and deletes tokens. Generated or custom plaintext appears only in the creation response. Datetimes are entered and displayed in local time but stored as UTC ISO strings. A blank expiry means no expiry. -**Gemini file uploads:** the authenticated start call crosses the proxy. Google returns an absolute, self-authenticating `x-goog-upload-url`, then the client uploads bytes directly to Google. That second leg avoids the Worker's 100 MB body cap and carries no provider key. +Admin mutations use `TokenWriter`; token creation is therefore a Durable Object operation too. Listing and request authorization read KV. The UI shows mutation results immediately rather than waiting for cross-location KV propagation. -```mermaid -sequenceDiagram - participant C as client - participant P as proxy - participant G as Google - C->>P: start resumable upload (proxy token) - P->>G: forward (real key swapped in) - G-->>C: absolute x-goog-upload-url (not rewritten) - C->>G: upload bytes straight to that URL (skips Worker + 100MB cap) -``` +## Security boundaries -## 9. OpenAI geo-403 egress (US-jurisdiction Durable Object) +- Provider keys are sent only from the Worker or its Durable Object to the selected provider. Application log statements do not include them. +- Rejected requests and preflight do not read provider keys. +- Token hashes protect stored data from immediately becoming usable credentials; provider keys must still be rotated if exposed. +- Do not deploy on an `*.openai.azure.com` or `*.cognitiveservices.azure.com` hostname because OpenAI clients may switch to Azure authentication. -OpenAI 403s `unsupported_country_region_territory` when a request egresses from an unsupported colo (e.g. Hong Kong). A Worker's `fetch()` egresses from the colo the invocation runs in, fixed per invocation, so an in-invocation retry can't escape a bad colo. +## Test coverage -The proxy tries the direct edge `fetch()` first and, **only on that geo-403**, reissues the request through `env.US_EGRESS.jurisdiction("us")`. This is a US jurisdiction constraint, not a best-effort `locationHint`. Only OpenAI bodies are buffered for replay; eight named objects (`oa-egress-`) spread fallback traffic. The provider key traverses Cloudflare's Worker/DO path and is then sent to OpenAI, never to a third-party relay. Evidence and tradeoffs: [`openai-egress-geo-block.md`](learnings/openai-egress-geo-block.md). +Workerd unit tests cover routing, authorization, credential removal, expiry, CORS, rate limiting, upstream fallback, streaming, and WebSocket behavior. Node and Python compatibility suites run real client libraries against an ephemeral Worker and mock upstream. They verify client configuration and wire behavior without contacting a live provider. -## 10. WebSocket (wss) proxying - -`handleWsProxy` is dispatched before HTTP on `Upgrade: websocket`. The tested endpoints are **OpenAI** `/v1/realtime` and `/v1/responses`, plus **Gemini Live** (`...BidiGenerateContent`). An `x-api-key` upgrade is also identified and forwarded as Anthropic, so the handler does not exclude that provider. - -The flow reuses `authorize()`, then opens the upstream with `fetch()` plus `Upgrade: websocket`, reads `resp.webSocket`, and pumps frames through a `WebSocketPair`. `fetch()` remains deliberate even though Workers now provide `new WebSocket()`: fetched sockets can opt into `accept({ allowHalfOpen: true })`, which the proxy needs to coordinate close frames. The manual pipe also echoes the negotiated subprotocol. A refused upgrade is returned verbatim. - -**Auth on a WS handshake has a wider slot set than HTTP** (why: [`websocket-proxy-auth-slots.md`](learnings/websocket-proxy-auth-slots.md)): - -| Inbound slot | Provider | Swapped to (upstream) | -|---|---|---| -| `Authorization: Bearer ` | openai or gemini-openai by path | `Authorization: Bearer ` | -| `x-api-key: ` | anthropic | `x-api-key: ` | -| `Sec-WebSocket-Protocol: openai-insecure-api-key.` | openai | key entry dropped; real key set as `Authorization: Bearer` (the worker *can* set headers); `realtime` + org/project/beta subprotocols kept | -| `?key=` | gemini | `?key=` in the query (Gemini Live reads the key there, not a header) | - -`prepareWsUpstream` applies the shared HTTP header/query stripping, removes OpenAI's key-bearing subprotocol entry, and sets one upstream credential. The OpenAI geo-403 fallback applies to upgrades too. - -Caveats: the rate limit gates the **connection**, not each frame, and revocation affects the next connection rather than an already-authorized socket. See [`websocket-proxy-auth-slots.md`](learnings/websocket-proxy-auth-slots.md). - -## 11. Admin dashboard - -Embedded **Hono** sub-app at `/admin` (`src/admin/`), server-rendered HTML via `hono/html` plus **HTMX 2.x** loaded from a CDN with a pinned version **and an SRI hash** (`integrity` + `crossorigin`): the page holds token-mint power and receives `ADMIN_SECRET`, so a tampered CDN response must refuse to execute. No authored client JS beyond a handful of inline `hx-on` attributes; nothing in the worker bundle but markup + attributes. The login form also carries `method="post"` so a no-htmx fallback submit can never default to GET and leak the password into the URL. - -- **Auth:** one `ADMIN_SECRET` password. `POST /admin/login` is rate-limited per client IP (dedicated `LOGIN_LIMITER`, 10/60s, fail-open) and compared in constant time (hono's `timingSafeEqual`, which hashes both sides with SHA-256); failures are logged. Success sets a signed cookie via `hono/cookie` (`setSignedCookie`: HMAC-SHA-256 over the issue timestamp, `Path=/admin; HttpOnly; Secure; SameSite=Strict; Max-Age=86400`). A middleware guards every `/admin/*` route except login; `getSignedCookie` verifies in constant time (`crypto.subtle.verify`) and the guard re-checks the 24h age server-side, so a client ignoring `Max-Age` gains nothing. Tampered/expired cookies are pinned by negative-path tests. -- **CRUD:** `GET`, `POST`, `PUT`, and `DELETE` under `/admin/api/tokens`. Hash params must be 64-hex; provider scope and status are whitelisted; custom tokens need at least 12 characters. `PUT` patches status and/or expiry - a blank expiry clears it (never expires). Creation, patches, and deletes are serialized through a per-hash `TokenWriter` Durable Object whose own storage is the merge base (KV guarantees neither atomic read-modify-write nor read-your-write, so merging from a KV read let a stale expiry patch resurrect a disabled token); KV is written through for the hot path, only pre-writer hashes bootstrap from a KV read, a deletion tombstone blocks stale echoes, and recreation clears it. Creation checks for an existing hash and returns 409, but KV offers no transaction across that read and write, so concurrent identical creations are not an atomic uniqueness guarantee. -- **UI:** creation returns the plaintext once, base URLs, and an out-of-band row; `PUT` returns a replacement row; `DELETE` returns an empty 200 body. The table localizes expiry and `lastUsed`, marks expired rows, edits expiry in place (click or focus+Enter on the cell, pick a local datetime, saved as UTC ISO when the editor closes with a changed value (per-segment change events must not commit half-edited values); a picker "Today" fill snaps to 23:59 visibly in the field before submit while hand-typed times are untouched; a past value renders as an expired row immediately; the poll pauses while an editor is focused), loads immediately, and refreshes every 120 seconds while visible. Polls and mutations share the persistent `#tokens` sync scope; in-flight rows dim but stay clickable so same-row gestures reach the writer. A different row's mutation can abort the earlier row swap, leaving that cell stale until the next poll. The immediate POST row avoids waiting for KV propagation, which can take 60 seconds or more in other locations. -- **Errors surface:** a body-level `hx-on::response-error` writes failures into a flash div (htmx swaps nothing on non-2xx by default - previously a wrong password or an expired session silently no-opped), and a 401 mid-session bounces back to the login page. - -## 12. Real key handling - -`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GEMINI_API_KEY`, and `ADMIN_SECRET` are Cloudflare secrets. Provider keys are read only after authorization, injected into the outbound provider request, not stored in KV or returned to clients, and omitted by the application's own log statements. Preflight and rejected requests never read them; an authorized cross-origin request does. - -## 13. Storage, bindings & config (`wrangler.toml`) - -| Binding | Kind | Purpose | -|---|---|---| -| `TOKENS` | KV namespace | token store (by `SHA-256`) + `:lu` last-used keys | -| `US_EGRESS` | SQLite Durable Object (`UsEgress`) | US-jurisdiction egress fallback for OpenAI (HTTP + wss) | -| `TOKEN_WRITER` | SQLite Durable Object (`TokenWriter`) | serializes admin token writes (KV has no atomic read-modify-write) | -| `RATE_LIMITER` | Rate Limit | per-token RPM ceiling (100/60s) | -| `LOGIN_LIMITER` | Rate Limit | per-IP `/admin/login` throttle (10/60s, separate ruleset) | - -Plus migrations `v1` (`UsEgress`) and `v2` (`TokenWriter`). Upstreams resolve through `upstreamBase()`: the `*_UPSTREAM` env vars (plain vars, not secrets) default to the real hosts and are overridden only by tests pointing at a mock; `rewriteToUpstream` rewrites just protocol/host/port. - -`[observability] enabled = true` persists `console.*` to Workers Logs. Infrastructure failures log their cause: KV reads, upstream fetches, geo-403 fallback, admin errors, failed logins, and `lastUsed` writes. Auth rejections and fail-open limiter errors stay unlogged to avoid request-driven log volume. - -## 14. Testing (two tiers) - -| Tier | Runner | Scope | -|---|---|---| -| 1 - proxy logic | `@cloudflare/vitest-pool-workers` (workerd) | routing, auth swap, expiry, CORS, rate limit, geo-403 fallback, SSE passthrough, **WS upgrade + subprotocol auth swap** (`test/ws.test.ts`); mocks `fetch`, seeds KV directly | -| 2 - real clients | `unstable_startWorker` + local `node:http` mock | official SDKs, Vercel AI SDK, LangChain, Genkit, LiteLLM, LlamaIndex, instructor, Pydantic AI, raw fetch, and a real `ws` round-trip | - -Each Node compatibility file owns an ephemeral worker (`persist: false`) and mock; Vitest file parallelism remains enabled. The Python runner exercises its four clients serially against one ephemeral worker. Auth slots prove routing, while distinct clients catch base-URL conventions, endpoint defaults, generated headers, transport choices, and stream parsing. Every current compatibility client therefore remains in scope. No automated case hits a live provider. See [`compat-is-the-auth-slot-not-the-sdk.md`](learnings/compat-is-the-auth-slot-not-the-sdk.md). - -## 15. Deployment - -```bash -nub install -nubx wrangler kv namespace create api-proxy-tokens # paste id into wrangler.toml -nubx wrangler secret put OPENAI_API_KEY # + ANTHROPIC / GEMINI / ADMIN_SECRET -nubx wrangler deploy -``` - -See the README's [cost note](../README.md#cost): OpenAI fallbacks and admin token mutations consume Durable Object request and duration allowance as well as the Worker request. - -## 16. Security model - -Invariants are detailed in §5 (auth swap), §6 (token hashing, revoke-safe `lastUsed`), §11 (admin HMAC cookie), and §12 (real-key handling). - -Caveats: - -- KV-backed create, revoke, status, and expiry changes can take 60 seconds or more to appear in another location; rotate the provider credential when a provider-wide cutoff cannot wait for KV propagation. -- Do not host on `*.openai.azure.com` / `*.cognitiveservices.azure.com` (the OpenAI SDK switches to Azure auth on those hostnames). +A shared routing slot does not prove that every client configures its base URL, endpoint, transport, or stream correctly. The policy for adding compatibility cases is in [the compatibility learning](learnings/compat-is-the-auth-slot-not-the-sdk.md). diff --git a/docs/learnings/README.md b/docs/learnings/README.md index 4e1baa0..7889f83 100644 --- a/docs/learnings/README.md +++ b/docs/learnings/README.md @@ -1,17 +1,13 @@ # Learnings -A running log of project-specific knowledge worth not rediscovering. One topic per file, kept short. +Project-specific decisions and evidence that are worth preserving. Mechanics belong in [`../architecture.md`](../architecture.md); these notes explain why the design exists. Keep relevant dates, sample sizes, and known gaps. -Write a file for anything **non-obvious and specific to this project** - a gotcha, constraint, decision, or platform quirk. Correct stale claims in place while preserving dates, sample sizes, and known gaps. +Keep one owner for each fact. Link to it elsewhere instead of copying tables, client lists, or implementation details. -Each file: the problem, what we found, and the decision we keep. Design/mechanics live in [`../architecture.md`](../architecture.md); these files hold only the why. - -- [openai-egress-geo-block.md](openai-egress-geo-block.md) - the historical geo-403 evidence, its missing denominator, and the measured US-jurisdiction fallback -- [provider-routing-by-auth-header.md](provider-routing-by-auth-header.md) - one base URL, no path prefix; route by which auth slot the SDK used -- [proxy-token-security.md](proxy-token-security.md) - auth-slot stripping and hashed proxy-token storage -- [token-expiry-check-at-validate.md](token-expiry-check-at-validate.md) - why expiry is checked at read time, not via KV TTL, and fail-closed on bad input -- [rate-limit-binding-free-and-loose.md](rate-limit-binding-free-and-loose.md) - the Workers Rate Limiting binding is free on the Free plan but a loose, per-location ceiling -- [cors-preflight-and-upload-passthrough.md](cors-preflight-and-upload-passthrough.md) - why the browser preflight is answered before auth, and why the Gemini upload URL is passed through untouched -- [compat-is-the-auth-slot-not-the-sdk.md](compat-is-the-auth-slot-not-the-sdk.md) - why routing is slot-based but every maintained client still needs its own compatibility case -- [websocket-proxy-auth-slots.md](websocket-proxy-auth-slots.md) - WebSocket auth slots, close coordination, and the fetch-with-upgrade choice -- [kv-free-tier-write-quota.md](kv-free-tier-write-quota.md) - 1,000 KV writes/day (account-wide, 100x scarcer than reads); why `lastUsed` stamps at most once per day +- [openai-egress-geo-block.md](openai-egress-geo-block.md) - evidence behind the US-jurisdiction fallback +- [token-expiry-check-at-validate.md](token-expiry-check-at-validate.md) - why expiry is validated instead of delegated to KV TTL +- [rate-limit-binding-free-and-loose.md](rate-limit-binding-free-and-loose.md) - why the limit is treated as loose abuse control +- [cors-preflight-and-upload-passthrough.md](cors-preflight-and-upload-passthrough.md) - why preflight bypasses auth and Gemini upload URLs pass through +- [compat-is-the-auth-slot-not-the-sdk.md](compat-is-the-auth-slot-not-the-sdk.md) - why distinct clients keep distinct compatibility cases +- [websocket-proxy-auth-slots.md](websocket-proxy-auth-slots.md) - why WebSockets need extra credential handling and a manual bridge +- [kv-free-tier-write-quota.md](kv-free-tier-write-quota.md) - why `lastUsed` is a coarse, throttled stamp diff --git a/docs/learnings/compat-is-the-auth-slot-not-the-sdk.md b/docs/learnings/compat-is-the-auth-slot-not-the-sdk.md index 0ac38ef..bb1c1c9 100644 --- a/docs/learnings/compat-is-the-auth-slot-not-the-sdk.md +++ b/docs/learnings/compat-is-the-auth-slot-not-the-sdk.md @@ -1,41 +1,19 @@ -# Compatibility is routing plus client behavior +# Compatibility includes client behavior ## Problem -Many clients share the same wire-level authentication, but that does not make their integrations interchangeable. A proxy can route a correct header and still break a client through base-URL joining, a default endpoint, generated headers, transport selection, or streaming behavior. +Several clients use the same wire-level credential slot, but still differ in base-URL joining, default endpoints, generated headers, transport, and streaming. -## What we found +## Decision -Routing has a small invariant: the auth slot and one path check select the provider, while the remaining path, query, body, and response stream pass through. +Give each maintained library one end-to-end case in one language. Add a case when another library has distinct configuration or transport behavior, and remove one only when that client is no longer supported or its package is replaced. Do not duplicate every language binding of the same SDK family. -| Route | Routing signal | -|---|---| -| OpenAI | `Authorization: Bearer` | -| Anthropic | `x-api-key` | -| Gemini native | `x-goog-api-key` or `?key=` | -| Gemini OpenAI-compatible | `Authorization: Bearer` plus `/v1beta/openai/` | +A client outside the suite may be described as compatible by routing construction when it supports a base-URL override and uses a proven credential slot. It is not tested compatible until its real configuration runs through the harness. -That invariant proves a new client needs no new proxy branch. It does **not** prove the client is configured correctly. The maintained compatibility cases exercise: +## Known caveats -- official OpenAI, Anthropic, and Google GenAI SDKs; -- Vercel AI SDK and LangChain adapters for all three providers; -- Genkit's Google adapter; -- LiteLLM, LlamaIndex, instructor, and Pydantic AI; -- raw HTTP and a real WebSocket round trip. +- Anthropic `authToken` mode sends Bearer and routes to OpenAI here; use its API-key mode. +- Legacy `google-generativeai` defaults to gRPC; use `transport="rest"` for this HTTP proxy. +- OpenAI-style clients may choose different default endpoints and usually expect `/v1` in the base URL. The official Anthropic SDK appends `/v1/messages` itself. -Together they verify the clients' actual base-URL options, endpoint defaults, implicit headers, request/response formats, and streaming parsers. They also expose conflicts such as a wrapper changing auth mode or a transport bypassing HTTP. - -## The decision we keep - -Keep every current compatibility client. Each distinct library gets one end-to-end case in one language, both as regression coverage and executable setup documentation. Sharing an auth slot is not a reason to delete its case. Repeating every language binding of the same SDK family usually is. - -Add a case when support is claimed for another library with distinct configuration or transport behavior. Remove one only when that client is no longer supported or its package is replaced, not merely because another test reaches the same route. - -Clients outside the suite can be described as **compatible by routing construction**, not tested compatible, when they expose a base-URL override and use a proven slot. This includes other language bindings and OpenAI-compatible end-user applications. - -## Caveats - -- Anthropic `authToken` mode sends Bearer and therefore routes to OpenAI here; use API-key (`x-api-key`) mode. -- Legacy `google-generativeai` for Python defaults to gRPC; use `transport="rest"` so it traverses this HTTP proxy. -- OpenAI clients may default to `/v1/responses` instead of `/v1/chat/completions`. Both route by Bearer, but the separate client tests still catch endpoint expectations. -- Base-URL conventions differ: OpenAI-style clients generally include `/v1`; the official Anthropic SDK appends `/v1/messages` itself. +Current cases and their setup are the files in `test/sdk-compat/`, which stays more accurate than a copied client list. diff --git a/docs/learnings/cors-preflight-and-upload-passthrough.md b/docs/learnings/cors-preflight-and-upload-passthrough.md index fca5b68..76a9524 100644 --- a/docs/learnings/cors-preflight-and-upload-passthrough.md +++ b/docs/learnings/cors-preflight-and-upload-passthrough.md @@ -2,14 +2,11 @@ ## Problem -Browser callers broke two ways: every cross-origin SDK call died before reaching the proxy, and Gemini file uploads would hit the Worker's 100 MB body cap. Both fixes are about what the proxy must *not* do. Full CORS behavior: architecture §8. +Browser preflight does not carry the credential headers used by the actual request. Gemini uploads also return a continuation URL for a body that may exceed the Worker's limit. -## What we found +## Decision -- A preflight omits credential headers but keeps the request URL, including Gemini's `?key=`. Auth-first would reject header-auth clients and waste work for query-auth, so every `OPTIONS` request is short-circuited. -- Gemini's upload-start call returns an **absolute, self-authenticating** `x-goog-upload-url`. Rewriting it to keep the proxy in the loop would cap uploads at 100 MB, for a leg that needs no key anyway (flow diagram: architecture §8). +- Answer `OPTIONS` with 204 before token validation. The later request still runs normal authorization and credential replacement. +- Return Gemini's absolute, self-authenticating `x-goog-upload-url` unchanged and expose the related response headers. The client then uploads directly to Google. -## The decision we keep - -- Answer `OPTIONS` with `204` before token work. The later authenticated cross-origin request does carry the real key from the Worker to the provider. CORS changes browser-visible response headers, not the outbound auth swap. -- Never rewrite the upload URL. The proxy exposes the `x-goog-upload-*` response headers so the browser can continue directly with Google. +Keeping the second upload leg outside the proxy avoids rejecting preflight and avoids routing large, already-authorized upload bodies through the Worker. diff --git a/docs/learnings/kv-free-tier-write-quota.md b/docs/learnings/kv-free-tier-write-quota.md index 3233f3e..679df75 100644 --- a/docs/learnings/kv-free-tier-write-quota.md +++ b/docs/learnings/kv-free-tier-write-quota.md @@ -1,25 +1,19 @@ -# Free-tier KV: writes are the budget, and the quota is account-wide +# Free-tier KV writes are the budget ## Problem -Every proxied request and WebSocket upgrade stamped `lastUsed` with one KV write. One day (~500 requests) triggered Cloudflare's "50% of your daily Workers KV limit" warning email, spending half the write quota on dashboard recency. +Writing `lastUsed` on every authorized request spent half the daily KV write allowance after roughly 500 requests. -## What we found +## Evidence -- Free-tier KV allows **1,000 writes/day** but **100,000 reads/day** (also 1k deletes, 1k lists, 1 GB; reset 00:00 UTC). Writes are the scarce resource, 100x scarcer than reads. -- **Daily quotas are per account, not per namespace.** Every worker and namespace on the account draws from one pool, and dashboard/wrangler KV operations count against it too. A dedicated namespace isolates data, not quota. -- **Exceeding a limit fails only that operation type.** Exhausted writes leave reads (token auth) working, and since the stamp runs in `ctx.waitUntil` after the response has streamed back, write exhaustion is invisible to clients - a stale column plus log noise, not an outage. The "429" in Cloudflare's warning email refers to the rejected `put()` calls themselves. -- `cacheTtl` on `get()` is a latency optimization only; cache-served reads still count as billed reads. To cut counted reads you must not call KV at all. -- The 50%/90% warning emails are real but **undocumented** (no threshold or schedule anywhere in the notifications catalog) - don't build on them. +The Free tier allows 1,000 writes but 100,000 reads per day. These quotas are account-wide, not isolated by namespace. Exhausting writes does not stop reads, so token authorization can continue while usage stamps fail. -## The decision we keep +`lastUsed` writes are scheduled with `ctx.waitUntil`; a failed stamp cannot change the response already chosen for the client. It only leaves stale dashboard data and a log entry. -`touchLastUsed` stamps **at most once per UTC day per token per isolate**. The first qualifying use observed by that isolate wins: an authorized HTTP request that receives any upstream response, or a successful WebSocket upgrade. The UI localizes the stored ISO timestamp, but it is a coarse first-observed marker rather than the literal latest use. +## Decision -A module-scope map claims the day before the first `await`, so concurrent requests in one isolate deduplicate. The map is never pruned and can grow by one entry per used token for that isolate's lifetime. Isolate churn can produce multiple writes per token/day; no duplication factor was measured. +Stamp at most once per UTC day, per token, per isolate. The value is a coarse first-observed marker, not an exact latest-use timestamp. Keep it in a separate `:lu` key so an activity write cannot overwrite token status or expiry. -A failed put releases the claim so a later request retries inside `waitUntil`; reads stay unmemoized so revocation is not delayed further. - -Related: [proxy-token-security.md](proxy-token-security.md) (why `lastUsed` lives in its own `:lu` side key), [rate-limit-binding-free-and-loose.md](rate-limit-binding-free-and-loose.md). +Isolate churn can still produce more than one write per token per day. A failed write releases the in-memory claim so a later request can retry. Sources: [KV pricing](https://developers.cloudflare.com/kv/platform/pricing/), [KV limits](https://developers.cloudflare.com/kv/platform/limits/), [Workers limits](https://developers.cloudflare.com/workers/platform/limits/). diff --git a/docs/learnings/openai-egress-geo-block.md b/docs/learnings/openai-egress-geo-block.md index dacc738..a995dde 100644 --- a/docs/learnings/openai-egress-geo-block.md +++ b/docs/learnings/openai-egress-geo-block.md @@ -2,38 +2,24 @@ ## Problem -Historical probes through the Worker saw OpenAI return `unsupported_country_region_territory` on roughly 40% of requests while Anthropic succeeded. The original run did not record its total request count, timing, or latency distribution, so 40% is a directional observation, not a reproducible rate. +Historical probes sometimes received OpenAI's `unsupported_country_region_territory` response through the Worker while Anthropic succeeded. The original notes estimated a 40% failure rate but did not retain the sample count, timing, or latency, so that number is directional only. -## What we found +## Evidence -Observed HKG egresses returned the geo-403 and observed SIN egresses returned 200. The notes did not retain per-colo sample counts, so they establish the failure mode but not its prevalence. A separate probe sent **6 sequential subrequests in one Worker invocation**; all six used the same egress colo. Retrying inside that invocation therefore did not escape the affected colo. +Observed HKG egress returned the geo-403 and observed SIN egress returned 200. Six sequential subrequests in one Worker invocation used the same egress location, so retrying inside that invocation did not escape the block. -Rejected alternatives: +A post-fix run returned 25/25 HTTP 200 responses through US-jurisdiction Durable Objects across observed DFW, LAX, DEN, SJC, and SEA egress. This verifies that run, not a general availability or latency guarantee. -- [Smart Placement](https://developers.cloudflare.com/workers/configuration/placement/) changes execution placement, not a guaranteed egress jurisdiction. -- A best-effort Durable Object `locationHint` is weaker than a jurisdiction constraint. -- [Dedicated CDN egress IPs](https://developers.cloudflare.com/smart-shield/configuration/dedicated-egress-ips/) and [Regional Services](https://developers.cloudflare.com/data-localization/regional-services/) are Enterprise products, outside this Free deployment. -- A third-party relay adds another operator that receives the provider credential. +## Rejected alternatives -## The decision we keep +- Smart Placement changes execution placement but does not guarantee egress jurisdiction. +- A Durable Object location hint is weaker than a jurisdiction constraint. +- Dedicated egress IPs and Regional Services are outside this Free deployment. +- A third-party relay would receive the provider credential. +- Routing every request through a Durable Object adds a hop and a Durable Object request even when direct egress works. -Try the direct edge request first. Only an OpenAI geo-403 is replayed through one of eight Durable Objects selected from `env.US_EGRESS.jurisdiction("us")`. The jurisdiction restricts the object to the US; the provider key stays out of clients, KV, and third-party relays, application log statements do not include it, and the Worker/DO necessarily sends it to OpenAI. +## Decision -The post-fix stress run produced **25/25 HTTP 200 responses** across observed DO egress colos DFW, LAX, DEN, SJC, and SEA. Streaming also completed, but its probe count was not recorded. This verifies that run, not a latency or availability guarantee. +Try direct edge egress first. Retry only OpenAI's geo-specific 403 through `env.US_EGRESS.jurisdiction("us")`. This keeps provider credentials inside Cloudflare while limiting fallback cost to affected requests. -## Quantified tradeoff - -For a comparison at exactly **1,000 requests** and an assumed **40%** geo-block rate: - -| Design | OpenAI attempts | DO requests | DO/upstream legs | -|---|---:|---:|---:| -| Current edge-first fallback | 1,400 (1,000 initial + 400 replay) | 400 | 1,800 | -| Always route through DO | 1,000 | 1,000 | 2,000 | - -Both designs also receive the same 1,000 incoming Worker requests, omitted from the table. Always-DO would issue **150% more DO requests** (`400 -> 1,000`) and **11.1% more counted DO/upstream legs** (`1,800 -> 2,000`), while eliminating 400 failed OpenAI attempts. Against Cloudflare's current Free allowance of **100,000 DO requests/day**, those scenario DO counts are **0.4%** and **1.0%**, respectively. These are scenario arithmetic, not production measurements. - -No latency samples were retained, so neither the extra delay on a fallback nor the saved delay on direct successes has an honest numeric estimate. OpenAI states that unsuccessful requests can count toward per-minute limits, but its guidance does not establish whether this pre-service geo-403 consumes RPM; that remains unmeasured. Durable Object active-duration consumption is also unmeasured. - -Cloudflare also lists **13,000 GB-s/day** of Free DO duration (pricing page updated 2026-06-19), but no duration samples were retained, so the scenario's share cannot be computed. - -Sources: [Cloudflare Durable Object data location](https://developers.cloudflare.com/durable-objects/reference/data-location/), [Cloudflare Durable Objects pricing](https://developers.cloudflare.com/durable-objects/platform/pricing/), [OpenAI rate-limit guidance](https://help.openai.com/en/articles/5955604-how-can-i-solv). +Sources: [Cloudflare Durable Object data location](https://developers.cloudflare.com/durable-objects/reference/data-location/), [Smart Placement](https://developers.cloudflare.com/workers/configuration/placement/), [Durable Objects pricing](https://developers.cloudflare.com/durable-objects/platform/pricing/). diff --git a/docs/learnings/provider-routing-by-auth-header.md b/docs/learnings/provider-routing-by-auth-header.md deleted file mode 100644 index 09fa05d..0000000 --- a/docs/learnings/provider-routing-by-auth-header.md +++ /dev/null @@ -1,30 +0,0 @@ -# Provider routing by auth slot - -## Problem - -One consolidated base URL has to transparently serve OpenAI, Anthropic, and Gemini. The goal: a client changes only its base URL and API key, nothing else. So the proxy must decide which upstream a request is for without the client adding a path prefix or custom header. - -## What we found - -Each SDK already announces its provider by *which auth slot it populates* - no path prefix or custom header needed. The slot-to-provider mapping lives in architecture §4; the check order matters and is (`src/auth.ts` `identify`): - -```mermaid -flowchart TD - R[inbound request] --> A{"x-api-key?"} - A -- yes --> ANT[Anthropic] - A -- no --> B{"x-goog-api-key?"} - B -- yes --> GEM[Gemini] - B -- no --> C{"Authorization: Bearer?"} - C -- no --> D{"?key= query param?"} - D -- yes --> GEM - D -- no --> E[401] - C -- yes --> P{"path starts /v1beta/openai/?"} - P -- yes --> GO["Gemini (OpenAI-compat)"] - P -- no --> OAI[OpenAI] -``` - -**Why not a path prefix:** the auth slot already identifies the provider. A prefix would add provider-specific stripping branches and alter the native paths clients expect without adding routing information. - -## The decision we keep - -Route by auth slot, keeping each SDK's native path intact - a true drop-in. The token is extracted from the same slot; the swap is [proxy-token-security.md](proxy-token-security.md)'s territory. diff --git a/docs/learnings/proxy-token-security.md b/docs/learnings/proxy-token-security.md deleted file mode 100644 index 29e3826..0000000 --- a/docs/learnings/proxy-token-security.md +++ /dev/null @@ -1,20 +0,0 @@ -# Proxy token security - -## Problem - -Share provider access with unmodified SDKs without disclosing the provider key to clients, KV, application logs, or another relay. - -## What we found - -- **Clients put credentials in unexpected slots** (e.g. `Authorization` *and* `?key=`). Forwarding headers as-received leaks the token upstream in the un-routed slot; deleting only the matched slot is not enough. -- **Plaintext in KV is an exfiltration surface** - the dashboard, `wrangler kv`, or a rendering bug could expose live credentials. -- **Stamping usage into the token record races revocation** - a hot-path `put` of the record can resurrect a token the admin just revoked. - -## The decision we keep - -- **The token rides the SDK's own auth slot** - the client swaps only base URL and key ([provider-routing-by-auth-header.md](provider-routing-by-auth-header.md)). -- **Strip-all-then-set-one:** `stripAuthSlots` owns the HTTP header/query list and is shared by HTTP and WebSocket paths; `ws.ts` separately removes OpenAI's key-bearing subprotocol entry. Then the proxy sets one provider credential. -- **Hashed at rest:** plaintext is shown once. KV holds the hash and metadata, plus a separate `:lu` timestamp key, never the usable proxy token. -- **`lastUsed` in a side key** (`:lu`), never the record - the hot path physically cannot re-enable a revoked token. - -Related: [websocket-proxy-auth-slots.md](websocket-proxy-auth-slots.md) (wider wss slot set), [kv-free-tier-write-quota.md](kv-free-tier-write-quota.md) (why the stamp is throttled). diff --git a/docs/learnings/rate-limit-binding-free-and-loose.md b/docs/learnings/rate-limit-binding-free-and-loose.md index 1959edc..d627814 100644 --- a/docs/learnings/rate-limit-binding-free-and-loose.md +++ b/docs/learnings/rate-limit-binding-free-and-loose.md @@ -1,17 +1,17 @@ -# Rate Limiting binding: free on Workers Free, but a loose per-location ceiling +# Rate limiting is loose abuse control ## Problem -A per-token request-rate cap with no new storage that never uses plaintext tokens as limiter keys. +Per-token throttling should not require another storage system or use plaintext tokens as keys. -## What we found +## Evidence -- **Free-plan eligibility is undocumented** (a research pass even fabricated a "no additional charge" quote). Verified empirically: `wrangler deploy` on the Free account accepts the binding (the summary lists `env.RATE_LIMITER (N requests/60s) - Rate Limit`) and `limit()` enforces - treat undocumented platform claims as "verify by deploying," not fact. -- **It is per-location and eventually consistent.** With `limit = 2 / 60s`, ~13 rapid requests slipped through before denials began in the local test. Because Cloudflare documents independent counters by location, roughly 2x across two locations is an inference, not a measurement from that run. -- The limit is **fixed per namespace at deploy time** - no per-token-variable limit without tiered namespaces or a Durable Object counter. +Cloudflare does not document Free-plan eligibility for this binding, but deployment on this Free account succeeds and the binding enforces locally. Counters are per location and eventually consistent: with a configured 2 requests per 60 seconds, a local burst allowed roughly 13 requests before denials began. That measurement shows the threshold is not a strict quota. -## The decision we keep +## Decision -Key on the hash, never the plaintext. Fail-open, because the real abuse defense is revoke + scope, not this loose ceiling. `Retry-After` is a static 60 because the binding returns no reset time. Config and semantics: architecture §7. +Key the binding on the token hash and fail open if it errors. Revocation and provider scope remain the real access controls. `Retry-After` is a static 60 seconds because the binding supplies no reset time. -Related: [proxy-token-security.md](proxy-token-security.md). Primary source: [Workers Rate Limiting binding](https://developers.cloudflare.com/workers/runtime-apis/bindings/rate-limit/). +The threshold is fixed per binding at deployment. Different per-token tiers would need separate bindings or a different counter design. + +Source: [Workers Rate Limiting binding](https://developers.cloudflare.com/workers/runtime-apis/bindings/rate-limit/). diff --git a/docs/learnings/token-expiry-check-at-validate.md b/docs/learnings/token-expiry-check-at-validate.md index 63d0da0..8e474c3 100644 --- a/docs/learnings/token-expiry-check-at-validate.md +++ b/docs/learnings/token-expiry-check-at-validate.md @@ -1,26 +1,15 @@ -# Token expiry: check-at-validate, not KV TTL +# Check token expiry during validation ## Problem -Optional per-token expiry, enforced cheaply, without a second storage backend. +Expired tokens should stop working while remaining visible in the admin dashboard. -## What we found +## Evidence -- **KV `expirationTtl` is the wrong tool:** 60s floor, it *deletes* the record on expiry (so the dashboard can't show an "expired" row), and it orphans the separate `:lu` last-used key. -- A check at read time is exact at the moment of validation and adds zero extra reads (the field rides in the JSON already fetched to validate). Admin edits to `expiresAt` simply change the compared value, subject to normal KV propagation like every other metadata change. +KV expiry has a 60-second floor, deletes the record, and would leave the separate `:lu` key behind. Checking the existing metadata adds no storage read and uses the current edited value. -## The decision we keep +## Decision -Store optional `expiresAt` (UTC ISO); enforce in `getValidatedByHash`: +Store `expiresAt` as an optional UTC ISO string and check it whenever the token is validated. Reject malformed values as well as past timestamps; otherwise an invalid date could fail open. Return a distinct `token expired` response so a correctly configured client can diagnose the expected failure. -```ts -if (meta.expiresAt) { - const t = Date.parse(meta.expiresAt); - if (Number.isNaN(t)) return null; // fail-closed on malformed - if (t <= Date.now()) return "expired"; // sentinel -> callers answer 401 "token expired" -} -``` - -**Fail-closed on malformed input:** `NaN <= Date.now()` is `false`, which fails *open* (a garbage `expiresAt` stays valid) - so `Number.isNaN(t)` is checked explicitly. The past-expiry case returns a distinct sentinel so the proxy can answer `401 token expired` instead of the generic invalid-token message: expiry is the one failure a correctly-configured client will eventually hit, so it should self-diagnose. The admin form converts its local `datetime-local` value to UTC ISO in the browser; the route rejects unparseable or offset-less input at creation (an offset-less string would be read in the runtime's timezone, not the admin's). The dashboard localizes timestamps back for display, so the value reads back as typed. - -Related: [proxy-token-security.md](proxy-token-security.md). +The admin converts local input to an offset-bearing UTC value before storage and localizes it for display. KV propagation remains the only delay after an edit. diff --git a/docs/learnings/websocket-proxy-auth-slots.md b/docs/learnings/websocket-proxy-auth-slots.md index 60cb878..f219412 100644 --- a/docs/learnings/websocket-proxy-auth-slots.md +++ b/docs/learnings/websocket-proxy-auth-slots.md @@ -1,23 +1,19 @@ -# WebSocket proxying, and the wider auth-slot set +# WebSocket proxying needs extra credential handling ## Problem -The proxy only forwarded HTTP. A realtime client hit `wss://api.openai.com/v1/responses` directly with a raw key (a dead one → `invalid_api_key`), bypassing the proxy entirely. We wanted the same token-swap for wss, for any provider with a wss API. +Realtime clients could bypass the proxy or send a proxy token upstream because browser WebSockets cannot set arbitrary authorization headers. -## What we found +## Evidence -- **The endpoint in the bug is real.** `wss://api.openai.com/v1/responses` is OpenAI's *Responses API WebSocket Mode* - distinct from Realtime (`/v1/realtime`), Bearer-header-only. A proxy handling only the Realtime subprotocol would pass the token straight through on `/v1/responses`. -- **A plain Worker is enough.** Workers now support outbound `new WebSocket()`, but constructor-created sockets cannot opt into half-open behavior. This proxy retains `fetch(httpUrl, { headers: { Upgrade: "websocket" } })` so the returned socket can use `accept({ allowHalfOpen: true })` and coordinate closes with the `WebSocketPair` endpoint. -- **Manual pipe over transparent pass-through.** Whether CF echoes the negotiated `Sec-WebSocket-Protocol` on a passed-through 101 is undocumented, and a browser handshake fails if the server picks none of the offered subprotocols - so we accept both ends and echo it explicitly. wrangler 4.x is past the old dev-WS echo bugs (workers-sdk #1767, fixed by PR #1930). -- **The WS auth-slot set is wider than HTTP.** OpenAI browser clients place the key in an `openai-insecure-api-key.` subprotocol entry because browser WebSockets cannot set arbitrary headers. Server OpenAI clients use Bearer, Gemini Live uses `?key=`, and an `x-api-key` upgrade routes to Anthropic. Slot mapping: architecture §10. +OpenAI server clients use Bearer, browser clients place the key in an `openai-insecure-api-key.` subprotocol entry, Gemini Live uses `?key=`, and Anthropic-style upgrades use `x-api-key`. -## The decision we keep +Constructor-created Worker sockets cannot opt into the half-open behavior used to coordinate close frames. A fetched upgrade can, and a manual bridge can echo the negotiated subprotocol explicitly. -Extend strip-all-then-set-one to the query and subprotocol slots too, and reuse the geo-403 DO fallback unchanged. Mechanics and the slot table: architecture §10. +## Decision -## Caveats +Use `fetch()` with an upgrade request, bridge the two sockets, and extend strip-all-then-set-one to query and subprotocol credentials. Reuse the OpenAI geo-403 fallback for upgrades. -- **The geo-blocked WS-over-DO hop is unproven live** - the trigger is unit-tested with a faked DO, and a real geo-403 can't be forced from here. -- **Live-verified against OpenAI (2026-07-05), not Gemini.** Realtime `session.created` via both the Bearer and subprotocol slots, and a `/v1/responses` WS-mode 101, on the deployed worker. Gemini Live remains mock-only (no key). Automated tests use a mock `ws` upstream by design. +The geo-blocked Durable Object upgrade is covered with a fake object but has not been forced live. On 2026-07-05, OpenAI Realtime and Responses upgrades were verified against the deployed Worker; Gemini Live remains mock-only. -Sources: [CF Workers WebSockets](https://developers.cloudflare.com/workers/runtime-apis/websockets/), [Workers compatibility flags](https://developers.cloudflare.com/workers/configuration/compatibility-flags/), [OpenAI Realtime (WebSocket)](https://developers.openai.com/api/docs/guides/realtime-websocket), [OpenAI Responses WebSocket Mode](https://developers.openai.com/api/docs/guides/websocket-mode), [Gemini Live API](https://ai.google.dev/gemini-api/docs/live-api/get-started-websocket). +Sources: [CF Workers WebSockets](https://developers.cloudflare.com/workers/runtime-apis/websockets/), [OpenAI Realtime](https://developers.openai.com/api/docs/guides/realtime-websocket), [OpenAI Responses WebSocket Mode](https://developers.openai.com/api/docs/guides/websocket-mode), [Gemini Live API](https://ai.google.dev/gemini-api/docs/live-api/get-started-websocket). diff --git a/lefthook.yml b/lefthook.yml index 8613bfc..97944c5 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -3,5 +3,5 @@ pre-commit: commands: check: glob: "*.{js,ts,cjs,mjs,mts,d.cts,d.mts,jsx,tsx,json,jsonc,css}" - run: nubx biome check --write --no-errors-on-unmatched --files-ignore-unknown=true {staged_files} + run: nub exec biome check --write --no-errors-on-unmatched --files-ignore-unknown=true {staged_files} stage_fixed: true diff --git a/nub.lock b/nub.lock index cd7019b..c9a5a6c 100644 --- a/nub.lock +++ b/nub.lock @@ -9,126 +9,117 @@ importers: .: dependencies: hono: - specifier: ^4.12.28 - version: 4.12.28 + specifier: ^4.12.32 + version: 4.12.32 devDependencies: '@ai-sdk/anthropic': - specifier: ^4.0.9 - version: 4.0.9(zod@4.4.3) + specifier: ^4.0.20 + version: 4.0.20(zod@4.4.3) '@ai-sdk/google': - specifier: ^4.0.9 - version: 4.0.9(zod@4.4.3) + specifier: ^4.0.24 + version: 4.0.24(zod@4.4.3) '@ai-sdk/openai': - specifier: ^4.0.8 - version: 4.0.8(zod@4.4.3) + specifier: ^4.0.20 + version: 4.0.20(zod@4.4.3) '@anthropic-ai/sdk': - specifier: ^0.110.0 - version: 0.110.0(zod@4.4.3) + specifier: ^0.115.0 + version: 0.115.0(zod@4.4.3) '@biomejs/biome': - specifier: ^2.5.3 - version: 2.5.3 + specifier: ^2.5.5 + version: 2.5.5 '@cloudflare/vitest-pool-workers': - specifier: ^0.18.2 - version: 0.18.2(@cloudflare/workers-types@5.20260708.1)(@vitest/runner@4.1.9)(@vitest/snapshot@4.1.9)(vitest@4.1.10(@opentelemetry/api@1.9.1)(@types/node@25.9.3)(vite@8.0.16(@types/node@25.9.3))) + specifier: ^0.18.8 + version: 0.18.8(@cloudflare/workers-types@5.20260724.1)(@vitest/runner@4.1.10)(@vitest/snapshot@4.1.10)(vitest@4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(vite@8.1.5(@types/node@26.1.1))) '@cloudflare/workers-types': - specifier: ^5.20260708.1 - version: 5.20260708.1 + specifier: ^5.20260724.1 + version: 5.20260724.1 '@genkit-ai/google-genai': - specifier: ^1.39.0 - version: 1.39.0(genkit@1.39.0) + specifier: ^1.40.1 + version: 1.40.1(genkit@1.40.1) '@google/genai': - specifier: ^2.10.0 - version: 2.10.0 + specifier: ^2.13.0 + version: 2.13.0 '@langchain/anthropic': - specifier: ^1.5.1 - version: 1.5.1(@langchain/core@1.2.1)(@opentelemetry/api@1.9.1)(openai@6.45.0(ws@8.21.0)(zod@4.4.3))(ws@8.21.0) + specifier: ^1.5.2 + version: 1.5.2(@langchain/core@1.2.3)(@opentelemetry/api@1.9.1)(openai@6.49.0(ws@8.21.1)(zod@4.4.3))(ws@8.21.1) '@langchain/core': - specifier: ^1.2.1 - version: 1.2.1(@opentelemetry/api@1.9.1)(openai@6.45.0(ws@8.21.0)(zod@4.4.3))(ws@8.21.0) + specifier: ^1.2.3 + version: 1.2.3(@opentelemetry/api@1.9.1)(openai@6.49.0(ws@8.21.1)(zod@4.4.3))(ws@8.21.1) '@langchain/google-genai': specifier: ^2.2.0 - version: 2.2.0(@langchain/core@1.2.1)(@opentelemetry/api@1.9.1)(openai@6.45.0(ws@8.21.0)(zod@4.4.3))(ws@8.21.0) + version: 2.2.0(@langchain/core@1.2.3)(@opentelemetry/api@1.9.1)(openai@6.49.0(ws@8.21.1)(zod@4.4.3))(ws@8.21.1) '@langchain/openai': - specifier: ^1.5.3 - version: 1.5.3(@langchain/core@1.2.1)(@opentelemetry/api@1.9.1)(ws@8.21.0) + specifier: ^1.5.5 + version: 1.5.5(@langchain/core@1.2.3)(@opentelemetry/api@1.9.1)(ws@8.21.1) '@types/ws': specifier: ^8.18.1 version: 8.18.1 ai: - specifier: ^7.0.17 - version: 7.0.17(zod@4.4.3) + specifier: ^7.0.37 + version: 7.0.37(zod@4.4.3) genkit: - specifier: ^1.39.0 - version: 1.39.0 + specifier: ^1.40.1 + version: 1.40.1 lefthook: - specifier: ^2.1.9 - version: 2.1.9 + specifier: ^2.1.10 + version: 2.1.10 openai: - specifier: ^6.45.0 - version: 6.45.0(ws@8.21.0)(zod@4.4.3) + specifier: ^6.49.0 + version: 6.49.0(ws@8.21.1)(zod@4.4.3) typescript: - specifier: ^6.0.3 - version: 6.0.3 + specifier: ^7.0.2 + version: 7.0.2 vitest: specifier: ^4.1.10 - version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@25.9.3)(esbuild@0.28.1)(vite@8.0.16(@types/node@25.9.3)) + version: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(esbuild@0.28.1)(vite@8.1.5(@types/node@26.1.1)) wrangler: - specifier: ^4.108.0 - version: 4.108.0(@cloudflare/workers-types@5.20260708.1) + specifier: ^4.114.0 + version: 4.114.0(@cloudflare/workers-types@5.20260724.1) ws: - specifier: ^8.21.0 - version: 8.21.0 + specifier: ^8.21.1 + version: 8.21.1 zod: specifier: ^4.4.3 version: 4.4.3 packages: - '@ai-sdk/anthropic@4.0.9': - resolution: {integrity: sha512-b20DXotqNObzrQ1EplKONwBwk8G6ECQQlYCPzJ8Gkdu1OIPe/GPEXFmuvfFIM1/ZTvrbAFRyM1ikFUk+xo8cEw==} + '@ai-sdk/anthropic@4.0.20': + resolution: {integrity: sha512-5QdZt6AkWIKIKuwRSjAQIBhN0JSSvthaIcAJKTHP7HPCvWMcNJFF6rz0uKfUlpI3h7nVbY+1Cy5dNl5zjzJ6qA==} engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/gateway@4.0.13': - resolution: {integrity: sha512-EIiMZZMEAc3yZ3nywrJfKigrkaNwqrQgGsj0QbQ6x3Y73MlQe68EElR2cm/8I5dvBci3PFyahMRe3NwR8OOb9A==} + '@ai-sdk/gateway@4.0.28': + resolution: {integrity: sha512-ee9TsNO3mkgHDWmTmJ8Fvltr6PFh52zhrV2+FaKJY3F3iu7kWZi5tCRJCR1HVhhlpj6lHniUb28nLQdPHkA/1Q==} engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/google@4.0.9': - resolution: {integrity: sha512-6tENh73rPEWeTeKByGh9kOCvFzFatHc4u37F0dLgYXPZiNrOMXsBXhp9zTiC5EZb0NNjS8t6lole5pnvsHJbDA==} + '@ai-sdk/google@4.0.24': + resolution: {integrity: sha512-W+kTGb/RRe2SEYwbKcKYM3N2EQryS2Iqjgou6wPsyP/2BwBU7Q23CF6/YWE8k7xtseDLcSY59jsR2MDpY4azRg==} engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/openai@4.0.8': - resolution: {integrity: sha512-yW2UuS6jlu2LRYCd+cSpVdu/umf+QjypihYAiGvKk5HnpqQf21ffNjFbke9xo9jhT+TBt2YR30Fs5Sy0md/dfA==} + '@ai-sdk/openai@4.0.20': + resolution: {integrity: sha512-/Hu+btLIO2zuYqCp//vBBAGdM/BeN4gds+NWrlv7Y9WrcTXwnEEwh6P3QZIWh2Tt1I1lswuDIpAJ4t/c/rws3Q==} engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/provider-utils@5.0.5': - resolution: {integrity: sha512-oI0t3dvCoqWNV1I8o1Rybi2DXDvHES5r/TrwtJW90tuFLVepgJlftPxrcjh8vaSvjqC2diTuA2vXyjKAyHJm4A==} + '@ai-sdk/provider-utils@5.0.12': + resolution: {integrity: sha512-bbhlOgHeYwrIGheLkM6fhS8hVger8uFPmcOLg+kxc9EFh7y30XYorWhthlYAgpadO3SJhFZrIcEknN7qEqEVvA==} engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/provider@4.0.2': - resolution: {integrity: sha512-pfPoy9J1B1xV7cqJ8MYHOsDYrMv5tR3+EMNfI249OhkD2uRakvav3Fo7XpD2luuN/YNCBY7KfEQc7vEV7KEtyw==} + '@ai-sdk/provider@4.0.3': + resolution: {integrity: sha512-e0CpNWJUY7OxAFAnCZkw+ri9QOHWwTs1tXP42782KFGCU07qt8NiXCrCVowyCB5dP2r5/Uls+g2oPd8kOJn9dw==} engines: {node: '>=22'} - '@anthropic-ai/sdk@0.103.0': - resolution: {integrity: sha512-1uG7RNgoHTUxzOXqSCODKt0UTVlxWiHk/2Tt2/uQJiPW7XzBeKVuJyd3Aw6T3LPyvZV/jDTnPLX7SaM70WLLjA==} - hasBin: true - peerDependencies: - zod: ^3.25.0 || ^4.0.0 - peerDependenciesMeta: - zod: - optional: true - - '@anthropic-ai/sdk@0.110.0': - resolution: {integrity: sha512-hOP4bNYXDFHDxxiEgzlILXrxZIYCDnhe8sry0RDRKD/QnsEpvZcQpablCdm9X/WuD/YgOiSIkkqsL1mLLlTqJw==} + '@anthropic-ai/sdk@0.115.0': + resolution: {integrity: sha512-BJrFIVyjNuU8lfDyIJTvlRYzgQg+zEl78BxE7fq8esULsGz9IRQvGtW5spq3tydmtjQb/GFdooKGdGsetpx+lQ==} hasBin: true peerDependencies: zod: ^3.25.0 || ^4.0.0 @@ -140,55 +131,55 @@ packages: resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} engines: {node: '>=6.9.0'} - '@biomejs/biome@2.5.3': - resolution: {integrity: sha512-MrJswFdei9EfDwwUy2tQrPDpK0AO+RmMFvBoaaJ6ayBc3sUbHdCE+XG5N8vp+5So41ZupZJQm0roHFFhMGVD7A==} + '@biomejs/biome@2.5.5': + resolution: {integrity: sha512-r1S8nFsAG1MY+vJFZALzIvwXAJv6ejDQ0mxP21Tgr9YK3ZFtjrvbBwDdNhx1rUqvccEIeNg20cYCNzl6Cr69pQ==} engines: {node: '>=14.21.3'} hasBin: true - '@biomejs/cli-darwin-arm64@2.5.3': - resolution: {integrity: sha512-QhYP9muVQ0nUO5zztFuPbEwi4+94sJWVjaZds9aMi1l/KNZBiUjdiSUrGHsTaMGDXrYl+r4AS2sUKfgH3w+V3g==} + '@biomejs/cli-darwin-arm64@2.5.5': + resolution: {integrity: sha512-kUrAhXVWUrwmAUnV2iXSK7umxKFysTwvqK+Ty6ptUcLY/7T3SnCAjUowE4uvwaEej6nXZ7hu/dTtbokKdsPeag==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [darwin] - '@biomejs/cli-darwin-x64@2.5.3': - resolution: {integrity: sha512-NC1Ss13UaW7QZX+y8j44bF7AP0jSJdBl6iRhe0MAkvaSqZy+mWg3GaXsrb+eSoHoGDBtaXWEbMVV0iVN2cZ7cQ==} + '@biomejs/cli-darwin-x64@2.5.5': + resolution: {integrity: sha512-DamiYc5bUYZ2uxlfc+RLEPtz1Abb6PO5eTbOkufLpSGwd/7AMQAdxhFYiXmwwkJL8IsT8S7GvdgwDHqaMFAvKw==} engines: {node: '>=14.21.3'} cpu: [x64] os: [darwin] - '@biomejs/cli-linux-arm64-musl@2.5.3': - resolution: {integrity: sha512-fccix0w6xp6csCXgxeC0dU/3ecgRQal0y+cv2SP9ajNlhe7Yrk2Ug7UDe2j9AT9ZDYitkXpvUKgZjjuoYeP4Vg==} + '@biomejs/cli-linux-arm64-musl@2.5.5': + resolution: {integrity: sha512-U4WMl/sy/E/Q73vf15VspakLRRs2LDFcCeBxJnQfXzssb88zpV6PJPaQ3ezhQ7H6Ht2/8bvuZeHgJWzmoxllZg==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - '@biomejs/cli-linux-arm64@2.5.3': - resolution: {integrity: sha512-ksx1KWeyYW18ILL04msF/J4ZBtBDN33znYK8Z/aNv/vlBVxL9/g3mGP+omgHJKy4+KWbK87vcmmpmurfNjSgiA==} + '@biomejs/cli-linux-arm64@2.5.5': + resolution: {integrity: sha512-lRKF/pH/1RiYiBKExi3TCZVAtvzEm77aifrvcNiDFrR9WxeAnDUjDnseb6y2XV85mjitLs6SILGm2XG77cHtSQ==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] - '@biomejs/cli-linux-x64-musl@2.5.3': - resolution: {integrity: sha512-O/yU9YKRUiHhmcjF2f38PSjseVk3G4VLWYc0G2HWpzdBVREV6G8IGWIVEFf7MFPfWIzNUIvPsEjeAZQIOgnLcQ==} + '@biomejs/cli-linux-x64-musl@2.5.5': + resolution: {integrity: sha512-m7wC7tjX5Lrmo69dc4md8FeKpPU1NTCY1v7xUoQQ2vadWwNnBS0KZOG8471otFPHrTHihQJAjQPgMObpLvDe6A==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - '@biomejs/cli-linux-x64@2.5.3': - resolution: {integrity: sha512-yMkJtilsgvILDcVkh187aVLTb64xYsrxYajx5kym+r1ULkO5HUOfu9AYKLGQbOVLwJtT2utNw7hhFNg+17mUYA==} + '@biomejs/cli-linux-x64@2.5.5': + resolution: {integrity: sha512-H/O39nJEw/2Zm/fm7hrmxxoF8kK/aU1uCoPp70ruXVbomaAdLpJJnCmL11Q2JotT8QVHH06So04Oq53lCSwSwQ==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] - '@biomejs/cli-win32-arm64@2.5.3': - resolution: {integrity: sha512-cX5z+GYwRcqEok0AH3KSfQGgqYd0Nomfp6Fbe1uiTtELE38hdH2k842wQ9wLNaF/JJ7r4rjJQ4VR+ce+fRmQbw==} + '@biomejs/cli-win32-arm64@2.5.5': + resolution: {integrity: sha512-7BryINPuYypLUAH3o/o5ZdgomJ4zn3EDR0ChZJst7n32S6ZhKbgHXuYydLu+YAnx59ehGFR0z/MG6qnzQi3Yyw==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [win32] - '@biomejs/cli-win32-x64@2.5.3': - resolution: {integrity: sha512-ExSaJWi4/u6+GXCszlSKpWSjKNbDseAYqqkCznsCsZ/4uidZ/BEqsCc5/3ctlq6dfIubdIIRSVLC/PG9xPl70Q==} + '@biomejs/cli-win32-x64@2.5.5': + resolution: {integrity: sha512-bIBFo+n6MIxdNcVFy5CrurbKiZQiUciK3bt8+O9I4wjFZNTfXLpi+giq47522eXqW5NBc9ulx7dR1SlZKi2J5g==} engines: {node: '>=14.21.3'} cpu: [x64] os: [win32] @@ -209,45 +200,45 @@ packages: workerd: optional: true - '@cloudflare/vitest-pool-workers@0.18.2': - resolution: {integrity: sha512-OvvKCusb0Y94abyR06rhFiNGdfbKHT+0B8NsHAkUGBTC+eq4bNIdeLNkwh27zwwS0+p4uQj89jBaa40GCN9onQ==} + '@cloudflare/vitest-pool-workers@0.18.8': + resolution: {integrity: sha512-O1kOMZqapidlezNFiBZ7Lbd+8mMEpkGmWwPj+nPLvOngxSL11lmWq7xl7vxyjDxbeD/7l22KqgvRGM7XFaYd9w==} peerDependencies: '@vitest/runner': ^4.1.0 '@vitest/snapshot': ^4.1.0 vitest: ^4.1.0 - '@cloudflare/workerd-darwin-64@1.20260706.1': - resolution: {integrity: sha512-61XleG5EaE+Zam2Y/fwOcMInMrjd3QMKIG0/+pHycZcVZC5Oxs5GfHSTnvyhcniigGW/bcIkvn1PptWbxlVleQ==} + '@cloudflare/workerd-darwin-64@1.20260722.1': + resolution: {integrity: sha512-vZOP8vIS3NwnuaO+gz0FZ7kIGeiO3bZmxV35Ph9zOXKSREhDFlH7wQ7mkCdhW3O4jnXsew+XT7b+DNEI2CcJGQ==} engines: {node: '>=16'} cpu: [x64] os: [darwin] - '@cloudflare/workerd-darwin-arm64@1.20260706.1': - resolution: {integrity: sha512-jbwuMEuhgrXEk+9MD8eHPRsXWlxqtNMqqCMBLJauTHk+NR+U2O6hJXElPqlAVlUTh0A0GPM+DfATupRXm7Ml8w==} + '@cloudflare/workerd-darwin-arm64@1.20260722.1': + resolution: {integrity: sha512-EmIQymihDq6WNdER4+LF8Qn80yqayBUpJ+tkOO7wmY8pmgfyXjIUFNXotl21AHovTeu2seR7HdVUgeN/BilCWw==} engines: {node: '>=16'} cpu: [arm64] os: [darwin] - '@cloudflare/workerd-linux-64@1.20260706.1': - resolution: {integrity: sha512-kppCFkt6WHTNmcE83aUj4chWV13hdQKOgXxn53sqpLiVnPi6HEIOWB1DNRAljG9IDt3KMgni9HdzCYVzq2drJA==} + '@cloudflare/workerd-linux-64@1.20260722.1': + resolution: {integrity: sha512-jvZ3k9fxcnEn04s80CgIYxQfpOyAiz/8qC42DP8EBa9tR27qWyg9wmm31zIobVlrgBZn/+8NfdP73avRGcQOjQ==} engines: {node: '>=16'} cpu: [x64] os: [linux] - '@cloudflare/workerd-linux-arm64@1.20260706.1': - resolution: {integrity: sha512-H4xpocM1vXNfIVrP/JiOhLooWBXi5erE81hBj2wmCvPIUcf+49CuvZEthpVwFYn9SFop/Y8+bUiV0vVrWf8xuw==} + '@cloudflare/workerd-linux-arm64@1.20260722.1': + resolution: {integrity: sha512-BOSB55SMNdy+DA5uj2WirgiNanpHGis5PVvXH1wSfvjRKr4JGgWK+EZzxz0RFUo6QjjQQC/NimEzNZ7va7jmKg==} engines: {node: '>=16'} cpu: [arm64] os: [linux] - '@cloudflare/workerd-windows-64@1.20260706.1': - resolution: {integrity: sha512-SPWuI+kBNtr/mhcKE7XOECgRWOaidmzVmvtmDrRZX5Y4/+XqD/heRAU5Oa17wOZm3eQ1CB8Xzxjrr/6uQaP8YA==} + '@cloudflare/workerd-windows-64@1.20260722.1': + resolution: {integrity: sha512-sYM8YgUpKnRz2xjvdJLX1Ojzoi4MlA4gk8WTTExhGydjYB2UTs5NIbv0ZmpKgMoK9io3ixgmiW56ZnTbcWOdiA==} engines: {node: '>=16'} cpu: [x64] os: [win32] - '@cloudflare/workers-types@5.20260708.1': - resolution: {integrity: sha512-FSRyCsxALKmmNnk/2HMkTiX9Iz9yqTiTWX/BJZdffGznMSunXmQgb3mKy9wGBX2BCTLOuRYWL36uh7/3Gm05Eg==} + '@cloudflare/workers-types@5.20260724.1': + resolution: {integrity: sha512-gl0brZ60JhkZU3INgr1jsxaFEiWf3AB9RsCjLTMwT5RKspWRUpsFd0wxwbys7gb8Ywkfq9tORhw0y9G+7bDUYw==} '@colors/colors@1.6.0': resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==} @@ -260,17 +251,14 @@ packages: '@dabh/diagnostics@2.0.8': resolution: {integrity: sha512-R4MSXTVnuMzGD7bzHdW2ZhhdPC/igELENcq5IjEverBvq5hn1SXCWcsi6eSsdWP0/Ur+SItRRjAktmdoX/8R/Q==} - '@emnapi/core@1.10.0': - resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} - - '@emnapi/runtime@1.10.0': - resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + '@emnapi/core@1.11.1': + resolution: {integrity: sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==} '@emnapi/runtime@1.11.1': resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} - '@emnapi/wasi-threads@1.2.1': - resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + '@emnapi/wasi-threads@1.2.2': + resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} '@esbuild/aix-ppc64@0.28.1': resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} @@ -463,43 +451,43 @@ packages: resolution: {integrity: sha512-LUdM4Wg7YM9Pq/49nGYySJA0CSQEKnGffFzWV8+6gXN7mGxn+FL1IqvFbuZUtAQcfZgHYDwCE1wwlK7rB7gl2g==} engines: {node: '>=20.0.0'} - '@genkit-ai/ai@1.39.0': - resolution: {integrity: sha512-e1ZI2ib4Y8ha2Zj/rN7Uioxd16rWMhalPe3krypLw8B4G36X8KZCqj2UhucKbCZJIffU0cxEvag7BP+JVQnsyQ==} + '@genkit-ai/ai@1.40.1': + resolution: {integrity: sha512-qQZegPEHv92SRwCii9F9VmLD9nsDsX2udjk3MslayLyviRJ0izt3JbqBcWJdLkT07VjGy+pdGqQttZjRPsnROg==} - '@genkit-ai/core@1.39.0': - resolution: {integrity: sha512-MI0cpmwc4K/KPVsXFAcHviOybt3T3IsVSsN37cEcOzo7mmv+s0JSdooxlQgZn68B6e3I8BNLL3Vk1vyc6qIlCw==} + '@genkit-ai/core@1.40.1': + resolution: {integrity: sha512-Q/QJJdSNdfJU54Nb0qPx1238hAp574jqhCd1F/l6sHQ6ZN7RPJJm5nBMBz4SQm8yc/vAhumXdfcWv+J11Ef6yw==} - '@genkit-ai/firebase@1.37.0': - resolution: {integrity: sha512-yutXazOCGqGeauiShCaPj9fjcS3nn3FUTj7/0nbHXx8mLVhddBEwBIH96MqVGz9pqt3Fl57TCROPguLOmIZaQQ==} + '@genkit-ai/firebase@1.40.1': + resolution: {integrity: sha512-VCK6hz9J73U4sfRkKksx8ziGad21Z4CBw6uhmsI29QByc9ulOAcJTqnaDwAbouUdLA++REri1gNeofvQoctpsw==} peerDependencies: '@google-cloud/firestore': ^7.11.0 firebase: '>=11.5.0' firebase-admin: '>=12.2' - genkit: ^1.37.0 + genkit: ^1.40.1 peerDependenciesMeta: firebase: optional: true - '@genkit-ai/google-cloud@1.37.0': - resolution: {integrity: sha512-THLcekr0kxzTyZksFVQ/gCIcprlQlenG7aGdGWjAokqWdtX28CU+2pmQF64m++IxOsuuqISIABjpyp0/fSPgjQ==} + '@genkit-ai/google-cloud@1.40.1': + resolution: {integrity: sha512-pL0gClnB7k+OCjWbQ+4Zh1BzGUpirNdc6QqazfJhMc5/KbXt5XxiyKVJC+7UTW8VWRmPa3ZN8p/HeA2+zftxzA==} peerDependencies: - genkit: ^1.37.0 + genkit: ^1.40.1 - '@genkit-ai/google-genai@1.39.0': - resolution: {integrity: sha512-ZP9nA6TlBJ1ZHCmSkz56v0lrRS/Wfh6L09oHgeOIZyD/Pq76uX3W+Uly8dPAbDtNax63l64TsEYZH1HHt8rC8A==} + '@genkit-ai/google-genai@1.40.1': + resolution: {integrity: sha512-U+Cl8009vVBVVRIW7L4sq4XOWE7O9wfOVqGdyp38cZWnkrQrxdsoMzg3svt/Vqn2C0lIMFNsdKeBGTxNx5RwbA==} peerDependencies: - genkit: ^1.39.0 + genkit: ^1.40.1 - '@google-cloud/common@5.0.2': - resolution: {integrity: sha512-V7bmBKYQyu0eVG2BFejuUjlBt+zrya6vtsKdY+JxMM/dNntPF41vZ9+LhOshEUH01zOHEqBSvI7Dad7ZS6aUeA==} - engines: {node: '>=14.0.0'} + '@google-cloud/common@6.1.0': + resolution: {integrity: sha512-Ohjxjvusr65+SiEVBrilpyn1ir9CM8ZqWjcf7bA8ph1GCunxI6bbwtcl7iGl67A7Lr4Nz7WpNzITNETwggc7pw==} + engines: {node: '>=18'} '@google-cloud/firestore@7.11.6': resolution: {integrity: sha512-EW/O8ktzwLfyWBOsNuhRoMi8lrC3clHM5LVFhGvO1HCsLozCOOXRAlHrYBoE6HL42Sc8yYMuCb2XqcnJ4OOEpw==} engines: {node: '>=14.0.0'} - '@google-cloud/firestore@8.6.0': - resolution: {integrity: sha512-TdvZHfwQj5B5CSDEgDqyrhdVqtOSupmBXDQPasMAJiC64tjsGvyMooNiC43fdk1TsUHeklyoZ6/vQ1TjWKVMbg==} + '@google-cloud/firestore@8.7.0': + resolution: {integrity: sha512-EvMpZQUXkTRdweSvOu6VL6EEQwHjHAgWz2UYZR+Mj6Ao52S+TWieHbSn15jiNnEw8F8RhbZj7IGXZ1PFB1eA+A==} engines: {node: '>=18'} '@google-cloud/logging-winston@6.0.2': @@ -508,9 +496,9 @@ packages: peerDependencies: winston: '>=3.2.1' - '@google-cloud/logging@11.2.3': - resolution: {integrity: sha512-iUIJ+3Bi6aw9whahT4JmS5Ccd1Eej2Ss9RjOSW2+qcVaWcleepJtFUBuyU2CpewtniVibBUV/731MQw9SWxQ3Q==} - engines: {node: '>=14.0.0'} + '@google-cloud/logging@11.3.0': + resolution: {integrity: sha512-8Y2lFRpPz6rZUQ+J//+toAZ7H0ZT/5KagS0NMhXWdT+sN3pPtNzgm+N0NJ46cf9XX3etj4yfE7HrjX3wMRLBZw==} + engines: {node: '>=18'} '@google-cloud/modelarmor@0.4.1': resolution: {integrity: sha512-CT9TpQF443aatjhRRvazrYNOvUot26HnFP3hhgmV89QYygNPB6owWvGFFOTsKK4zSvTDfkeeb+E6diVXxn9t4g==} @@ -560,8 +548,8 @@ packages: resolution: {integrity: sha512-l+IFTkd+6Y5LoAuXyYCKNAKtw/Ci+rAMqgdTB1jv4iZiLhw0rtq+0qjIRbBizXkNzEFmXiXUW0H7sZQQvk1ffA==} engines: {node: '>=14'} - '@google/genai@2.10.0': - resolution: {integrity: sha512-e4cFxj3tiuMtsgOT4G9c1hXyGJhg7/Buj7VVeBacRY3fRtkRZZ59Q3nuVp2xbq8BGQXLXCDB253qMhklMOeUDg==} + '@google/genai@2.13.0': + resolution: {integrity: sha512-GM7C8Kaomvjz05x5JEO6+l3d/pciL9LxAG9dUjJLD7nTPZ9X0Cfsf2Z7eET6UjgWyUmxXCHtYnQoQ77F9+ZIOQ==} engines: {node: '>=20.0.0'} peerDependencies: '@modelcontextprotocol/sdk': ^1.25.2 @@ -591,149 +579,145 @@ packages: resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} engines: {node: '>=18'} - '@img/sharp-darwin-arm64@0.34.5': - resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-darwin-arm64@0.35.2': + resolution: {integrity: sha512-eEieHsMksAW4IiO5NzauESRl2D2qz3J/kwUxUrSfV06A93eEaRfMpHXyUb1mAqrR7i8U9A0GRqE9pjn6u1Jjpg==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.34.5': - resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-darwin-x64@0.35.2': + resolution: {integrity: sha512-BaktuGPCeHJMARpodR8jK4uKiZrPAy9WrfQW0sdI37clracq8Bp01AYS3SZgi5FS/y5twa9t4+LIuuxQjqRrWw==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.2.4': - resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + '@img/sharp-freebsd-wasm32@0.35.2': + resolution: {integrity: sha512-YoAxdnd8hPUkvLHd3bWY+YA8nw3xM/RyRopYucNsWHVSan8NLVM3X2volsfoRDcXdUJPg6tXahSd7HXPK7lRnw==} + engines: {node: '>=20.9.0'} + os: [freebsd] + + '@img/sharp-libvips-darwin-arm64@1.3.1': + resolution: {integrity: sha512-4V/M3roRMTYjiwZY9IOVQOE8OyeCxFAkYmyZDrZl51uOKjibm3oeEJ4WAmLxutAfzFbC9jqUiPs2gbnGflH+7g==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.2.4': - resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + '@img/sharp-libvips-darwin-x64@1.3.1': + resolution: {integrity: sha512-c0/DxItpJv2+dGhgycJBBgotdqruGYDvA79drdh0MD1dFpy7JzJ/PlXwi1H4rFf0eTy8tgbI91aHDnZIceY3jQ==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.2.4': - resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + '@img/sharp-libvips-linux-arm64@1.3.1': + resolution: {integrity: sha512-JznefmcK9j1JKPz8AkQDh89kjojubyfOasWBPKfzMIhPwsgDy9evpE/naJTXXXmghS1iFwR8u/kTwh/I2/+GCw==} cpu: [arm64] os: [linux] - libc: [glibc] - '@img/sharp-libvips-linux-arm@1.2.4': - resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + '@img/sharp-libvips-linux-arm@1.3.1': + resolution: {integrity: sha512-aGGy9aWzXgHBG7HNyQPWorZthlp7+x6fDRoPAQbGO3ThcttuTyKIx3NuSHb6zb4gBNq6/yNn9f1cy9nFKS/Vmg==} cpu: [arm] os: [linux] - libc: [glibc] - '@img/sharp-libvips-linux-ppc64@1.2.4': - resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + '@img/sharp-libvips-linux-ppc64@1.3.1': + resolution: {integrity: sha512-1EkwGNCZk6iWNCMWqrvdJ+r1j0PT1zIz60CNPhYnJlK/zyeWqlsPZIe+ocBVqPF8k/Ssee/NCk+tE9Ryrko6ng==} cpu: [ppc64] os: [linux] - '@img/sharp-libvips-linux-riscv64@1.2.4': - resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + '@img/sharp-libvips-linux-riscv64@1.3.1': + resolution: {integrity: sha512-Ilays+w2bXdnxzxtQdmXR62u8o8GYa3eL4+Gr+1KiE4xperMZUslRaVPJwwPkzlHEjGfXAfRVAa/7CYCtSqsBw==} cpu: [riscv64] os: [linux] - '@img/sharp-libvips-linux-s390x@1.2.4': - resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + '@img/sharp-libvips-linux-s390x@1.3.1': + resolution: {integrity: sha512-VfBwVHQTbRoj4XlpA/KLZ7ltgMpz+4WSejFzQ+GnoImjo1PtEJ59QB2qR1xQEeRPYIkNrPIm2L4cICMvz4C2ew==} cpu: [s390x] os: [linux] - libc: [glibc] - '@img/sharp-libvips-linux-x64@1.2.4': - resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + '@img/sharp-libvips-linux-x64@1.3.1': + resolution: {integrity: sha512-+c8ukgwU62DS54nCAjw7keOfHUkmr0B5QHEdcOqRnodF/MNXJbVI8Eopoj4B/0H8Asr65I+A4Amrn7a85/md6A==} cpu: [x64] os: [linux] - libc: [glibc] - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': - resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + '@img/sharp-libvips-linuxmusl-arm64@1.3.1': + resolution: {integrity: sha512-qlKb/pwbkAi1WMsJrYHk7CuDrd12s27U2QnRhFYUoJNrRCmkosMTttuRFat/DDB3IlDm5qE1TJgZ4JDnHX8Ldw==} cpu: [arm64] os: [linux] - libc: [musl] - '@img/sharp-libvips-linuxmusl-x64@1.2.4': - resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + '@img/sharp-libvips-linuxmusl-x64@1.3.1': + resolution: {integrity: sha512-yO21HwoUVLN8Qa+/SBjQLMYwBWAVJjeGPNe+hc0OUeMeifEtJqu5a1c4HayE1nNpDih9y3/KkoltfkDodmKAlg==} cpu: [x64] os: [linux] - '@img/sharp-linux-arm64@0.34.5': - resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-arm64@0.35.2': + resolution: {integrity: sha512-af12Pnd0ZGu2HfP8NayB0kk6eC/lrfbQE6HlR4jD+34wdJ1Vw9TF6TMn6ZvffT+WgqVsl0hRbmNvz2u/23VmwA==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [linux] - libc: [glibc] - '@img/sharp-linux-arm@0.34.5': - resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-arm@0.35.2': + resolution: {integrity: sha512-SE4kzF2mepn6z+6E7L6lsV8FzuLL6IPQdyX8ZiwROAG/G8td+hP/m7FsFPwidtrF19gvajuC9l6TxAVcsA4S7A==} + engines: {node: '>=20.9.0'} cpu: [arm] os: [linux] - libc: [glibc] - '@img/sharp-linux-ppc64@0.34.5': - resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-ppc64@0.35.2': + resolution: {integrity: sha512-hYSBm7zcNtDCozCxQHYZJiu63b/bXsgRZuOxCIBZsStMM9Vap47iFHdbX4kCvQsblPB/k+clhELpdQJHQLSHvg==} + engines: {node: '>=20.9.0'} cpu: [ppc64] os: [linux] - libc: [glibc] - '@img/sharp-linux-riscv64@0.34.5': - resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-riscv64@0.35.2': + resolution: {integrity: sha512-qQt0Kc13+Hoan/Awq/qMSQw3L+RI1NCRPgD5cUJ/1WSSmIoysLOc72jlRM3E0OHN9Yr313jgeQ2T+zW+F03QFA==} + engines: {node: '>=20.9.0'} cpu: [riscv64] os: [linux] - libc: [glibc] - '@img/sharp-linux-s390x@0.34.5': - resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-s390x@0.35.2': + resolution: {integrity: sha512-E4fLLfRPzDLlEeDaTzI98OFLcv++WL5ChLLMwPoVd0CIoZQqupBSNbOisPL5am9XsbQ9T84+iiMpUvbFtkunbA==} + engines: {node: '>=20.9.0'} cpu: [s390x] os: [linux] - libc: [glibc] - '@img/sharp-linux-x64@0.34.5': - resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-x64@0.35.2': + resolution: {integrity: sha512-gi0zFJJRLswfCZmHtJdikXPOc5u7qamSOS3NHedLqLd4W8Q0NqjdBr6TTRIgsfFjqfTsHFgdfvJ9LwqSgcHiAA==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [linux] - libc: [glibc] - '@img/sharp-linuxmusl-arm64@0.34.5': - resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linuxmusl-arm64@0.35.2': + resolution: {integrity: sha512-siWbOW1u6HFnFLrp0waKyW7VEf7jYvcDWdrXEFa8AkdAQgEvuu5Fz8/Y70w9EeqAdwDtfU012BhEHHaDqvQNzg==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [linux] - libc: [musl] - '@img/sharp-linuxmusl-x64@0.34.5': - resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linuxmusl-x64@0.35.2': + resolution: {integrity: sha512-YBqMMcjDi4QGYiSn4vNOYBhmlC4z5AXqkOUUqI2e0AFA4urNv4ESgOgwNl3K+4etQhha0twXlzeF20bbULm9Yg==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [linux] - libc: [musl] - '@img/sharp-wasm32@0.34.5': - resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-wasm32@0.35.2': + resolution: {integrity: sha512-Mrv4JQNYVQ94xH+jzZ9r+gowleN8mv2FTgKT+PI6bx5C0G8TdNYndu161pg2i7uoBwxy2ImPMHrJOM2LZef7Bw==} + engines: {node: '>=20.9.0'} + + '@img/sharp-webcontainers-wasm32@0.35.2': + resolution: {integrity: sha512-QNV27pxs9wpApEiCfvHM1RDoP1w1+2KrUWWDPEhEwg+latvOrfuhWrHWZKwdSFwU6jh3myjw/yOCRsUIuOft3g==} + engines: {node: '>=20.9.0'} cpu: [wasm32] - '@img/sharp-win32-arm64@0.34.5': - resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-win32-arm64@0.35.2': + resolution: {integrity: sha512-BiVRYc/t6/Vl3e1hBx0hugG4oN9Pydf4fgMSpxTQJmwGUg/YoXTWHiFeRymHfCZzifxu4F4rpk/I67D0LQ20wQ==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [win32] - '@img/sharp-win32-ia32@0.34.5': - resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-win32-ia32@0.35.2': + resolution: {integrity: sha512-YYEhx9PImCC7T0tI8JDMi4DB9LwLCXCU5OWNYEXAxh5Q1ShKkyC6byxzoBJ3gEFDnH2lQckWuDe70G7mB2XJog==} + engines: {node: ^20.9.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.34.5': - resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-win32-x64@0.35.2': + resolution: {integrity: sha512-imoOyBcoM/iiUr4J6VPpCNjPnjvP/Gks95898yB8YqoGGYmHYbOyCuNv9FMhFgtaiHFGbHW8bxKqRV6VjtXThQ==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [win32] @@ -766,14 +750,14 @@ packages: peerDependencies: jsep: ^0.4.0||^1.0.0 - '@langchain/anthropic@1.5.1': - resolution: {integrity: sha512-j92zCCd5BFH3rHMRzc2wBmSKDoVpinof1oh8aFiAz9TWbSOc4tGU4n6bqwy/wP0GH1uO96zZHLGCHBMPgrxTNw==} + '@langchain/anthropic@1.5.2': + resolution: {integrity: sha512-lYOHo5BpRbgmQVSggwPLhBNFtatiAFlVirY44tnfocx5tQKfeLYo5emqPwNwcNBuw236sr0tsDxZcmbLASN/GA==} engines: {node: '>=20'} peerDependencies: - '@langchain/core': ^1.2.1 + '@langchain/core': ^1.2.3 - '@langchain/core@1.2.1': - resolution: {integrity: sha512-NNG/cC5FGuHDOAP56h0ddp8Rfk8p+othWzEK5RV9JIG6RvnF5vGa5r0AEGtKfQieed7s1kC42GuIzVOBvMBL/g==} + '@langchain/core@1.2.3': + resolution: {integrity: sha512-F+L5SsciykwDl7eDxacnhDTcWe1IF6jetzfkvI5PPfq6ogWHO7xcjU90SGh/3lqbbS0tgun+qF01KIqxawrCsA==} engines: {node: '>=20'} '@langchain/google-genai@2.2.0': @@ -782,20 +766,20 @@ packages: peerDependencies: '@langchain/core': ^1.2.0 - '@langchain/openai@1.5.3': - resolution: {integrity: sha512-OStS2AUvy9oe/hEf/3ndBOFztUDOfuJYLNXh89m3iiJAI2Cp5Dp0n/pvpO27MO0b+VgENd+xSHVyQZ7fe+ulxg==} + '@langchain/openai@1.5.5': + resolution: {integrity: sha512-wX7dwb9z4nf5FHXlIl/X2mk08pzonvRHCt1D4+s1zXLP0duYDC95j7dulPIQJ6fmhbyYQc9Ki8mEhY/D1lB8kw==} engines: {node: '>=20'} peerDependencies: - '@langchain/core': ^1.2.1 + '@langchain/core': ^1.2.2 - '@napi-rs/wasm-runtime@1.1.5': - resolution: {integrity: sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==} + '@napi-rs/wasm-runtime@1.1.6': + resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==} peerDependencies: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 - '@nodable/entities@2.2.0': - resolution: {integrity: sha512-9uGyhaQavEUMC8AIddIjau4NsnsXhou+j5sBAGojCM1oxmQpVKTWR/9JxABD6UAv12vpIms55fPZKFQEhG6uBg==} + '@nodable/entities@3.0.0': + resolution: {integrity: sha512-8L9xFeTYKhm49xfIypoe2W5wV1m/3Z58kT+7kR9A8OyFxcPduI4VmxaUMQyKYrRjUoLLSXv6EKKID5Tvj9cUVw==} '@opentelemetry/api-logs@0.52.1': resolution: {integrity: sha512-qnSqB2DQ9TPP96dl8cDubDvrUyWc0/sK81xHTK8eSUspzDM3bsewX903qclQFvVhgStjRWdC5bLb3kQqMkfV5A==} @@ -1114,6 +1098,7 @@ packages: '@opentelemetry/propagation-utils@0.30.16': resolution: {integrity: sha512-ZVQ3Z/PQ+2GQlrBfbMMMT0U7MzvYZLCPP800+ooyaBqm4hMvuQHfP028gB9/db0mwkmyEAMad9houukUVxhwcw==} engines: {node: '>=14'} + deprecated: The use of process spans has been removed from Messaging Semantic Conventions. It is now recommended to connect pub/sub spans via Span Links. See https://opentelemetry.io/docs/specs/semconv/messaging/messaging-spans/ for details. peerDependencies: '@opentelemetry/api': ^1.0.0 @@ -1213,8 +1198,8 @@ packages: resolution: {integrity: sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==} engines: {node: '>=14'} - '@opentelemetry/semantic-conventions@1.41.1': - resolution: {integrity: sha512-/UhIkaZgPutTFmQ7RnIJGgDXZmtEJ7Dvi86xNTFWcnRxVRNk/aotsqDJYeEvDP+FSMB2SdW+pQzNMcWP0rwuNA==} + '@opentelemetry/semantic-conventions@1.43.0': + resolution: {integrity: sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==} engines: {node: '>=14'} '@opentelemetry/sql-common@0.40.1': @@ -1223,8 +1208,8 @@ packages: peerDependencies: '@opentelemetry/api': ^1.1.0 - '@oxc-project/types@0.133.0': - resolution: {integrity: sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==} + '@oxc-project/types@0.139.0': + resolution: {integrity: sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==} '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} @@ -1263,100 +1248,100 @@ packages: '@protobufjs/pool@1.1.0': resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} - '@protobufjs/utf8@1.1.1': - resolution: {integrity: sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==} + '@protobufjs/utf8@1.1.2': + resolution: {integrity: sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==} - '@rolldown/binding-android-arm64@1.0.3': - resolution: {integrity: sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==} + '@rolldown/binding-android-arm64@1.1.5': + resolution: {integrity: sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.0.3': - resolution: {integrity: sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==} + '@rolldown/binding-darwin-arm64@1.1.5': + resolution: {integrity: sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.3': - resolution: {integrity: sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==} + '@rolldown/binding-darwin-x64@1.1.5': + resolution: {integrity: sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.0.3': - resolution: {integrity: sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==} + '@rolldown/binding-freebsd-x64@1.1.5': + resolution: {integrity: sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.0.3': - resolution: {integrity: sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==} + '@rolldown/binding-linux-arm-gnueabihf@1.1.5': + resolution: {integrity: sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.3': - resolution: {integrity: sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==} + '@rolldown/binding-linux-arm64-gnu@1.1.5': + resolution: {integrity: sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-musl@1.0.3': - resolution: {integrity: sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==} + '@rolldown/binding-linux-arm64-musl@1.1.5': + resolution: {integrity: sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@rolldown/binding-linux-ppc64-gnu@1.0.3': - resolution: {integrity: sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==} + '@rolldown/binding-linux-ppc64-gnu@1.1.5': + resolution: {integrity: sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.0.3': - resolution: {integrity: sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==} + '@rolldown/binding-linux-s390x-gnu@1.1.5': + resolution: {integrity: sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.0.3': - resolution: {integrity: sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==} + '@rolldown/binding-linux-x64-gnu@1.1.5': + resolution: {integrity: sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.0.3': - resolution: {integrity: sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==} + '@rolldown/binding-linux-x64-musl@1.1.5': + resolution: {integrity: sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@rolldown/binding-openharmony-arm64@1.0.3': - resolution: {integrity: sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==} + '@rolldown/binding-openharmony-arm64@1.1.5': + resolution: {integrity: sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-wasm32-wasi@1.0.3': - resolution: {integrity: sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==} + '@rolldown/binding-wasm32-wasi@1.1.5': + resolution: {integrity: sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] - '@rolldown/binding-win32-arm64-msvc@1.0.3': - resolution: {integrity: sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==} + '@rolldown/binding-win32-arm64-msvc@1.1.5': + resolution: {integrity: sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.3': - resolution: {integrity: sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==} + '@rolldown/binding-win32-x64-msvc@1.1.5': + resolution: {integrity: sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -1384,8 +1369,8 @@ packages: resolution: {integrity: sha512-HqmEUIGRJ5fSXchkVgR5F7qn48bDBzv0kWj/Kfu5e6uci4UlEeng4331LnBkWffb++Ei3FOVLxo8JJWMFBDMeQ==} engines: {node: '>= 10'} - '@tybys/wasm-util@0.10.2': - resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} + '@tybys/wasm-util@0.10.3': + resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} '@types/aws-lambda@8.10.122': resolution: {integrity: sha512-vBkIh9AY22kVOCEKo5CJlyCgmSWvasC+SWUxL/x/vOwRobMpI/HG1xp/Ae3AqmSiZeLUbOhW0FCD3ZjqqUxmXw==} @@ -1429,8 +1414,8 @@ packages: '@types/node@20.19.43': resolution: {integrity: sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==} - '@types/node@25.9.3': - resolution: {integrity: sha512-603BddQMv3pUcr4U2dhujk83N2tTDVr/34wII2B6bJy6g+8WD6yUb11jszNs0gdi4PesVWl7ABt8nYMVpnLUcg==} + '@types/node@26.1.1': + resolution: {integrity: sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw==} '@types/pg-pool@2.0.4': resolution: {integrity: sha512-qZAvkv1K3QbmHHFYSNRYPkRjOWRLBYrL4B9c+wG0GSVGBw0NtJwPcgx/DSddeDJvRGMHCEQ4VMEVfuJ/0gZ3XQ==} @@ -1459,6 +1444,126 @@ packages: '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + '@typescript/typescript-aix-ppc64@7.0.2': + resolution: {integrity: sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==} + engines: {node: '>=16.20.0'} + cpu: [ppc64] + os: [aix] + + '@typescript/typescript-darwin-arm64@7.0.2': + resolution: {integrity: sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [darwin] + + '@typescript/typescript-darwin-x64@7.0.2': + resolution: {integrity: sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [darwin] + + '@typescript/typescript-freebsd-arm64@7.0.2': + resolution: {integrity: sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [freebsd] + + '@typescript/typescript-freebsd-x64@7.0.2': + resolution: {integrity: sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [freebsd] + + '@typescript/typescript-linux-arm64@7.0.2': + resolution: {integrity: sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [linux] + + '@typescript/typescript-linux-arm@7.0.2': + resolution: {integrity: sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==} + engines: {node: '>=16.20.0'} + cpu: [arm] + os: [linux] + + '@typescript/typescript-linux-loong64@7.0.2': + resolution: {integrity: sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==} + engines: {node: '>=16.20.0'} + cpu: [loong64] + os: [linux] + + '@typescript/typescript-linux-mips64el@7.0.2': + resolution: {integrity: sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==} + engines: {node: '>=16.20.0'} + cpu: [mips64el] + os: [linux] + + '@typescript/typescript-linux-ppc64@7.0.2': + resolution: {integrity: sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==} + engines: {node: '>=16.20.0'} + cpu: [ppc64] + os: [linux] + + '@typescript/typescript-linux-riscv64@7.0.2': + resolution: {integrity: sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==} + engines: {node: '>=16.20.0'} + cpu: [riscv64] + os: [linux] + + '@typescript/typescript-linux-s390x@7.0.2': + resolution: {integrity: sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==} + engines: {node: '>=16.20.0'} + cpu: [s390x] + os: [linux] + + '@typescript/typescript-linux-x64@7.0.2': + resolution: {integrity: sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [linux] + + '@typescript/typescript-netbsd-arm64@7.0.2': + resolution: {integrity: sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [netbsd] + + '@typescript/typescript-netbsd-x64@7.0.2': + resolution: {integrity: sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [netbsd] + + '@typescript/typescript-openbsd-arm64@7.0.2': + resolution: {integrity: sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [openbsd] + + '@typescript/typescript-openbsd-x64@7.0.2': + resolution: {integrity: sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [openbsd] + + '@typescript/typescript-sunos-x64@7.0.2': + resolution: {integrity: sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [sunos] + + '@typescript/typescript-win32-arm64@7.0.2': + resolution: {integrity: sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [win32] + + '@typescript/typescript-win32-x64@7.0.2': + resolution: {integrity: sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [win32] + '@vercel/oidc@3.2.0': resolution: {integrity: sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug==} engines: {node: '>= 20'} @@ -1480,30 +1585,18 @@ packages: '@vitest/pretty-format@4.1.10': resolution: {integrity: sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==} - '@vitest/pretty-format@4.1.9': - resolution: {integrity: sha512-s0iufns3iIFitdgm+YR7g1whCAaGtXz459VS9/PqyKDEEFgYIhsHOQmXgIgDuYCt7DeQmiZT0Qe2OA2p4ZPu5A==} - '@vitest/runner@4.1.10': resolution: {integrity: sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==} - '@vitest/runner@4.1.9': - resolution: {integrity: sha512-KXLMDtc7oe70+3mJfGrPUWPesswH+3sTxAMAMl8DG7I8IUQT4XW718dY5ID3vPUcmlu27CcKfY4P3h3I29SLJg==} - '@vitest/snapshot@4.1.10': resolution: {integrity: sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==} - '@vitest/snapshot@4.1.9': - resolution: {integrity: sha512-Jc7RKGNBo8Z28WYIm0Niej4xdSPByRf6mU58VpHQkd6Zh05rlnA+twjbK5HyeIGHxrzsc3mJgS43uM0CZKzaIA==} - '@vitest/spy@4.1.10': resolution: {integrity: sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==} '@vitest/utils@4.1.10': resolution: {integrity: sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==} - '@vitest/utils@4.1.9': - resolution: {integrity: sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA==} - '@workflow/serde@4.1.0': resolution: {integrity: sha512-pav4F2BoirECWR7Nf1TKt+2eETcBj7jj4cBefQ8VXQCA6NPkaKeLfj/zMgi+3zYV5ZIBT4GuUiphsj0/b9hPQQ==} @@ -1533,8 +1626,8 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} - ai@7.0.17: - resolution: {integrity: sha512-kpIjNtN0tyUaxzkAs7b8YF48WZzc71dKu0HqFPSAWg/avu1Ogv50UPE9hpVMr+kb33zsEa6LrAU9DZHMNscvzw==} + ai@7.0.37: + resolution: {integrity: sha512-stF+SEQJgKY3Qfe3FwNzqUrehHviOp2l7LemoI8YMOa0Zk5PxKsRNgUk3cHXz0RAue9RRyCAis2fz6LSCP6EKw==} engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 @@ -1604,12 +1697,12 @@ packages: blake3-wasm@2.1.5: resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==} - body-parser@1.20.5: - resolution: {integrity: sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==} + body-parser@1.20.6: + resolution: {integrity: sha512-p5tAzS57i5MV9fZFDj9LeIiTZEufbSe2eDozP+ElheSUq1m74CRq1jI4mYNDdVs9vQztXFLuk/Gd6BWTdwRJ5g==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - brace-expansion@2.1.1: - resolution: {integrity: sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==} + brace-expansion@2.1.2: + resolution: {integrity: sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==} buffer-equal-constant-time@1.0.1: resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} @@ -1648,8 +1741,8 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - color-name@2.1.0: - resolution: {integrity: sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==} + color-name@2.1.1: + resolution: {integrity: sha512-p2FdgwVx1a9yWBHP2wI0VgShkDpgN4kZISkxdNipGBJWpa5G6b04OINlVWCyJj0JmfvcPrgqt95E9k8yvaOJFg==} engines: {node: '>=12.20'} color-string@2.1.4: @@ -1779,8 +1872,8 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-module-lexer@2.1.0: - resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} + es-module-lexer@2.3.1: + resolution: {integrity: sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==} es-object-atoms@1.1.2: resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} @@ -1816,16 +1909,12 @@ packages: eventemitter3@4.0.7: resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} - eventid@2.0.1: - resolution: {integrity: sha512-sPNTqiMokAvV048P2c9+foqVJzk49o6d4e0D/sq5jog3pw+4kBgyR0gaM1FM7Mx6Kzd9dztesh9oYz1LWWOpzw==} - engines: {node: '>=10'} - eventsource-parser@3.1.0: resolution: {integrity: sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==} engines: {node: '>=18.0.0'} - expect-type@1.3.0: - resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + expect-type@1.4.0: + resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} engines: {node: '>=12.0.0'} express@4.22.2: @@ -1835,24 +1924,20 @@ packages: extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - farmhash-modern@1.1.0: - resolution: {integrity: sha512-6ypT4XfgqJk/F3Yuv4SX26I3doUjt0GTG4a+JgWxXQpxXzTBq8fPUeGHfcYMMDPHJHm3yPOSjaeBwBGAHWXCdA==} - engines: {node: '>=18.0.0'} - fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} fast-sha256@1.3.0: resolution: {integrity: sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==} - fast-uri@3.1.2: - resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} + fast-uri@3.1.4: + resolution: {integrity: sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==} - fast-xml-builder@1.2.0: - resolution: {integrity: sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q==} + fast-xml-builder@1.3.0: + resolution: {integrity: sha512-F74cZEdCvuw9P41GAC3rod4X04jjWGM1JPEv/GWSqFTWLsdyMSBMBMlm9Hk3GLBgLBbdBNY8yee0pQh2RBVESQ==} - fast-xml-parser@5.9.3: - resolution: {integrity: sha512-brCNCeScma/kqa54J4PIDriSSSLssRkuYaUCpvHJulGc3HGI/xxKUCTDcYkAdqJsyb//ydpbxecjC3hB9+tb/g==} + fast-xml-parser@5.10.1: + resolution: {integrity: sha512-IEMIf7298kXuZSRFoGfMYrl7is8LpavODgbNz1cwIudv7KwVFnuU+UsMporfq6PD6aXSlawZlARiA3UywCTfMw==} hasBin: true faye-websocket@0.11.4: @@ -1879,8 +1964,8 @@ packages: resolution: {integrity: sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==} engines: {node: '>= 0.8'} - firebase-admin@14.0.0: - resolution: {integrity: sha512-U88/r6VWiBQ05+UlLaF1A1AN4Y3SAGQKcQWawzafEAnXVaCZ21+2KclMPdlIQAAF5pUtN+FkXCSQnJEpc6QDZA==} + firebase-admin@14.2.0: + resolution: {integrity: sha512-zfs5PdccEgjX479bbMmz95Rqc7ttQ4LV3qkGFlPiqOaOu/suBZc3fG52Qzn2hQjiSHkBM4NP2AZV5r2NvAt0TQ==} engines: {node: '>=22'} fn.name@1.1.0: @@ -1921,8 +2006,8 @@ packages: resolution: {integrity: sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==} engines: {node: '>=14'} - gaxios@7.1.5: - resolution: {integrity: sha512-5FZy72Rh8LhtjmvDrKkI+lVhrsQrVKVsItxMoDm5mNQE+xR0WVIIs+jzPSJgBvKVsLi24fZhXJIsNI0bihDzFg==} + gaxios@7.3.0: + resolution: {integrity: sha512-RB5vLV+vvQeoFPCX4QMK6/hjVkbIamPp1QSUD0CiZcnj12qbpiL+pLbYtgD+oZkWl0tl9z+o2Utp+MpM3QRhBA==} engines: {node: '>=18'} gcp-metadata@6.1.1: @@ -1933,8 +2018,8 @@ packages: resolution: {integrity: sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==} engines: {node: '>=18'} - genkit@1.39.0: - resolution: {integrity: sha512-Qz9ef/LfAEDMzO1+Nd6l6dMYK/V4ZfWDIp79rz/1V6xDM5VuJMkoqOTCDwXAviuAnjoO2noJug2wIK81ilMhWA==} + genkit@1.40.1: + resolution: {integrity: sha512-YzHnrHSkLwz2h90auI5ABAxITlrM/LHvbLfSBIqe61z7gCRbCmw5Xmm36goo4flM/Q5CJ972QwO22qdiezX6BA==} get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} @@ -1961,8 +2046,8 @@ packages: resolution: {integrity: sha512-7ABviyMOlX5hIVD60YOfHw4/CxOfBhyduaYB+wbFWCWoni4N7SLcV46hrVRktuBbZjFC9ONyqamZITN7q3n32w==} engines: {node: '>=18'} - google-auth-library@10.7.0: - resolution: {integrity: sha512-QpTAbNJ36TliZLx3TTtahR8HG0hN9RllL1e3FymOvQSIKK8JmgV58H924ub2wa2DsS3ANjjP1Aw1N+Ramc8hqQ==} + google-auth-library@10.9.1: + resolution: {integrity: sha512-i1ydyHrqcIxXkWh/uBmVkzCvIuq5yiK2ATndIe5XxKholrG/MTYP9xGYka4sQhrbIAgGjL2B6NOE7rFaiF3fXw==} engines: {node: '>=18'} google-auth-library@9.15.1: @@ -1973,8 +2058,8 @@ packages: resolution: {integrity: sha512-V6eky/xz2mcKfAd1Ioxyd6nmA61gao3n01C+YeuIwu3vzM9EDR6wcVzMSIbLMDXWeoi9SHYctXuKYC5uJUT3eQ==} engines: {node: '>=14'} - google-gax@5.0.7: - resolution: {integrity: sha512-EhiqaWWJ+9h7sCcKJTsoo6tMcjokVHhWsbSuWCnZJT4vIBP3y4mAoFLnt9SzgkVZeq24ZsFaArr06nnYYku2yA==} + google-gax@5.0.8: + resolution: {integrity: sha512-M4vpZcXQIC1gqIVGQ7eaU3jXQA6zecStyTXu514TYfThlgSurYJOxHZo9fzU6hAgwPWvuEynAVHWyaIk80VeEA==} engines: {node: '>=18'} google-logging-utils@0.0.2: @@ -2022,8 +2107,8 @@ packages: resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} engines: {node: '>= 0.4'} - hono@4.12.28: - resolution: {integrity: sha512-YwUvVpSF7m1yOblFPrU3Hbo8XhPheBoiyfGuII6z19LnOr6JpDnyyp7LFNrfV56wS8tpvtBFGRISHN02pDdLOA==} + hono@4.12.32: + resolution: {integrity: sha512-XcuyW9qE2kJn07PkecMOBd5Vq/hMy7mmGw+idz1yblbg9N17ijJODrvPkn7/dwL3Kulj8LcRJ69DLOWf91dRUg==} engines: {node: '>=16.9.0'} html-entities@2.6.0: @@ -2082,8 +2167,8 @@ packages: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} - is-unsafe@1.0.1: - resolution: {integrity: sha512-CLK2+VdgERgD96EYm5lUQssZYlRg2tkZnbsxZoacmSiRxiFJ4Nk4SzjCl+Ur+v3kXIY9dTIdb3IH22y1mZ56LA==} + is-unsafe@2.0.0: + resolution: {integrity: sha512-2LdV822R+wmI86unXA93WCFpL6g+av8ynWk0nrHyJqGop5VoocYsSLFgN8jrfalT6iGeLNM4KXuVSsULP53kEA==} isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -2091,8 +2176,8 @@ packages: jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - jose@6.2.3: - resolution: {integrity: sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==} + jose@6.2.4: + resolution: {integrity: sha512-N8acGzVsQy6M/fjFcxtysNc4Q379TcM5dM/qKkNtsHFji88yANnXTr7BLeP75iPnFwBfQzM/jg2BZ9+HZrHCZA==} js-tiktoken@1.0.21: resolution: {integrity: sha512-biOj/6M5qdgx5TKjDnFT1ymSpM5tbd3ylwDtrQvFQSu0Z7bBYko2dF+W/aUkXUPuk6IVpRxk/3Q2sHOzGlS36g==} @@ -2145,8 +2230,8 @@ packages: kuler@2.0.0: resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==} - langsmith@0.7.10: - resolution: {integrity: sha512-3EjJx9zGMzqF60eT9JADHF+Hn/T5ayTgEVp4d3M5yvJIJi3q6seX0p5jT8ecBCWBi1kIvvssWrcDxfwgSier7Q==} + langsmith@0.8.7: + resolution: {integrity: sha512-QWcc7JwmGy+sPRJwqCf9xLiiSIhwc/i7oVwjQezkx6UzyFlokME3Wxy80qKqirTyJvWG1S9ylqtxBDpFRpas5g==} peerDependencies: '@opentelemetry/api': '*' '@opentelemetry/exporter-trace-otlp-proto': '*' @@ -2165,132 +2250,128 @@ packages: ws: optional: true - lefthook-darwin-arm64@2.1.9: - resolution: {integrity: sha512-119HryNcvr4nqn0wUIrNPgpMEPn9yMQzEcW/lezRsnb56PCJriJB92+MCySPVcWDxJnZef7o0T3jdnPNiSH7Qg==} + lefthook-darwin-arm64@2.1.10: + resolution: {integrity: sha512-nw+X8wRNDoUUV6WSteyKBbcLySq+fsmZt5WV/s50ZJpysmsDKJOUMln6SllNfP+60dzUahAO7REco/2633BsLg==} cpu: [arm64] os: [darwin] - lefthook-darwin-x64@2.1.9: - resolution: {integrity: sha512-dwo5Tke2XcQCM56DGHgFKBfRbJIL6xs2wZ0zG1TUVZgl4t4mQUt6LiZ4V/ZQfYHTZF9qywvXoIlR5N35qOaiVQ==} + lefthook-darwin-x64@2.1.10: + resolution: {integrity: sha512-KQ/bHmvpkFdHMn4pZnUdTf+GuSC+aBBgBTxZT4GW+6cSf+qbErKZBhK7cH6BmILsvx43+VzEArvHYY7YOfRFOQ==} cpu: [x64] os: [darwin] - lefthook-freebsd-arm64@2.1.9: - resolution: {integrity: sha512-+09PVap6nl6xsaHch5JLtq7WvIR++U1Q2MzA2ai0M4uB/VP3AqrvKqHw6+9hjyKnIH+HHL83uqi77EAY+LaxLA==} + lefthook-freebsd-arm64@2.1.10: + resolution: {integrity: sha512-8su6DwydP7+pv7kG0zCtjphqsw4ouOnfexRUErapy5GTxYBoUOhYz3RSHTSWNRsK6W4jva7FPUh2Lp5/PSn30w==} cpu: [arm64] os: [freebsd] - lefthook-freebsd-x64@2.1.9: - resolution: {integrity: sha512-8XresjKIYpkE9ARgCtBEZgJZxAU3T4MIqzj4zNy15XRT59I1Us+QdqXTNm+pkZ41Yd2X/nxs2Pkvbq3NWWlIGw==} + lefthook-freebsd-x64@2.1.10: + resolution: {integrity: sha512-GeAJEFxko3Lk+AsnS3NleAFrpyMLFUKOlgJvPKuU0xHwVEI/z+ZoCcmuO0BX+4CS0NLbZhC/YQAvBASqDvvVdQ==} cpu: [x64] os: [freebsd] - lefthook-linux-arm64@2.1.9: - resolution: {integrity: sha512-1oNIQfwrPe6rgU2KcDM3aF6+hpZDCKx1TmawQKpXUY5gVsbZ7MqX0Sk/1lnnWxqPm+kQQ5f6J2dpFWd+4xH8jg==} + lefthook-linux-arm64@2.1.10: + resolution: {integrity: sha512-1sHTCmpTWjVMs+yKPBLRNT1kuuIr1yjietlk7rCB6wFPVOS6Ph3o2zPFH2AvW1UymHlqwyHXzBr9EtDpQ7j1mQ==} cpu: [arm64] os: [linux] - lefthook-linux-x64@2.1.9: - resolution: {integrity: sha512-fT+7Q+BJyGp+CslFQkNXmdFRgyVXsPHPi9NAsDX0a6QOyNnoORByAsvx6zeAKuF5rL3BBgNfho1/v2RuGxGy9w==} + lefthook-linux-x64@2.1.10: + resolution: {integrity: sha512-z/VlRB3bh6mBvW3r1rwnJ5vP8z+Krx5gJzkZ4veDXh+6FlRTx8wtd3g3fllOv/yZMxkgmL3fQoFXv05Esa7vBQ==} cpu: [x64] os: [linux] - lefthook-openbsd-arm64@2.1.9: - resolution: {integrity: sha512-4bVuafBk3dddVNo0+3hMbjcJs4mqYAstxpPMmX2ufkudSTYFNIhWoqwuGVQV/SS/xdcOKJAldW4qayAzed2ysw==} + lefthook-openbsd-arm64@2.1.10: + resolution: {integrity: sha512-430zL8sSIKw5P0YXGG6PB+eAhHa06n0PXuaERaAQE4Ss3odfqwnl5Mq9hQmkEnOS1EGiQEKkd0UHv/i4PtMNIQ==} cpu: [arm64] os: [openbsd] - lefthook-openbsd-x64@2.1.9: - resolution: {integrity: sha512-PmPoMmLP/wQQWcQ9u2YH86bTZ3UCfBsxuEmVTEyPU2U8R1qSTp5r/Gs3G8cN5Mxo91XB9oBERtF1n+xD3W6aVA==} + lefthook-openbsd-x64@2.1.10: + resolution: {integrity: sha512-bgkO8PphGZVDhQgCJ524aYYPI5491pVmCiLPGjBIo1AvOSlIyw4N1Y+1C3QfqwEmechzw+Aq16SNc8pqv6UuXg==} cpu: [x64] os: [openbsd] - lefthook-windows-arm64@2.1.9: - resolution: {integrity: sha512-KphfkBKmwBnmolyrdhIl3lrBaOyTcCgXBT2AB/9OHnEXhOLvv5uTCUkrD4YRAxXPtFKq6UvnapIeoL3GZq0bdA==} + lefthook-windows-arm64@2.1.10: + resolution: {integrity: sha512-5Q6etF0Fla2DDA4ilDySrdNgiR5+W7cJZwnZ69Je3kvWCaWm4wnkuc8FEdjp3kiL2x3ZXipdI00f5vpO8aWmog==} cpu: [arm64] os: [win32] - lefthook-windows-x64@2.1.9: - resolution: {integrity: sha512-2qlUtkJHZ3MyUxgV5XTEmcrIoNZA07iwaquoswAcqv/1MeBFXlD+O+koFRfrzWng2O5WYEbpJnd8tvaYnV8fTA==} + lefthook-windows-x64@2.1.10: + resolution: {integrity: sha512-c/XH8YZtylG4XaxzqFfXluvq2LXq2W/p54Bnzn3+Z7E5X2Fk3JlFJAibulMbIt2+w8T7UI/r97ok5GqE4kGaeA==} cpu: [x64] os: [win32] - lefthook@2.1.9: - resolution: {integrity: sha512-bwDaIOViTktE8kJLf9jP0p+H2/RDTlFFlc43Am2YgUsX22hI6Sq4RbzsrecwzY5y+MHTipOH7WsmWSEniePHWQ==} + lefthook@2.1.10: + resolution: {integrity: sha512-K7mM4WoqMwqfXYK11EHy+lSH1uW8XHni3Yn/bSqyerPkUPygGdf3xn18JoV5HyA06xuQL3ofGAOjG01QX9oJ4w==} hasBin: true - lightningcss-android-arm64@1.32.0: - resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + lightningcss-android-arm64@1.33.0: + resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [android] - lightningcss-darwin-arm64@1.32.0: - resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + lightningcss-darwin-arm64@1.33.0: + resolution: {integrity: sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] - lightningcss-darwin-x64@1.32.0: - resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + lightningcss-darwin-x64@1.33.0: + resolution: {integrity: sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] - lightningcss-freebsd-x64@1.32.0: - resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + lightningcss-freebsd-x64@1.33.0: + resolution: {integrity: sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] - lightningcss-linux-arm-gnueabihf@1.32.0: - resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + lightningcss-linux-arm-gnueabihf@1.33.0: + resolution: {integrity: sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] - lightningcss-linux-arm64-gnu@1.32.0: - resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + lightningcss-linux-arm64-gnu@1.33.0: + resolution: {integrity: sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [glibc] - lightningcss-linux-arm64-musl@1.32.0: - resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + lightningcss-linux-arm64-musl@1.33.0: + resolution: {integrity: sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - libc: [musl] - lightningcss-linux-x64-gnu@1.32.0: - resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + lightningcss-linux-x64-gnu@1.33.0: + resolution: {integrity: sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [glibc] - lightningcss-linux-x64-musl@1.32.0: - resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + lightningcss-linux-x64-musl@1.33.0: + resolution: {integrity: sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - libc: [musl] - lightningcss-win32-arm64-msvc@1.32.0: - resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + lightningcss-win32-arm64-msvc@1.33.0: + resolution: {integrity: sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] - lightningcss-win32-x64-msvc@1.32.0: - resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + lightningcss-win32-x64-msvc@1.33.0: + resolution: {integrity: sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] - lightningcss@1.32.0: - resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + lightningcss@1.33.0: + resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==} engines: {node: '>= 12.0.0'} limiter@1.1.5: @@ -2339,8 +2420,8 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - lru-cache@11.5.1: - resolution: {integrity: sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==} + lru-cache@11.5.2: + resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==} engines: {node: 20 || >=22} lru-memoizer@3.0.0: @@ -2382,8 +2463,8 @@ packages: engines: {node: '>=10.0.0'} hasBin: true - miniflare@4.20260706.0: - resolution: {integrity: sha512-UiqGo9Es/D7kJvDVpjhTQ/M2ppCSCsRc5EEKec6i4BvnCkFCRaZHRmFkMHzLhlg+daSZ+zvBaycWmgLZHn/1tQ==} + miniflare@4.20260722.0: + resolution: {integrity: sha512-LW6ABMhCx/yIEFBLC/DO4yAhdm2T/G7jp7pr5T2kj895+CCIaHZqpMXdW9O6YE48LcYcCJChwWc8aEs1vpbTXw==} engines: {node: '>=22.0.0'} hasBin: true @@ -2411,8 +2492,8 @@ packages: resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} hasBin: true - nanoid@3.3.14: - resolution: {integrity: sha512-U9kYi5bpVMEI31yC8iw4bJJp0avcHXA0W8/wNfLfnvJYzihQo2ZRPYPvpAAd570HAcCBjCTN7vnr+v4StKl1IQ==} + nanoid@3.3.16: + resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true @@ -2453,8 +2534,8 @@ packages: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} - obug@2.1.3: - resolution: {integrity: sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==} + obug@2.1.4: + resolution: {integrity: sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==} engines: {node: '>=12.20.0'} on-finished@2.4.1: @@ -2467,8 +2548,8 @@ packages: one-time@1.0.0: resolution: {integrity: sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==} - openai@6.45.0: - resolution: {integrity: sha512-5DQVNErssk0afNpTTHUm/qZPU4iKR9OYdNid8Ib4puq4gHNNvGWZht2zY4h9a8JMF949Ik6m8gQutllVPbjdnw==} + openai@6.49.0: + resolution: {integrity: sha512-aYCc0C6L864eR6WSYIwQGyXriw/nIyZx0ObvhzOEVuk0zoBDpynjSbrionWI7q65B5H8jJX0DXR9snEzM6bfPg==} peerDependencies: '@aws-sdk/credential-provider-node': '>=3.972.0 <4' '@smithy/hash-node': '>=4.3.0 <5' @@ -2517,8 +2598,8 @@ packages: partial-json@0.1.7: resolution: {integrity: sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==} - path-expression-matcher@1.6.0: - resolution: {integrity: sha512-e5y7RCLHKjemsgQ4eqGJtPyr10ILz25HO7flzxhTV8bgvd5yHx98DGtCAtbVW9f2TqnYI/gEVZd+vz7snrdPTw==} + path-expression-matcher@1.6.2: + resolution: {integrity: sha512-enSlaiat05iasnzmgNxRj8reFdj3puY2QpNgP1aPIaVfT6nn9ICuPoFlKHk8EN22HcwewshO+mN2DGbkCEOtqQ==} engines: {node: '>=14.0.0'} path-key@3.1.1: @@ -2555,12 +2636,12 @@ packages: picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - picomatch@4.0.4: - resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + picomatch@4.0.5: + resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} engines: {node: '>=12'} - postcss@8.5.15: - resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} + postcss@8.5.23: + resolution: {integrity: sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==} engines: {node: ^10 || ^12 || >=14} postgres-array@2.0.0: @@ -2587,8 +2668,8 @@ packages: resolution: {integrity: sha512-E1sbAYg3aEbXrq0n1ojJkRHQJGE1kaE/O6GLA94y8rnJBfgvOPTOd1b9hOceQK1FFZI9qMh1vBERCyO2ifubcw==} engines: {node: '>=18'} - protobufjs@7.6.4: - resolution: {integrity: sha512-RJJPTTpvFfHcWLkIa2JFWK4XvtSzS0yEWDmunqHXli1h3JlkbcQZXDZdcWxv+JK3Xsl5/UFDPZ0iGm7DAengYw==} + protobufjs@7.6.5: + resolution: {integrity: sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw==} engines: {node: '>=12.0.0'} proxy-addr@2.0.7: @@ -2601,8 +2682,8 @@ packages: pumpify@2.0.1: resolution: {integrity: sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==} - qs@6.15.2: - resolution: {integrity: sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==} + qs@6.15.3: + resolution: {integrity: sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==} engines: {node: '>=0.6'} range-parser@1.2.1: @@ -2638,8 +2719,8 @@ packages: resolution: {integrity: sha512-dUOvLMJ0/JJYEn8NrpOaGNE7X3vpI5XlZS/u0ANjqtcZVKnIxP7IgCFwrKTxENw29emmwug53awKtaMm4i9g5w==} engines: {node: '>=14'} - retry-request@8.0.3: - resolution: {integrity: sha512-qqoc4kkGgP9cmQDWELlOpAmfgJOg0Yi7MT82ZjiPWu451ayju4itwomjM4/dBEliify8C1b3tSaeCOldugtwPQ==} + retry-request@8.0.4: + resolution: {integrity: sha512-pI6/7eabUYkZxamkOq0g0uMxKLLGnjzhefY+vL8bVXag5rto4OU2YBTPytWLuHH7aEKD6fn7kJycQfid0Mwnkw==} engines: {node: '>=18'} retry@0.13.1: @@ -2650,8 +2731,8 @@ packages: resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==} hasBin: true - rolldown@1.0.3: - resolution: {integrity: sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==} + rolldown@1.1.5: + resolution: {integrity: sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -2665,8 +2746,8 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - semver@7.8.4: - resolution: {integrity: sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==} + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} engines: {node: '>=10'} hasBin: true @@ -2681,9 +2762,9 @@ packages: setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - sharp@0.34.5: - resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + sharp@0.35.2: + resolution: {integrity: sha512-FVtFjtBCMiJS6yb5CX7Sop45WFMpeGw6oRKuJnXYgf/f1ms/D7LE/ZUSNxnW7rZ/dbslQWYkoqFHGPaDBtaK4w==} + engines: {node: '>=20.9.0'} shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} @@ -2740,8 +2821,8 @@ packages: resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} engines: {node: '>= 0.8'} - std-env@4.1.0: - resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} + std-env@4.2.0: + resolution: {integrity: sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==} stream-events@1.0.5: resolution: {integrity: sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==} @@ -2792,8 +2873,8 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - teeny-request@10.1.3: - resolution: {integrity: sha512-5yDliI1uWkYPo7W+Zvrxg6YmoWuj5iC5EydewqrRTvc68nyMTZhlPPlLg6cptUGfbQAb+N9XDPDPzF6N081lug==} + teeny-request@10.1.4: + resolution: {integrity: sha512-R1Cg4Vu0UULeDfHL/kjABLaTW++9yD/B6n2g48y5dJ04hsEaxcfmAqbNDzNsbqAYJyIpZafjklLG9YxRu9uzOg==} engines: {node: '>=18'} teeny-request@9.0.0: @@ -2839,9 +2920,9 @@ packages: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} - typescript@6.0.3: - resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} - engines: {node: '>=14.17'} + typescript@7.0.2: + resolution: {integrity: sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==} + engines: {node: '>=16.20.0'} hasBin: true uglify-js@3.19.3: @@ -2852,8 +2933,8 @@ packages: undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - undici-types@7.24.6: - resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} + undici-types@8.3.0: + resolution: {integrity: sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==} undici@7.28.0: resolution: {integrity: sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==} @@ -2884,11 +2965,6 @@ packages: deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). hasBin: true - uuid@8.3.2: - resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} - deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). - hasBin: true - uuid@9.0.1: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). @@ -2898,13 +2974,13 @@ packages: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} - vite@8.0.16: - resolution: {integrity: sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==} + vite@8.1.5: + resolution: {integrity: sha512-7ULLwsCdYx/nRyrpiEwvqb5TFHrMVZyBt+rg/OAXT7rgj/z+DtTDyKFeLAdDkubDVDKD8jOsndmy7m55XcfUsw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: '@types/node': ^20.19.0 || >=22.12.0 - '@vitejs/devtools': ^0.1.18 + '@vitejs/devtools': ^0.3.0 esbuild: ^0.27.0 || ^0.28.0 jiti: '>=1.21.0' less: ^4.0.0 @@ -3022,17 +3098,17 @@ packages: wordwrap@1.0.0: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - workerd@1.20260706.1: - resolution: {integrity: sha512-0DOmgysJiPZRwtlg9Bh70aDnHuVech70fKVM4721RbdfewL29ODxn4TpgkusybLYrQAkgHkW53SUt2AdkBa+Og==} + workerd@1.20260722.1: + resolution: {integrity: sha512-NycKuc1x2onvsRfGGpM093vRlLFU2zHDAM0+APpccfg4+gZxDGCH27RmdDvkeBuoZyYqgLo3oAfF6re4mvC3vQ==} engines: {node: '>=16'} hasBin: true - wrangler@4.108.0: - resolution: {integrity: sha512-mJnY6vf2Tminfo0Jy5OreBgUjIKW3iM1TQtOrZZRpFUyiQvAYUDVN0aRcDn8/aEfF0bmZgcixRdwwVHZMZaE7w==} + wrangler@4.114.0: + resolution: {integrity: sha512-M65P25t5UHA1TIJfgZXDcj+YzVobgKdRguM2QPz0xnxLFuOcuE3ErgllDht0iaho7MS4o0g/Bb4YK2+GT+bibg==} engines: {node: '>=22.0.0'} hasBin: true peerDependencies: - '@cloudflare/workers-types': ^5.20260706.1 + '@cloudflare/workers-types': ^5.20260722.1 peerDependenciesMeta: '@cloudflare/workers-types': optional: true @@ -3065,8 +3141,20 @@ packages: utf-8-validate: optional: true - xml-naming@0.1.0: - resolution: {integrity: sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==} + ws@8.21.1: + resolution: {integrity: sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + xml-naming@0.3.0: + resolution: {integrity: sha512-ghig2TBE/H11aOVgmahA3MhimvkBr6JIYknH/Dhdk10nXwdbIqBJsbfMxpvFPG8bAw77gN29aQWvKpmVoPlvPQ==} engines: {node: '>=16.0.0'} xtend@4.0.2: @@ -3113,50 +3201,44 @@ packages: snapshots: - '@ai-sdk/anthropic@4.0.9(zod@4.4.3)': + '@ai-sdk/anthropic@4.0.20(zod@4.4.3)': dependencies: - '@ai-sdk/provider': 4.0.2 - '@ai-sdk/provider-utils': 5.0.5(zod@4.4.3) + '@ai-sdk/provider': 4.0.3 + '@ai-sdk/provider-utils': 5.0.12(zod@4.4.3) zod: 4.4.3 - '@ai-sdk/gateway@4.0.13(zod@4.4.3)': + '@ai-sdk/gateway@4.0.28(zod@4.4.3)': dependencies: - '@ai-sdk/provider': 4.0.2 - '@ai-sdk/provider-utils': 5.0.5(zod@4.4.3) + '@ai-sdk/provider': 4.0.3 + '@ai-sdk/provider-utils': 5.0.12(zod@4.4.3) '@vercel/oidc': 3.2.0 zod: 4.4.3 - '@ai-sdk/google@4.0.9(zod@4.4.3)': + '@ai-sdk/google@4.0.24(zod@4.4.3)': dependencies: - '@ai-sdk/provider': 4.0.2 - '@ai-sdk/provider-utils': 5.0.5(zod@4.4.3) + '@ai-sdk/provider': 4.0.3 + '@ai-sdk/provider-utils': 5.0.12(zod@4.4.3) zod: 4.4.3 - '@ai-sdk/openai@4.0.8(zod@4.4.3)': + '@ai-sdk/openai@4.0.20(zod@4.4.3)': dependencies: - '@ai-sdk/provider': 4.0.2 - '@ai-sdk/provider-utils': 5.0.5(zod@4.4.3) + '@ai-sdk/provider': 4.0.3 + '@ai-sdk/provider-utils': 5.0.12(zod@4.4.3) zod: 4.4.3 - '@ai-sdk/provider-utils@5.0.5(zod@4.4.3)': + '@ai-sdk/provider-utils@5.0.12(zod@4.4.3)': dependencies: - '@ai-sdk/provider': 4.0.2 + '@ai-sdk/provider': 4.0.3 '@standard-schema/spec': 1.1.0 '@workflow/serde': 4.1.0 eventsource-parser: 3.1.0 zod: 4.4.3 - '@ai-sdk/provider@4.0.2': + '@ai-sdk/provider@4.0.3': dependencies: json-schema: 0.4.0 - '@anthropic-ai/sdk@0.103.0(zod@4.4.3)': - dependencies: - json-schema-to-ts: 3.1.1 - standardwebhooks: 1.0.0 - zod: 4.4.3 - - '@anthropic-ai/sdk@0.110.0(zod@4.4.3)': + '@anthropic-ai/sdk@0.115.0(zod@4.4.3)': dependencies: json-schema-to-ts: 3.1.1 standardwebhooks: 1.0.0 @@ -3164,80 +3246,80 @@ snapshots: '@babel/runtime@7.29.7': {} - '@biomejs/biome@2.5.3': + '@biomejs/biome@2.5.5': optionalDependencies: - '@biomejs/cli-darwin-arm64': 2.5.3 - '@biomejs/cli-darwin-x64': 2.5.3 - '@biomejs/cli-linux-arm64': 2.5.3 - '@biomejs/cli-linux-arm64-musl': 2.5.3 - '@biomejs/cli-linux-x64': 2.5.3 - '@biomejs/cli-linux-x64-musl': 2.5.3 - '@biomejs/cli-win32-arm64': 2.5.3 - '@biomejs/cli-win32-x64': 2.5.3 + '@biomejs/cli-darwin-arm64': 2.5.5 + '@biomejs/cli-darwin-x64': 2.5.5 + '@biomejs/cli-linux-arm64': 2.5.5 + '@biomejs/cli-linux-arm64-musl': 2.5.5 + '@biomejs/cli-linux-x64': 2.5.5 + '@biomejs/cli-linux-x64-musl': 2.5.5 + '@biomejs/cli-win32-arm64': 2.5.5 + '@biomejs/cli-win32-x64': 2.5.5 - '@biomejs/cli-darwin-arm64@2.5.3': + '@biomejs/cli-darwin-arm64@2.5.5': optional: true - '@biomejs/cli-darwin-x64@2.5.3': + '@biomejs/cli-darwin-x64@2.5.5': optional: true - '@biomejs/cli-linux-arm64-musl@2.5.3': + '@biomejs/cli-linux-arm64-musl@2.5.5': optional: true - '@biomejs/cli-linux-arm64@2.5.3': + '@biomejs/cli-linux-arm64@2.5.5': optional: true - '@biomejs/cli-linux-x64-musl@2.5.3': + '@biomejs/cli-linux-x64-musl@2.5.5': optional: true - '@biomejs/cli-linux-x64@2.5.3': + '@biomejs/cli-linux-x64@2.5.5': optional: true - '@biomejs/cli-win32-arm64@2.5.3': + '@biomejs/cli-win32-arm64@2.5.5': optional: true - '@biomejs/cli-win32-x64@2.5.3': + '@biomejs/cli-win32-x64@2.5.5': optional: true '@cfworker/json-schema@4.1.1': {} '@cloudflare/kv-asset-handler@0.5.0': {} - '@cloudflare/unenv-preset@2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260706.1)': + '@cloudflare/unenv-preset@2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260722.1)': dependencies: unenv: 2.0.0-rc.24 - workerd: 1.20260706.1 + workerd: 1.20260722.1 - '@cloudflare/vitest-pool-workers@0.18.2(@cloudflare/workers-types@5.20260708.1)(@vitest/runner@4.1.9)(@vitest/snapshot@4.1.9)(vitest@4.1.10(@opentelemetry/api@1.9.1)(@types/node@25.9.3)(vite@8.0.16(@types/node@25.9.3)))': + '@cloudflare/vitest-pool-workers@0.18.8(@cloudflare/workers-types@5.20260724.1)(@vitest/runner@4.1.10)(@vitest/snapshot@4.1.10)(vitest@4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(vite@8.1.5(@types/node@26.1.1)))': dependencies: - '@vitest/runner': 4.1.9 - '@vitest/snapshot': 4.1.9 + '@vitest/runner': 4.1.10 + '@vitest/snapshot': 4.1.10 cjs-module-lexer: 1.2.3 esbuild: 0.28.1 - miniflare: 4.20260706.0 - vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@25.9.3)(esbuild@0.28.1)(vite@8.0.16(@types/node@25.9.3)) - wrangler: 4.108.0(@cloudflare/workers-types@5.20260708.1) + miniflare: 4.20260722.0 + vitest: 4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(esbuild@0.28.1)(vite@8.1.5(@types/node@26.1.1)) + wrangler: 4.114.0(@cloudflare/workers-types@5.20260724.1) zod: 3.25.76 transitivePeerDependencies: - bufferutil - utf-8-validate - '@cloudflare/workerd-darwin-64@1.20260706.1': + '@cloudflare/workerd-darwin-64@1.20260722.1': optional: true - '@cloudflare/workerd-darwin-arm64@1.20260706.1': + '@cloudflare/workerd-darwin-arm64@1.20260722.1': optional: true - '@cloudflare/workerd-linux-64@1.20260706.1': + '@cloudflare/workerd-linux-64@1.20260722.1': optional: true - '@cloudflare/workerd-linux-arm64@1.20260706.1': + '@cloudflare/workerd-linux-arm64@1.20260722.1': optional: true - '@cloudflare/workerd-windows-64@1.20260706.1': + '@cloudflare/workerd-windows-64@1.20260722.1': optional: true - '@cloudflare/workers-types@5.20260708.1': {} + '@cloudflare/workers-types@5.20260724.1': {} '@colors/colors@1.6.0': optional: true @@ -3253,14 +3335,9 @@ snapshots: kuler: 2.0.0 optional: true - '@emnapi/core@1.10.0': - dependencies: - '@emnapi/wasi-threads': 1.2.1 - tslib: 2.8.1 - optional: true - - '@emnapi/runtime@1.10.0': + '@emnapi/core@1.11.1': dependencies: + '@emnapi/wasi-threads': 1.2.2 tslib: 2.8.1 optional: true @@ -3269,7 +3346,7 @@ snapshots: tslib: 2.8.1 optional: true - '@emnapi/wasi-threads@1.2.1': + '@emnapi/wasi-threads@1.2.2': dependencies: tslib: 2.8.1 optional: true @@ -3409,9 +3486,9 @@ snapshots: tslib: 2.8.1 optional: true - '@genkit-ai/ai@1.39.0(@google-cloud/firestore@7.11.6)(firebase-admin@14.0.0)(genkit@1.39.0)': + '@genkit-ai/ai@1.40.1(@google-cloud/firestore@7.11.6)(firebase-admin@14.2.0)(genkit@1.40.1)': dependencies: - '@genkit-ai/core': 1.39.0(@google-cloud/firestore@7.11.6)(firebase-admin@14.0.0)(genkit@1.39.0) + '@genkit-ai/core': 1.40.1(@google-cloud/firestore@7.11.6)(firebase-admin@14.2.0)(genkit@1.40.1) '@opentelemetry/api': 1.9.1 '@types/node': 20.19.43 colorette: 2.0.20 @@ -3429,7 +3506,7 @@ snapshots: - supports-color - utf-8-validate - '@genkit-ai/core@1.39.0(@google-cloud/firestore@7.11.6)(firebase-admin@14.0.0)(genkit@1.39.0)': + '@genkit-ai/core@1.40.1(@google-cloud/firestore@7.11.6)(firebase-admin@14.2.0)(genkit@1.40.1)': dependencies: '@opentelemetry/api': 1.9.1 '@opentelemetry/api-logs': 0.52.1 @@ -3448,12 +3525,12 @@ snapshots: express: 4.22.2 get-port: 5.1.1 json-schema: 0.4.0 - ws: 8.21.0 + ws: 8.21.1 zod: 3.25.76 zod-to-json-schema: 3.25.2(zod@3.25.76) optionalDependencies: '@cfworker/json-schema': 4.1.1 - '@genkit-ai/firebase': 1.37.0(@google-cloud/firestore@7.11.6)(firebase-admin@14.0.0)(genkit@1.39.0) + '@genkit-ai/firebase': 1.40.1(@google-cloud/firestore@7.11.6)(firebase-admin@14.2.0)(genkit@1.40.1) transitivePeerDependencies: - bufferutil - encoding @@ -3461,19 +3538,20 @@ snapshots: - supports-color - utf-8-validate - '@genkit-ai/firebase@1.37.0(@google-cloud/firestore@7.11.6)(firebase-admin@14.0.0)(genkit@1.39.0)': + '@genkit-ai/firebase@1.40.1(@google-cloud/firestore@7.11.6)(firebase-admin@14.2.0)(genkit@1.40.1)': dependencies: - '@genkit-ai/google-cloud': 1.37.0(genkit@1.39.0) + '@genkit-ai/google-cloud': 1.40.1(genkit@1.40.1) '@google-cloud/firestore': 7.11.6 - firebase-admin: 14.0.0 - genkit: 1.39.0 + firebase-admin: 14.2.0 + genkit: 1.40.1 transitivePeerDependencies: - encoding - supports-color optional: true - '@genkit-ai/google-cloud@1.37.0(genkit@1.39.0)': + '@genkit-ai/google-cloud@1.40.1(genkit@1.40.1)': dependencies: + '@google-cloud/firestore': 7.11.6 '@google-cloud/logging-winston': 6.0.2(winston@3.19.0) '@google-cloud/modelarmor': 0.4.1 '@google-cloud/opentelemetry-cloud-monitoring-exporter': 0.19.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@1.25.1(@opentelemetry/api@1.9.1))(@opentelemetry/resources@1.25.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-metrics@1.25.1(@opentelemetry/api@1.9.1)) @@ -3489,7 +3567,7 @@ snapshots: '@opentelemetry/sdk-metrics': 1.25.1(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-node': 0.52.1(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-trace-base': 1.25.1(@opentelemetry/api@1.9.1) - genkit: 1.39.0 + genkit: 1.40.1 google-auth-library: 9.15.1 node-fetch: 3.3.2 winston: 3.19.0 @@ -3498,28 +3576,27 @@ snapshots: - supports-color optional: true - '@genkit-ai/google-genai@1.39.0(genkit@1.39.0)': + '@genkit-ai/google-genai@1.40.1(genkit@1.40.1)': dependencies: - genkit: 1.39.0 + genkit: 1.40.1 google-auth-library: 9.15.1 jsonpath-plus: 10.4.0 transitivePeerDependencies: - encoding - supports-color - '@google-cloud/common@5.0.2': + '@google-cloud/common@6.1.0': dependencies: '@google-cloud/projectify': 4.0.0 '@google-cloud/promisify': 4.0.0 arrify: 2.0.1 duplexify: 4.1.3 extend: 3.0.2 - google-auth-library: 9.15.1 + google-auth-library: 10.9.1 html-entities: 2.6.0 - retry-request: 7.0.2 - teeny-request: 9.0.0 + retry-request: 8.0.4 + teeny-request: 10.1.4 transitivePeerDependencies: - - encoding - supports-color optional: true @@ -3529,27 +3606,27 @@ snapshots: fast-deep-equal: 3.1.3 functional-red-black-tree: 1.0.1 google-gax: 4.6.1 - protobufjs: 7.6.4 + protobufjs: 7.6.5 transitivePeerDependencies: - encoding - supports-color optional: true - '@google-cloud/firestore@8.6.0': + '@google-cloud/firestore@8.7.0': dependencies: '@opentelemetry/api': 1.9.1 fast-deep-equal: 3.1.3 functional-red-black-tree: 1.0.1 - google-gax: 5.0.7 - protobufjs: 7.6.4 + google-gax: 5.0.8 + protobufjs: 7.6.5 transitivePeerDependencies: - supports-color optional: true '@google-cloud/logging-winston@6.0.2(winston@3.19.0)': dependencies: - '@google-cloud/logging': 11.2.3 - google-auth-library: 10.7.0 + '@google-cloud/logging': 11.3.0 + google-auth-library: 10.9.1 lodash.mapvalues: 4.6.0 winston: 3.19.0 winston-transport: 4.9.0 @@ -3558,9 +3635,9 @@ snapshots: - supports-color optional: true - '@google-cloud/logging@11.2.3': + '@google-cloud/logging@11.3.0': dependencies: - '@google-cloud/common': 5.0.2 + '@google-cloud/common': 6.1.0 '@google-cloud/paginator': 5.0.2 '@google-cloud/projectify': 4.0.0 '@google-cloud/promisify': 4.0.0 @@ -3568,10 +3645,9 @@ snapshots: '@opentelemetry/api': 1.9.1 arrify: 2.0.1 dot-prop: 6.0.1 - eventid: 2.0.1 extend: 3.0.2 gcp-metadata: 6.1.1 - google-auth-library: 9.15.1 + google-auth-library: 10.9.1 google-gax: 4.6.1 long: 5.3.2 on-finished: 2.4.1 @@ -3584,7 +3660,7 @@ snapshots: '@google-cloud/modelarmor@0.4.1': dependencies: - google-gax: 5.0.7 + google-gax: 5.0.8 transitivePeerDependencies: - supports-color optional: true @@ -3652,7 +3728,7 @@ snapshots: abort-controller: 3.0.0 async-retry: 1.3.3 duplexify: 4.1.3 - fast-xml-parser: 5.9.3 + fast-xml-parser: 5.10.1 gaxios: 6.7.1 google-auth-library: 9.15.1 html-entities: 2.6.0 @@ -3665,12 +3741,12 @@ snapshots: - supports-color optional: true - '@google/genai@2.10.0': + '@google/genai@2.13.0': dependencies: google-auth-library: 10.5.0 p-retry: 4.6.2 - protobufjs: 7.6.4 - ws: 8.21.0 + protobufjs: 7.6.5 + ws: 8.21.1 transitivePeerDependencies: - bufferutil - supports-color @@ -3687,7 +3763,7 @@ snapshots: dependencies: lodash.camelcase: 4.3.0 long: 5.3.2 - protobufjs: 7.6.4 + protobufjs: 7.6.5 yargs: 17.7.3 optional: true @@ -3695,103 +3771,113 @@ snapshots: dependencies: lodash.camelcase: 4.3.0 long: 5.3.2 - protobufjs: 7.6.4 + protobufjs: 7.6.5 yargs: 17.7.3 '@img/colour@1.1.0': {} - '@img/sharp-darwin-arm64@0.34.5': + '@img/sharp-darwin-arm64@0.35.2': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-arm64': 1.3.1 optional: true - '@img/sharp-darwin-x64@0.34.5': + '@img/sharp-darwin-x64@0.35.2': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.3.1 optional: true - '@img/sharp-libvips-darwin-arm64@1.2.4': + '@img/sharp-freebsd-wasm32@0.35.2': + dependencies: + '@img/sharp-wasm32': 0.35.2 optional: true - '@img/sharp-libvips-darwin-x64@1.2.4': + '@img/sharp-libvips-darwin-arm64@1.3.1': optional: true - '@img/sharp-libvips-linux-arm64@1.2.4': + '@img/sharp-libvips-darwin-x64@1.3.1': optional: true - '@img/sharp-libvips-linux-arm@1.2.4': + '@img/sharp-libvips-linux-arm64@1.3.1': optional: true - '@img/sharp-libvips-linux-ppc64@1.2.4': + '@img/sharp-libvips-linux-arm@1.3.1': optional: true - '@img/sharp-libvips-linux-riscv64@1.2.4': + '@img/sharp-libvips-linux-ppc64@1.3.1': optional: true - '@img/sharp-libvips-linux-s390x@1.2.4': + '@img/sharp-libvips-linux-riscv64@1.3.1': optional: true - '@img/sharp-libvips-linux-x64@1.2.4': + '@img/sharp-libvips-linux-s390x@1.3.1': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + '@img/sharp-libvips-linux-x64@1.3.1': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.2.4': + '@img/sharp-libvips-linuxmusl-arm64@1.3.1': optional: true - '@img/sharp-linux-arm64@0.34.5': + '@img/sharp-libvips-linuxmusl-x64@1.3.1': + optional: true + + '@img/sharp-linux-arm64@0.35.2': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.3.1 optional: true - '@img/sharp-linux-arm@0.34.5': + '@img/sharp-linux-arm@0.35.2': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.3.1 optional: true - '@img/sharp-linux-ppc64@0.34.5': + '@img/sharp-linux-ppc64@0.35.2': optionalDependencies: - '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.3.1 optional: true - '@img/sharp-linux-riscv64@0.34.5': + '@img/sharp-linux-riscv64@0.35.2': optionalDependencies: - '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.3.1 optional: true - '@img/sharp-linux-s390x@0.34.5': + '@img/sharp-linux-s390x@0.35.2': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.3.1 optional: true - '@img/sharp-linux-x64@0.34.5': + '@img/sharp-linux-x64@0.35.2': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.3.1 optional: true - '@img/sharp-linuxmusl-arm64@0.34.5': + '@img/sharp-linuxmusl-arm64@0.35.2': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.1 optional: true - '@img/sharp-linuxmusl-x64@0.34.5': + '@img/sharp-linuxmusl-x64@0.35.2': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.3.1 optional: true - '@img/sharp-wasm32@0.34.5': + '@img/sharp-wasm32@0.35.2': dependencies: '@emnapi/runtime': 1.11.1 optional: true - '@img/sharp-win32-arm64@0.34.5': + '@img/sharp-webcontainers-wasm32@0.35.2': + dependencies: + '@img/sharp-wasm32': 0.35.2 optional: true - '@img/sharp-win32-ia32@0.34.5': + '@img/sharp-win32-arm64@0.35.2': optional: true - '@img/sharp-win32-x64@0.34.5': + '@img/sharp-win32-ia32@0.35.2': + optional: true + + '@img/sharp-win32-x64@0.35.2': optional: true '@isaacs/cliui@8.0.2': @@ -3823,18 +3909,18 @@ snapshots: dependencies: jsep: 1.4.0 - '@langchain/anthropic@1.5.1(@langchain/core@1.2.1)(@opentelemetry/api@1.9.1)(openai@6.45.0(ws@8.21.0)(zod@4.4.3))(ws@8.21.0)': + '@langchain/anthropic@1.5.2(@langchain/core@1.2.3)(@opentelemetry/api@1.9.1)(openai@6.49.0(ws@8.21.1)(zod@4.4.3))(ws@8.21.1)': dependencies: - '@anthropic-ai/sdk': 0.103.0(zod@4.4.3) - '@langchain/core': 1.2.1(@opentelemetry/api@1.9.1)(openai@6.45.0(ws@8.21.0)(zod@4.4.3))(ws@8.21.0) + '@anthropic-ai/sdk': 0.115.0(zod@4.4.3) + '@langchain/core': 1.2.3(@opentelemetry/api@1.9.1)(openai@6.49.0(ws@8.21.1)(zod@4.4.3))(ws@8.21.1) zod: 4.4.3 - '@langchain/core@1.2.1(@opentelemetry/api@1.9.1)(openai@6.45.0(ws@8.21.0)(zod@4.4.3))(ws@8.21.0)': + '@langchain/core@1.2.3(@opentelemetry/api@1.9.1)(openai@6.49.0(ws@8.21.1)(zod@4.4.3))(ws@8.21.1)': dependencies: '@cfworker/json-schema': 4.1.1 '@standard-schema/spec': 1.1.0 js-tiktoken: 1.0.21 - langsmith: 0.7.10(@opentelemetry/api@1.9.1)(openai@6.45.0(ws@8.21.0)(zod@4.4.3))(ws@8.21.0) + langsmith: 0.8.7(@opentelemetry/api@1.9.1)(openai@6.49.0(ws@8.21.1)(zod@4.4.3))(ws@8.21.1) mustache: 4.2.0 p-queue: 6.6.2 zod: 4.4.3 @@ -3842,30 +3928,30 @@ snapshots: - '@opentelemetry/exporter-trace-otlp-proto' - '@opentelemetry/sdk-trace-base' - '@langchain/google-genai@2.2.0(@langchain/core@1.2.1)(@opentelemetry/api@1.9.1)(openai@6.45.0(ws@8.21.0)(zod@4.4.3))(ws@8.21.0)': + '@langchain/google-genai@2.2.0(@langchain/core@1.2.3)(@opentelemetry/api@1.9.1)(openai@6.49.0(ws@8.21.1)(zod@4.4.3))(ws@8.21.1)': dependencies: '@google/generative-ai': 0.24.1 - '@langchain/core': 1.2.1(@opentelemetry/api@1.9.1)(openai@6.45.0(ws@8.21.0)(zod@4.4.3))(ws@8.21.0) + '@langchain/core': 1.2.3(@opentelemetry/api@1.9.1)(openai@6.49.0(ws@8.21.1)(zod@4.4.3))(ws@8.21.1) - '@langchain/openai@1.5.3(@langchain/core@1.2.1)(@opentelemetry/api@1.9.1)(ws@8.21.0)': + '@langchain/openai@1.5.5(@langchain/core@1.2.3)(@opentelemetry/api@1.9.1)(ws@8.21.1)': dependencies: - '@langchain/core': 1.2.1(@opentelemetry/api@1.9.1)(openai@6.45.0(ws@8.21.0)(zod@4.4.3))(ws@8.21.0) + '@langchain/core': 1.2.3(@opentelemetry/api@1.9.1)(openai@6.49.0(ws@8.21.1)(zod@4.4.3))(ws@8.21.1) js-tiktoken: 1.0.21 - openai: 6.45.0(ws@8.21.0)(zod@4.4.3) + openai: 6.49.0(ws@8.21.1)(zod@4.4.3) zod: 4.4.3 transitivePeerDependencies: - '@aws-sdk/credential-provider-node' - '@smithy/hash-node' - '@smithy/signature-v4' - '@napi-rs/wasm-runtime@1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 - '@tybys/wasm-util': 0.10.2 + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 + '@tybys/wasm-util': 0.10.3 optional: true - '@nodable/entities@2.2.0': + '@nodable/entities@3.0.0': optional: true '@opentelemetry/api-logs@0.52.1': @@ -4064,7 +4150,7 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.1 '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.1) - semver: 7.8.4 + semver: 7.8.5 transitivePeerDependencies: - supports-color optional: true @@ -4139,7 +4225,7 @@ snapshots: '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.1) '@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.1) '@opentelemetry/semantic-conventions': 1.25.1 - semver: 7.8.4 + semver: 7.8.5 transitivePeerDependencies: - supports-color optional: true @@ -4363,7 +4449,7 @@ snapshots: '@types/shimmer': 1.2.0 import-in-the-middle: 1.15.0 require-in-the-middle: 7.5.2 - semver: 7.8.4 + semver: 7.8.5 shimmer: 1.2.1 transitivePeerDependencies: - supports-color @@ -4391,7 +4477,7 @@ snapshots: '@opentelemetry/sdk-logs': 0.52.1(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-metrics': 1.25.1(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-trace-base': 1.25.1(@opentelemetry/api@1.9.1) - protobufjs: 7.6.4 + protobufjs: 7.6.5 '@opentelemetry/propagation-utils@0.30.16(@opentelemetry/api@1.9.1)': dependencies: @@ -4421,7 +4507,7 @@ snapshots: '@opentelemetry/api': 1.9.1 '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) '@opentelemetry/resources': 1.25.1(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.41.1 + '@opentelemetry/semantic-conventions': 1.43.0 optional: true '@opentelemetry/resource-detector-aws@1.12.0(@opentelemetry/api@1.9.1)': @@ -4429,7 +4515,7 @@ snapshots: '@opentelemetry/api': 1.9.1 '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.1) '@opentelemetry/resources': 1.25.1(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.41.1 + '@opentelemetry/semantic-conventions': 1.43.0 optional: true '@opentelemetry/resource-detector-azure@0.2.12(@opentelemetry/api@1.9.1)': @@ -4437,7 +4523,7 @@ snapshots: '@opentelemetry/api': 1.9.1 '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.1) '@opentelemetry/resources': 1.25.1(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.41.1 + '@opentelemetry/semantic-conventions': 1.43.0 optional: true '@opentelemetry/resource-detector-container@0.4.4(@opentelemetry/api@1.9.1)': @@ -4445,7 +4531,7 @@ snapshots: '@opentelemetry/api': 1.9.1 '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) '@opentelemetry/resources': 1.25.1(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.41.1 + '@opentelemetry/semantic-conventions': 1.43.0 optional: true '@opentelemetry/resource-detector-gcp@0.29.13(@opentelemetry/api@1.9.1)': @@ -4453,7 +4539,7 @@ snapshots: '@opentelemetry/api': 1.9.1 '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.1) '@opentelemetry/resources': 1.25.1(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.41.1 + '@opentelemetry/semantic-conventions': 1.43.0 gcp-metadata: 6.1.1 transitivePeerDependencies: - encoding @@ -4514,14 +4600,14 @@ snapshots: '@opentelemetry/propagator-b3': 1.25.1(@opentelemetry/api@1.9.1) '@opentelemetry/propagator-jaeger': 1.25.1(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-trace-base': 1.25.1(@opentelemetry/api@1.9.1) - semver: 7.8.4 + semver: 7.8.5 '@opentelemetry/semantic-conventions@1.25.1': {} '@opentelemetry/semantic-conventions@1.28.0': optional: true - '@opentelemetry/semantic-conventions@1.41.1': + '@opentelemetry/semantic-conventions@1.43.0': optional: true '@opentelemetry/sql-common@0.40.1(@opentelemetry/api@1.9.1)': @@ -4530,7 +4616,7 @@ snapshots: '@opentelemetry/core': 1.25.1(@opentelemetry/api@1.9.1) optional: true - '@oxc-project/types@0.133.0': {} + '@oxc-project/types@0.139.0': {} '@pkgjs/parseargs@0.11.0': optional: true @@ -4565,55 +4651,55 @@ snapshots: '@protobufjs/pool@1.1.0': {} - '@protobufjs/utf8@1.1.1': {} + '@protobufjs/utf8@1.1.2': {} - '@rolldown/binding-android-arm64@1.0.3': + '@rolldown/binding-android-arm64@1.1.5': optional: true - '@rolldown/binding-darwin-arm64@1.0.3': + '@rolldown/binding-darwin-arm64@1.1.5': optional: true - '@rolldown/binding-darwin-x64@1.0.3': + '@rolldown/binding-darwin-x64@1.1.5': optional: true - '@rolldown/binding-freebsd-x64@1.0.3': + '@rolldown/binding-freebsd-x64@1.1.5': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.3': + '@rolldown/binding-linux-arm-gnueabihf@1.1.5': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.3': + '@rolldown/binding-linux-arm64-gnu@1.1.5': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.3': + '@rolldown/binding-linux-arm64-musl@1.1.5': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.0.3': + '@rolldown/binding-linux-ppc64-gnu@1.1.5': optional: true - '@rolldown/binding-linux-s390x-gnu@1.0.3': + '@rolldown/binding-linux-s390x-gnu@1.1.5': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.3': + '@rolldown/binding-linux-x64-gnu@1.1.5': optional: true - '@rolldown/binding-linux-x64-musl@1.0.3': + '@rolldown/binding-linux-x64-musl@1.1.5': optional: true - '@rolldown/binding-openharmony-arm64@1.0.3': + '@rolldown/binding-openharmony-arm64@1.1.5': optional: true - '@rolldown/binding-wasm32-wasi@1.0.3': + '@rolldown/binding-wasm32-wasi@1.1.5': dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 - '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.3': + '@rolldown/binding-win32-arm64-msvc@1.1.5': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.3': + '@rolldown/binding-win32-x64-msvc@1.1.5': optional: true '@rolldown/pluginutils@1.0.1': {} @@ -4635,7 +4721,7 @@ snapshots: '@tootallnate/once@2.0.1': optional: true - '@tybys/wasm-util@0.10.2': + '@tybys/wasm-util@0.10.3': dependencies: tslib: 2.8.1 optional: true @@ -4645,7 +4731,7 @@ snapshots: '@types/bunyan@1.8.9': dependencies: - '@types/node': 25.9.3 + '@types/node': 26.1.1 optional: true '@types/caseless@0.12.5': @@ -4658,7 +4744,7 @@ snapshots: '@types/connect@3.4.36': dependencies: - '@types/node': 25.9.3 + '@types/node': 26.1.1 optional: true '@types/deep-eql@4.0.2': {} @@ -4670,7 +4756,7 @@ snapshots: '@types/jsonwebtoken@9.0.10': dependencies: '@types/ms': 2.1.0 - '@types/node': 25.9.3 + '@types/node': 26.1.1 optional: true '@types/long@4.0.2': @@ -4678,7 +4764,7 @@ snapshots: '@types/memcached@2.2.10': dependencies: - '@types/node': 25.9.3 + '@types/node': 26.1.1 optional: true '@types/ms@2.1.0': @@ -4686,16 +4772,16 @@ snapshots: '@types/mysql@2.15.22': dependencies: - '@types/node': 25.9.3 + '@types/node': 26.1.1 optional: true '@types/node@20.19.43': dependencies: undici-types: 6.21.0 - '@types/node@25.9.3': + '@types/node@26.1.1': dependencies: - undici-types: 7.24.6 + undici-types: 8.3.0 '@types/pg-pool@2.0.4': dependencies: @@ -4704,7 +4790,7 @@ snapshots: '@types/pg@8.6.1': dependencies: - '@types/node': 25.9.3 + '@types/node': 26.1.1 pg-protocol: 1.15.0 pg-types: 2.2.0 optional: true @@ -4712,7 +4798,7 @@ snapshots: '@types/request@2.48.13': dependencies: '@types/caseless': 0.12.5 - '@types/node': 25.9.3 + '@types/node': 26.1.1 '@types/tough-cookie': 4.0.5 form-data: 2.5.6 optional: true @@ -4723,7 +4809,7 @@ snapshots: '@types/tedious@4.0.14': dependencies: - '@types/node': 25.9.3 + '@types/node': 26.1.1 optional: true '@types/tough-cookie@4.0.5': @@ -4736,6 +4822,66 @@ snapshots: dependencies: '@types/node': 20.19.43 + '@typescript/typescript-aix-ppc64@7.0.2': + optional: true + + '@typescript/typescript-darwin-arm64@7.0.2': + optional: true + + '@typescript/typescript-darwin-x64@7.0.2': + optional: true + + '@typescript/typescript-freebsd-arm64@7.0.2': + optional: true + + '@typescript/typescript-freebsd-x64@7.0.2': + optional: true + + '@typescript/typescript-linux-arm64@7.0.2': + optional: true + + '@typescript/typescript-linux-arm@7.0.2': + optional: true + + '@typescript/typescript-linux-loong64@7.0.2': + optional: true + + '@typescript/typescript-linux-mips64el@7.0.2': + optional: true + + '@typescript/typescript-linux-ppc64@7.0.2': + optional: true + + '@typescript/typescript-linux-riscv64@7.0.2': + optional: true + + '@typescript/typescript-linux-s390x@7.0.2': + optional: true + + '@typescript/typescript-linux-x64@7.0.2': + optional: true + + '@typescript/typescript-netbsd-arm64@7.0.2': + optional: true + + '@typescript/typescript-netbsd-x64@7.0.2': + optional: true + + '@typescript/typescript-openbsd-arm64@7.0.2': + optional: true + + '@typescript/typescript-openbsd-x64@7.0.2': + optional: true + + '@typescript/typescript-sunos-x64@7.0.2': + optional: true + + '@typescript/typescript-win32-arm64@7.0.2': + optional: true + + '@typescript/typescript-win32-x64@7.0.2': + optional: true + '@vercel/oidc@3.2.0': {} '@vitest/expect@4.1.10': @@ -4747,31 +4893,22 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.10(esbuild@0.28.1)(vite@8.0.16(@types/node@25.9.3))': + '@vitest/mocker@4.1.10(esbuild@0.28.1)(vite@8.1.5(@types/node@26.1.1))': dependencies: '@vitest/spy': 4.1.10 estree-walker: 3.0.3 magic-string: 0.30.21 - vite: 8.0.16(@types/node@25.9.3)(esbuild@0.28.1) + vite: 8.1.5(@types/node@26.1.1)(esbuild@0.28.1) '@vitest/pretty-format@4.1.10': dependencies: tinyrainbow: 3.1.0 - '@vitest/pretty-format@4.1.9': - dependencies: - tinyrainbow: 3.1.0 - '@vitest/runner@4.1.10': dependencies: '@vitest/utils': 4.1.10 pathe: 2.0.3 - '@vitest/runner@4.1.9': - dependencies: - '@vitest/utils': 4.1.9 - pathe: 2.0.3 - '@vitest/snapshot@4.1.10': dependencies: '@vitest/pretty-format': 4.1.10 @@ -4779,13 +4916,6 @@ snapshots: magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/snapshot@4.1.9': - dependencies: - '@vitest/pretty-format': 4.1.9 - '@vitest/utils': 4.1.9 - magic-string: 0.30.21 - pathe: 2.0.3 - '@vitest/spy@4.1.10': {} '@vitest/utils@4.1.10': @@ -4794,12 +4924,6 @@ snapshots: convert-source-map: 2.0.0 tinyrainbow: 3.1.0 - '@vitest/utils@4.1.9': - dependencies: - '@vitest/pretty-format': 4.1.9 - convert-source-map: 2.0.0 - tinyrainbow: 3.1.0 - '@workflow/serde@4.1.0': {} abort-controller@3.0.0: @@ -4827,11 +4951,11 @@ snapshots: agent-base@7.1.4: {} - ai@7.0.17(zod@4.4.3): + ai@7.0.37(zod@4.4.3): dependencies: - '@ai-sdk/gateway': 4.0.13(zod@4.4.3) - '@ai-sdk/provider': 4.0.2 - '@ai-sdk/provider-utils': 5.0.5(zod@4.4.3) + '@ai-sdk/gateway': 4.0.28(zod@4.4.3) + '@ai-sdk/provider': 4.0.3 + '@ai-sdk/provider-utils': 5.0.12(zod@4.4.3) zod: 4.4.3 ajv-formats@3.0.1(ajv@8.20.0): @@ -4841,7 +4965,7 @@ snapshots: ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.2 + fast-uri: 3.1.4 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 @@ -4891,7 +5015,7 @@ snapshots: blake3-wasm@2.1.5: {} - body-parser@1.20.5: + body-parser@1.20.6: dependencies: bytes: 3.1.2 content-type: 1.0.5 @@ -4901,12 +5025,12 @@ snapshots: http-errors: 2.0.1 iconv-lite: 0.4.24 on-finished: 2.4.1 - qs: 6.15.2 + qs: 6.15.3 raw-body: 2.5.3 type-is: 1.6.18 unpipe: 1.0.0 - brace-expansion@2.1.1: + brace-expansion@2.1.2: dependencies: balanced-match: 1.0.2 optional: true @@ -4941,17 +5065,17 @@ snapshots: color-convert@3.1.3: dependencies: - color-name: 2.1.0 + color-name: 2.1.1 optional: true color-name@1.1.4: {} - color-name@2.1.0: + color-name@2.1.1: optional: true color-string@2.1.4: dependencies: - color-name: 2.1.0 + color-name: 2.1.1 optional: true color@5.0.3: @@ -5066,7 +5190,7 @@ snapshots: es-errors@1.3.0: {} - es-module-lexer@2.1.0: {} + es-module-lexer@2.3.1: {} es-object-atoms@1.1.2: dependencies: @@ -5124,20 +5248,15 @@ snapshots: eventemitter3@4.0.7: {} - eventid@2.0.1: - dependencies: - uuid: 8.3.2 - optional: true - eventsource-parser@3.1.0: {} - expect-type@1.3.0: {} + expect-type@1.4.0: {} express@4.22.2: dependencies: accepts: 1.3.8 array-flatten: 1.1.1 - body-parser: 1.20.5 + body-parser: 1.20.6 content-disposition: 0.5.4 content-type: 1.0.5 cookie: 0.7.2 @@ -5156,7 +5275,7 @@ snapshots: parseurl: 1.3.3 path-to-regexp: 0.1.13 proxy-addr: 2.0.7 - qs: 6.15.2 + qs: 6.15.3 range-parser: 1.2.1 safe-buffer: 5.2.1 send: 0.19.2 @@ -5169,29 +5288,26 @@ snapshots: extend@3.0.2: {} - farmhash-modern@1.1.0: - optional: true - fast-deep-equal@3.1.3: {} fast-sha256@1.3.0: {} - fast-uri@3.1.2: {} + fast-uri@3.1.4: {} - fast-xml-builder@1.2.0: + fast-xml-builder@1.3.0: dependencies: - path-expression-matcher: 1.6.0 - xml-naming: 0.1.0 + path-expression-matcher: 1.6.2 + xml-naming: 0.3.0 optional: true - fast-xml-parser@5.9.3: + fast-xml-parser@5.10.1: dependencies: - '@nodable/entities': 2.2.0 - fast-xml-builder: 1.2.0 - is-unsafe: 1.0.1 - path-expression-matcher: 1.6.0 + '@nodable/entities': 3.0.0 + fast-xml-builder: 1.3.0 + is-unsafe: 2.0.0 + path-expression-matcher: 1.6.2 strnum: 2.4.1 - xml-naming: 0.1.0 + xml-naming: 0.3.0 optional: true faye-websocket@0.11.4: @@ -5199,9 +5315,9 @@ snapshots: websocket-driver: 0.7.5 optional: true - fdir@6.5.0(picomatch@4.0.4): + fdir@6.5.0(picomatch@4.0.5): dependencies: - picomatch: 4.0.4 + picomatch: 4.0.5 fecha@4.2.3: optional: true @@ -5221,18 +5337,17 @@ snapshots: statuses: 2.0.2 unpipe: 1.0.0 - firebase-admin@14.0.0: + firebase-admin@14.2.0: dependencies: '@fastify/busboy': 3.2.0 '@firebase/database-compat': 2.1.4 '@firebase/database-types': 1.0.20 - farmhash-modern: 1.1.0 fast-deep-equal: 3.1.3 - google-auth-library: 10.7.0 + google-auth-library: 10.9.1 jsonwebtoken: 9.0.3 jwks-rsa: 4.1.0 optionalDependencies: - '@google-cloud/firestore': 8.6.0 + '@google-cloud/firestore': 8.7.0 '@google-cloud/storage': 7.21.0 transitivePeerDependencies: - encoding @@ -5285,7 +5400,7 @@ snapshots: - encoding - supports-color - gaxios@7.1.5: + gaxios@7.3.0: dependencies: extend: 3.0.2 https-proxy-agent: 7.0.6 @@ -5304,16 +5419,16 @@ snapshots: gcp-metadata@8.1.2: dependencies: - gaxios: 7.1.5 + gaxios: 7.3.0 google-logging-utils: 1.1.3 json-bigint: 1.0.0 transitivePeerDependencies: - supports-color - genkit@1.39.0: + genkit@1.40.1: dependencies: - '@genkit-ai/ai': 1.39.0(@google-cloud/firestore@7.11.6)(firebase-admin@14.0.0)(genkit@1.39.0) - '@genkit-ai/core': 1.39.0(@google-cloud/firestore@7.11.6)(firebase-admin@14.0.0)(genkit@1.39.0) + '@genkit-ai/ai': 1.40.1(@google-cloud/firestore@7.11.6)(firebase-admin@14.2.0)(genkit@1.40.1) + '@genkit-ai/core': 1.40.1(@google-cloud/firestore@7.11.6)(firebase-admin@14.2.0)(genkit@1.40.1) uuid: 10.0.0 transitivePeerDependencies: - bufferutil @@ -5358,7 +5473,7 @@ snapshots: dependencies: base64-js: 1.5.1 ecdsa-sig-formatter: 1.0.11 - gaxios: 7.1.5 + gaxios: 7.3.0 gcp-metadata: 8.1.2 google-logging-utils: 1.1.3 gtoken: 8.0.0 @@ -5366,11 +5481,11 @@ snapshots: transitivePeerDependencies: - supports-color - google-auth-library@10.7.0: + google-auth-library@10.9.1: dependencies: base64-js: 1.5.1 ecdsa-sig-formatter: 1.0.11 - gaxios: 7.1.5 + gaxios: 7.3.0 gcp-metadata: 8.1.2 google-logging-utils: 1.1.3 jws: 4.0.1 @@ -5401,7 +5516,7 @@ snapshots: node-fetch: 2.7.0 object-hash: 3.0.0 proto3-json-serializer: 2.0.2 - protobufjs: 7.6.4 + protobufjs: 7.6.5 retry-request: 7.0.2 uuid: 9.0.1 transitivePeerDependencies: @@ -5409,7 +5524,7 @@ snapshots: - supports-color optional: true - google-gax@5.0.7: + google-gax@5.0.8: dependencies: '@grpc/grpc-js': 1.14.4 '@grpc/proto-loader': 0.8.1 @@ -5419,8 +5534,8 @@ snapshots: node-fetch: 3.3.2 object-hash: 3.0.0 proto3-json-serializer: 3.0.4 - protobufjs: 7.6.4 - retry-request: 8.0.3 + protobufjs: 7.6.5 + retry-request: 8.0.4 rimraf: 5.0.10 transitivePeerDependencies: - supports-color @@ -5435,7 +5550,7 @@ snapshots: extend: 3.0.2 gaxios: 6.7.1 google-auth-library: 9.15.1 - qs: 6.15.2 + qs: 6.15.3 url-template: 2.0.8 uuid: 9.0.1 transitivePeerDependencies: @@ -5464,7 +5579,7 @@ snapshots: gtoken@8.0.0: dependencies: - gaxios: 7.1.5 + gaxios: 7.3.0 jws: 4.0.1 transitivePeerDependencies: - supports-color @@ -5489,7 +5604,7 @@ snapshots: dependencies: function-bind: 1.1.2 - hono@4.12.28: {} + hono@4.12.32: {} html-entities@2.6.0: optional: true @@ -5563,7 +5678,7 @@ snapshots: is-stream@2.0.1: {} - is-unsafe@1.0.1: + is-unsafe@2.0.0: optional: true isexe@2.0.0: @@ -5576,7 +5691,7 @@ snapshots: '@pkgjs/parseargs': 0.11.0 optional: true - jose@6.2.3: + jose@6.2.4: optional: true js-tiktoken@1.0.21: @@ -5617,7 +5732,7 @@ snapshots: lodash.isstring: 4.0.1 lodash.once: 4.1.1 ms: 2.1.3 - semver: 7.8.4 + semver: 7.8.5 optional: true jwa@2.0.1: @@ -5630,9 +5745,9 @@ snapshots: dependencies: '@types/jsonwebtoken': 9.0.10 debug: 4.4.3 - jose: 6.2.3 + jose: 6.2.4 limiter: 1.1.5 - lru-cache: 11.5.1 + lru-cache: 11.5.2 lru-memoizer: 3.0.0 transitivePeerDependencies: - supports-color @@ -5648,104 +5763,104 @@ snapshots: kuler@2.0.0: optional: true - langsmith@0.7.10(@opentelemetry/api@1.9.1)(openai@6.45.0(ws@8.21.0)(zod@4.4.3))(ws@8.21.0): + langsmith@0.8.7(@opentelemetry/api@1.9.1)(openai@6.49.0(ws@8.21.1)(zod@4.4.3))(ws@8.21.1): dependencies: '@opentelemetry/api': 1.9.1 - openai: 6.45.0(ws@8.21.0)(zod@4.4.3) + openai: 6.49.0(ws@8.21.1)(zod@4.4.3) p-queue: 6.6.2 - ws: 8.21.0 + ws: 8.21.1 - lefthook-darwin-arm64@2.1.9: + lefthook-darwin-arm64@2.1.10: optional: true - lefthook-darwin-x64@2.1.9: + lefthook-darwin-x64@2.1.10: optional: true - lefthook-freebsd-arm64@2.1.9: + lefthook-freebsd-arm64@2.1.10: optional: true - lefthook-freebsd-x64@2.1.9: + lefthook-freebsd-x64@2.1.10: optional: true - lefthook-linux-arm64@2.1.9: + lefthook-linux-arm64@2.1.10: optional: true - lefthook-linux-x64@2.1.9: + lefthook-linux-x64@2.1.10: optional: true - lefthook-openbsd-arm64@2.1.9: + lefthook-openbsd-arm64@2.1.10: optional: true - lefthook-openbsd-x64@2.1.9: + lefthook-openbsd-x64@2.1.10: optional: true - lefthook-windows-arm64@2.1.9: + lefthook-windows-arm64@2.1.10: optional: true - lefthook-windows-x64@2.1.9: + lefthook-windows-x64@2.1.10: optional: true - lefthook@2.1.9: + lefthook@2.1.10: optionalDependencies: - lefthook-darwin-arm64: 2.1.9 - lefthook-darwin-x64: 2.1.9 - lefthook-freebsd-arm64: 2.1.9 - lefthook-freebsd-x64: 2.1.9 - lefthook-linux-arm64: 2.1.9 - lefthook-linux-x64: 2.1.9 - lefthook-openbsd-arm64: 2.1.9 - lefthook-openbsd-x64: 2.1.9 - lefthook-windows-arm64: 2.1.9 - lefthook-windows-x64: 2.1.9 + lefthook-darwin-arm64: 2.1.10 + lefthook-darwin-x64: 2.1.10 + lefthook-freebsd-arm64: 2.1.10 + lefthook-freebsd-x64: 2.1.10 + lefthook-linux-arm64: 2.1.10 + lefthook-linux-x64: 2.1.10 + lefthook-openbsd-arm64: 2.1.10 + lefthook-openbsd-x64: 2.1.10 + lefthook-windows-arm64: 2.1.10 + lefthook-windows-x64: 2.1.10 - lightningcss-android-arm64@1.32.0: + lightningcss-android-arm64@1.33.0: optional: true - lightningcss-darwin-arm64@1.32.0: + lightningcss-darwin-arm64@1.33.0: optional: true - lightningcss-darwin-x64@1.32.0: + lightningcss-darwin-x64@1.33.0: optional: true - lightningcss-freebsd-x64@1.32.0: + lightningcss-freebsd-x64@1.33.0: optional: true - lightningcss-linux-arm-gnueabihf@1.32.0: + lightningcss-linux-arm-gnueabihf@1.33.0: optional: true - lightningcss-linux-arm64-gnu@1.32.0: + lightningcss-linux-arm64-gnu@1.33.0: optional: true - lightningcss-linux-arm64-musl@1.32.0: + lightningcss-linux-arm64-musl@1.33.0: optional: true - lightningcss-linux-x64-gnu@1.32.0: + lightningcss-linux-x64-gnu@1.33.0: optional: true - lightningcss-linux-x64-musl@1.32.0: + lightningcss-linux-x64-musl@1.33.0: optional: true - lightningcss-win32-arm64-msvc@1.32.0: + lightningcss-win32-arm64-msvc@1.33.0: optional: true - lightningcss-win32-x64-msvc@1.32.0: + lightningcss-win32-x64-msvc@1.33.0: optional: true - lightningcss@1.32.0: + lightningcss@1.33.0: dependencies: detect-libc: 2.1.2 optionalDependencies: - lightningcss-android-arm64: 1.32.0 - lightningcss-darwin-arm64: 1.32.0 - lightningcss-darwin-x64: 1.32.0 - lightningcss-freebsd-x64: 1.32.0 - lightningcss-linux-arm-gnueabihf: 1.32.0 - lightningcss-linux-arm64-gnu: 1.32.0 - lightningcss-linux-arm64-musl: 1.32.0 - lightningcss-linux-x64-gnu: 1.32.0 - lightningcss-linux-x64-musl: 1.32.0 - lightningcss-win32-arm64-msvc: 1.32.0 - lightningcss-win32-x64-msvc: 1.32.0 + lightningcss-android-arm64: 1.33.0 + lightningcss-darwin-arm64: 1.33.0 + lightningcss-darwin-x64: 1.33.0 + lightningcss-freebsd-x64: 1.33.0 + lightningcss-linux-arm-gnueabihf: 1.33.0 + lightningcss-linux-arm64-gnu: 1.33.0 + lightningcss-linux-arm64-musl: 1.33.0 + lightningcss-linux-x64-gnu: 1.33.0 + lightningcss-linux-x64-musl: 1.33.0 + lightningcss-win32-arm64-msvc: 1.33.0 + lightningcss-win32-x64-msvc: 1.33.0 limiter@1.1.5: optional: true @@ -5796,13 +5911,13 @@ snapshots: lru-cache@10.4.3: optional: true - lru-cache@11.5.1: + lru-cache@11.5.2: optional: true lru-memoizer@3.0.0: dependencies: lodash.clonedeep: 4.5.0 - lru-cache: 11.5.1 + lru-cache: 11.5.2 optional: true magic-string@0.30.21: @@ -5828,12 +5943,12 @@ snapshots: mime@3.0.0: optional: true - miniflare@4.20260706.0: + miniflare@4.20260722.0: dependencies: '@cspotcode/source-map-support': 0.8.1 - sharp: 0.34.5 + sharp: 0.35.2 undici: 7.28.0 - workerd: 1.20260706.1 + workerd: 1.20260722.1 ws: 8.21.0 youch: 4.1.0-beta.10 transitivePeerDependencies: @@ -5842,7 +5957,7 @@ snapshots: minimatch@9.0.9: dependencies: - brace-expansion: 2.1.1 + brace-expansion: 2.1.2 optional: true minimist@1.2.8: {} @@ -5858,7 +5973,7 @@ snapshots: mustache@4.2.0: {} - nanoid@3.3.14: {} + nanoid@3.3.16: {} negotiator@0.6.3: {} @@ -5883,7 +5998,7 @@ snapshots: object-inspect@1.13.4: {} - obug@2.1.3: {} + obug@2.1.4: {} on-finished@2.4.1: dependencies: @@ -5899,9 +6014,9 @@ snapshots: fn.name: 1.1.0 optional: true - openai@6.45.0(ws@8.21.0)(zod@4.4.3): + openai@6.49.0(ws@8.21.1)(zod@4.4.3): dependencies: - ws: 8.21.0 + ws: 8.21.1 zod: 4.4.3 p-finally@1.0.0: {} @@ -5932,7 +6047,7 @@ snapshots: partial-json@0.1.7: {} - path-expression-matcher@1.6.0: + path-expression-matcher@1.6.2: optional: true path-key@3.1.1: @@ -5969,11 +6084,11 @@ snapshots: picocolors@1.1.1: {} - picomatch@4.0.4: {} + picomatch@4.0.5: {} - postcss@8.5.15: + postcss@8.5.23: dependencies: - nanoid: 3.3.14 + nanoid: 3.3.16 picocolors: 1.1.1 source-map-js: 1.2.1 @@ -5993,15 +6108,15 @@ snapshots: proto3-json-serializer@2.0.2: dependencies: - protobufjs: 7.6.4 + protobufjs: 7.6.5 optional: true proto3-json-serializer@3.0.4: dependencies: - protobufjs: 7.6.4 + protobufjs: 7.6.5 optional: true - protobufjs@7.6.4: + protobufjs@7.6.5: dependencies: '@protobufjs/aspromise': 1.1.2 '@protobufjs/base64': 1.1.2 @@ -6011,8 +6126,8 @@ snapshots: '@protobufjs/float': 1.0.2 '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 - '@protobufjs/utf8': 1.1.1 - '@types/node': 25.9.3 + '@protobufjs/utf8': 1.1.2 + '@types/node': 26.1.1 long: 5.3.2 proxy-addr@2.0.7: @@ -6033,8 +6148,9 @@ snapshots: pump: 3.0.4 optional: true - qs@6.15.2: + qs@6.15.3: dependencies: + es-define-property: 1.0.1 side-channel: 1.1.1 range-parser@1.2.1: {} @@ -6082,10 +6198,10 @@ snapshots: - supports-color optional: true - retry-request@8.0.3: + retry-request@8.0.4: dependencies: extend: 3.0.2 - teeny-request: 10.1.3 + teeny-request: 10.1.4 transitivePeerDependencies: - supports-color optional: true @@ -6097,26 +6213,26 @@ snapshots: glob: 10.5.0 optional: true - rolldown@1.0.3: + rolldown@1.1.5: dependencies: - '@oxc-project/types': 0.133.0 + '@oxc-project/types': 0.139.0 '@rolldown/pluginutils': 1.0.1 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.3 - '@rolldown/binding-darwin-arm64': 1.0.3 - '@rolldown/binding-darwin-x64': 1.0.3 - '@rolldown/binding-freebsd-x64': 1.0.3 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.3 - '@rolldown/binding-linux-arm64-gnu': 1.0.3 - '@rolldown/binding-linux-arm64-musl': 1.0.3 - '@rolldown/binding-linux-ppc64-gnu': 1.0.3 - '@rolldown/binding-linux-s390x-gnu': 1.0.3 - '@rolldown/binding-linux-x64-gnu': 1.0.3 - '@rolldown/binding-linux-x64-musl': 1.0.3 - '@rolldown/binding-openharmony-arm64': 1.0.3 - '@rolldown/binding-wasm32-wasi': 1.0.3 - '@rolldown/binding-win32-arm64-msvc': 1.0.3 - '@rolldown/binding-win32-x64-msvc': 1.0.3 + '@rolldown/binding-android-arm64': 1.1.5 + '@rolldown/binding-darwin-arm64': 1.1.5 + '@rolldown/binding-darwin-x64': 1.1.5 + '@rolldown/binding-freebsd-x64': 1.1.5 + '@rolldown/binding-linux-arm-gnueabihf': 1.1.5 + '@rolldown/binding-linux-arm64-gnu': 1.1.5 + '@rolldown/binding-linux-arm64-musl': 1.1.5 + '@rolldown/binding-linux-ppc64-gnu': 1.1.5 + '@rolldown/binding-linux-s390x-gnu': 1.1.5 + '@rolldown/binding-linux-x64-gnu': 1.1.5 + '@rolldown/binding-linux-x64-musl': 1.1.5 + '@rolldown/binding-openharmony-arm64': 1.1.5 + '@rolldown/binding-wasm32-wasi': 1.1.5 + '@rolldown/binding-win32-arm64-msvc': 1.1.5 + '@rolldown/binding-win32-x64-msvc': 1.1.5 safe-buffer@5.2.1: {} @@ -6125,7 +6241,7 @@ snapshots: safer-buffer@2.1.2: {} - semver@7.8.4: {} + semver@7.8.5: {} send@0.19.2: dependencies: @@ -6152,36 +6268,37 @@ snapshots: setprototypeof@1.2.0: {} - sharp@0.34.5: + sharp@0.35.2: dependencies: '@img/colour': 1.1.0 detect-libc: 2.1.2 - semver: 7.8.4 + semver: 7.8.5 optionalDependencies: - '@img/sharp-darwin-arm64': 0.34.5 - '@img/sharp-darwin-x64': 0.34.5 - '@img/sharp-libvips-darwin-arm64': 1.2.4 - '@img/sharp-libvips-darwin-x64': 1.2.4 - '@img/sharp-libvips-linux-arm': 1.2.4 - '@img/sharp-libvips-linux-arm64': 1.2.4 - '@img/sharp-libvips-linux-ppc64': 1.2.4 - '@img/sharp-libvips-linux-riscv64': 1.2.4 - '@img/sharp-libvips-linux-s390x': 1.2.4 - '@img/sharp-libvips-linux-x64': 1.2.4 - '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 - '@img/sharp-libvips-linuxmusl-x64': 1.2.4 - '@img/sharp-linux-arm': 0.34.5 - '@img/sharp-linux-arm64': 0.34.5 - '@img/sharp-linux-ppc64': 0.34.5 - '@img/sharp-linux-riscv64': 0.34.5 - '@img/sharp-linux-s390x': 0.34.5 - '@img/sharp-linux-x64': 0.34.5 - '@img/sharp-linuxmusl-arm64': 0.34.5 - '@img/sharp-linuxmusl-x64': 0.34.5 - '@img/sharp-wasm32': 0.34.5 - '@img/sharp-win32-arm64': 0.34.5 - '@img/sharp-win32-ia32': 0.34.5 - '@img/sharp-win32-x64': 0.34.5 + '@img/sharp-darwin-arm64': 0.35.2 + '@img/sharp-darwin-x64': 0.35.2 + '@img/sharp-freebsd-wasm32': 0.35.2 + '@img/sharp-libvips-darwin-arm64': 1.3.1 + '@img/sharp-libvips-darwin-x64': 1.3.1 + '@img/sharp-libvips-linux-arm': 1.3.1 + '@img/sharp-libvips-linux-arm64': 1.3.1 + '@img/sharp-libvips-linux-ppc64': 1.3.1 + '@img/sharp-libvips-linux-riscv64': 1.3.1 + '@img/sharp-libvips-linux-s390x': 1.3.1 + '@img/sharp-libvips-linux-x64': 1.3.1 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.1 + '@img/sharp-libvips-linuxmusl-x64': 1.3.1 + '@img/sharp-linux-arm': 0.35.2 + '@img/sharp-linux-arm64': 0.35.2 + '@img/sharp-linux-ppc64': 0.35.2 + '@img/sharp-linux-riscv64': 0.35.2 + '@img/sharp-linux-s390x': 0.35.2 + '@img/sharp-linux-x64': 0.35.2 + '@img/sharp-linuxmusl-arm64': 0.35.2 + '@img/sharp-linuxmusl-x64': 0.35.2 + '@img/sharp-webcontainers-wasm32': 0.35.2 + '@img/sharp-win32-arm64': 0.35.2 + '@img/sharp-win32-ia32': 0.35.2 + '@img/sharp-win32-x64': 0.35.2 shebang-command@2.0.0: dependencies: @@ -6242,7 +6359,7 @@ snapshots: statuses@2.0.2: {} - std-env@4.1.0: {} + std-env@4.2.0: {} stream-events@1.0.5: dependencies: @@ -6303,7 +6420,7 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - teeny-request@10.1.3: + teeny-request@10.1.4: dependencies: http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 @@ -6334,8 +6451,8 @@ snapshots: tinyglobby@0.2.17: dependencies: - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 + fdir: 6.5.0(picomatch@4.0.5) + picomatch: 4.0.5 tinyrainbow@3.1.0: {} @@ -6355,14 +6472,35 @@ snapshots: media-typer: 0.3.0 mime-types: 2.1.35 - typescript@6.0.3: {} + typescript@7.0.2: + optionalDependencies: + '@typescript/typescript-aix-ppc64': 7.0.2 + '@typescript/typescript-darwin-arm64': 7.0.2 + '@typescript/typescript-darwin-x64': 7.0.2 + '@typescript/typescript-freebsd-arm64': 7.0.2 + '@typescript/typescript-freebsd-x64': 7.0.2 + '@typescript/typescript-linux-arm': 7.0.2 + '@typescript/typescript-linux-arm64': 7.0.2 + '@typescript/typescript-linux-loong64': 7.0.2 + '@typescript/typescript-linux-mips64el': 7.0.2 + '@typescript/typescript-linux-ppc64': 7.0.2 + '@typescript/typescript-linux-riscv64': 7.0.2 + '@typescript/typescript-linux-s390x': 7.0.2 + '@typescript/typescript-linux-x64': 7.0.2 + '@typescript/typescript-netbsd-arm64': 7.0.2 + '@typescript/typescript-netbsd-x64': 7.0.2 + '@typescript/typescript-openbsd-arm64': 7.0.2 + '@typescript/typescript-openbsd-x64': 7.0.2 + '@typescript/typescript-sunos-x64': 7.0.2 + '@typescript/typescript-win32-arm64': 7.0.2 + '@typescript/typescript-win32-x64': 7.0.2 uglify-js@3.19.3: optional: true undici-types@6.21.0: {} - undici-types@7.24.6: {} + undici-types@8.3.0: {} undici@7.28.0: {} @@ -6384,60 +6522,57 @@ snapshots: uuid@10.0.0: {} - uuid@8.3.2: - optional: true - uuid@9.0.1: {} vary@1.1.2: {} - vite@8.0.16(@types/node@25.9.3): + vite@8.1.5(@types/node@26.1.1): dependencies: - '@types/node': 25.9.3 - lightningcss: 1.32.0 - picomatch: 4.0.4 - postcss: 8.5.15 - rolldown: 1.0.3 + '@types/node': 26.1.1 + lightningcss: 1.33.0 + picomatch: 4.0.5 + postcss: 8.5.23 + rolldown: 1.1.5 tinyglobby: 0.2.17 optionalDependencies: fsevents: 2.3.3 optional: true - vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1): + vite@8.1.5(@types/node@26.1.1)(esbuild@0.28.1): dependencies: - '@types/node': 25.9.3 + '@types/node': 26.1.1 esbuild: 0.28.1 - lightningcss: 1.32.0 - picomatch: 4.0.4 - postcss: 8.5.15 - rolldown: 1.0.3 + lightningcss: 1.33.0 + picomatch: 4.0.5 + postcss: 8.5.23 + rolldown: 1.1.5 tinyglobby: 0.2.17 optionalDependencies: fsevents: 2.3.3 - vitest@4.1.10(@opentelemetry/api@1.9.1)(@types/node@25.9.3)(esbuild@0.28.1)(vite@8.0.16(@types/node@25.9.3)): + vitest@4.1.10(@opentelemetry/api@1.9.1)(@types/node@26.1.1)(esbuild@0.28.1)(vite@8.1.5(@types/node@26.1.1)): dependencies: '@opentelemetry/api': 1.9.1 - '@types/node': 25.9.3 + '@types/node': 26.1.1 '@vitest/expect': 4.1.10 - '@vitest/mocker': 4.1.10(esbuild@0.28.1)(vite@8.0.16(@types/node@25.9.3)) + '@vitest/mocker': 4.1.10(esbuild@0.28.1)(vite@8.1.5(@types/node@26.1.1)) '@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.1.0 - expect-type: 1.3.0 + es-module-lexer: 2.3.1 + expect-type: 1.4.0 magic-string: 0.30.21 - obug: 2.1.3 + obug: 2.1.4 pathe: 2.0.3 - picomatch: 4.0.4 - std-env: 4.1.0 + 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.0.16(@types/node@25.9.3)(esbuild@0.28.1) + vite: 8.1.5(@types/node@26.1.1)(esbuild@0.28.1) why-is-node-running: 2.3.0 transitivePeerDependencies: - msw @@ -6495,25 +6630,25 @@ snapshots: wordwrap@1.0.0: {} - workerd@1.20260706.1: + workerd@1.20260722.1: optionalDependencies: - '@cloudflare/workerd-darwin-64': 1.20260706.1 - '@cloudflare/workerd-darwin-arm64': 1.20260706.1 - '@cloudflare/workerd-linux-64': 1.20260706.1 - '@cloudflare/workerd-linux-arm64': 1.20260706.1 - '@cloudflare/workerd-windows-64': 1.20260706.1 + '@cloudflare/workerd-darwin-64': 1.20260722.1 + '@cloudflare/workerd-darwin-arm64': 1.20260722.1 + '@cloudflare/workerd-linux-64': 1.20260722.1 + '@cloudflare/workerd-linux-arm64': 1.20260722.1 + '@cloudflare/workerd-windows-64': 1.20260722.1 - wrangler@4.108.0(@cloudflare/workers-types@5.20260708.1): + wrangler@4.114.0(@cloudflare/workers-types@5.20260724.1): dependencies: '@cloudflare/kv-asset-handler': 0.5.0 - '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260706.1) - '@cloudflare/workers-types': 5.20260708.1 + '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260722.1) + '@cloudflare/workers-types': 5.20260724.1 blake3-wasm: 2.1.5 esbuild: 0.28.1 - miniflare: 4.20260706.0 + miniflare: 4.20260722.0 path-to-regexp: 6.3.0 unenv: 2.0.0-rc.24 - workerd: 1.20260706.1 + workerd: 1.20260722.1 optionalDependencies: fsevents: 2.3.3 transitivePeerDependencies: @@ -6545,7 +6680,9 @@ snapshots: ws@8.21.0: {} - xml-naming@0.1.0: + ws@8.21.1: {} + + xml-naming@0.3.0: optional: true xtend@4.0.2: diff --git a/package.json b/package.json index d2a8dc4..2c59ab1 100644 --- a/package.json +++ b/package.json @@ -3,14 +3,13 @@ "type": "module", "private": true, "license": "MIT", - "packageManager": "nub@0.4.7", "engines": { - "node": ">=24" + "node": ">=26" }, "devEngines": { "packageManager": { "name": "nub", - "version": "^0.4.7", + "version": "^0.5.0", "onFail": "warn" } }, @@ -24,31 +23,32 @@ "prepare": "lefthook install" }, "devDependencies": { - "@ai-sdk/anthropic": "^4.0.9", - "@ai-sdk/google": "^4.0.9", - "@ai-sdk/openai": "^4.0.8", - "@anthropic-ai/sdk": "^0.110.0", - "@biomejs/biome": "^2.5.3", - "@cloudflare/vitest-pool-workers": "^0.18.2", - "@cloudflare/workers-types": "^5.20260708.1", - "@genkit-ai/google-genai": "^1.39.0", - "@google/genai": "^2.10.0", - "@langchain/anthropic": "^1.5.1", - "@langchain/core": "^1.2.1", + "@ai-sdk/anthropic": "^4.0.20", + "@ai-sdk/google": "^4.0.24", + "@ai-sdk/openai": "^4.0.20", + "@anthropic-ai/sdk": "^0.115.0", + "@biomejs/biome": "^2.5.5", + "@cloudflare/vitest-pool-workers": "^0.18.8", + "@cloudflare/workers-types": "^5.20260724.1", + "@genkit-ai/google-genai": "^1.40.1", + "@google/genai": "^2.13.0", + "@langchain/anthropic": "^1.5.2", + "@langchain/core": "^1.2.3", "@langchain/google-genai": "^2.2.0", - "@langchain/openai": "^1.5.3", + "@langchain/openai": "^1.5.5", "@types/ws": "^8.18.1", - "ai": "^7.0.17", - "genkit": "^1.39.0", - "lefthook": "^2.1.9", - "openai": "^6.45.0", - "typescript": "^6.0.3", + "ai": "^7.0.37", + "genkit": "^1.40.1", + "lefthook": "^2.1.10", + "openai": "^6.49.0", + "typescript": "^7.0.2", "vitest": "^4.1.10", - "wrangler": "^4.108.0", - "ws": "^8.21.0", + "wrangler": "^4.114.0", + "ws": "^8.21.1", "zod": "^4.4.3" }, "dependencies": { - "hono": "^4.12.28" - } + "hono": "^4.12.32" + }, + "packageManager": "nub@0.5.0" } diff --git a/test/ws.test.ts b/test/ws.test.ts index 67c00a0..ddeeb46 100644 --- a/test/ws.test.ts +++ b/test/ws.test.ts @@ -250,50 +250,53 @@ describe("handleWsProxy: close propagation", () => { it.each([ ["upstream", 4101, "upstream finished"], ["client", 4102, "client finished"], - ] as const)("propagates a %s close code and reason", async (source, code, reason) => { - await seed(`tk-close-${source}`, ["openai"]); - let upstreamPeer: WebSocket | undefined; - upstreamReply = () => { - const [worker, peer] = Object.values(new WebSocketPair()); - upstreamPeer = peer; - peer.accept({ allowHalfOpen: true }); - return new Response(null, { status: 101, webSocket: worker }); - }; + ] as const)( + "propagates a %s close code and reason", + async (source, code, reason) => { + await seed(`tk-close-${source}`, ["openai"]); + let upstreamPeer: WebSocket | undefined; + upstreamReply = () => { + const [worker, peer] = Object.values(new WebSocketPair()); + upstreamPeer = peer; + peer.accept({ allowHalfOpen: true }); + return new Response(null, { status: 101, webSocket: worker }); + }; - const res = await callWs( - new Request("https://proxy.example/v1/responses", { - headers: { authorization: `Bearer tk-close-${source}` }, - }), - ); - expect(res.status).toBe(101); - const client = res.webSocket!; - const upstream = upstreamPeer!; - client.accept({ allowHalfOpen: true }); - const order: string[] = []; - const clientClosed = closeEvent(client, "client").then((event) => { - order.push("client"); - return event; - }); - const upstreamClosed = closeEvent(upstream, "upstream").then((event) => { - order.push("upstream"); - return event; - }); + const res = await callWs( + new Request("https://proxy.example/v1/responses", { + headers: { authorization: `Bearer tk-close-${source}` }, + }), + ); + expect(res.status).toBe(101); + const client = res.webSocket!; + const upstream = upstreamPeer!; + client.accept({ allowHalfOpen: true }); + const order: string[] = []; + const clientClosed = closeEvent(client, "client").then((event) => { + order.push("client"); + return event; + }); + const upstreamClosed = closeEvent(upstream, "upstream").then((event) => { + order.push("upstream"); + return event; + }); - try { - (source === "client" ? client : upstream).close(code, reason); - for (const event of await Promise.all([clientClosed, upstreamClosed])) { - expect(event.code).toBe(code); - expect(event.reason).toBe(reason); + try { + (source === "client" ? client : upstream).close(code, reason); + for (const event of await Promise.all([clientClosed, upstreamClosed])) { + expect(event.code).toBe(code); + expect(event.reason).toBe(reason); + } + // The destination must reciprocate before the initiator's close completes. + expect(order).toEqual( + source === "client" ? ["upstream", "client"] : ["client", "upstream"], + ); + } finally { + if (client.readyState !== WebSocket.CLOSED) client.close(); + if (upstream.readyState !== WebSocket.CLOSED) upstream.close(); } - // The destination must reciprocate before the initiator's close completes. - expect(order).toEqual( - source === "client" ? ["upstream", "client"] : ["client", "upstream"], - ); - } finally { - if (client.readyState !== WebSocket.CLOSED) client.close(); - if (upstream.readyState !== WebSocket.CLOSED) upstream.close(); - } - }); + }, + ); }); describe("forwardCloseCode (close-code sanitization)", () => { diff --git a/wrangler.toml b/wrangler.toml index 0ab2956..04be544 100644 --- a/wrangler.toml +++ b/wrangler.toml @@ -10,7 +10,7 @@ preview_urls = false enabled = true # Dedicated token store; do not share it with another worker. -# Create with `nubx wrangler kv namespace create api-proxy-tokens`; tests use an in-memory namespace. +# Create with `nub exec wrangler kv namespace create api-proxy-tokens`; tests use an in-memory namespace. [[kv_namespaces]] binding = "TOKENS" id = "1b212581e15144fb9f931b221a8cc5cd" @@ -52,7 +52,7 @@ namespace_id = "1002" limit = 10 period = 60 -# Secrets (set with `nubx wrangler secret put `), never committed: +# Secrets (set with `nub exec wrangler secret put `), never committed: # OPENAI_API_KEY ANTHROPIC_API_KEY GEMINI_API_KEY ADMIN_SECRET # Optional upstream overrides (plain vars, NOT secrets) default to the real hosts: # OPENAI_UPSTREAM ANTHROPIC_UPSTREAM GEMINI_UPSTREAM