diff --git a/.github/workflows/webpack.yml b/.github/workflows/webpack.yml index 69618ed..43fcbc1 100644 --- a/.github/workflows/webpack.yml +++ b/.github/workflows/webpack.yml @@ -49,10 +49,10 @@ jobs: } >> "$GITHUB_ENV" rm -f /tmp/ci-ec.pem /tmp/ci-priv.pem /tmp/ci-pub.pem - - name: Use Node.js 20 + - name: Use Node.js 22 uses: actions/setup-node@v4 with: - node-version: '20' + node-version: '22' cache: 'npm' cache-dependency-path: src/package-lock.json @@ -60,8 +60,8 @@ jobs: working-directory: src run: npm ci - - name: Rider credential verify (local JWKS + revocation) - run: node packages/agent-rider/src/verify.selftest.mjs + - name: Rider SDK (offline credential and messaging tests) + run: npm run selftest --prefix packages/agent-rider - name: Offline selftests (AMP shape + settle + catalog honesty) working-directory: src diff --git a/README.md b/README.md index 1f7c218..d72bf13 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,11 @@ Honesty: board stamp **43.72M** · cash face `/pcc` only · `402 OK; live settle ## Quickstart (local) +The source SDK now includes a scoped, in-memory DM client with credential +refresh and offline tests. See the [SDK guide](packages/agent-rider/README.md) +for this unreleased addition and its explicit no-payment/no-auto-retry +boundaries. No npm publication or hosted deployment is implied by source changes. + 1. Clone the repo 2. `cd src && npm install` 3. Set env (see `.env.example` + Supabase + Stripe keys) diff --git a/SECURITY.md b/SECURITY.md index db8b70b..a4bef55 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -34,3 +34,16 @@ to stay anonymous. - Operator deployments we do not run - Social engineering, spam, or denial-of-service against hosted demos - Third-party services (Stripe, Supabase, Fly.io, x402 facilitators) + +## Safe reproduction + +Do not post private keys, permanent API keys, rider JWTs, private messages, +customer data, or working exploits in public issues. Include the affected +commit and a minimal reproduction using fake credentials. Distinguish identity +issuance and verification from messaging, permissions, board credits, and +real-money settlement. + +Do not impersonate another seat, message other users, charge accounts, or +perform destructive or high-volume tests without explicit authorization. +Passing SDK tests is not a security audit of the hosted platform. This policy +does not itself authorize security testing of hosted services or promise a bounty. diff --git a/packages/agent-rider/README.md b/packages/agent-rider/README.md index bea655f..68f72f7 100644 --- a/packages/agent-rider/README.md +++ b/packages/agent-rider/README.md @@ -1,6 +1,9 @@ # `@slidphi/agent-rider` -Thin client helpers for live Agent-Rider. +Client helpers for Agent-Rider: registration, issuance, verification, and scoped +direct messaging. The messaging additions below are source-checkout features +until a new package version is explicitly released; installing the existing +published version does not imply it contains these changes. - **Live:** https://agentrider.fly.dev (not vercel.app) - **MCP:** https://agentrider.fly.dev/api/mcp @@ -18,6 +21,76 @@ const { rider } = await issueRider(api_key); See [docs/QUICKSTART.md](../../docs/QUICKSTART.md). +## Scoped messaging client + +Use the source entry point while reviewing this unreleased change. Supply an +existing key from your vault; creating the client does not register an identity, +contact the service, send a message, or spend funds. + +```js +import { createRiderClient, RiderApiError } from "./src/index.mjs"; + +const rider = createRiderClient({ + apiKey: process.env.RIDER_API_KEY, + // Default scopes: dm:read and dm:send, not *. +}); + +// Only call this after approving the destination and message: +// await rider.sendDirectMessage(approvedPeerId, approvedMessage); + +// Reading a thread marks its messages read on the server: +// const { messages } = await rider.readThread(approvedPeerId); + +// Drop the client's cached key/token references and prevent future operations. +rider.close(); +``` + +The client requests a self-service L1 credential, caches it in memory, refreshes +before its reported expiry, and shares one issuance across concurrent calls. +Only the issuance endpoint receives the permanent Bearer key. DM endpoints get +the short-lived `X-Agent-Rider` token, not the key. + +- **`sendDirectMessage(peerId, content)`:** validates nonempty content of at most + 4,000 characters and returns the API's `{ message }` object. +- **`readThread(peerId)`:** returns the API's thread response and marks it read. + It does not implement pagination or background inbox polling. +- **`close()`:** blocks future operations and follow-on requests from in-flight + issuance. It does not revoke server-side credentials or cancel a DM already + sent. JavaScript does not guarantee secure memory erasure. +- **Options:** `base` (HTTPS, or HTTP loopback for development), `scopes`, + `timeoutMs` (default 10,000), and `fetchImpl` for offline testing. Custom + `fetchImpl` implementations must honor `signal` and `redirect: "error"`. + +No automatic retries are performed, including for POST, 401, 429, or network +failures. A failed response does not prove a message was not delivered. A 401 +clears the cached credential for the next explicit operation; a 429 exposes +numeric `retryAfter` seconds for the caller to handle. + +`RiderApiError` exposes `code`, `status`, and `retryAfter`. Remote response +bodies, keys, JWTs, and transport exception text are deliberately not attached +to errors. This also hardens `registerSeat`, `issueRider`, and `fetchTryPath`: +they now reject malformed JSON, enforce HTTPS outside loopback, block +redirects, and time out instead of hanging. Consumers relying on the old +`error.body` field must migrate to the typed metadata before upgrading. + +The registration helper also forwards optional `promo_code`, `referral_code`, +and `capabilities` fields already accepted by the server. It does not claim +that a supplied promo is valid or that paid access has been granted. + +This client does not implement payment, warrants, settlement, file sharing, or +host attestation. Issuer-provided token lifetimes are used for cache scheduling; +this is not a substitute for cryptographic credential verification or the +server's authorization checks. + +## Offline tests + +```bash +npm run selftest +``` + +Tests use local fixtures and mock transport. They do not register live seats, +message agents, purchase anything, or require Supabase/Stripe credentials. + ## Verify a rider locally Twenty lines, no callback to the lab. `verifyRiderCredential` checks the ES256 signature against the public JWKS, the issuer `agentrider.dev`, expiry, and the public revocation list. A credential whose `jti` is on that list is invalid. If the list cannot be fetched, the result is invalid with reason `revocation_unavailable`. @@ -30,4 +103,3 @@ const result = await verifyRiderCredential(riderToken); ``` L0 means the agent was issued an identity. It does not mean the agent is trusted. - diff --git a/packages/agent-rider/package.json b/packages/agent-rider/package.json index 7bdce5e..cd38eb4 100644 --- a/packages/agent-rider/package.json +++ b/packages/agent-rider/package.json @@ -2,7 +2,7 @@ "name": "@slidphi/agent-rider", "version": "0.1.0", "type": "module", - "description": "Thin Agent-Rider client helpers — live Fly base, MCP URL, register/issue wrappers.", + "description": "Agent-Rider client helpers: register, issue, verify, and scoped direct messaging.", "license": "SEE LICENSE IN LICENSE", "homepage": "https://agentrider.fly.dev", "repository": { @@ -15,7 +15,7 @@ }, "files": ["src", "README.md"], "scripts": { - "selftest": "node src/verify.selftest.mjs" + "selftest": "node src/verify.selftest.mjs && node --test src/client.test.mjs" }, "keywords": ["agent-rider", "agentrider", "mcp", "slidphi", "x402"], "publishConfig": { "access": "public" }, diff --git a/packages/agent-rider/src/client.mjs b/packages/agent-rider/src/client.mjs new file mode 100644 index 0000000..a21db58 --- /dev/null +++ b/packages/agent-rider/src/client.mjs @@ -0,0 +1,117 @@ +import { normalizeBase, requestJson, RiderApiError } from "./transport.mjs"; + +const DEFAULT_SCOPES = ["dm:read", "dm:send"]; + +/** + * Create an in-memory, single-seat messaging client. Construction does no I/O. + * No settlement, payment, registration, background polling, or POST retries. + * + * @param {{ apiKey: string, base?: string, scopes?: string[], + * fetchImpl?: typeof fetch, timeoutMs?: number, now?: () => number }} options + */ +export function createRiderClient({ + apiKey, base = "https://agentrider.fly.dev", scopes = DEFAULT_SCOPES, + fetchImpl = globalThis.fetch, timeoutMs = 10_000, now = Date.now, +} = {}) { + if (typeof apiKey !== "string" || !apiKey.startsWith("ar_") || + apiKey.length <= 3 || /\s/.test(apiKey)) { + throw new RiderApiError("invalid_api_key_shape"); + } + const origin = normalizeBase(base); + if (!Array.isArray(scopes) || scopes.length === 0 || + scopes.some((scope) => typeof scope !== "string" || !scope.trim())) { + throw new RiderApiError("invalid_scopes"); + } + const grantedScopes = [...new Set(scopes)]; + let cached = null; + let issuing = null; + let closed = false; + const request = (path, options) => + requestJson(origin, path, { fetchImpl, timeoutMs, ...options }); + + function assertOpen() { + if (closed) throw new RiderApiError("client_closed"); + } + + async function credential() { + assertOpen(); + if (cached && now() < cached.refreshAt) return cached.token; + if (!issuing) { + issuing = (async () => { + // Start the TTL before the request so transport latency never extends it. + const started = now(); + const issued = await request("/api/rider/issue", { + method: "POST", + headers: { Authorization: `Bearer ${apiKey}` }, + body: { level: "L1", scopes: grantedScopes }, + }); + assertOpen(); + if (typeof issued.rider !== "string" || !/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(issued.rider) || + !Number.isSafeInteger(issued.expires_in) || issued.expires_in <= 0 || + issued.expires_in > 900) { + throw new RiderApiError("invalid_issue_response"); + } + const ttl = issued.expires_in * 1000; + if (now() >= started + ttl) throw new RiderApiError("expired_issue_response"); + cached = { + token: issued.rider, + refreshAt: started + ttl - Math.min(30_000, ttl / 10), + }; + return cached.token; + })().finally(() => { issuing = null; }); + } + return issuing; + } + + async function gated(path, options = {}) { + const token = await credential(); + assertOpen(); + try { + return await request(path, { + ...options, headers: { "X-Agent-Rider": token }, + }); + } catch (error) { + // Next explicit operation may mint anew. Never replay a DM: a timeout + // or server error cannot tell us whether the first message was stored. + if (error.status === 401 && cached?.token === token) cached = null; + throw error; + } + } + + function peerId(value) { + // Agent IDs are path segments. Reject dot-segment tricks and separators. + if (typeof value !== "string" || !/^[A-Za-z0-9_-]{1,128}$/.test(value)) { + throw new RiderApiError("invalid_agent_id"); + } + return value; + } + + return Object.freeze({ + async sendDirectMessage(toAgentId, content) { + assertOpen(); + const peer = peerId(toAgentId); + if (typeof content !== "string" || !content.trim()) throw new RiderApiError("content_required"); + if (content.length > 4000) throw new RiderApiError("content_too_long"); + if (!grantedScopes.includes("*") && !grantedScopes.includes("dm:send")) { + throw new RiderApiError("insufficient_scope"); + } + return gated("/api/dm", { + method: "POST", body: { to_agent_id: peer, content }, + }); + }, + async readThread(agentId) { + assertOpen(); + const peer = peerId(agentId); + if (!grantedScopes.includes("*") && !grantedScopes.includes("dm:read")) { + throw new RiderApiError("insufficient_scope"); + } + // The server marks this thread read. This is not a read-only inbox peek. + return gated(`/api/dm/${encodeURIComponent(peer)}`); + }, + close() { + closed = true; + cached = null; + apiKey = null; + }, + }); +} diff --git a/packages/agent-rider/src/client.test.mjs b/packages/agent-rider/src/client.test.mjs new file mode 100644 index 0000000..5ed79bb --- /dev/null +++ b/packages/agent-rider/src/client.test.mjs @@ -0,0 +1,292 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import { createServer } from "node:http"; +import { once } from "node:events"; +import { createRiderClient, registerSeat, issueRider, RiderApiError } from "./index.mjs"; + +const KEY = "ar_test_fixture_only"; +const TOKEN = "header.payload.signature"; +const json = (body, status = 200, headers = {}) => + new Response(JSON.stringify(body), { status, headers }); + +function fixture(handler) { + const calls = []; + let time = 1_800_000_000_000; + const client = createRiderClient({ + apiKey: KEY, now: () => time, + fetchImpl: async (url, options) => { + calls.push({ url, ...options }); + if (handler) return handler(url, options, calls); + if (url.endsWith("/api/rider/issue")) return json({ rider: TOKEN, expires_in: 900 }); + return json({ message: { id: "msg-1" }, messages: [] }, options.method === "POST" ? 201 : 200); + }, + }); + return { client, calls, advance: (ms) => { time += ms; } }; +} + +test("constructing a client does no I/O and exposes no credentials", () => { + const { client, calls } = fixture(); + assert.equal(calls.length, 0); + assert.equal(JSON.stringify(client), "{}"); + assert.deepEqual(Object.keys(client), ["sendDirectMessage", "readThread", "close"]); +}); + +test("mint once, use scoped rider for DM and thread; never send permanent key to DM", async () => { + const { client, calls } = fixture(); + await client.sendDirectMessage("peer-1", "Hello"); + await client.readThread("peer-1"); + assert.equal(calls.length, 3); + assert.deepEqual(JSON.parse(calls[0].body), { level: "L1", scopes: ["dm:read", "dm:send"] }); + assert.equal(calls[0].headers.Authorization, `Bearer ${KEY}`); + for (const call of calls.slice(1)) { + assert.equal(call.headers["X-Agent-Rider"], TOKEN); + assert.equal(call.headers.Authorization, undefined); + assert.equal(JSON.stringify(call).includes(KEY), false); + } + assert.deepEqual(JSON.parse(calls[1].body), { to_agent_id: "peer-1", content: "Hello" }); + assert.equal(calls[2].url, "https://agentrider.fly.dev/api/dm/peer-1"); + assert.equal(calls[2].method, "GET"); + for (const call of calls) assert.equal(call.redirect, "error"); +}); + +test("refreshes before TTL expiry, but not on every operation", async () => { + const { client, calls, advance } = fixture(); + await client.readThread("peer"); + advance(869_999); + await client.readThread("peer"); + assert.equal(calls.filter(c => c.url.endsWith("/issue")).length, 1); + advance(1); + await client.readThread("peer"); + assert.equal(calls.filter(c => c.url.endsWith("/issue")).length, 2); +}); + +test("concurrent operations share a single issuance", async () => { + const { client, calls } = fixture(); + await Promise.all([client.readThread("one"), client.readThread("two"), client.readThread("three")]); + assert.equal(calls.filter(c => c.url.endsWith("/issue")).length, 1); + assert.equal(calls.length, 4); +}); + +test("failed issuance clears single-flight so a later explicit attempt can work", async () => { + let attempts = 0; + const { client, calls } = fixture((url) => { + if (url.endsWith("/issue")) { + attempts++; + return attempts === 1 ? json({ error: "invalid_api_key" }, 401) : json({ rider: TOKEN, expires_in: 900 }); + } + return json({ messages: [] }); + }); + await assert.rejects(client.readThread("peer"), { code: "invalid_api_key", status: 401 }); + assert.equal(calls.length, 1); + await client.readThread("peer"); + assert.equal(attempts, 2); +}); + +test("401 invalidates credential but never automatically resends a DM", async () => { + const { client, calls } = fixture((url) => url.endsWith("/issue") + ? json({ rider: TOKEN, expires_in: 900 }) + : json({ error: "invalid_rider" }, 401)); + await assert.rejects(client.sendDirectMessage("peer", "Hello"), { code: "invalid_rider", status: 401 }); + assert.equal(calls.length, 2); + await assert.rejects(client.sendDirectMessage("peer", "Explicit retry"), { code: "invalid_rider" }); + assert.equal(calls.length, 4); +}); + +test("429 exposes retry-after without retrying", async () => { + const { client, calls } = fixture((url) => url.endsWith("/issue") + ? json({ rider: TOKEN, expires_in: 900 }) + : json({ error: "rate_limit_exceeded" }, 429, { "Retry-After": "60" })); + await assert.rejects(client.sendDirectMessage("peer", "Hello"), { status: 429, retryAfter: 60 }); + assert.equal(calls.length, 2); +}); + +test("500 response never automatically retries a possibly delivered message", async () => { + const { client, calls } = fixture((url) => url.endsWith("/issue") + ? json({ rider: TOKEN, expires_in: 900 }) + : json({ error: `remote echoed ${KEY} ${TOKEN}` }, 500)); + await assert.rejects(client.sendDirectMessage("peer", "Hello"), error => { + assert.equal(error.code, "http_500"); + assert.equal(`${error.stack}${JSON.stringify(error)}`.includes(KEY), false); + assert.equal(error.body, undefined); + return true; + }); + assert.equal(calls.length, 2); +}); + +test("network failure is sanitized and is not retried", async () => { + const { client, calls } = fixture(() => { throw new Error(`transport exposed ${KEY}`); }); + await assert.rejects(client.readThread("peer"), error => { + assert.equal(error.code, "network_error"); + assert.equal(error.stack.includes(KEY), false); + assert.equal(error.cause, undefined); + return true; + }); + assert.equal(calls.length, 1); +}); + +test("timeout aborts the request", async () => { + let aborted = false; + const client = createRiderClient({ + apiKey: KEY, timeoutMs: 5, + fetchImpl: async (_url, { signal }) => new Promise((_resolve, reject) => { + signal.addEventListener("abort", () => { aborted = true; reject(new Error("aborted")); }, { once: true }); + }), + }); + await assert.rejects(client.readThread("peer"), { code: "request_timeout" }); + assert.equal(aborted, true); +}); + +for (const base of ["http://example.com", "https://user:pass@example.com", "https://example.com/path", "https://example.com?key=x", "https://example.com#x", "file:///tmp"]) { + test(`rejects unsafe destination ${base}`, () => { + assert.throws(() => createRiderClient({ apiKey: KEY, base }), { code: "invalid_base_url" }); + }); +} + +test("allows explicit loopback development and normalizes trailing slash", async () => { + let destination; + await issueRider(KEY, { + base: "http://127.0.0.1:3000/", + fetchImpl: async url => { destination = url; return json({ rider: TOKEN, expires_in: 900 }); }, + }); + assert.equal(destination, "http://127.0.0.1:3000/api/rider/issue"); +}); + +test("input errors never mint a credential", async () => { + const { client, calls } = fixture(); + for (const id of ["", "..", "a/b", "a?b", "a#b", "a b"]) { + await assert.rejects(client.readThread(id), { code: "invalid_agent_id" }); + } + await assert.rejects(client.sendDirectMessage("peer", " "), { code: "content_required" }); + await assert.rejects(client.sendDirectMessage("peer", "x".repeat(4001)), { code: "content_too_long" }); + assert.equal(calls.length, 0); +}); + +test("read-only scopes cannot send messages", async () => { + let calls = 0; + const client = createRiderClient({ + apiKey: KEY, scopes: ["dm:read"], + fetchImpl: async () => { calls++; return json({}); }, + }); + await assert.rejects(client.sendDirectMessage("peer", "Hello"), { code: "insufficient_scope" }); + assert.equal(calls, 0); +}); + +test("close prevents more operations", async () => { + const { client, calls } = fixture(); + await client.readThread("peer"); + client.close(); + await assert.rejects(client.readThread("peer"), { code: "client_closed" }); + assert.equal(calls.length, 2); +}); + +test("close during issuance prevents follow-on DM", async () => { + let resolve; + const { client, calls } = fixture(() => new Promise(r => { resolve = r; })); + const pending = client.sendDirectMessage("peer", "Hello"); + client.close(); + resolve(json({ rider: TOKEN, expires_in: 900 })); + await assert.rejects(pending, { code: "client_closed" }); + assert.equal(calls.length, 1); +}); + +test("malformed JSON is a typed error, not a successful empty object", async () => { + const { client } = fixture(() => new Response("upstream down", { status: 502 })); + await assert.rejects(client.readThread("peer"), { code: "invalid_json_response", status: 502 }); +}); + +test("malformed issuance cannot reach a gated route", async () => { + for (const body of [{}, { rider: TOKEN }, { rider: TOKEN, expires_in: 0 }, { rider: TOKEN, expires_in: 901 }, { rider: "bad", expires_in: 900 }, { rider: "..", expires_in: 900 }]) { + const { client, calls } = fixture(() => json(body)); + await assert.rejects(client.readThread("peer"), { code: "invalid_issue_response" }); + assert.equal(calls.length, 1); + } +}); + +test("registration forwards promo, referral and capability fields", async () => { + let sent; + const result = await registerSeat({ + name: "test-seat", promo_code: "TEST-PROMO", referral_code: "TEST-REF", + capabilities: ["fetch"], + fetchImpl: async (_url, options) => { sent = JSON.parse(options.body); return json({ agent_id: "test", api_key: KEY }, 201); }, + }); + assert.equal(sent.promo_code, "TEST-PROMO"); + assert.equal(sent.referral_code, "TEST-REF"); + assert.deepEqual(sent.capabilities, ["fetch"]); + assert.equal(result.api_key, KEY); +}); + +test("typed transport errors are exported", async () => { + await assert.rejects(issueRider(KEY, { + fetchImpl: async () => json({ error: "invalid_api_key" }, 401), + }), error => error instanceof RiderApiError && error.status === 401); +}); + +async function localServer(t, handler) { + const server = createServer(handler); + server.listen(0, "127.0.0.1"); + await once(server, "listening"); + t.after(() => new Promise(resolve => { + server.close(resolve); + server.closeAllConnections(); + })); + return `http://127.0.0.1:${server.address().port}`; +} + +test("native HTTP transport performs issue -> send -> read with correct auth separation", async t => { + const seen = []; + const base = await localServer(t, async (req, res) => { + let body = ""; + for await (const chunk of req) body += chunk; + seen.push({ path: req.url, method: req.method, headers: req.headers, body }); + res.setHeader("Content-Type", "application/json"); + if (req.url === "/api/rider/issue") res.end(JSON.stringify({ rider: TOKEN, expires_in: 900 })); + else if (req.method === "POST") { res.statusCode = 201; res.end(JSON.stringify({ message: { id: "local-message" } })); } + else res.end(JSON.stringify({ messages: [{ id: "local-message" }] })); + }); + const client = createRiderClient({ apiKey: KEY, base }); + const sent = await client.sendDirectMessage("local-peer", "Local fixture only"); + const thread = await client.readThread("local-peer"); + assert.equal(sent.message.id, "local-message"); + assert.equal(thread.messages[0].id, "local-message"); + assert.equal(seen.length, 3); + assert.equal(seen[0].headers.authorization, `Bearer ${KEY}`); + for (const call of seen.slice(1)) { + assert.equal(call.headers.authorization, undefined); + assert.equal(call.headers["x-agent-rider"], TOKEN); + } + client.close(); +}); + +test("native HTTP transport never follows issuance or messaging redirects", async t => { + let leaked = 0; + const destination = await localServer(t, (_req, res) => { leaked++; res.end("{}"); }); + for (const redirectIssue of [true, false]) { + let calls = 0; + const base = await localServer(t, (req, res) => { + calls++; + if (!redirectIssue && req.url === "/api/rider/issue") { + res.setHeader("Content-Type", "application/json"); + res.end(JSON.stringify({ rider: TOKEN, expires_in: 900 })); + } else { + res.writeHead(307, { Location: `${destination}/must-not-receive-credentials` }); + res.end(); + } + }); + const client = createRiderClient({ apiKey: KEY, base }); + await assert.rejects(client.sendDirectMessage("local-peer", "Local fixture"), { code: "network_error" }); + assert.equal(calls, redirectIssue ? 1 : 2); + client.close(); + } + assert.equal(leaked, 0); +}); + +test("issuance transport latency cannot extend the token lifetime", async () => { + let now = 1_800_000_000_000; + let calls = 0; + const client = createRiderClient({ + apiKey: KEY, now: () => now, + fetchImpl: async () => { calls++; now += 901_000; return json({ rider: TOKEN, expires_in: 900 }); }, + }); + await assert.rejects(client.readThread("peer"), { code: "expired_issue_response" }); + assert.equal(calls, 1); +}); diff --git a/packages/agent-rider/src/index.mjs b/packages/agent-rider/src/index.mjs index e62fcaf..d20db5d 100644 --- a/packages/agent-rider/src/index.mjs +++ b/packages/agent-rider/src/index.mjs @@ -1,8 +1,12 @@ /** - * Thin Agent-Rider client — constants + register/issue helpers. + * Agent-Rider client: constants, register/issue, and scoped messaging. * Never logs api_key / rider JWT. Live host is Fly only. */ +import { requestJson } from "./transport.mjs"; +export { RiderApiError } from "./transport.mjs"; +export { createRiderClient } from "./client.mjs"; + export const LIVE_BASE = "https://agentrider.fly.dev"; export const MCP_URL = `${LIVE_BASE}/api/mcp`; export const PUBLIC_CASH_URL = "https://www.slidphilabs.com/pcc"; @@ -13,66 +17,58 @@ export const AGENTS_URL = `${LIVE_BASE}/api/agents`; export const RIDER_ISSUE_URL = `${LIVE_BASE}/api/rider/issue`; /** - * @param {{ name: string, type?: "agent"|"human", operator_id?: string, base?: string }} input + * @param {{ name: string, type?: "agent"|"human", operator_id?: string, + * promo_code?: string, referral_code?: string, capabilities?: string[], + * base?: string, fetchImpl?: typeof fetch, timeoutMs?: number }} input */ export async function registerSeat(input) { const base = input.base ?? LIVE_BASE; - const res = await fetch(`${base}/api/agents`, { + return requestJson(base, "/api/agents", { method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ + fetchImpl: input.fetchImpl, + timeoutMs: input.timeoutMs, + body: { name: input.name, type: input.type ?? "agent", operator_id: input.operator_id ?? "sandbox", - }), + promo_code: input.promo_code, + referral_code: input.referral_code, + capabilities: input.capabilities, + }, }); - const body = await res.json().catch(() => ({})); - if (!res.ok) { - const err = new Error(body.error || `register_failed_${res.status}`); - err.status = res.status; - err.body = body; - throw err; - } - return body; } /** * Mint L1 rider JWT from a vaulted ar_ key. Does not echo the key. * @param {string} apiKey - * @param {{ level?: string, scopes?: string[], base?: string }} [opts] + * @param {{ level?: string, scopes?: string[], base?: string, + * fetchImpl?: typeof fetch, timeoutMs?: number }} [opts] */ export async function issueRider(apiKey, opts = {}) { if (typeof apiKey !== "string" || !apiKey.startsWith("ar_")) { throw new Error("invalid_api_key_shape"); } const base = opts.base ?? LIVE_BASE; - const res = await fetch(`${base}/api/rider/issue`, { + return requestJson(base, "/api/rider/issue", { method: "POST", + fetchImpl: opts.fetchImpl, + timeoutMs: opts.timeoutMs, headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json", }, - body: JSON.stringify({ + body: { level: opts.level ?? "L1", scopes: opts.scopes ?? ["*"], - }), + }, }); - const body = await res.json().catch(() => ({})); - if (!res.ok) { - const err = new Error(body.error || `issue_failed_${res.status}`); - err.status = res.status; - err.body = body; - throw err; - } - return body; } /** Machine try_path from live discovery (free → paid pointers). */ export { verifyRiderCredential, ISSUER } from "./verify.mjs"; export async function fetchTryPath(base = LIVE_BASE) { - const res = await fetch(`${base}/api/discovery`); - const body = await res.json(); + const body = await requestJson(base, "/api/discovery"); return body.try_path ?? null; } diff --git a/packages/agent-rider/src/transport.mjs b/packages/agent-rider/src/transport.mjs new file mode 100644 index 0000000..87a23e1 --- /dev/null +++ b/packages/agent-rider/src/transport.mjs @@ -0,0 +1,73 @@ +/** Transport shared by the thin helpers and stateful messaging client. */ +export class RiderApiError extends Error { + constructor(code, { status = null, retryAfter = null } = {}) { + super(code); + this.name = "RiderApiError"; + this.code = code; + this.status = status; + this.retryAfter = retryAfter; + } +} + +const PUBLIC_ERRORS = new Set([ + "missing_name", "register_failed", "missing_auth", "invalid_api_key", + "missing_rider", "invalid_rider", "insufficient_clearance", "insufficient_scope", + "rate_limit_exceeded", "recipient_not_found", "content_required", + "content_too_long", "missing_fields", "sandbox_not_configured", +]); + +export function normalizeBase(base) { + let url; + try { url = new URL(base); } catch { throw new RiderApiError("invalid_base_url"); } + const loopback = ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname); + if ( + (url.protocol !== "https:" && !(url.protocol === "http:" && loopback)) || + url.username || url.password || url.search || url.hash || url.pathname !== "/" + ) throw new RiderApiError("invalid_base_url"); + return url.origin; +} + +export async function requestJson(base, path, { + method = "GET", headers = {}, body, fetchImpl = globalThis.fetch, + timeoutMs = 10_000, +} = {}) { + if (!Number.isFinite(timeoutMs) || timeoutMs <= 0 || timeoutMs > 2_147_483_647) { + throw new RiderApiError("invalid_timeout"); + } + const controller = new AbortController(); + const timer = setTimeout(() => controller.abort(), timeoutMs); + try { + const res = await fetchImpl(`${normalizeBase(base)}${path}`, { + method, + headers: { Accept: "application/json", ...headers, ...(body === undefined ? {} : { "Content-Type": "application/json" }) }, + body: body === undefined ? undefined : JSON.stringify(body), + signal: controller.signal, + // Never forward a permanent key or rider to a redirected destination. + redirect: "error", + }); + let data; + try { data = await res.json(); } catch { + if (controller.signal.aborted) throw new RiderApiError("request_timeout"); + throw new RiderApiError("invalid_json_response", { status: res.status }); + } + if (!res.ok) { + const code = PUBLIC_ERRORS.has(data?.error) ? data.error : `http_${res.status}`; + const retry = res.headers?.get("retry-after"); + const seconds = retry && /^\d+$/.test(retry) ? Number(retry) : null; + // No raw body, headers, request URL, key, token, or remote error echo. + throw new RiderApiError(code, { + status: res.status, + retryAfter: Number.isSafeInteger(seconds) ? seconds : null, + }); + } + if (!data || typeof data !== "object" || Array.isArray(data)) { + throw new RiderApiError("invalid_json_response", { status: res.status }); + } + return data; + } catch (error) { + if (error instanceof RiderApiError) throw error; + throw new RiderApiError(controller.signal.aborted ? "request_timeout" : "network_error"); + } finally { + clearTimeout(timer); + } +} diff --git a/src/next-env.d.ts b/src/next-env.d.ts index 9edff1c..ce4e94a 100644 --- a/src/next-env.d.ts +++ b/src/next-env.d.ts @@ -1,6 +1,7 @@ /// /// import "./.next/types/routes.d.ts"; +import "./.next/types/root-params.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/src/package-lock.json b/src/package-lock.json index 3543837..caf42f5 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -7,15 +7,15 @@ "": { "name": "agentrider", "version": "2.1.0", - "license": "SEE LICENSE IN LICENSE", + "license": "(AGPL-3.0-or-later OR LicenseRef-SlidPhiLabs-Commercial)", "dependencies": { "@anthropic-ai/sdk": "^0.68.0", "@coinbase/cdp-sdk": "^1.56.0", - "@modelcontextprotocol/sdk": "^1.19.1", + "@modelcontextprotocol/sdk": "^1.31.0", "@supabase/supabase-js": "^2.45.4", "@vercel/analytics": "^2.0.1", "jose": "^6.2.3", - "next": "16.2.10", + "next": "16.3.6", "react": "19.2.7", "react-dom": "19.2.7", "stripe": "^22.3.1", @@ -27,6 +27,9 @@ "@types/react-dom": "19.2.3", "typescript": "^5.5.4" }, + "engines": { + "node": ">=22" + }, "funding": { "type": "individual", "url": "https://agentrider.fly.dev/api/discovery" @@ -106,9 +109,9 @@ } }, "node_modules/@emnapi/runtime": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz", - "integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==", + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", + "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", "license": "MIT", "optional": true, "dependencies": { @@ -116,11 +119,12 @@ } }, "node_modules/@hono/node-server": { - "version": "1.19.14", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz", - "integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-2.1.3.tgz", + "integrity": "sha512-TA//nWMqPhbfdfneACk6t5a9eqbS9lABEPyKn0/xZTah3H3U2XaVg85rJFl0/Fyit0I552YDHgXGVSf3GwqbUw==", + "license": "MIT", "engines": { - "node": ">=18.14.1" + "node": ">=20" }, "peerDependencies": { "hono": "^4" @@ -137,9 +141,9 @@ } }, "node_modules/@img/sharp-darwin-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", - "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.5.tgz", + "integrity": "sha512-QRUlFQ0WxvdWyqqG/WtI3iupfD5rBzmCHXSdPsY91sAtVtTo7Q4cb6zOccZ3gqEqkr0f1As1ehLqmEpDsRf+lg==", "cpu": [ "arm64" ], @@ -149,19 +153,19 @@ "darwin" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.2.4" + "@img/sharp-libvips-darwin-arm64": "1.3.4" } }, "node_modules/@img/sharp-darwin-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", - "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.5.tgz", + "integrity": "sha512-+BR255RhDlpygUpOc/Jdt1nT6DQ3XG/ERo5wbcdOf5Q320dKtPCKPLR1LJs9VGXRaMa8l1uUa0tkCNOXiAxZUw==", "cpu": [ "x64" ], @@ -171,19 +175,38 @@ "darwin" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.4" + "@img/sharp-libvips-darwin-x64": "1.3.4" + } + }, + "node_modules/@img/sharp-freebsd-wasm32": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.5.tgz", + "integrity": "sha512-Y/z91nEZ4uIBX5X3nfTovjU9lHNKFYbL2lpHCLVNmXQK03VIZvXBBt0KxbPGp2SdGSF+2mQU4e+hQaWOt86iAw==", + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "dependencies": { + "@img/sharp-wasm32": "0.35.5" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" } }, "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", - "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.4.tgz", + "integrity": "sha512-5R89nBYiRdUlSWJxPhO+GVtaXzXSxKnRu/xqMn3KTA3L9EB9Oy/P+Nn2f2vlhPuUdy/Zusb2DarbyTpGCfEDuw==", "cpu": [ "arm64" ], @@ -197,9 +220,9 @@ } }, "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", - "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.4.tgz", + "integrity": "sha512-iR2OKH80yi0U+dUplyh3/xdpFvps6YkCwsXenIJxqxR1v9o+xtKTGbS9H7cps+2Vxjc8B1j96p75NmTGjIhtpQ==", "cpu": [ "x64" ], @@ -213,9 +236,9 @@ } }, "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", - "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.4.tgz", + "integrity": "sha512-LmRtTsOHuvM2+wlO2Db37dx5MiZhB0FvSunciw48YjdOkZz9KAiRbm8ujeMOA1INqmei5NapFxYEK1D1ZSidmw==", "cpu": [ "arm" ], @@ -229,9 +252,9 @@ } }, "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", - "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.4.tgz", + "integrity": "sha512-Y3dgX/6lE2QhQb+Gxy0WZxfg9MEm/JBjamZpS2IklP7xIQoKN4hzAm7KcMVGtaVDt3neE9OKBC7vAfonA/Lr1A==", "cpu": [ "arm64" ], @@ -245,9 +268,9 @@ } }, "node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", - "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.4.tgz", + "integrity": "sha512-Le6boB8Tai0Nis+gIxIpKx68UDVVIqdR8Tin5Yf1z2LJJQLDJvCDRqRu+jC2qCoD+eIomonmOwB4smBRxfVpYQ==", "cpu": [ "ppc64" ], @@ -261,9 +284,9 @@ } }, "node_modules/@img/sharp-libvips-linux-riscv64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", - "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.4.tgz", + "integrity": "sha512-aHkkIEHPRdQEegJN20MLmGtxYD9R2wQr3Cwpddnu5+YKMt6Uzax7S9h5gpZTo8wyrGuZSlfQ63OevL5mTyOC7Q==", "cpu": [ "riscv64" ], @@ -277,9 +300,9 @@ } }, "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", - "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.4.tgz", + "integrity": "sha512-ra/mB6MikESDUO7Yg+Mi95bFBb9GsObURuhnOv3OqknjGe9sZrG8tCe9q0xSIGrtLgvgw0gKnFWcK4blSgQOuQ==", "cpu": [ "s390x" ], @@ -293,9 +316,9 @@ } }, "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", - "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.4.tgz", + "integrity": "sha512-GJ//SSXbnwSDes02umB3nDJLFcQzw8a18V8fyhqr6tV515tOEMdImjjxj1AoafMRz56F3PHgftnj1QEKSU1zkw==", "cpu": [ "x64" ], @@ -309,9 +332,9 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", - "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.4.tgz", + "integrity": "sha512-hvulFwtjUcagsis6BBxHwGFwWoNZjgYmULGVrZcyfNbjA8hKILbRxGg15/7w5HDyXHXUos/j6baAWqnCyQ2DWA==", "cpu": [ "arm64" ], @@ -325,9 +348,9 @@ } }, "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", - "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.4.tgz", + "integrity": "sha512-6zXKeE/p39I1AmA3cJG35eyBGNqNddLnUXjhwBnsGjFPWqf5VKkDBEqaEkPDoTEtkxwi2vv8Tcr2mDyP4So7Fg==", "cpu": [ "x64" ], @@ -341,9 +364,9 @@ } }, "node_modules/@img/sharp-linux-arm": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", - "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.5.tgz", + "integrity": "sha512-LEaXK2WdXVK5ykcw0buWyPMsmLLL2vpHLD6yrNSW+JGEL3BZPA4tpKN6iaMc4AxTTAoaX/sU1rOL51lcIz48ZQ==", "cpu": [ "arm" ], @@ -353,19 +376,19 @@ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.4" + "@img/sharp-libvips-linux-arm": "1.3.4" } }, "node_modules/@img/sharp-linux-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", - "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.5.tgz", + "integrity": "sha512-LYVx5JTsOM2CBzmxreh+nl64/3H6Xb09iSLknqH47z2T2DFFxDeFLP5y4dJwe6H7uGQlHPyEEtIqyo3DYsRwdQ==", "cpu": [ "arm64" ], @@ -375,19 +398,19 @@ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.4" + "@img/sharp-libvips-linux-arm64": "1.3.4" } }, "node_modules/@img/sharp-linux-ppc64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", - "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.5.tgz", + "integrity": "sha512-QVxAAq8evVRI9ia2vqgwrmWucn5Dfv+JdWzj75pD8omHLPSP7f8p20O8jxzjCcuCEQEOtYOZUmX1hkiZ0kdevA==", "cpu": [ "ppc64" ], @@ -397,19 +420,19 @@ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.2.4" + "@img/sharp-libvips-linux-ppc64": "1.3.4" } }, "node_modules/@img/sharp-linux-riscv64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", - "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.5.tgz", + "integrity": "sha512-LtdreXguaavKODPIfzJ4kffx7UNt1omwtK0rch4EBbbSTXPnxWmYSayXdLJw0fJzQ97kHt1gL/yh4tvU+nCyRQ==", "cpu": [ "riscv64" ], @@ -419,19 +442,19 @@ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-riscv64": "1.2.4" + "@img/sharp-libvips-linux-riscv64": "1.3.4" } }, "node_modules/@img/sharp-linux-s390x": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", - "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.5.tgz", + "integrity": "sha512-UZasTOFiYzotTsGOCu42BfUzP6Tu6Do/947iRm1RsLKvlllxwGcn4RN27LibGWceix4Y+Pmw3jsnTcCQIgWjqA==", "cpu": [ "s390x" ], @@ -441,19 +464,19 @@ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.2.4" + "@img/sharp-libvips-linux-s390x": "1.3.4" } }, "node_modules/@img/sharp-linux-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", - "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.5.tgz", + "integrity": "sha512-SxFtLTeJInhAA9Q836kux2vZNeOBQEx658qvbboZScr0wIARym3IcGmW7KpVD5sbVg0Ojy+udFQdayYIZyoNog==", "cpu": [ "x64" ], @@ -463,19 +486,19 @@ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.4" + "@img/sharp-libvips-linux-x64": "1.3.4" } }, "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", - "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.5.tgz", + "integrity": "sha512-9HbMclmI1zlNkFRs3z9/eBtDjfD0sGlrX1z6b1qwmiFY5ElDLh4BC0LPBdVp7z1DXFiKlIcznf+ZlsuZzLxQqg==", "cpu": [ "arm64" ], @@ -485,19 +508,19 @@ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + "@img/sharp-libvips-linuxmusl-arm64": "1.3.4" } }, "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", - "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.5.tgz", + "integrity": "sha512-4KOphqB035HrVdqLZfCgMzzERrQkkzOwRhl4OAkRO1YCldbaFjySXMaK534Mo0V+LndnlJk+sbUyLeU0ULyD1A==", "cpu": [ "x64" ], @@ -507,38 +530,54 @@ "linux" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + "@img/sharp-libvips-linuxmusl-x64": "1.3.4" } }, "node_modules/@img/sharp-wasm32": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", - "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.5.tgz", + "integrity": "sha512-Ptsga1su4tQx+LLF1ECS9U6nz5kmrXKo6XVbtR48Ke3ZRxxgaWBu7IDtEe1quo8hiupwm6WFqxVlXaSf7IINGQ==", + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.11.3" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-webcontainers-wasm32": { + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.5.tgz", + "integrity": "sha512-hfhF/FmoQyTUkA0bIKFOtw536BQSeBMe6BF6QyWlrPxT754+TFLaZ7sKKTfvvM0yJgKgaYTwnFCIZ/GuDw5SUA==", "cpu": [ "wasm32" ], - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "license": "Apache-2.0", "optional": true, "dependencies": { - "@emnapi/runtime": "^1.7.0" + "@img/sharp-wasm32": "0.35.5" }, "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" } }, "node_modules/@img/sharp-win32-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", - "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.5.tgz", + "integrity": "sha512-X4t7g+7ZA5DKblCBEXGjUqqemj4vczING/5viFwAL8h4N3qYeyjwdCvRLHi4EdOUI+2Z7UFlp1VM+p/AuEtm6Q==", "cpu": [ "arm64" ], @@ -548,16 +587,16 @@ "win32" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" } }, "node_modules/@img/sharp-win32-ia32": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", - "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.5.tgz", + "integrity": "sha512-5Zm82LoBc43nhwNybZlG7Y1KO//Zhsn306fQl29ZOuStHLGTo3BWL83q3cznX0poxSAMuYL1On/BHBxkBeKr6A==", "cpu": [ "ia32" ], @@ -567,16 +606,16 @@ "win32" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": "^20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" } }, "node_modules/@img/sharp-win32-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", - "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.5.tgz", + "integrity": "sha512-x76eH0vEiHlcMQu8Y8IenntaACtddpT6W0wmXtWrnKcnKI7ME5DdgqhAD6SEWOEl1v2zDvkZDhFA9KnURwpfqg==", "cpu": [ "x64" ], @@ -586,18 +625,19 @@ "win32" ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" } }, "node_modules/@modelcontextprotocol/sdk": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz", - "integrity": "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==", + "version": "1.32.1", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.32.1.tgz", + "integrity": "sha512-2DdE+SJDtzLEEWzY1ZjY7Q+VcPhcV1KisD3zI4u0XZyktsjHum1mwbMI+JaulUBi2OZk+KJAi2uPXzxichPkdw==", + "license": "MIT", "dependencies": { - "@hono/node-server": "^1.19.9", + "@hono/node-server": "^1.19.9 || ^2.0.5", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", @@ -632,15 +672,15 @@ } }, "node_modules/@next/env": { - "version": "16.2.10", - "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.10.tgz", - "integrity": "sha512-zLPxg9M0MEHmygpj5OuxjQ+vHMiy/K7cSp74G8ecYolmgUWw0RwN02tF56npup/+qaI8JB97hQgS/r2Hb6QwVA==", + "version": "16.3.6", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.3.6.tgz", + "integrity": "sha512-x9Vblze1EbtltQYnNH38xCPWU3TVfBd1eXqA3+w9+BTpedkkdNpAaltXlGQ/nsc1+E0mVTNrtcbX3GoO09zeLQ==", "license": "MIT" }, "node_modules/@next/swc-darwin-arm64": { - "version": "16.2.10", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.10.tgz", - "integrity": "sha512-v9IdJCa0H0mbo+8z5zwUpOk1Vj7RjkcI5uNYf5Ws1y6szf/p3Mzl9hLaST8SCt6L9h8NGnruZcd2+o0NTNwDhA==", + "version": "16.3.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.3.6.tgz", + "integrity": "sha512-E/7GEqaUkt8mk/T8v9lAnrhzR06kdq1ZBkC12F8tAMkdIadwNp3H1KqHynDHrpcTlGCUdq/qu6vUL2aYVyYBdw==", "cpu": [ "arm64" ], @@ -654,9 +694,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "16.2.10", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.10.tgz", - "integrity": "sha512-17IS0jJRViROGmA9uGdNR8VPJpfbnaVG7E9qhso5jDLkmyd0lSDORWxbcKINzcFqzZqGwGtMSnrFRxBpuUYjLQ==", + "version": "16.3.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.3.6.tgz", + "integrity": "sha512-yBE893/nDWTlaiBD1p+qgt7NUen4U5R6FXyH0s67Npq1S3E0cVSef1WIXC2xBRgQvwAvJq6DnS6Y6PrY0cy4Ew==", "cpu": [ "x64" ], @@ -670,9 +710,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "16.2.10", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.10.tgz", - "integrity": "sha512-GRQRsRtuciNJvB54AvvuQTiq0oZtFwa1owQqtZD8wwnGpM2L39MV22kpI72YSXLKIyY40LC66EiLFv4PiicXxg==", + "version": "16.3.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.3.6.tgz", + "integrity": "sha512-KJDpjBqBPYlvkivmyrp+Qys6k/7ksbqGQvRVc6ZEGfR+cjQxx+nUkJaWmNZJsmoOrqYNbaXByF8wa0lBwDhB3Q==", "cpu": [ "arm64" ], @@ -686,9 +726,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "16.2.10", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.10.tgz", - "integrity": "sha512-zkN9MQYS7UQBro+FnISUq1itaQjXI9xqISzuQ+2bc921NcJ1x4yPCqrn77tVN6/dOOXaaWVX3k6/bR07pPwK+A==", + "version": "16.3.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.3.6.tgz", + "integrity": "sha512-mqNg2K+hvWskSRb/QM+Ix412DvBsuSF0XV+frTSw5vmoucNnIlynFwKYew8D01bfATErMOM7Bujrf0BA5DRKFA==", "cpu": [ "arm64" ], @@ -702,9 +742,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "16.2.10", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.10.tgz", - "integrity": "sha512-iCVJnwvrPYECvA6WM/7+oo+OiTvedIKLxtCLAZP4xZR3nXa1zmzZyLPbYCmWvpd4CvMYF1EMTafd0ii3DygLvA==", + "version": "16.3.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.3.6.tgz", + "integrity": "sha512-nFncBNGAYouRHjRVaITs9beZRfhX4ssVwpnvPIAbkZVH6LtGoAVlH4bJ8Cnf9SOo9bsXgPFer/GdHtEE3JNOkw==", "cpu": [ "x64" ], @@ -718,9 +758,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "16.2.10", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.10.tgz", - "integrity": "sha512-ov2g4H0dHY9bPoOU83m91hWT7Iq5qy13bUnyyshLU3HGR1Ownn0X9QpmDPc5iIUaahTp7f7LeGAhV4DSFtackw==", + "version": "16.3.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.3.6.tgz", + "integrity": "sha512-5Mf3cHDGR/Iz0ng2Bj3zUR3p5QS9YK3Hn2QiAfavFmyF48zwThAjpFoiTKNIcOHLYS4zEk+gzyJ/9deQ2ZB8yQ==", "cpu": [ "x64" ], @@ -734,9 +774,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "16.2.10", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.10.tgz", - "integrity": "sha512-DwAnhLX76HQiFFQNgWlcK+JzlnD1rZ+UK/WY0ZMI/deXpvgnesjNYrqcfo1JzBuz4Kf7o3brIBL0glI1junatA==", + "version": "16.3.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.3.6.tgz", + "integrity": "sha512-0jkJy0C2kbrJWTk4YLa3xk80pVBpx8FCHJym7CnUfDAXe/FWv5qT7SQJbR0KuemyxaEDlEx5WT4VQJoTW+/9Qw==", "cpu": [ "arm64" ], @@ -750,9 +790,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "16.2.10", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.10.tgz", - "integrity": "sha512-0JXq3b85Jk9Jg4ntLUbXSPvoDw3gpZou7twuKdoFG2jOw635v7+IiXfTaa0TxVMyx78pUjnrVYwLgjKfX4e6/A==", + "version": "16.3.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.3.6.tgz", + "integrity": "sha512-/YXjI1e5OXcZ7YpxRwgP/1jAV/SBKTzeVKqN2mk7mLpcICsyn3Gl5+dIfDTJp70M0ccMhyMMRso4v6mPDCGepg==", "cpu": [ "x64" ], @@ -1863,9 +1903,9 @@ } }, "node_modules/@swc/helpers": { - "version": "0.5.15", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", - "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "version": "0.5.23", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz", + "integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.8.0" @@ -2056,9 +2096,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.10.43", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.43.tgz", - "integrity": "sha512-AjYpR78kDWAY3Efj+cDTFH9t9SCoL7OoTp1BOb0mQV7S+6CiLwnWM3FyxhJtdPufDFKzmCSFoUncKjWgJEZTCQ==", + "version": "2.11.27", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.27.tgz", + "integrity": "sha512-ElY12DaROGuan+lMmZ8Cvo/ZUbXPe7Enc/9VU/b1T3Kp4dwytRcNdR8DoSJN5SNJT/CuvcCA0DHDVmMOCePdRQ==", "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.cjs" @@ -2509,9 +2549,9 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-uri": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.3.tgz", - "integrity": "sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", + "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", "funding": [ { "type": "github", @@ -2521,7 +2561,8 @@ "type": "opencollective", "url": "https://opencollective.com/fastify" } - ] + ], + "license": "BSD-3-Clause" }, "node_modules/finalhandler": { "version": "2.1.1", @@ -2708,9 +2749,10 @@ } }, "node_modules/hono": { - "version": "4.12.30", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.30.tgz", - "integrity": "sha512-emn+JoJjrN9YTpRDS5it/UI2SO9BAE37T6I3d963RxcZ81G9A4pr2SZTEiiaiKbzx+NKRg5BZ89fCL7gCJCUog==", + "version": "4.13.13", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.13.13.tgz", + "integrity": "sha512-CQ46U0ZkAGmbT/4UxdzzGJpacP2IeKgY4a5/tOI9AABbpOMfK739wfDXmv1usCk+3RkKj1hQy4/fjhiwa2xlrA==", + "license": "MIT", "engines": { "node": ">=16.9.0" } @@ -2776,9 +2818,10 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ip-address": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", - "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.3.tgz", + "integrity": "sha512-A1kdq/tSb5QjvKvAMgIoEvDBIgL7qaqVP/jkvSwYYRZ9iEzvPpopxp2wQfu3SuZRHtpHNxMn8Fs0bS+gf5Xmwg==", + "license": "MIT", "engines": { "node": ">= 12" } @@ -2932,9 +2975,9 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/nanoid": { - "version": "3.3.15", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz", - "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", + "version": "3.3.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.20.tgz", + "integrity": "sha512-uKdg2G3GNCKQn9byYOpxbGqrT2fGO5KRt5J/8b3pok8rT6qxGWF6hxMyJiEYtAf+FVyYuD9hRaDqX5uPFYJ4ZQ==", "funding": [ { "type": "github", @@ -2958,16 +3001,16 @@ } }, "node_modules/next": { - "version": "16.2.10", - "resolved": "https://registry.npmjs.org/next/-/next-16.2.10.tgz", - "integrity": "sha512-2som5AVXb3kE6Yjine3/mNbBayYF58eguBWIVVUdr1y/L426xyVEgYxgBG+1QC34P2x5E+tcDup6XkuOAX3dCA==", + "version": "16.3.6", + "resolved": "https://registry.npmjs.org/next/-/next-16.3.6.tgz", + "integrity": "sha512-L+otWM/aQbYTx98aZhgEoMb4bZAXx1YVW4UMA/vuCyCoWG5HJyZUili8QAkqzrcC+5///tsz3s0M+SlyB5bLMw==", "license": "MIT", "dependencies": { - "@next/env": "16.2.10", - "@swc/helpers": "0.5.15", + "@next/env": "16.3.6", + "@swc/helpers": "0.5.23", "baseline-browser-mapping": "^2.9.19", "caniuse-lite": "^1.0.30001579", - "postcss": "8.4.31", + "postcss": "8.5.23", "styled-jsx": "5.1.6" }, "bin": { @@ -2977,15 +3020,15 @@ "node": ">=20.9.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "16.2.10", - "@next/swc-darwin-x64": "16.2.10", - "@next/swc-linux-arm64-gnu": "16.2.10", - "@next/swc-linux-arm64-musl": "16.2.10", - "@next/swc-linux-x64-gnu": "16.2.10", - "@next/swc-linux-x64-musl": "16.2.10", - "@next/swc-win32-arm64-msvc": "16.2.10", - "@next/swc-win32-x64-msvc": "16.2.10", - "sharp": "^0.34.5" + "@next/swc-darwin-arm64": "16.3.6", + "@next/swc-darwin-x64": "16.3.6", + "@next/swc-linux-arm64-gnu": "16.3.6", + "@next/swc-linux-arm64-musl": "16.3.6", + "@next/swc-linux-x64-gnu": "16.3.6", + "@next/swc-linux-x64-musl": "16.3.6", + "@next/swc-win32-arm64-msvc": "16.3.6", + "@next/swc-win32-x64-msvc": "16.3.6", + "sharp": "^0.35.4" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", @@ -3139,9 +3182,9 @@ } }, "node_modules/postcss": { - "version": "8.5.16", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.16.tgz", - "integrity": "sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==", + "version": "8.5.29", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.29.tgz", + "integrity": "sha512-49cGhUbXj8Qenv0iTMxA1cFBzxXoctpC9Ujd77t1WcbJIr6nF/eI7g/8MgxrYldFRuAXvja7xQRwavoW7kgrxQ==", "funding": [ { "type": "opencollective", @@ -3158,24 +3201,29 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.12", + "nanoid": "^3.3.19", "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "source-map-js": "^1.2.2" }, "engines": { "node": "^10 || ^12 || >=14" } }, "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.8.tgz", + "integrity": "sha512-5nnx0yGyVUcY6t9RnWcARWtwT9F1D8O9rt08htPvnd49W1IgZtmLkhu9WfMzQj1cFxjHIO6connUNVW5k7AVyQ==", + "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" }, "engines": { "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/proxy-from-env": { @@ -3188,9 +3236,10 @@ } }, "node_modules/qs": { - "version": "6.15.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", - "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz", + "integrity": "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==", + "license": "BSD-3-Clause", "dependencies": { "es-define-property": "^1.0.1", "side-channel": "^1.1.1" @@ -3345,48 +3394,53 @@ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "node_modules/sharp": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", - "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", - "hasInstallScript": true, + "version": "0.35.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.5.tgz", + "integrity": "sha512-Ywn4OnzGukp7CDMrp08RQ50YKmuwG47brZgIVPTvBaaAfQlRlygrRqSrxdCiL9M+LlzLBiJ68IR1QqvzHyjC7g==", "license": "Apache-2.0", "optional": true, "dependencies": { - "@img/colour": "^1.0.0", + "@img/colour": "^1.1.0", "detect-libc": "^2.1.2", - "semver": "^7.7.3" + "semver": "^7.8.5" }, "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=20.9.0" }, "funding": { "url": "https://opencollective.com/libvips" }, "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.5", + "@img/sharp-darwin-x64": "0.35.5", + "@img/sharp-freebsd-wasm32": "0.35.5", + "@img/sharp-libvips-darwin-arm64": "1.3.4", + "@img/sharp-libvips-darwin-x64": "1.3.4", + "@img/sharp-libvips-linux-arm": "1.3.4", + "@img/sharp-libvips-linux-arm64": "1.3.4", + "@img/sharp-libvips-linux-ppc64": "1.3.4", + "@img/sharp-libvips-linux-riscv64": "1.3.4", + "@img/sharp-libvips-linux-s390x": "1.3.4", + "@img/sharp-libvips-linux-x64": "1.3.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.3.4", + "@img/sharp-libvips-linuxmusl-x64": "1.3.4", + "@img/sharp-linux-arm": "0.35.5", + "@img/sharp-linux-arm64": "0.35.5", + "@img/sharp-linux-ppc64": "0.35.5", + "@img/sharp-linux-riscv64": "0.35.5", + "@img/sharp-linux-s390x": "0.35.5", + "@img/sharp-linux-x64": "0.35.5", + "@img/sharp-linuxmusl-arm64": "0.35.5", + "@img/sharp-linuxmusl-x64": "0.35.5", + "@img/sharp-webcontainers-wasm32": "0.35.5", + "@img/sharp-win32-arm64": "0.35.5", + "@img/sharp-win32-ia32": "0.35.5", + "@img/sharp-win32-x64": "0.35.5" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, "node_modules/shebang-command": { @@ -3477,9 +3531,9 @@ } }, "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" diff --git a/src/package.json b/src/package.json index 89f568a..bbe827d 100644 --- a/src/package.json +++ b/src/package.json @@ -1,6 +1,7 @@ { "name": "agentrider", "version": "2.1.0", + "engines": { "node": ">=22" }, "scripts": { "dev": "next dev", "build": "next build", @@ -43,11 +44,11 @@ "dependencies": { "@coinbase/cdp-sdk": "^1.56.0", "@anthropic-ai/sdk": "^0.68.0", - "@modelcontextprotocol/sdk": "^1.19.1", + "@modelcontextprotocol/sdk": "^1.31.0", "@supabase/supabase-js": "^2.45.4", "@vercel/analytics": "^2.0.1", "jose": "^6.2.3", - "next": "16.2.10", + "next": "16.3.6", "react": "19.2.7", "react-dom": "19.2.7", "stripe": "^22.3.1", @@ -62,7 +63,7 @@ "overrides": { "@types/react": "19.2.17", "@types/react-dom": "19.2.3", - "postcss": "^8.5.10" + "postcss": "^8.5.23" }, "license": "(AGPL-3.0-or-later OR LicenseRef-SlidPhiLabs-Commercial)", "homepage": "https://agentrider.fly.dev",