diff --git a/apps/dashboard/src/components/agents/agent-integration-guides/cloudflare-agent-hosting-guide.tsx b/apps/dashboard/src/components/agents/agent-integration-guides/cloudflare-agent-hosting-guide.tsx new file mode 100644 index 00000000000..a385253de00 --- /dev/null +++ b/apps/dashboard/src/components/agents/agent-integration-guides/cloudflare-agent-hosting-guide.tsx @@ -0,0 +1,92 @@ +import { AgentIntegrationGuideSection } from './agent-integration-guide-section'; +import { AgentIntegrationGuideStep } from './agent-integration-guide-step'; + +type CloudflareAgentHostingGuideProps = { + agentIdentifier: string; +}; + +const WORKER_SNIPPET = `import { AIChatAgent } from '@cloudflare/ai-chat'; +import { routeAgentRequest } from 'agents'; +import { withNovuAgent, createNovuRouter } from '@novu/framework/cloudflare'; + +export class MyAgent extends withNovuAgent(AIChatAgent) { + static novuAgentId = '{{AGENT_ID}}'; + + async onNovuMessage(ctx) { + await ctx.reply('Hello from Cloudflare Workers!'); + } +} + +export default { + fetch: createNovuRouter({ + agents: { MyAgent }, + fallthrough: routeAgentRequest, + }), +};`; + +const WRANGLER_SNIPPET = `{ + "durable_objects": { + "bindings": [{ "name": "MyAgent", "class_name": "MyAgent" }] + }, + "migrations": [ + { "tag": "v1", "new_sqlite_classes": ["MyAgent"] } + ] +}`; + +export function CloudflareAgentHostingGuide({ agentIdentifier }: CloudflareAgentHostingGuideProps) { + const workerCode = WORKER_SNIPPET.replace('{{AGENT_ID}}', agentIdentifier); + + return ( +
+ +

+ Use @novu/framework/cloudflare to run your agent as a + Cloudflare Durable Object with built-in per-conversation state, scheduling, and multi-channel delivery through + Novu. +

+
+ +
+

Steps

+ + + + + {workerCode} + + } + /> + + + {WRANGLER_SNIPPET} + + } + /> + + + + +
+
+ ); +} diff --git a/examples/cloudflare-agent/README.md b/examples/cloudflare-agent/README.md new file mode 100644 index 00000000000..c4b1297390d --- /dev/null +++ b/examples/cloudflare-agent/README.md @@ -0,0 +1,60 @@ +# Novu + Cloudflare Agents Example + +A minimal example showing how to connect a Cloudflare `AIChatAgent` Durable Object to Novu's multi-channel delivery (Slack, WhatsApp, Teams, etc.). + +## How it works + +1. A user sends a message in Slack (or WhatsApp, Teams, etc.) +2. Novu receives the webhook and normalizes it +3. Novu POSTs a signed `AgentBridgeRequest` to your Worker's bridge URL +4. `createNovuRouter` verifies the HMAC and routes to the correct Durable Object (keyed by conversation ID) +5. `withNovuAgent` intercepts the request inside the DO and calls your `onNovuMessage` handler +6. Your handler calls `ctx.reply()` which POSTs back to Novu +7. Novu delivers the reply to the original channel + +## Setup + +### 1. Install dependencies + +```bash +npm install +``` + +### 2. Set your Novu secret key + +```bash +wrangler secret put NOVU_SECRET_KEY +``` + +Paste the secret key from your Novu dashboard (Settings > API Keys). + +### 3. Deploy + +```bash +npm run deploy +``` + +### 4. Connect to Novu + +In the Novu dashboard: + +1. Go to **Agents** and create an agent with identifier `wine-bot` +2. Set the **Bridge URL** to `https://.workers.dev/` +3. Add a channel integration (Slack, WhatsApp, etc.) to the agent + +That's it. Messages from the connected channel will now flow through your Cloudflare Agent. + +## Local development + +```bash +npm run dev +``` + +Use `wrangler dev --remote` for a stable URL that Novu can reach, or use a tunnel like `cloudflared tunnel`. + +## Key concepts + +- **`withNovuAgent(AIChatAgent)`** — mixin that adds `onNovuMessage`, `onNovuAction`, `onNovuReaction`, `onNovuResolve` lifecycle hooks to any Cloudflare Agent class +- **`createNovuRouter`** — Worker fetch handler that verifies Novu signatures, routes bridge calls to the right DO, and falls through to `routeAgentRequest` for standard Cloudflare Agent traffic +- **`ctx.serialize()`** — returns a `NovuConversationRef` you can pass to `this.schedule()`, `this.setState()`, or any other persistence mechanism to reply later +- **`this.replyFromRef(ref, content)`** — reply to a Novu conversation from any context (scheduled task, `@callable`, `onEmail`, etc.) diff --git a/examples/cloudflare-agent/package.json b/examples/cloudflare-agent/package.json new file mode 100644 index 00000000000..c492c8717e6 --- /dev/null +++ b/examples/cloudflare-agent/package.json @@ -0,0 +1,17 @@ +{ + "name": "novu-cloudflare-agent-example", + "private": true, + "type": "module", + "scripts": { + "dev": "wrangler dev", + "deploy": "wrangler deploy" + }, + "dependencies": { + "@novu/framework": "file:../../packages/framework", + "agents": "latest" + }, + "devDependencies": { + "wrangler": "latest", + "typescript": "^5.5.0" + } +} diff --git a/examples/cloudflare-agent/src/index.ts b/examples/cloudflare-agent/src/index.ts new file mode 100644 index 00000000000..1a1ad93fd59 --- /dev/null +++ b/examples/cloudflare-agent/src/index.ts @@ -0,0 +1,88 @@ +import { Agent, routeAgentRequest } from 'agents'; +import { + withNovuAgent, + createNovuRouter, + toMessageList, + Card, + CardText, + Actions, + Button, + type NovuConversationRef, + type AgentContext, +} from '@novu/framework/cloudflare'; + +interface Env { + AI: Ai; + CleaningBot: DurableObjectNamespace; + NOVU_SECRET_KEY: string; +} + +export class CleaningBot extends withNovuAgent(Agent) { + static novuAgentId = 'cleaning-bot'; + + async onNovuMessage(ctx: AgentContext) { + const messages = toMessageList(ctx); + + const result = await this.env.AI.run('@cf/meta/llama-3.3-70b-instruct-fp8-fast', { + messages: [ + { + role: 'system', + content: + 'You are a helpful cleaning assistant. Keep answers concise (2-3 sentences max). Give practical cleaning tips.', + }, + ...messages, + ], + }); + + const text = (result as { response?: string }).response ?? 'Sorry, I could not generate a response.'; + + await ctx.reply( + Card({ + title: 'Cleaning Assistant', + children: [ + CardText(text), + Actions([ + Button({ id: 'follow-up', label: 'Remind me in 30s', style: 'primary' }), + Button({ id: 'done', label: 'Thanks, all clean!', style: 'secondary' }), + ]), + ], + }) + ); + } + + async onNovuAction(ctx: AgentContext) { + if (ctx.action?.actionId === 'follow-up') { + await ctx.reply('Got it! I\'ll send you a reminder in 30 seconds.'); + this.schedule(30, 'sendReminder', ctx.serialize()); + + return; + } + + if (ctx.action?.actionId === 'done') { + ctx.metadata.set('resolved', true); + ctx.metadata.set('resolvedAt', new Date().toISOString()); + await ctx.reply( + Card({ + title: 'Session complete', + children: [ + CardText('Great job! Your space is sparkling clean. Message me anytime you need more tips.'), + ], + }) + ); + ctx.resolve('User marked as done'); + } + } + + async sendReminder(ref: NovuConversationRef) { + await this.replyFromRef(ref, { + markdown: 'Hey! Just checking in — did you finish that cleaning task? Let me know if you need more tips!', + }); + } +} + +export default { + fetch: createNovuRouter({ + agents: { CleaningBot }, + fallthrough: routeAgentRequest, + }), +}; diff --git a/examples/cloudflare-agent/wrangler.jsonc b/examples/cloudflare-agent/wrangler.jsonc new file mode 100644 index 00000000000..b7e4063604c --- /dev/null +++ b/examples/cloudflare-agent/wrangler.jsonc @@ -0,0 +1,33 @@ +{ + "name": "novu-cloudflare-agent-example", + "main": "src/index.ts", + "compatibility_date": "2025-04-01", + "compatibility_flags": ["nodejs_compat"], + "observability": { + "logs": { + "enabled": true, + "invocation_logs": true + } + }, + "ai": { + "binding": "AI" + }, + "durable_objects": { + "bindings": [ + { + "name": "CleaningBot", + "class_name": "CleaningBot" + } + ] + }, + "migrations": [ + { + "tag": "v1", + "new_sqlite_classes": ["WineBot"] + }, + { + "tag": "v2", + "renamed_classes": [{ "from": "WineBot", "to": "CleaningBot" }] + } + ] +} diff --git a/packages/framework/cloudflare/helpers/package.json b/packages/framework/cloudflare/helpers/package.json new file mode 100644 index 00000000000..8f40ffcf8fb --- /dev/null +++ b/packages/framework/cloudflare/helpers/package.json @@ -0,0 +1,3 @@ +{ + "main": "../../dist/cjs/servers/cloudflare/helpers.cjs" +} diff --git a/packages/framework/cloudflare/package.json b/packages/framework/cloudflare/package.json new file mode 100644 index 00000000000..7f9d1b5b7b9 --- /dev/null +++ b/packages/framework/cloudflare/package.json @@ -0,0 +1,3 @@ +{ + "main": "../dist/cjs/servers/cloudflare/index.cjs" +} diff --git a/packages/framework/docs/cloudflare-agents.md b/packages/framework/docs/cloudflare-agents.md new file mode 100644 index 00000000000..3d8ee191400 --- /dev/null +++ b/packages/framework/docs/cloudflare-agents.md @@ -0,0 +1,198 @@ +# Cloudflare Agents Integration + +Deploy Novu agents on Cloudflare Workers using Durable Objects for per-conversation state, scheduling, and multi-channel delivery. + +## Install + +```bash +npm install @novu/framework agents @cloudflare/ai-chat +``` + +## Quick start + +```ts +// src/index.ts +import { AIChatAgent } from '@cloudflare/ai-chat'; +import { routeAgentRequest } from 'agents'; +import { withNovuAgent, createNovuRouter, type NovuConversationRef } from '@novu/framework/cloudflare'; + +export class WineBot extends withNovuAgent(AIChatAgent) { + static novuAgentId = 'wine-bot'; + + async onNovuMessage(ctx) { + await ctx.reply({ markdown: `You said: **${ctx.message?.text}**` }); + + // Schedule a follow-up using the serialized conversation ref + this.schedule('2h', 'followUp', ctx.serialize()); + } + + async followUp(ref: NovuConversationRef) { + await this.replyFromRef(ref, { markdown: 'Still thinking about that pairing?' }); + } +} + +export default { + fetch: createNovuRouter({ + agents: { WineBot }, + fallthrough: routeAgentRequest, + }), +}; +``` + +`wrangler.jsonc`: + +```jsonc +{ + "durable_objects": { + "bindings": [{ "name": "WineBot", "class_name": "WineBot" }] + }, + "migrations": [{ "tag": "v1", "new_sqlite_classes": ["WineBot"] }] +} +``` + +Set the secret key: + +```bash +wrangler secret put NOVU_SECRET_KEY +``` + +In the Novu dashboard, create an agent with identifier `wine-bot` and set the Bridge URL to your Worker URL. + +## API Reference + +### `withNovuAgent(Base)` + +A class mixin that adds Novu lifecycle hooks to any Cloudflare `Agent` or `AIChatAgent`: + +```ts +export class MyBot extends withNovuAgent(AIChatAgent) { + static novuAgentId = 'my-bot'; // must match the Novu agent identifier + + async onNovuMessage(ctx) { /* ... */ } + async onNovuAction(ctx) { /* ... */ } + async onNovuReaction(ctx) { /* ... */ } + async onNovuResolve(ctx) { /* ... */ } +} +``` + +#### Lifecycle hooks + +| Hook | When it fires | +|------|-------------| +| `onNovuMessage(ctx)` | Inbound message from any channel | +| `onNovuAction(ctx)` | Interactive element action (button click, select) | +| `onNovuReaction(ctx)` | Emoji reaction added/removed | +| `onNovuResolve(ctx)` | Conversation resolved | + +#### Instance methods + +| Method | Description | +|--------|-------------| +| `replyFromRef(ref, content)` | Reply to a conversation using a `NovuConversationRef`. Works from any context: `schedule`, `@callable`, `onEmail`. | +| `triggerWorkflow(workflowId, opts?)` | Trigger a Novu workflow from anywhere in the DO. | + +### `toMessageList(ctx)` + +Converts `ctx.history` + `ctx.message` into a `{ role, content }[]` array ready for any LLM client: + +```ts +import { toMessageList } from '@novu/framework/cloudflare'; + +async onNovuMessage(ctx) { + const result = await generateText({ + model: workersai('@cf/meta/llama-3.3-70b-instruct'), + messages: toMessageList(ctx), + }); + await ctx.reply({ markdown: result.text }); +} +``` + +Role mapping: `'agent'` / `'assistant'` → `'assistant'`, `'system'` → `'system'`, everything else → `'user'`. The current inbound message (if present) is appended as the final user turn. + +### `createNovuRouter(options)` + +Worker `fetch` handler that routes bridge traffic to DOs and delegates everything else. + +```ts +createNovuRouter({ + agents: { WineBot, SupportBot }, // binding name → class + workflows: [handoffWorkflow], // optional Novu workflows + fallthrough: routeAgentRequest, // optional — Cloudflare Agents SDK routing +}) +``` + +Order of operations: + +1. `POST ?action=agent-event` → verify HMAC, route to the DO via `getAgentByName(env.X, conversationId)` +2. Other `action` values (`trigger`, `execute`, `preview`, `health-check`, `discover`) → delegate to `NovuRequestHandler` +3. No action match → `fallthrough` (e.g. `routeAgentRequest` for Cloudflare SDK's `/agents/*` routing) +4. Nothing matches → `404` + +### `ctx.serialize()` → `NovuConversationRef` + +Returns a JSON-safe ref you can pass to any persistence mechanism: + +```ts +type NovuConversationRef = { + replyUrl: string; + conversationId: string; + integrationIdentifier: string; +}; +``` + +| Persistence path | How | +|-----------------|-----| +| Schedule payload | `this.schedule('2h', 'method', ctx.serialize())` | +| DO state | `this.setState({ ref: ctx.serialize() })` | +| DO SQL | `this.sql\`INSERT ... VALUES (${JSON.stringify(ctx.serialize())})\`` | +| Workflow payload | Pass as workflow step input | + +The Novu secret key is **never** in the ref — it's always read from `this.env.NOVU_SECRET_KEY` at call time. + +### `verifyNovuSignature` + +For custom routing scenarios where you need to verify outside the router: + +```ts +import { verifyNovuSignature } from '@novu/framework/cloudflare'; + +await verifyNovuSignature(body, signatureHeader, secretKey, true); +``` + +## Opt-in helpers + +For users who want automatic "last ref" tracking: + +```ts +import { rememberLastRef, replyToLastConversation } from '@novu/framework/cloudflare/helpers'; + +class Bot extends withNovuAgent(Agent) { + async onNovuMessage(ctx) { + rememberLastRef(this, ctx); + await ctx.reply('Got it!'); + } + + async scheduledTask() { + await replyToLastConversation(this, { markdown: 'Still there?' }); + } +} +``` + +These helpers write `ctx.serialize()` to `this.setState()` under a private key. Import them explicitly from `@novu/framework/cloudflare/helpers` — the default mixin has zero implicit state writes. + +## How it compares to other adapters + +| Feature | `@novu/framework/lambda` | `@novu/framework/cloudflare` | +|---------|------------------------|----------------------------| +| Per-conversation state | None (stateless) | Built-in DO SQL + state | +| Deferred replies | Not possible | `schedule` + `replyFromRef` | +| React/WebSocket clients | Not supported | Works via `routeAgentRequest` fallthrough | + +The Cloudflare adapter is the only one that leverages the hosting platform's state primitives. Other adapters treat the bridge endpoint as stateless. + +## Environment variables + +| Variable | Required | Description | +|----------|----------|-------------| +| `NOVU_SECRET_KEY` | Yes | Novu API secret key (set via `wrangler secret put`) | +| `NOVU_API_URL` | No | Override for self-hosted Novu (defaults to `https://api.novu.co`) | diff --git a/packages/framework/package.json b/packages/framework/package.json index ad33479c85b..aeaabde1b6f 100644 --- a/packages/framework/package.json +++ b/packages/framework/package.json @@ -26,6 +26,7 @@ "remix", "step-resolver", "sveltekit", + "cloudflare", "jsx-runtime", "jsx-dev-runtime", "validators", @@ -60,7 +61,9 @@ "next", "nuxt", "h3", - "express" + "express", + "cloudflare", + "durable-objects" ], "author": "Novu Team ", "license": "ISC", @@ -204,6 +207,26 @@ "types": "./dist/esm/validators.d.ts", "default": "./dist/esm/validators.js" } + }, + "./cloudflare": { + "require": { + "types": "./dist/cjs/servers/cloudflare/index.d.cts", + "default": "./dist/cjs/servers/cloudflare/index.cjs" + }, + "import": { + "types": "./dist/esm/servers/cloudflare/index.d.ts", + "default": "./dist/esm/servers/cloudflare/index.js" + } + }, + "./cloudflare/helpers": { + "require": { + "types": "./dist/cjs/servers/cloudflare/helpers.d.cts", + "default": "./dist/cjs/servers/cloudflare/helpers.cjs" + }, + "import": { + "types": "./dist/esm/servers/cloudflare/helpers.d.ts", + "default": "./dist/esm/servers/cloudflare/helpers.js" + } } }, "peerDependencies": { @@ -214,6 +237,8 @@ "express": ">=4.19.2", "h3": ">=1.8.1", "next": ">=12.0.0", + "agents": ">=0.1.0", + "@cloudflare/ai-chat": ">=0.1.0", "zod": ">=3.0.0", "zod-to-json-schema": ">=3.0.0" }, @@ -247,6 +272,12 @@ }, "zod-to-json-schema": { "optional": true + }, + "agents": { + "optional": true + }, + "@cloudflare/ai-chat": { + "optional": true } }, "devDependencies": { diff --git a/packages/framework/src/handler.ts b/packages/framework/src/handler.ts index 455418b5630..6336536dbf5 100644 --- a/packages/framework/src/handler.ts +++ b/packages/framework/src/handler.ts @@ -6,25 +6,13 @@ import { HttpQueryKeysEnum, HttpStatusEnum, PostActionEnum, - SIGNATURE_TIMESTAMP_TOLERANCE, } from './constants'; -import { - BridgeError, - FrameworkError, - InvalidActionError, - isFrameworkError, - MethodNotAllowedError, - SignatureExpiredError, - SignatureInvalidError, - SignatureMismatchError, - SignatureNotFoundError, - SigningKeyNotFoundError, -} from './errors'; +import { BridgeError, FrameworkError, InvalidActionError, isFrameworkError, MethodNotAllowedError } from './errors'; import { isPlatformError } from './errors/guard.errors'; import type { Agent, AgentBridgeRequest } from './resources/agent'; import { AgentContextImpl, AgentEventEnum } from './resources/agent'; import type { Awaitable, EventTriggerParams, Workflow } from './types'; -import { createHmacSubtle, initApiClient } from './utils'; +import { initApiClient, validateNovuSignature } from './utils'; export interface ServeHandlerOptions { client?: Client; @@ -346,34 +334,6 @@ export class NovuRequestHandler { } private async validateHmac(payload: unknown, hmacHeader: string | null): Promise { - if (!this.hmacEnabled) return; - if (!hmacHeader) { - throw new SignatureNotFoundError(); - } - - if (!this.client.secretKey) { - throw new SigningKeyNotFoundError(); - } - - const [timestampPart, signaturePart] = hmacHeader.split(','); - if (!timestampPart || !signaturePart) { - throw new SignatureInvalidError(); - } - - const [timestamp, timestampPayload] = timestampPart.split('='); - - const [signatureVersion, signaturePayload] = signaturePart.split('='); - - if (Number(timestamp) < Date.now() - SIGNATURE_TIMESTAMP_TOLERANCE) { - throw new SignatureExpiredError(); - } - - const localHash = await createHmacSubtle(this.client.secretKey, `${timestampPayload}.${JSON.stringify(payload)}`); - - const isMatching = localHash === signaturePayload; - - if (!isMatching) { - throw new SignatureMismatchError(); - } + return validateNovuSignature(payload, hmacHeader, this.client.secretKey, this.hmacEnabled); } } diff --git a/packages/framework/src/index.ts b/packages/framework/src/index.ts index fe8a6ff1daa..ad0fa861100 100644 --- a/packages/framework/src/index.ts +++ b/packages/framework/src/index.ts @@ -21,6 +21,7 @@ export type { FileRef, MessageContent, MetadataSignal, + NovuConversationRef, ReplyContent, Signal, TriggerSignal, diff --git a/packages/framework/src/resources/agent/agent.context.ts b/packages/framework/src/resources/agent/agent.context.ts index e4764ddfd65..85f5315e0f1 100644 --- a/packages/framework/src/resources/agent/agent.context.ts +++ b/packages/framework/src/resources/agent/agent.context.ts @@ -11,6 +11,7 @@ import type { AgentReplyPayload, AgentSubscriber, MessageContent, + NovuConversationRef, ReplyContent, Signal, } from './agent.types'; @@ -19,7 +20,7 @@ function isCardElement(content: object): content is import('chat').CardElement { return 'type' in content && (content as { type: string }).type === 'card'; } -function serializeContent(content: MessageContent): ReplyContent { +export function serializeContent(content: MessageContent): ReplyContent { if (typeof content === 'string') { return { text: content }; } @@ -128,6 +129,14 @@ export class AgentContextImpl implements AgentContext { this._signals.push({ type: 'trigger', workflowId, ...opts }); } + serialize(): NovuConversationRef { + return { + replyUrl: this._replyUrl, + conversationId: this._conversationId, + integrationIdentifier: this._integrationIdentifier, + }; + } + /** * Flush any remaining signals that weren't sent with reply(). * Called internally after onResolve returns. diff --git a/packages/framework/src/resources/agent/agent.types.ts b/packages/framework/src/resources/agent/agent.types.ts index d746e10fbc9..9d19bffb781 100644 --- a/packages/framework/src/resources/agent/agent.types.ts +++ b/packages/framework/src/resources/agent/agent.types.ts @@ -117,6 +117,13 @@ export interface AgentReaction { message: AgentMessage | null; } +/** Serializable handle for replying to a conversation outside a live bridge request. */ +export interface NovuConversationRef { + replyUrl: string; + conversationId: string; + integrationIdentifier: string; +} + export interface AgentContext { readonly event: string; readonly action: AgentAction | null; @@ -135,6 +142,9 @@ export interface AgentContext { set(key: string, value: unknown): void; }; trigger(workflowId: string, opts?: { to?: string; payload?: Record }): void; + + /** Return a JSON-safe ref that can be passed to schedule payloads, setState, etc. */ + serialize(): NovuConversationRef; } export interface AgentHandlers { diff --git a/packages/framework/src/resources/agent/index.ts b/packages/framework/src/resources/agent/index.ts index 30eac7a88a9..728de201806 100644 --- a/packages/framework/src/resources/agent/index.ts +++ b/packages/framework/src/resources/agent/index.ts @@ -11,7 +11,7 @@ export type { TextInputElement, } from 'chat'; export { Actions, Button, Card, CardLink, CardText, Divider, Select, SelectOption, TextInput } from 'chat'; -export { AgentContextImpl } from './agent.context'; +export { AgentContextImpl, serializeContent } from './agent.context'; export { agent } from './agent.resource'; export type { Agent, @@ -31,6 +31,7 @@ export type { FileRef, MessageContent, MetadataSignal, + NovuConversationRef, ReplyContent, Signal, TriggerSignal, diff --git a/packages/framework/src/servers/cloudflare/cloudflare.test.ts b/packages/framework/src/servers/cloudflare/cloudflare.test.ts new file mode 100644 index 00000000000..fd2ffd02463 --- /dev/null +++ b/packages/framework/src/servers/cloudflare/cloudflare.test.ts @@ -0,0 +1,385 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { AgentContextImpl } from '../../resources/agent/agent.context'; +import type { AgentBridgeRequest, NovuConversationRef } from '../../resources/agent/agent.types'; +import { validateNovuSignature } from '../../utils/signature.utils'; +import { createHmacSubtle } from '../../utils/crypto.utils'; + +function createMockBridgeRequest(overrides?: Partial): AgentBridgeRequest { + return { + version: 1, + timestamp: new Date().toISOString(), + deliveryId: 'del-123', + event: 'onMessage', + agentId: 'test-bot', + replyUrl: 'https://api.novu.co/v1/agents/test-bot/reply', + conversationId: 'conv-456', + integrationIdentifier: 'slack-main', + action: null, + reaction: null, + message: { + text: 'Hello bot!', + platformMessageId: 'msg-789', + author: { userId: 'u1', fullName: 'Alice', userName: 'alice', isBot: false }, + timestamp: new Date().toISOString(), + }, + conversation: { + identifier: 'conv-456', + status: 'active', + metadata: {}, + messageCount: 1, + createdAt: new Date().toISOString(), + lastActivityAt: new Date().toISOString(), + }, + subscriber: { + subscriberId: 'sub-001', + firstName: 'Alice', + email: 'alice@example.com', + }, + history: [], + platform: 'slack', + platformContext: { threadId: 't1', channelId: 'c1', isDM: false }, + ...overrides, + }; +} + +describe('AgentContextImpl.serialize()', () => { + it('should return a NovuConversationRef with the correct fields', () => { + const body = createMockBridgeRequest(); + const ctx = new AgentContextImpl(body, 'test-secret'); + + const ref = ctx.serialize(); + + expect(ref).toEqual({ + replyUrl: 'https://api.novu.co/v1/agents/test-bot/reply', + conversationId: 'conv-456', + integrationIdentifier: 'slack-main', + }); + }); + + it('should return the same ref on multiple calls', () => { + const body = createMockBridgeRequest(); + const ctx = new AgentContextImpl(body, 'test-secret'); + + const ref1 = ctx.serialize(); + const ref2 = ctx.serialize(); + + expect(ref1).toEqual(ref2); + }); + + it('should be JSON-safe (round-trips through JSON)', () => { + const body = createMockBridgeRequest(); + const ctx = new AgentContextImpl(body, 'test-secret'); + + const ref = ctx.serialize(); + const roundTripped = JSON.parse(JSON.stringify(ref)) as NovuConversationRef; + + expect(roundTripped).toEqual(ref); + }); +}); + +describe('validateNovuSignature()', () => { + const secretKey = 'test-secret-key'; + const payload = { foo: 'bar' }; + + async function buildSignatureHeader(secret: string, body: unknown): Promise { + const timestamp = Date.now(); + const hash = await createHmacSubtle(secret, `${timestamp}.${JSON.stringify(body)}`); + + return `t=${timestamp},v1=${hash}`; + } + + it('should pass for a valid signature', async () => { + const header = await buildSignatureHeader(secretKey, payload); + + await expect(validateNovuSignature(payload, header, secretKey, true)).resolves.toBeUndefined(); + }); + + it('should skip validation when hmacEnabled is false', async () => { + await expect(validateNovuSignature(payload, null, undefined, false)).resolves.toBeUndefined(); + }); + + it('should throw SignatureNotFoundError when header is null', async () => { + await expect(validateNovuSignature(payload, null, secretKey, true)).rejects.toThrow('Signature not found'); + }); + + it('should throw SigningKeyNotFoundError when secretKey is missing', async () => { + await expect(validateNovuSignature(payload, 'some-header', undefined, true)).rejects.toThrow( + 'Signature key not found' + ); + }); + + it('should throw SignatureInvalidError when header format is wrong', async () => { + await expect(validateNovuSignature(payload, 'bad-format', secretKey, true)).rejects.toThrow( + 'Signature is invalid' + ); + }); + + it('should throw SignatureMismatchError for wrong secret', async () => { + const header = await buildSignatureHeader('wrong-secret', payload); + + await expect(validateNovuSignature(payload, header, secretKey, true)).rejects.toThrow( + 'Signature does not match' + ); + }); + + it('should throw SignatureExpiredError for old timestamps', async () => { + const oldTimestamp = Date.now() - 1000 * 60 * 60; + const hash = await createHmacSubtle(secretKey, `${oldTimestamp}.${JSON.stringify(payload)}`); + const header = `t=${oldTimestamp},v1=${hash}`; + + await expect(validateNovuSignature(payload, header, secretKey, true)).rejects.toThrow('Signature expired'); + }); + + it('should throw SignatureVersionInvalidError for wrong version', async () => { + const timestamp = Date.now(); + const hash = await createHmacSubtle(secretKey, `${timestamp}.${JSON.stringify(payload)}`); + const header = `t=${timestamp},v2=${hash}`; + + await expect(validateNovuSignature(payload, header, secretKey, true)).rejects.toThrow('Signature version is invalid'); + }); +}); + +describe('withNovuAgent mixin', () => { + let fetchMock: ReturnType; + const originalFetch = global.fetch; + + beforeEach(() => { + fetchMock = vi.fn().mockResolvedValue({ + ok: true, + text: () => Promise.resolve('{}'), + json: () => Promise.resolve({ status: 'ok' }), + }); + global.fetch = fetchMock as typeof fetch; + }); + + afterEach(() => { + global.fetch = originalFetch; + }); + + it('replyFromRef should POST to the replyUrl with correct auth and body', async () => { + const { withNovuAgent } = await import('./with-novu-agent'); + + class FakeAgent { + env = { NOVU_SECRET_KEY: 'my-secret' }; + } + + class TestBot extends withNovuAgent(FakeAgent as any) { + static novuAgentId = 'test-bot'; + } + + const bot = new TestBot() as any; + + const ref: NovuConversationRef = { + replyUrl: 'https://api.novu.co/v1/agents/test-bot/reply', + conversationId: 'conv-123', + integrationIdentifier: 'slack-main', + }; + + await bot.replyFromRef(ref, 'Hello from schedule!'); + + expect(fetchMock).toHaveBeenCalledTimes(1); + + const [url, opts] = fetchMock.mock.calls[0]; + expect(url).toBe('https://api.novu.co/v1/agents/test-bot/reply'); + expect(opts.method).toBe('POST'); + expect(opts.headers.Authorization).toBe('ApiKey my-secret'); + + const body = JSON.parse(opts.body); + expect(body.conversationId).toBe('conv-123'); + expect(body.integrationIdentifier).toBe('slack-main'); + expect(body.reply.text).toBe('Hello from schedule!'); + }); + + it('replyFromRef should throw when NOVU_SECRET_KEY is missing', async () => { + const { withNovuAgent } = await import('./with-novu-agent'); + + class FakeAgent { + env = {}; + } + + class TestBot extends withNovuAgent(FakeAgent as any) { + static novuAgentId = 'test-bot'; + } + + const bot = new TestBot() as any; + const ref: NovuConversationRef = { + replyUrl: 'https://api.novu.co/v1/agents/test-bot/reply', + conversationId: 'conv-123', + integrationIdentifier: 'slack-main', + }; + + await expect(bot.replyFromRef(ref, 'hi')).rejects.toThrow('NOVU_SECRET_KEY'); + }); + + it('replyFromRef should throw when the reply endpoint returns non-ok', async () => { + fetchMock.mockResolvedValueOnce({ + ok: false, + status: 401, + text: () => Promise.resolve('Unauthorized'), + }); + + const { withNovuAgent } = await import('./with-novu-agent'); + + class FakeAgent { + env = { NOVU_SECRET_KEY: 'my-secret' }; + } + + class TestBot extends withNovuAgent(FakeAgent as any) { + static novuAgentId = 'test-bot'; + } + + const bot = new TestBot() as any; + const ref: NovuConversationRef = { + replyUrl: 'https://api.novu.co/v1/agents/test-bot/reply', + conversationId: 'conv-123', + integrationIdentifier: 'slack-main', + }; + + await expect(bot.replyFromRef(ref, 'hi')).rejects.toThrow('replyFromRef failed (401)'); + }); + +}); + +describe('helpers: rememberLastRef / replyToLastConversation', () => { + let fetchMock: ReturnType; + const originalFetch = global.fetch; + + beforeEach(() => { + fetchMock = vi.fn().mockResolvedValue({ + ok: true, + text: () => Promise.resolve('{}'), + }); + global.fetch = fetchMock as typeof fetch; + }); + + afterEach(() => { + global.fetch = originalFetch; + }); + + it('round-trips a ref through setState / state', async () => { + const { rememberLastRef, replyToLastConversation } = await import('./helpers'); + + let storedState: Record = { other: 'keep-me' }; + + const fakeAgent = { + env: { NOVU_SECRET_KEY: 'test-key' }, + state: storedState, + setState(newState: Record) { + storedState = newState; + this.state = storedState; + }, + }; + + const body = createMockBridgeRequest(); + const ctx = new AgentContextImpl(body, 'test-key'); + + rememberLastRef(fakeAgent, ctx); + + expect(storedState.__novuLastRef).toEqual({ + replyUrl: 'https://api.novu.co/v1/agents/test-bot/reply', + conversationId: 'conv-456', + integrationIdentifier: 'slack-main', + }); + expect(storedState.other).toBe('keep-me'); + + await replyToLastConversation(fakeAgent, 'ping'); + + expect(fetchMock).toHaveBeenCalledTimes(1); + const [url, opts] = fetchMock.mock.calls[0]; + expect(url).toBe('https://api.novu.co/v1/agents/test-bot/reply'); + + const sentBody = JSON.parse(opts.body); + expect(sentBody.reply.text).toBe('ping'); + expect(sentBody.conversationId).toBe('conv-456'); + }); + + it('replyToLastConversation throws when no ref was stored', async () => { + const { replyToLastConversation } = await import('./helpers'); + + const fakeAgent = { + env: { NOVU_SECRET_KEY: 'test-key' }, + state: {}, + setState() {}, + }; + + await expect(replyToLastConversation(fakeAgent, 'hello')).rejects.toThrow( + 'No conversation ref stored' + ); + }); +}); + +describe('toMessageList()', () => { + it('should map history + current message into LLM messages', async () => { + const { toMessageList } = await import('./convert-history'); + + const body = createMockBridgeRequest({ + history: [ + { role: 'subscriber', type: 'message', content: 'Hi there', createdAt: '2025-01-01T00:00:00Z' }, + { role: 'agent', type: 'message', content: 'Hello! How can I help?', createdAt: '2025-01-01T00:00:01Z' }, + ], + message: { + text: 'Tell me about Merlot', + platformMessageId: 'msg-2', + author: { userId: 'u1', fullName: 'Alice', userName: 'alice', isBot: false }, + timestamp: new Date().toISOString(), + }, + }); + const ctx = new AgentContextImpl(body, 'test-secret'); + + const messages = toMessageList(ctx); + + expect(messages).toEqual([ + { role: 'user', content: 'Hi there' }, + { role: 'assistant', content: 'Hello! How can I help?' }, + { role: 'user', content: 'Tell me about Merlot' }, + ]); + }); + + it('should handle empty history with only current message', async () => { + const { toMessageList } = await import('./convert-history'); + + const body = createMockBridgeRequest({ history: [] }); + const ctx = new AgentContextImpl(body, 'test-secret'); + + const messages = toMessageList(ctx); + + expect(messages).toEqual([{ role: 'user', content: 'Hello bot!' }]); + }); + + it('should handle history only (no current message)', async () => { + const { toMessageList } = await import('./convert-history'); + + const body = createMockBridgeRequest({ + message: null, + history: [ + { role: 'subscriber', type: 'message', content: 'Previous msg', createdAt: '2025-01-01T00:00:00Z' }, + ], + }); + const ctx = new AgentContextImpl(body, 'test-secret'); + + const messages = toMessageList(ctx); + + expect(messages).toEqual([{ role: 'user', content: 'Previous msg' }]); + }); + + it('should map system role entries', async () => { + const { toMessageList } = await import('./convert-history'); + + const body = createMockBridgeRequest({ + message: null, + history: [ + { role: 'system', type: 'message', content: 'You are a wine bot', createdAt: '2025-01-01T00:00:00Z' }, + { role: 'subscriber', type: 'message', content: 'Hello', createdAt: '2025-01-01T00:00:01Z' }, + ], + }); + const ctx = new AgentContextImpl(body, 'test-secret'); + + const messages = toMessageList(ctx); + + expect(messages).toEqual([ + { role: 'system', content: 'You are a wine bot' }, + { role: 'user', content: 'Hello' }, + ]); + }); +}); diff --git a/packages/framework/src/servers/cloudflare/convert-history.ts b/packages/framework/src/servers/cloudflare/convert-history.ts new file mode 100644 index 00000000000..dd711764e20 --- /dev/null +++ b/packages/framework/src/servers/cloudflare/convert-history.ts @@ -0,0 +1,48 @@ +import type { AgentContext, AgentHistoryEntry } from '../../resources/agent'; + +type LLMMessage = { + role: 'user' | 'assistant' | 'system'; + content: string; +}; + +/** + * Convert a Novu agent context into a message list ready for any LLM client + * (Vercel AI SDK, OpenAI, Anthropic, Workers AI, etc.). + * + * Includes the full conversation history plus the current inbound message + * (if present) as the final user turn. + * + * @example + * ```ts + * import { toMessageList } from '@novu/framework/cloudflare'; + * + * async onNovuMessage(ctx) { + * const result = await generateText({ + * model: workersai('@cf/meta/llama-3.3-70b-instruct'), + * messages: toMessageList(ctx), + * }); + * await ctx.reply({ markdown: result.text }); + * } + * ``` + */ +export function toMessageList(ctx: AgentContext): LLMMessage[] { + const messages: LLMMessage[] = ctx.history.map(mapHistoryEntry); + + if (ctx.message?.text) { + messages.push({ role: 'user', content: ctx.message.text }); + } + + return messages; +} + +function mapHistoryEntry(entry: AgentHistoryEntry): LLMMessage { + if (entry.role === 'agent' || entry.role === 'assistant') { + return { role: 'assistant', content: entry.content }; + } + + if (entry.role === 'system') { + return { role: 'system', content: entry.content }; + } + + return { role: 'user', content: entry.content }; +} diff --git a/packages/framework/src/servers/cloudflare/helpers.ts b/packages/framework/src/servers/cloudflare/helpers.ts new file mode 100644 index 00000000000..92f9862b193 --- /dev/null +++ b/packages/framework/src/servers/cloudflare/helpers.ts @@ -0,0 +1,75 @@ +/** + * Opt-in helpers for users who want automatic "last ref" tracking without + * manually threading NovuConversationRef through schedule payloads or state. + * + * @example + * ```ts + * import { rememberLastRef, replyToLastConversation } from '@novu/framework/cloudflare/helpers'; + * + * class Bot extends withNovuAgent(Agent) { + * async onNovuMessage(ctx) { + * rememberLastRef(this, ctx); + * await ctx.reply('Got it!'); + * } + * + * async scheduledFollowUp() { + * await replyToLastConversation(this, { markdown: 'Still there?' }); + * } + * } + * ``` + */ + +import type { AgentContext, AgentReplyPayload, MessageContent, NovuConversationRef } from '../../resources/agent'; +import { serializeContent } from '../../resources/agent'; + +const STATE_KEY = '__novuLastRef'; + +interface StatefulAgent { + state: Record; + setState(patch: Record): void; + env: Record; +} + +/** + * Stash the current conversation ref on the agent's DO state. + * Call this inside `onNovuMessage` / `onNovuAction` / etc. + */ +export function rememberLastRef(agent: StatefulAgent, ctx: AgentContext): void { + agent.setState({ ...agent.state, [STATE_KEY]: ctx.serialize() }); +} + +/** + * Reply to the most recently remembered conversation. + * Requires `rememberLastRef` to have been called at least once. + */ +export async function replyToLastConversation(agent: StatefulAgent, content: MessageContent): Promise { + const ref = agent.state[STATE_KEY] as NovuConversationRef | undefined; + if (!ref?.replyUrl) { + throw new Error('No conversation ref stored — call rememberLastRef(agent, ctx) first'); + } + + const secretKey = agent.env.NOVU_SECRET_KEY as string | undefined; + if (!secretKey) { + throw new Error('NOVU_SECRET_KEY is not set in the Worker environment'); + } + + const body: AgentReplyPayload = { + conversationId: ref.conversationId, + integrationIdentifier: ref.integrationIdentifier, + reply: serializeContent(content), + }; + + const response = await fetch(ref.replyUrl, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `ApiKey ${secretKey}`, + }, + body: JSON.stringify(body), + }); + + if (!response.ok) { + const text = await response.text().catch(() => ''); + throw new Error(`replyToLastConversation failed (${response.status}): ${text}`); + } +} diff --git a/packages/framework/src/servers/cloudflare/index.ts b/packages/framework/src/servers/cloudflare/index.ts new file mode 100644 index 00000000000..00098737fa1 --- /dev/null +++ b/packages/framework/src/servers/cloudflare/index.ts @@ -0,0 +1,18 @@ +/* + * Re-export all top level exports from the main package. + * This results in better DX reduces the chances of the dual package hazard for ESM + CJS packages. + * + * Example: + * + * import { withNovuAgent, createNovuRouter, type NovuConversationRef } from '@novu/framework/cloudflare'; + * + * instead of + * + * import { withNovuAgent, createNovuRouter } from '@novu/framework/cloudflare'; + * import { type NovuConversationRef } from '@novu/framework'; + */ +export * from '../../index'; +export { withNovuAgent } from './with-novu-agent'; +export { createNovuRouter, verifyNovuSignature, frameworkName } from './router'; +export type { CreateNovuRouterOptions } from './router'; +export { toMessageList } from './convert-history'; diff --git a/packages/framework/src/servers/cloudflare/router.ts b/packages/framework/src/servers/cloudflare/router.ts new file mode 100644 index 00000000000..0956816bb29 --- /dev/null +++ b/packages/framework/src/servers/cloudflare/router.ts @@ -0,0 +1,202 @@ +import { Client } from '../../client'; +import { NovuRequestHandler, type ServeHandlerOptions } from '../../handler'; +import type { Workflow } from '../../types'; +import type { SupportedFrameworkName } from '../../types/server.types'; +import { validateNovuSignature } from '../../utils'; + +export const frameworkName: SupportedFrameworkName = 'cloudflare'; + +interface NovuAgentClass { + novuAgentId: string; + // biome-ignore lint/suspicious/noExplicitAny: Agent constructors vary + new (...args: any[]): any; +} + +interface CloudflareExecutionContext { + waitUntil(promise: Promise): void; + passThroughOnException(): void; +} + +export interface CreateNovuRouterOptions { + client?: ServeHandlerOptions['client']; + agents: Record; + workflows?: Workflow[]; + /** + * Fallback handler for requests that don't match any Novu action. + * Typically `routeAgentRequest` from the `agents` package so the + * Cloudflare Agents SDK's `/agents/*` routing keeps working. + */ + // biome-ignore lint/suspicious/noExplicitAny: env shape is user-defined + fallthrough?: (request: Request, env: any, ctx?: CloudflareExecutionContext) => Promise; +} + +/** + * Worker `fetch` handler that routes Novu bridge traffic to the correct + * Durable Object and delegates everything else (workflows, health checks) + * to the standard `NovuRequestHandler`. + * + * @example + * ```ts + * import { routeAgentRequest } from 'agents'; + * import { createNovuRouter } from '@novu/framework/cloudflare'; + * + * export default { + * fetch: createNovuRouter({ + * agents: { WineBot }, + * workflows: [handoffWorkflow], + * fallthrough: routeAgentRequest, + * }), + * }; + * ``` + */ +export function createNovuRouter(options: CreateNovuRouterOptions) { + const agentIdToBinding = new Map(); + for (const [bindingName, agentClass] of Object.entries(options.agents)) { + if (agentClass.novuAgentId) { + agentIdToBinding.set(agentClass.novuAgentId, bindingName); + } + } + + let cachedHandler: ((...args: [Request, unknown, CloudflareExecutionContext]) => Promise) | null = null; + let cachedClient: { secretKey: string; strictAuthentication: boolean } | null = null; + + // biome-ignore lint/suspicious/noExplicitAny: env shape is user-defined + function getOrCreateHandler(env: any) { + if (cachedHandler && cachedClient) { + return { baseHandler: cachedHandler, client: cachedClient }; + } + + const secretKey = env.NOVU_SECRET_KEY as string | undefined; + const client = options.client ?? new Client({ + secretKey, + strictAuthentication: Boolean(secretKey), + }); + + const novuHandler = new NovuRequestHandler({ + frameworkName, + client, + workflows: options.workflows, + handler: (request: Request, _env: unknown, ctx: CloudflareExecutionContext) => ({ + body: () => request.clone().json(), + headers: (key: string) => request.headers.get(key), + method: () => request.method, + url: () => new URL(request.url), + queryString: (key: string, url: URL) => url.searchParams.get(key), + waitUntil: ctx?.waitUntil?.bind(ctx), + transformResponse: ({ status, headers, body }) => new Response(body, { status, headers }), + }), + }); + + cachedHandler = novuHandler.createHandler(); + cachedClient = novuHandler.client; + + return { baseHandler: cachedHandler, client: cachedClient }; + } + + // biome-ignore lint/suspicious/noExplicitAny: env shape is user-defined + return async (request: Request, env: any, ctx: CloudflareExecutionContext): Promise => { + const url = new URL(request.url); + const action = url.searchParams.get('action') || ''; + + if (request.method === 'POST' && action === 'agent-event') { + const secretKey = env.NOVU_SECRET_KEY as string | undefined; + + return handleAgentEvent(request, url, env, agentIdToBinding, { + secretKey: secretKey || '', + strictAuthentication: Boolean(secretKey), + }); + } + + const { baseHandler } = getOrCreateHandler(env); + + if (request.method === 'OPTIONS') { + return baseHandler(request, env, ctx); + } + + if (action && action !== 'agent-event') { + return baseHandler(request, env, ctx); + } + + if (options.fallthrough) { + const result = await options.fallthrough(request, env, ctx); + if (result) { + return result; + } + } + + return new Response(JSON.stringify({ error: 'Not found' }), { + status: 404, + headers: { 'Content-Type': 'application/json' }, + }); + }; +} + +async function handleAgentEvent( + request: Request, + url: URL, + // biome-ignore lint/suspicious/noExplicitAny: env shape is user-defined + env: any, + agentIdToBinding: Map, + client: { secretKey: string; strictAuthentication: boolean } +): Promise { + try { + const bodyText = await request.text(); + const body = JSON.parse(bodyText); + + await validateNovuSignature( + body, + request.headers.get('x-novu-signature'), + client.secretKey, + client.strictAuthentication + ); + + const agentId = url.searchParams.get('agentId') || ''; + const bindingName = agentIdToBinding.get(agentId); + + if (!bindingName) { + return Response.json({ error: `Agent '${agentId}' not registered` }, { status: 404 }); + } + + const binding = env[bindingName]; + if (!binding) { + return Response.json( + { error: `Durable Object binding '${bindingName}' not found in env` }, + { status: 500 } + ); + } + + const conversationId = body.conversationId; + if (!conversationId) { + return Response.json({ error: 'Missing conversationId in body' }, { status: 400 }); + } + + const doId = binding.idFromName(conversationId); + const stub = binding.get(doId); + + const headers = new Headers(request.headers); + headers.set('x-novu-agent-namespace', bindingName); + headers.set('x-novu-agent-room', conversationId); + if (!headers.has('x-partykit-namespace')) { + headers.set('x-partykit-namespace', bindingName); + } + if (!headers.has('x-partykit-room')) { + headers.set('x-partykit-room', conversationId); + } + + const forwardedRequest = new Request(request.url, { + method: 'POST', + headers, + body: bodyText, + }); + + return stub.fetch(forwardedRequest); + } catch (err) { + const message = err instanceof Error ? err.message : 'Internal error'; + // biome-ignore lint/suspicious/noExplicitAny: error shape varies + const status = (err as any)?.statusCode ?? 500; + + return Response.json({ error: message }, { status }); + } +} + +export { validateNovuSignature as verifyNovuSignature } from '../../utils'; diff --git a/packages/framework/src/servers/cloudflare/with-novu-agent.ts b/packages/framework/src/servers/cloudflare/with-novu-agent.ts new file mode 100644 index 00000000000..aa266f9b6f8 --- /dev/null +++ b/packages/framework/src/servers/cloudflare/with-novu-agent.ts @@ -0,0 +1,190 @@ +import { AgentContextImpl, AgentEventEnum, serializeContent } from '../../resources/agent'; +import type { + AgentBridgeRequest, + AgentContext, + AgentReplyPayload, + MessageContent, + NovuConversationRef, +} from '../../resources/agent'; + +type Constructor = abstract new (...args: any[]) => T; + +interface NovuAgentStatics { + novuAgentId: string; +} + +interface NovuAgentInstance { + onNovuMessage?(ctx: AgentContext): Promise; + onNovuAction?(ctx: AgentContext): Promise; + onNovuReaction?(ctx: AgentContext): Promise; + onNovuResolve?(ctx: AgentContext): Promise; + + replyFromRef(ref: NovuConversationRef, content: MessageContent): Promise; + triggerWorkflow(workflowId: string, opts?: { to?: string; payload?: Record }): Promise; +} + +/** + * Mixin that adds Novu multi-channel agent capabilities to a Cloudflare + * `Agent` or `AIChatAgent` Durable Object. + * + * @example + * ```ts + * import { AIChatAgent } from '@cloudflare/ai-chat'; + * import { withNovuAgent } from '@novu/framework/cloudflare'; + * + * export class WineBot extends withNovuAgent(AIChatAgent) { + * static novuAgentId = 'wine-bot'; + * + * async onNovuMessage(ctx) { + * await ctx.reply('Hello from Cloudflare!'); + * } + * } + * ``` + */ +export function withNovuAgent(Base: TBase) { + abstract class NovuAgentMixin extends Base implements NovuAgentInstance { + static novuAgentId: string; + + declare env: Record; + + async onNovuMessage(_ctx: AgentContext): Promise { + /* override in subclass */ + } + + async onNovuAction(_ctx: AgentContext): Promise { + /* override in subclass */ + } + + async onNovuReaction(_ctx: AgentContext): Promise { + /* override in subclass */ + } + + async onNovuResolve(_ctx: AgentContext): Promise { + /* override in subclass */ + } + + /** + * Handle an inbound HTTP request. Novu bridge calls (with `?action=agent-event`) + * are intercepted; everything else passes through to the base class. + */ + async onRequest(request: Request): Promise { + const url = new URL(request.url); + const action = url.searchParams.get('action'); + + if (request.method === 'POST' && action === 'agent-event') { + return this._handleNovuBridgeRequest(request, url); + } + + if (typeof (Base.prototype as any).onRequest === 'function') { + return (Base.prototype as any).onRequest.call(this, request); + } + + return new Response('Not found', { status: 404 }); + } + + /** + * Post a reply to a Novu conversation using a previously serialized ref. + * Works from any context: scheduled tasks, @callable methods, onEmail, etc. + */ + async replyFromRef(ref: NovuConversationRef, content: MessageContent): Promise { + const secretKey = this.env.NOVU_SECRET_KEY as string | undefined; + if (!secretKey) { + throw new Error('NOVU_SECRET_KEY is not set in the Worker environment'); + } + + const body: AgentReplyPayload = { + conversationId: ref.conversationId, + integrationIdentifier: ref.integrationIdentifier, + reply: serializeContent(content), + }; + + const response = await fetch(ref.replyUrl, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `ApiKey ${secretKey}`, + }, + body: JSON.stringify(body), + }); + + if (!response.ok) { + const text = await response.text().catch(() => ''); + throw new Error(`replyFromRef failed (${response.status}): ${text}`); + } + } + + /** + * Trigger a Novu workflow from anywhere in the DO. + */ + async triggerWorkflow( + workflowId: string, + opts?: { to?: string; payload?: Record } + ): Promise { + const secretKey = this.env.NOVU_SECRET_KEY as string | undefined; + const apiUrl = (this.env.NOVU_API_URL as string) || 'https://api.novu.co'; + if (!secretKey) { + throw new Error('NOVU_SECRET_KEY is not set in the Worker environment'); + } + + const response = await fetch(`${apiUrl}/v1/events/trigger`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `ApiKey ${secretKey}`, + }, + body: JSON.stringify({ + name: workflowId, + to: opts?.to, + payload: opts?.payload ?? {}, + }), + }); + + if (!response.ok) { + const text = await response.text().catch(() => ''); + throw new Error(`triggerWorkflow failed (${response.status}): ${text}`); + } + } + + private async _handleNovuBridgeRequest(request: Request, url: URL): Promise { + try { + const body = (await request.json()) as AgentBridgeRequest; + const event = url.searchParams.get('event') || ''; + const secretKey = this.env.NOVU_SECRET_KEY as string | undefined; + + if (!secretKey) { + return Response.json({ error: 'NOVU_SECRET_KEY not configured' }, { status: 500 }); + } + + const ctx = new AgentContextImpl(body, secretKey); + + const handlerMap: Partial Promise>> = { + [AgentEventEnum.ON_MESSAGE]: this.onNovuMessage.bind(this), + [AgentEventEnum.ON_ACTION]: this.onNovuAction.bind(this), + [AgentEventEnum.ON_REACTION]: this.onNovuReaction.bind(this), + [AgentEventEnum.ON_RESOLVE]: this.onNovuResolve.bind(this), + }; + + const handler = handlerMap[event as AgentEventEnum]; + if (!handler) { + console.warn(`[novu-agent] Unknown event: ${event}`); + + return Response.json({ error: `Unknown event: ${event}` }, { status: 400 }); + } + + await handler(ctx); + await ctx.flush(); + + return Response.json({ status: 'ok' }); + } catch (err) { + console.error('[novu-agent] Bridge handler error:', err); + + return Response.json( + { error: err instanceof Error ? err.message : 'Internal error' }, + { status: 500 } + ); + } + } + } + + return NovuAgentMixin as unknown as TBase & NovuAgentStatics & (new (...args: any[]) => NovuAgentInstance); +} diff --git a/packages/framework/src/types/server.types.ts b/packages/framework/src/types/server.types.ts index 64400b228af..abbda1ad75b 100644 --- a/packages/framework/src/types/server.types.ts +++ b/packages/framework/src/types/server.types.ts @@ -1 +1,10 @@ -export type SupportedFrameworkName = 'next' | 'express' | 'nuxt' | 'h3' | 'sveltekit' | 'remix' | 'lambda' | 'nest'; +export type SupportedFrameworkName = + | 'next' + | 'express' + | 'nuxt' + | 'h3' + | 'sveltekit' + | 'remix' + | 'lambda' + | 'nest' + | 'cloudflare'; diff --git a/packages/framework/src/utils/index.ts b/packages/framework/src/utils/index.ts index 834c81faf13..52ff4958300 100644 --- a/packages/framework/src/utils/index.ts +++ b/packages/framework/src/utils/index.ts @@ -5,4 +5,5 @@ export * from './liquid.utils'; export * from './log.utils'; export * from './options.utils'; export * from './sanitize.utils'; +export * from './signature.utils'; export * from './string.utils'; diff --git a/packages/framework/src/utils/signature.utils.ts b/packages/framework/src/utils/signature.utils.ts new file mode 100644 index 00000000000..8a6a058792c --- /dev/null +++ b/packages/framework/src/utils/signature.utils.ts @@ -0,0 +1,49 @@ +import { SIGNATURE_TIMESTAMP_TOLERANCE } from '../constants'; +import { + SignatureExpiredError, + SignatureInvalidError, + SignatureMismatchError, + SignatureNotFoundError, + SigningKeyNotFoundError, +} from '../errors'; +import { createHmacSubtle } from './crypto.utils'; + +/** + * Validate the Novu HMAC signature header against a payload. + * + * Header format: `=,=` + */ +export async function validateNovuSignature( + payload: unknown, + hmacHeader: string | null, + secretKey: string | undefined, + hmacEnabled: boolean +): Promise { + if (!hmacEnabled) return; + + if (!hmacHeader) { + throw new SignatureNotFoundError(); + } + + if (!secretKey) { + throw new SigningKeyNotFoundError(); + } + + const [timestampPart, signaturePart] = hmacHeader.split(','); + if (!timestampPart || !signaturePart) { + throw new SignatureInvalidError(); + } + + const [timestamp, timestampPayload] = timestampPart.split('='); + const [, signaturePayload] = signaturePart.split('='); + + if (Number(timestamp) < Date.now() - SIGNATURE_TIMESTAMP_TOLERANCE) { + throw new SignatureExpiredError(); + } + + const localHash = await createHmacSubtle(secretKey, `${timestampPayload}.${JSON.stringify(payload)}`); + + if (localHash !== signaturePayload) { + throw new SignatureMismatchError(); + } +} diff --git a/packages/framework/tsup.config.ts b/packages/framework/tsup.config.ts index 4ca33520fea..a4f47699a80 100644 --- a/packages/framework/tsup.config.ts +++ b/packages/framework/tsup.config.ts @@ -2,7 +2,16 @@ import { defineConfig, type Options } from 'tsup'; import { version } from './package.json'; import { type SupportedFrameworkName } from './src/internal'; -const frameworks: SupportedFrameworkName[] = ['h3', 'express', 'next', 'nuxt', 'sveltekit', 'remix', 'lambda', 'nest']; +const frameworks: SupportedFrameworkName[] = [ + 'h3', + 'express', + 'next', + 'nuxt', + 'sveltekit', + 'remix', + 'lambda', + 'nest', +]; const baseConfig: Options = { entry: [ @@ -13,6 +22,8 @@ const baseConfig: Options = { 'src/step-resolver.ts', 'src/validators.ts', ...frameworks.map((framework) => `src/servers/${framework}.ts`), + 'src/servers/cloudflare/index.ts', + 'src/servers/cloudflare/helpers.ts', ], sourcemap: false, clean: true, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d1b97d44af5..b95574de0d8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -152,13 +152,13 @@ importers: version: 1.5.0 '@nx/jest': specifier: 21.3.11 - version: 21.3.11(@babel/traverse@7.28.0)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.15.13)(babel-plugin-macros@3.1.0)(esbuild-register@3.5.0(esbuild@0.27.3))(nx@21.3.11(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15)))(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.15.13)(typescript@5.6.2))(typescript@5.6.2) + version: 21.3.11(@babel/traverse@7.29.0)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.15.13)(babel-plugin-macros@3.1.0)(esbuild-register@3.5.0(esbuild@0.27.3))(nx@21.3.11(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15)))(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.15.13)(typescript@5.6.2))(typescript@5.6.2) '@nx/js': specifier: 21.3.11 - version: 21.3.11(@babel/traverse@7.28.0)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))(nx@21.3.11(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))) + version: 21.3.11(@babel/traverse@7.29.0)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))(nx@21.3.11(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))) '@nx/plugin': specifier: 21.3.11 - version: 21.3.11(@babel/traverse@7.28.0)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.15.13)(@zkochan/js-yaml@0.0.7)(babel-plugin-macros@3.1.0)(esbuild-register@3.5.0(esbuild@0.27.3))(eslint@9.39.4(jiti@2.6.1))(nx@21.3.11(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15)))(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.15.13)(typescript@5.6.2))(typescript@5.6.2) + version: 21.3.11(@babel/traverse@7.29.0)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.15.13)(@zkochan/js-yaml@0.0.7)(babel-plugin-macros@3.1.0)(esbuild-register@3.5.0(esbuild@0.27.3))(eslint@9.39.4(jiti@2.6.1))(nx@21.3.11(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15)))(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.15.13)(typescript@5.6.2))(typescript@5.6.2) '@nx/workspace': specifier: 21.3.11 version: 21.3.11(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15)) @@ -700,7 +700,7 @@ importers: version: 3.0.51(react@19.2.3)(zod@4.3.5) '@better-auth/sso': specifier: ^1.3.0 - version: 1.4.7(better-auth@1.5.6(f5eede22a65d6cd0c93a8bf1a87b70c5)) + version: 1.4.7(better-auth@1.5.6(bfb0779f1cc865575f8ea1b2503ee818)) '@calcom/embed-react': specifier: 1.5.2 version: 1.5.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -907,7 +907,7 @@ importers: version: 6.2.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) better-auth: specifier: ^1.4.9 - version: 1.5.6(f5eede22a65d6cd0c93a8bf1a87b70c5) + version: 1.5.6(bfb0779f1cc865575f8ea1b2503ee818) class-variance-authority: specifier: ^0.7.0 version: 0.7.1 @@ -2052,13 +2052,13 @@ importers: dependencies: '@better-auth/sso': specifier: ^1.4.9 - version: 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1)(better-auth@1.5.6(aac79383f71d2c0e811dbd569d97ebd4))(better-call@1.3.2(zod@4.3.6)) + version: 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1)(better-auth@1.5.6(778471f5f7178e7ab9fe0c8426d67ae9))(better-call@1.3.2(zod@4.3.6)) '@clerk/backend': specifier: ^1.25.2 version: 1.25.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@clerk/express': specifier: ^1.3.53 - version: 1.3.53(express@5.0.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + version: 1.3.53(express@5.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@nestjs/common': specifier: 10.4.18 version: 10.4.18(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) @@ -2091,7 +2091,7 @@ importers: version: link:../../../packages/stateless better-auth: specifier: ^1.4.9 - version: 1.5.6(aac79383f71d2c0e811dbd569d97ebd4) + version: 1.5.6(778471f5f7178e7ab9fe0c8426d67ae9) better-call: specifier: ^1.3.2 version: 1.3.2(zod@4.3.6) @@ -2383,7 +2383,7 @@ importers: version: 5.8.3 wrangler: specifier: ^4.49.0 - version: 4.68.1 + version: 4.68.1(@cloudflare/workers-types@4.20260416.2) libs/application-generic: dependencies: @@ -2731,7 +2731,7 @@ importers: devDependencies: '@nx/js': specifier: 20.1.2 - version: 20.1.2(@babel/traverse@7.28.0)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.15.13)(nx@20.1.2(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15)))(typescript@5.6.2)(verdaccio@5.31.0(encoding@0.1.13)(typanion@3.14.0)) + version: 20.1.2(@babel/traverse@7.29.0)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.15.13)(nx@20.1.2(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15)))(typescript@5.6.2)(verdaccio@5.31.0(encoding@0.1.13)(typanion@3.14.0)) '@swc-node/register': specifier: 1.10.10 version: 1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2) @@ -3312,6 +3312,12 @@ importers: packages/framework: dependencies: + '@cloudflare/ai-chat': + specifier: '>=0.1.0' + version: 0.4.4(@ai-sdk/react@3.0.51(react@19.2.3)(zod@3.25.20))(agents@0.11.0)(ai@6.0.68(zod@3.25.20))(react@19.2.3)(zod@3.25.20) + agents: + specifier: '>=0.1.0' + version: 0.11.0(@ai-sdk/react@3.0.51(react@19.2.3)(zod@3.25.20))(@babel/core@7.28.0)(@babel/runtime@7.28.3)(@cloudflare/ai-chat@0.4.4)(@cloudflare/workers-types@4.20260416.2)(ai@6.0.68(zod@3.25.20))(react@19.2.3)(rolldown@1.0.0-rc.16)(vite@6.4.2(@types/node@22.15.13)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.77.8)(sugarss@4.0.1(postcss@8.5.8))(terser@5.31.6)(tsx@4.16.2)(yaml@2.8.3))(zod@3.25.20) ajv: specifier: ^8.18.0 version: 8.18.0 @@ -5131,6 +5137,10 @@ packages: resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + engines: {node: '>=6.9.0'} + '@babel/compat-data@7.25.4': resolution: {integrity: sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==} engines: {node: '>=6.9.0'} @@ -5147,6 +5157,10 @@ packages: resolution: {integrity: sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==} engines: {node: '>=6.9.0'} + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + engines: {node: '>=6.9.0'} + '@babel/helper-annotate-as-pure@7.22.5': resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==} engines: {node: '>=6.9.0'} @@ -5183,6 +5197,12 @@ packages: peerDependencies: '@babel/core': 7.28.0 + '@babel/helper-create-class-features-plugin@7.28.6': + resolution: {integrity: sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': 7.28.0 + '@babel/helper-create-regexp-features-plugin@7.22.15': resolution: {integrity: sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==} engines: {node: '>=6.9.0'} @@ -5221,6 +5241,10 @@ packages: resolution: {integrity: sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==} engines: {node: '>=6.9.0'} + '@babel/helper-member-expression-to-functions@7.28.5': + resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} + engines: {node: '>=6.9.0'} + '@babel/helper-module-imports@7.18.6': resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} engines: {node: '>=6.9.0'} @@ -5259,6 +5283,10 @@ packages: resolution: {integrity: sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==} engines: {node: '>=6.9.0'} + '@babel/helper-optimise-call-expression@7.27.1': + resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} + engines: {node: '>=6.9.0'} + '@babel/helper-plugin-utils@7.22.5': resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} engines: {node: '>=6.9.0'} @@ -5271,6 +5299,10 @@ packages: resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} engines: {node: '>=6.9.0'} + '@babel/helper-plugin-utils@7.28.6': + resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} + engines: {node: '>=6.9.0'} + '@babel/helper-remap-async-to-generator@7.25.0': resolution: {integrity: sha512-NhavI2eWEIz/H9dbrG0TuOicDhNexze43i5z7lEqwYm0WEZVTwnPpA0EafUTP7+6/W79HWIP2cTe3Z5NiSTVpw==} engines: {node: '>=6.9.0'} @@ -5283,6 +5315,12 @@ packages: peerDependencies: '@babel/core': 7.28.0 + '@babel/helper-replace-supers@7.28.6': + resolution: {integrity: sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': 7.28.0 + '@babel/helper-simple-access@7.22.5': resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} engines: {node: '>=6.9.0'} @@ -5295,6 +5333,10 @@ packages: resolution: {integrity: sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==} engines: {node: '>=6.9.0'} + '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} + engines: {node: '>=6.9.0'} + '@babel/helper-split-export-declaration@7.22.6': resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} engines: {node: '>=6.9.0'} @@ -5380,6 +5422,12 @@ packages: peerDependencies: '@babel/core': 7.28.0 + '@babel/plugin-proposal-decorators@7.29.0': + resolution: {integrity: sha512-CVBVv3VY/XRMxRYq5dwr2DS7/MvqPm23cOCjbwNnVrfOqcWlnefua1uUs0sjdKOGjvPUG633o07uWzJq4oI6dA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': 7.28.0 + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2': resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} engines: {node: '>=6.9.0'} @@ -5420,6 +5468,12 @@ packages: peerDependencies: '@babel/core': 7.28.0 + '@babel/plugin-syntax-decorators@7.28.6': + resolution: {integrity: sha512-71EYI0ONURHJBL4rSFXnITXqXrrY8q4P0q006DPfN+Rk+ASM+++IBXem/ruokgBZR8YNEWZ8R6B+rCb8VcUTqA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': 7.28.0 + '@babel/plugin-syntax-dynamic-import@7.8.3': resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} peerDependencies: @@ -5892,6 +5946,10 @@ packages: '@babel/regjsgen@0.8.0': resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==} + '@babel/runtime-corejs3@7.29.2': + resolution: {integrity: sha512-Lc94FOD5+0aXhdb0Tdg3RUtqT6yWbI/BbFWvlaSJ3gAb9Ks+99nHRDKADVqC37er4eCB0fHyWT+y+K3QOvJKbw==} + engines: {node: '>=6.9.0'} + '@babel/runtime@7.28.3': resolution: {integrity: sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==} engines: {node: '>=6.9.0'} @@ -5904,6 +5962,10 @@ packages: resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + engines: {node: '>=6.9.0'} + '@babel/traverse@7.25.6': resolution: {integrity: sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==} engines: {node: '>=6.9.0'} @@ -5912,6 +5974,10 @@ packages: resolution: {integrity: sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==} engines: {node: '>=6.9.0'} + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + engines: {node: '>=6.9.0'} + '@babel/types@7.29.0': resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} @@ -6201,6 +6267,15 @@ packages: resolution: {integrity: sha512-fuquQswRSHWM6D079ZeuGqkMOsqtcUPL06UdTnowmoeeYjVrqisfVmvnw8pc3OeKS4kVb91oygb/MfLDiMs0TQ==} engines: {node: '>=16'} + '@cloudflare/ai-chat@0.4.4': + resolution: {integrity: sha512-XYuqT/MPJ9DMgy8PFR1IAgQn8T61kg0ylHgTJFwUB3vBljKgCtfrAxWDMekdu1kTbo1VYdSRfj/v4Cs5xxkKIA==} + peerDependencies: + '@ai-sdk/react': ^3.0.0 + agents: '>=0.8.7 <1.0.0' + ai: ^6.0.0 + react: ^19.0.0 + zod: ^4.0.0 + '@cloudflare/kv-asset-handler@0.4.2': resolution: {integrity: sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ==} engines: {node: '>=18.0.0'} @@ -6244,6 +6319,9 @@ packages: cpu: [x64] os: [win32] + '@cloudflare/workers-types@4.20260416.2': + resolution: {integrity: sha512-f7VGuKsHckH5n9KATTPJQ6AGdc2q58eM2waGzzDoCKw+PBtw9j2TWdRz8tLkviv7XcjkcuKy181vQFffXJicrA==} + '@codemirror/autocomplete@6.18.3': resolution: {integrity: sha512-1dNIOmiM0z4BIBwxmxEfA1yoxh1MF/6KPBbh20a5vphGV0ictKlgQsbJs6D6SkR6iJpGbpwRsa6PFMNlg9T9pQ==} peerDependencies: @@ -6659,15 +6737,24 @@ packages: '@emnapi/core@1.4.3': resolution: {integrity: sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==} + '@emnapi/core@1.9.2': + resolution: {integrity: sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==} + '@emnapi/runtime@1.4.3': resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==} '@emnapi/runtime@1.7.1': resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} + '@emnapi/runtime@1.9.2': + resolution: {integrity: sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==} + '@emnapi/wasi-threads@1.0.2': resolution: {integrity: sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA==} + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + '@emotion/babel-plugin@11.10.6': resolution: {integrity: sha512-p2dAqtVrkhSa7xz1u/m9eHYdLi+en8NowrmXeF/dKtJpU8lCWli8RUAati7NcSl0afsBott48pdnANuD0wh9QQ==} @@ -7307,6 +7394,12 @@ packages: '@hapi/topo@6.0.2': resolution: {integrity: sha512-KR3rD5inZbGMrHmgPxsJ9dbi6zEK+C3ZwUwTa+eMwWLz7oijWUTWD2pMSNNYJAU6Qq+65NkxXjqHr/7LM2Xkqg==} + '@hono/node-server@1.19.14': + resolution: {integrity: sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + '@hookform/devtools@4.3.1': resolution: {integrity: sha512-CrWxEoHQZaOXJZVQ8KBgOuAa8p2LI8M0DAN5GTRTmdCieRwFVjVDEmuTAVazWVRRkpEQSgSt3KYp7VmmqXdEnw==} peerDependencies: @@ -8033,6 +8126,16 @@ packages: '@microsoft/tsdoc@0.15.0': resolution: {integrity: sha512-HZpPoABogPvjeJOdzCOSJsXeL/SMCBgBZMVC3X3d7YYp2gf31MfxhUoYUNwf1ERPJOnQc0wkFn9trqI6ZEdZuA==} + '@modelcontextprotocol/sdk@1.29.0': + resolution: {integrity: sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==} + engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true + '@mole-inc/bin-wrapper@8.0.1': resolution: {integrity: sha512-sTGoeZnjI8N4KS+sW2AN95gDBErhAguvkw/tWdCjeM8bvxpz5lqrnd0vOJABA1A+Ic3zED7PYoLP/RANLgVotA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -8100,6 +8203,12 @@ packages: '@napi-rs/wasm-runtime@0.2.4': resolution: {integrity: sha512-9zESzOO5aDByvhIAsOy9TbpZ0Ur2AJbUI7UT73kcUTS2mxAMHOBaa1st/jAymNoCtvrit99kkzT1FZuXVcgfIQ==} + '@napi-rs/wasm-runtime@1.1.4': + resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + '@nestjs/axios@3.0.3': resolution: {integrity: sha512-h6TCn3yJwD6OKqqqfmtRS5Zo4E46Ip2n+gK1sqwzNBC+qxQ9xpCu+ODVRFur6V3alHSCSBxb3nNtt73VEdluyA==} peerDependencies: @@ -9750,6 +9859,9 @@ packages: peerDependencies: '@opentelemetry/api': ^1.1.0 + '@oxc-project/types@0.126.0': + resolution: {integrity: sha512-oGfVtjAgwQVVpfBrbtk4e1XDyWHRFta6BS3GWVzrF8xYBT2VGQAk39yJS/wFSMrZqoiCU4oghT3Ch0HaHGIHcQ==} + '@oxc-resolver/binding-darwin-arm64@5.3.0': resolution: {integrity: sha512-hXem5ZAguS7IlSiHg/LK0tEfLj4eUo+9U6DaFwwBEGd0L0VIF9LmuiHydRyOrdnnmi9iAAFMAn/wl2cUoiuruA==} cpu: [arm64] @@ -11528,9 +11640,124 @@ packages: peerDependencies: '@rjsf/utils': ^5.16.x + '@rolldown/binding-android-arm64@1.0.0-rc.16': + resolution: {integrity: sha512-rhY3k7Bsae9qQfOtph2Pm2jZEA+s8Gmjoz4hhmx70K9iMQ/ddeae+xhRQcM5IuVx5ry1+bGfkvMn7D6MJggVSA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.0-rc.16': + resolution: {integrity: sha512-rNz0yK078yrNn3DrdgN+PKiMOW8HfQ92jQiXxwX8yW899ayV00MLVdaCNeVBhG/TbH3ouYVObo8/yrkiectkcQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.0-rc.16': + resolution: {integrity: sha512-r/OmdR00HmD4i79Z//xO06uEPOq5hRXdhw7nzkxQxwSavs3PSHa1ijntdpOiZ2mzOQ3fVVu8C1M19FoNM+dMUQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.0-rc.16': + resolution: {integrity: sha512-KcRE5w8h0OnjUatG8pldyD14/CQ5Phs1oxfR+3pKDjboHRo9+MkqQaiIZlZRpsxC15paeXme/I127tUa9TXJ6g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.16': + resolution: {integrity: sha512-bT0guA1bpxEJ/ZhTRniQf7rNF8ybvXOuWbNIeLABaV5NGjx4EtOWBTSRGWFU9ZWVkPOZ+HNFP8RMcBokBiZ0Kg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.16': + resolution: {integrity: sha512-+tHktCHWV8BDQSjemUqm/Jl/TPk3QObCTIjmdDy/nlupcujZghmKK2962LYrqFpWu+ai01AN/REOH3NEpqvYQg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.16': + resolution: {integrity: sha512-3fPzdREH806oRLxpTWW1Gt4tQHs0TitZFOECB2xzCFLPKnSOy90gwA7P29cksYilFO6XVRY1kzga0cL2nRjKPg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.16': + resolution: {integrity: sha512-EKwI1tSrLs7YVw+JPJT/G2dJQ1jl9qlTTTEG0V2Ok/RdOenRfBw2PQdLPyjhIu58ocdBfP7vIRN/pvMsPxs/AQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.16': + resolution: {integrity: sha512-Uknladnb3Sxqu6SEcqBldQyJUpk8NleooZEc0MbRBJ4inEhRYWZX0NJu12vNf2mqAq7gsofAxHrGghiUYjhaLQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.16': + resolution: {integrity: sha512-FIb8+uG49sZBtLTn+zt1AJ20TqVcqWeSIyoVt0or7uAWesgKaHbiBh6OpA/k9v0LTt+PTrb1Lao133kP4uVxkg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-musl@1.0.0-rc.16': + resolution: {integrity: sha512-RuERhF9/EgWxZEXYWCOaViUWHIboceK4/ivdtQ3R0T44NjLkIIlGIAVAuCddFxsZ7vnRHtNQUrt2vR2n2slB2w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rolldown/binding-openharmony-arm64@1.0.0-rc.16': + resolution: {integrity: sha512-mXcXnvd9GpazCxeUCCnZ2+YF7nut+ZOEbE4GtaiPtyY6AkhZWbK70y1KK3j+RDhjVq5+U8FySkKRb/+w0EeUwA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.0-rc.16': + resolution: {integrity: sha512-3Q2KQxnC8IJOLqXmUMoYwyIPZU9hzRbnHaoV3Euz+VVnjZKcY8ktnNP8T9R4/GGQtb27C/UYKABxesKWb8lsvQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.16': + resolution: {integrity: sha512-tj7XRemQcOcFwv7qhpUxMTBbI5mWMlE4c1Omhg5+h8GuLXzyj8HviYgR+bB2DMDgRqUE+jiDleqSCRjx4aYk/Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.16': + resolution: {integrity: sha512-PH5DRZT+F4f2PTXRXR8uJxnBq2po/xFtddyabTJVJs/ZYVHqXPEgNIr35IHTEa6bpa0Q8Awg+ymkTaGnKITw4g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/plugin-babel@0.2.3': + resolution: {integrity: sha512-+zEk16yGlz1F9STiRr6uG9hmIXb6nprjLczV/htGptYuLoCuxb+itZ03RKCEeOhBpDDd1NU7qF6x1VLMUp62bw==} + engines: {node: '>=22.12.0 || ^24.0.0'} + peerDependencies: + '@babel/core': 7.28.0 + '@babel/plugin-transform-runtime': ^7.29.0 || ^8.0.0-rc.1 + '@babel/runtime': ^7.27.0 || ^8.0.0-rc.1 + rolldown: ^1.0.0-rc.5 + vite: ^8.0.0 + peerDependenciesMeta: + '@babel/plugin-transform-runtime': + optional: true + '@babel/runtime': + optional: true + vite: + optional: true + '@rolldown/pluginutils@1.0.0-beta.27': resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} + '@rolldown/pluginutils@1.0.0-rc.16': + resolution: {integrity: sha512-45+YtqxLYKDWQouLKCrpIZhke+nXxhsw+qAHVzHDVwttyBlHNBVs2K25rDXrZzhpTp9w1FlAlvweV1H++fdZoA==} + '@rollup/plugin-commonjs@22.0.2': resolution: {integrity: sha512-//NdP6iIwPbMTcazYsiBMbJW7gfmpHom33u1beiIoHDEM0Q9clvtQB1T0efvMqHeKsGohiHo97BCPCkBXdscwg==} engines: {node: '>= 12.0.0'} @@ -13512,6 +13739,9 @@ packages: '@tybys/wasm-util@0.10.0': resolution: {integrity: sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==} + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@tybys/wasm-util@0.9.0': resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==} @@ -14856,6 +15086,39 @@ packages: resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} engines: {node: '>= 8.0.0'} + agents@0.11.0: + resolution: {integrity: sha512-FBjTA0G5ejwYMcizqTkX2ONJFXV1vqMM5P0yqOu6r0dWzTmaW84LKQACMava2HkPO4+nVhesW94+kf1E/a+MDw==} + hasBin: true + peerDependencies: + '@ai-sdk/react': ^3.0.0 + '@cloudflare/ai-chat': ^0.4.2 + '@cloudflare/codemode': ^0.3.4 + '@tanstack/ai': ^0.10.2 + '@x402/core': ^2.0.0 + '@x402/evm': ^2.0.0 + ai: ^6.0.0 + react: ^19.0.0 + viem: '>=2.0.0' + vite: ^6.4.2 + zod: ^4.0.0 + peerDependenciesMeta: + '@ai-sdk/react': + optional: true + '@cloudflare/ai-chat': + optional: true + '@cloudflare/codemode': + optional: true + '@tanstack/ai': + optional: true + '@x402/core': + optional: true + '@x402/evm': + optional: true + viem: + optional: true + vite: + optional: true + aggregate-error@3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} @@ -16136,6 +16399,10 @@ packages: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} + cliui@9.0.1: + resolution: {integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==} + engines: {node: '>=20'} + clone-deep@4.0.1: resolution: {integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==} engines: {node: '>=6'} @@ -16431,6 +16698,9 @@ packages: core-js-compat@3.38.1: resolution: {integrity: sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==} + core-js-pure@3.49.0: + resolution: {integrity: sha512-XM4RFka59xATyJv/cS3O3Kml72hQXUeGRuuTmMYFxwzc9/7C8OYTaIR/Ji+Yt8DXzsFLNhat15cE/JP15HrCgw==} + core-js@2.6.12: resolution: {integrity: sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==} deprecated: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js. @@ -16500,6 +16770,10 @@ packages: resolution: {integrity: sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==} engines: {node: '>=12.0.0'} + cron-schedule@6.0.0: + resolution: {integrity: sha512-BoZaseYGXOo5j5HUwTaegIog3JJbuH4BbrY9A1ArLjXpy+RWb3mV28F/9Gv1dDA7E2L8kngWva4NWisnLTyfgQ==} + engines: {node: '>=20'} + cron@3.1.7: resolution: {integrity: sha512-tlBg7ARsAMQLzgwqVxy8AZl/qlTc5nibqYwtNGoCrd+cV+ugI+tvZC1oT/8dFH8W455YrywGykx/KMmAqOr7Jw==} @@ -17419,6 +17693,9 @@ packages: resolution: {integrity: sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==} engines: {node: '>=10'} + emoji-regex@10.6.0: + resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} + emoji-regex@7.0.3: resolution: {integrity: sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==} @@ -17765,6 +18042,10 @@ packages: resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} engines: {node: '>=18.0.0'} + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} + execa@0.11.0: resolution: {integrity: sha512-k5AR22vCt1DcfeiRixW46U5tMLtBg44ssdJM9PiXw3D8Bn5qyxFCSnKY/eR22y+ctFDGPqafpaXg2G4Emyua4A==} engines: {node: '>=6'} @@ -17827,6 +18108,12 @@ packages: express-rate-limit@5.5.1: resolution: {integrity: sha512-MTjE2eIbHv5DyfuFz4zLYWxpqVhEhkTiwFGuB74Q9CSou2WHO52nlE5y3Zlg6SIsiYUIPj6ifFxnkPz6O3sIUg==} + express-rate-limit@8.3.2: + resolution: {integrity: sha512-77VmFeJkO0/rvimEDuUC5H30oqUC4EyOhyGccfqoLebB0oiEYfM7nwPrsDsBL1gsTpwfzX8SFy2MT3TDyRq+bg==} + engines: {node: '>= 16'} + peerDependencies: + express: ^4.20.0 + express@4.21.2: resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} engines: {node: '>= 0.10.0'} @@ -17835,6 +18122,10 @@ packages: resolution: {integrity: sha512-ORF7g6qGnD+YtUG9yx4DFoqCShNMmUKiXuT5oWMHiOvt/4WFbHC6yCwQMTSBMno7AqntNCAzzcnnjowRkTL9eQ==} engines: {node: '>= 18'} + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + ext-list@2.2.2: resolution: {integrity: sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==} engines: {node: '>=0.10.0'} @@ -18051,6 +18342,10 @@ packages: resolution: {integrity: sha512-MX6Zo2adDViYh+GcxxB1dpO43eypOGUOL12rLCOTMQv/DfIbpSJUy4oQIIZhVZkH9e+bZWKMon0XHFEju16tkQ==} engines: {node: '>= 0.8'} + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} + find-cache-dir@3.3.2: resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} engines: {node: '>=8'} @@ -18775,6 +19070,10 @@ packages: hoist-non-react-statics@3.3.2: resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + hono@4.12.14: + resolution: {integrity: sha512-am5zfg3yu6sqn5yjKBNqhnTX7Cv+m00ox+7jbaKkrLMRJ4rAdldd1xPd/JzbBWspqaQv6RSTrgFN95EsfhC+7w==} + engines: {node: '>=16.9.0'} + hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} @@ -20010,6 +20309,9 @@ packages: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} + js-base64@3.7.8: + resolution: {integrity: sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==} + js-cookie@3.0.1: resolution: {integrity: sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw==} engines: {node: '>=12'} @@ -20127,6 +20429,11 @@ packages: resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==} engines: {node: '>=16'} + json-schema-to-typescript@15.0.4: + resolution: {integrity: sha512-Su9oK8DR4xCmDsLlyvadkXzX6+GGXJpbhwoLtOGArAG61dvbW4YQmSEno2y66ahpIdmLMg6YUf/QHLgiwvkrHQ==} + engines: {node: '>=16.0.0'} + hasBin: true + json-schema-to-zod@2.7.0: resolution: {integrity: sha512-eW59l3NQ6sa3HcB+Ahf7pP6iGU7MY4we5JsPqXQ2ZcIPF8QxSg/lkY8lN0Js/AG0NjMbk+nZGUfHlceiHF+bwQ==} hasBin: true @@ -20137,6 +20444,9 @@ packages: json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + json-schema-typed@8.0.2: + resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} + json-schema@0.4.0: resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} @@ -21250,6 +21560,10 @@ packages: resolution: {integrity: sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==} engines: {node: '>= 0.6'} + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} @@ -21258,6 +21572,10 @@ packages: resolution: {integrity: sha512-XqoSHeCGjVClAmoGFG3lVFqQFRIrTVw2OH3axRqAcfaw+gHWIfnASS92AV+Rl/mk0MupgZTRHQOjxY6YVnzK5w==} engines: {node: '>= 0.6'} + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + mime@1.6.0: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} engines: {node: '>=4'} @@ -21277,6 +21595,9 @@ packages: resolution: {integrity: sha512-ipzNp6TBsNfD3hButGlPVlGmuCgybIM9SBf8YwIG+SYmBgtU0u8wjf+BSrJX0mvqtv59SLmwphw/XiCbkLWv7w==} deprecated: This project is unmaintained + mimetext@3.0.28: + resolution: {integrity: sha512-eQXpbNrtxLCjUtiVbR/qR09dbPgZ2o+KR1uA7QKqGhbn8QV7HIL16mXXsobBL4/8TqoYh1us31kfz+dNfCev9g==} + mimic-fn@1.2.0: resolution: {integrity: sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==} engines: {node: '>=4'} @@ -21624,6 +21945,11 @@ packages: engines: {node: ^18 || >=20} hasBin: true + nanoid@5.1.9: + resolution: {integrity: sha512-ZUvP7KeBLe3OZ1ypw6dI/TzYJuvHP77IM4Ry73waSQTLn8/g8rpdjfyVAh7t1/+FjBtG4lCP42MEbDxOsRpBMw==} + engines: {node: ^18 || >=20} + hasBin: true + nanostores@1.2.0: resolution: {integrity: sha512-F0wCzbsH80G7XXo0Jd9/AVQC7ouWY6idUCTnMwW5t/Rv9W8qmO6endavDwg7TNp5GbugwSukFMVZqzPSrSMndg==} engines: {node: ^20.0.0 || >=22.0.0} @@ -22454,9 +22780,22 @@ packages: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} + partyserver@0.4.1: + resolution: {integrity: sha512-StSs0oY8RmTxjGNil7VbCG4gnTN+4rYX20fiUIItAxTPpr/5rPDZT6PIvMROkk9M1Gn7GzE1wuQXwhxceaGhXA==} + peerDependencies: + '@cloudflare/workers-types': ^4.20240729.0 + partysocket@0.0.17: resolution: {integrity: sha512-8Re9nmgP2LzQhq+FBs9+BZNTjmMwoF4geEKlpH0lxW1JKp3FmplN74306afGH9EsOjdfcXqKY2VCZtc3iAHIow==} + partysocket@1.1.16: + resolution: {integrity: sha512-d7xFv+ZC7x0p/DAHWJ5FhxQhimIx+ucyZY+kxL0cKddLBmK9c4p2tEA/L+dOOrWm6EYrRwrBjKQV0uSzOY9x1w==} + peerDependencies: + react: '>=17' + peerDependenciesMeta: + react: + optional: true + partysocket@1.1.4: resolution: {integrity: sha512-jXP7PFj2h5/v4UjDS8P7MZy6NJUQ7sspiFyxL4uc/+oKOL+KdtXzHnTV8INPGxBrLTXgalyG3kd12Qm7WrYc3A==} @@ -22678,6 +23017,10 @@ packages: piscina@4.6.1: resolution: {integrity: sha512-z30AwWGtQE+Apr+2WBZensP2lIvwoaMcOPkQlIEmSGMJNUvaYACylPYrQM6wSdUNJlnDVMSpLv7xTMJqlVshOA==} + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + pkg-conf@2.1.0: resolution: {integrity: sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g==} engines: {node: '>=4'} @@ -24112,6 +24455,11 @@ packages: robust-predicates@3.0.2: resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} + rolldown@1.0.0-rc.16: + resolution: {integrity: sha512-rzi5WqKzEZw3SooTt7cgm4eqIoujPIyGcJNGFL7iPEuajQw7vxMHUkXylu4/vhCkJGXsgRmxqMKXUpT6FEgl0g==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + rollup@2.80.0: resolution: {integrity: sha512-cIFJOD1DESzpjOBl763Kp1AH7UE/0fcdHe6rZXUdQ9c50uvgigvW97u3IcSeBwOkgqL/PXPBktBCh0KEu5L8XQ==} engines: {node: '>=10.0.0'} @@ -24135,6 +24483,10 @@ packages: resolution: {integrity: sha512-/m/NSLxeYEgWNtyC+WtNHCF7jbGxOibVWKnn+1Psff4dJGOfoXP+MuC/f2CwSmyiHdOIzYnYFp4W6GxWfekaLA==} engines: {node: '>= 18'} + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + rrdom@2.0.0-alpha.16: resolution: {integrity: sha512-m8aoeORWUz7AFdEb7hES7wPeL6fl/oP23RoAlzLXyA/f2+NqCDM7KEyCXY4sHu6CChN3OAUP2BaUGEXn0zynlw==} @@ -24340,6 +24692,10 @@ packages: resolution: {integrity: sha512-v67WcEouB5GxbTWL/4NeToqcZiAWEq90N888fczVArY8A79J0L4FD7vj5hm3eUMua5EpoQ59wa/oovY6TLvRUA==} engines: {node: '>= 18'} + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + sentence-case@2.1.1: resolution: {integrity: sha512-ENl7cYHaK/Ktwk5OTD+aDbQ3uC8IByu/6Bkg+HDv8Mm+XnBnppVNalcfJTNsp1ibstKh030/JKQQWglDvtKwEQ==} @@ -24365,6 +24721,10 @@ packages: resolution: {integrity: sha512-A3We5UfEjG8Z7VkDv6uItWw6HY2bBSBJT1KtVESn6EOoOr2jAxNhxWCLY3jDE2WcuHXByWju74ck3ZgLwL8xmA==} engines: {node: '>= 18'} + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} @@ -24865,6 +25225,10 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + string.fromcodepoint@0.2.1: resolution: {integrity: sha512-n69H31OnxSGSZyZbgBlvYIXlrMhJQ0dQAX1js1QDhpaUH6zmU3QYlj07bCwCNlPOu3oRXIubGPl2gDGnHsiCqg==} @@ -26744,6 +27108,10 @@ packages: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} engines: {node: '>=12'} + wrap-ansi@9.0.2: + resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} + engines: {node: '>=18'} + wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -26938,6 +27306,10 @@ packages: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + yargs-parser@22.0.0: + resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + yargs-unparser@2.0.0: resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} engines: {node: '>=10'} @@ -26957,6 +27329,10 @@ packages: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} + yargs@18.0.0: + resolution: {integrity: sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + yauzl@2.10.0: resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} @@ -27072,6 +27448,13 @@ snapshots: '@vercel/oidc': 3.1.0 zod: 4.3.5 + '@ai-sdk/gateway@3.0.22(zod@3.25.20)': + dependencies: + '@ai-sdk/provider': 3.0.5 + '@ai-sdk/provider-utils': 4.0.9(zod@3.25.20) + '@vercel/oidc': 3.1.0 + zod: 3.25.20 + '@ai-sdk/gateway@3.0.22(zod@4.3.5)': dependencies: '@ai-sdk/provider': 3.0.5 @@ -27178,6 +27561,16 @@ snapshots: transitivePeerDependencies: - zod + '@ai-sdk/react@3.0.51(react@19.2.3)(zod@3.25.20)': + dependencies: + '@ai-sdk/provider-utils': 4.0.9(zod@3.25.20) + ai: 6.0.49(zod@3.25.20) + react: 19.2.3 + swr: 2.3.4(react@19.2.3) + throttleit: 2.1.0 + transitivePeerDependencies: + - zod + '@ai-sdk/react@3.0.51(react@19.2.3)(zod@4.3.5)': dependencies: '@ai-sdk/provider-utils': 4.0.9(zod@4.3.5) @@ -29561,6 +29954,12 @@ snapshots: js-tokens: 4.0.0 picocolors: 1.1.1 + '@babel/code-frame@7.29.0': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + '@babel/compat-data@7.25.4': {} '@babel/compat-data@7.28.0': {} @@ -29593,6 +29992,14 @@ snapshots: '@jridgewell/trace-mapping': 0.3.30 jsesc: 3.1.0 + '@babel/generator@7.29.1': + dependencies: + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.30 + jsesc: 3.1.0 + '@babel/helper-annotate-as-pure@7.22.5': dependencies: '@babel/types': 7.29.0 @@ -29656,6 +30063,19 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.28.0) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/traverse': 7.29.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + '@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 @@ -29708,6 +30128,13 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-member-expression-to-functions@7.28.5': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + '@babel/helper-module-imports@7.18.6': dependencies: '@babel/types': 7.29.0 @@ -29764,12 +30191,18 @@ snapshots: dependencies: '@babel/types': 7.29.0 + '@babel/helper-optimise-call-expression@7.27.1': + dependencies: + '@babel/types': 7.29.0 + '@babel/helper-plugin-utils@7.22.5': {} '@babel/helper-plugin-utils@7.24.8': {} '@babel/helper-plugin-utils@7.27.1': {} + '@babel/helper-plugin-utils@7.28.6': {} + '@babel/helper-remap-async-to-generator@7.25.0(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 @@ -29788,6 +30221,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-replace-supers@7.28.6(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + '@babel/helper-simple-access@7.22.5': dependencies: '@babel/types': 7.29.0 @@ -29806,6 +30248,13 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + '@babel/helper-split-export-declaration@7.22.6': dependencies: '@babel/types': 7.29.0 @@ -29894,6 +30343,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-proposal-decorators@7.29.0(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.28.0) + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-syntax-decorators': 7.28.6(@babel/core@7.28.0) + transitivePeerDependencies: + - supports-color + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 @@ -29933,6 +30391,11 @@ snapshots: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-decorators@7.28.6(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.28.0)': dependencies: '@babel/core': 7.28.0 @@ -30544,6 +31007,10 @@ snapshots: '@babel/regjsgen@0.8.0': {} + '@babel/runtime-corejs3@7.29.2': + dependencies: + core-js-pure: 3.49.0 + '@babel/runtime@7.28.3': {} '@babel/template@7.25.0': @@ -30558,6 +31025,12 @@ snapshots: '@babel/parser': 7.29.0 '@babel/types': 7.29.0 + '@babel/template@7.28.6': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.0 + '@babel/types': 7.29.0 + '@babel/traverse@7.25.6': dependencies: '@babel/code-frame': 7.27.1 @@ -30582,6 +31055,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/traverse@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.29.0 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + debug: 4.4.3(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + '@babel/types@7.29.0': dependencies: '@babel/helper-string-parser': 7.27.1 @@ -30601,7 +31086,7 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} - '@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0)': + '@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0)': dependencies: '@better-auth/utils': 0.3.1 '@better-fetch/fetch': 1.1.21 @@ -30613,51 +31098,53 @@ snapshots: kysely: 0.28.14 nanostores: 1.2.0 zod: 4.3.6 + optionalDependencies: + '@cloudflare/workers-types': 4.20260416.2 - '@better-auth/drizzle-adapter@1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1)': + '@better-auth/drizzle-adapter@1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1)': dependencies: - '@better-auth/core': 1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0) + '@better-auth/core': 1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0) '@better-auth/utils': 0.3.1 - '@better-auth/kysely-adapter@1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1)(kysely@0.28.14)': + '@better-auth/kysely-adapter@1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1)(kysely@0.28.14)': dependencies: - '@better-auth/core': 1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0) + '@better-auth/core': 1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0) '@better-auth/utils': 0.3.1 optionalDependencies: kysely: 0.28.14 - '@better-auth/memory-adapter@1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1)': + '@better-auth/memory-adapter@1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1)': dependencies: - '@better-auth/core': 1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0) + '@better-auth/core': 1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0) '@better-auth/utils': 0.3.1 - '@better-auth/mongo-adapter@1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1)(mongodb@6.21.0(@aws-sdk/credential-providers@3.637.0(@aws-sdk/client-sso-oidc@3.637.0(@aws-sdk/client-sts@3.637.0)))(gcp-metadata@5.3.0(encoding@0.1.13))(socks@2.8.7))': + '@better-auth/mongo-adapter@1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1)(mongodb@6.21.0(@aws-sdk/credential-providers@3.637.0(@aws-sdk/client-sso-oidc@3.637.0(@aws-sdk/client-sts@3.637.0)))(gcp-metadata@5.3.0(encoding@0.1.13))(socks@2.8.7))': dependencies: - '@better-auth/core': 1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0) + '@better-auth/core': 1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0) '@better-auth/utils': 0.3.1 optionalDependencies: mongodb: 6.21.0(@aws-sdk/credential-providers@3.637.0(@aws-sdk/client-sso-oidc@3.637.0(@aws-sdk/client-sts@3.637.0)))(gcp-metadata@5.3.0(encoding@0.1.13))(socks@2.8.7) - '@better-auth/prisma-adapter@1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1)': + '@better-auth/prisma-adapter@1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1)': dependencies: - '@better-auth/core': 1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0) + '@better-auth/core': 1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0) '@better-auth/utils': 0.3.1 - '@better-auth/sso@1.4.7(better-auth@1.5.6(f5eede22a65d6cd0c93a8bf1a87b70c5))': + '@better-auth/sso@1.4.7(better-auth@1.5.6(bfb0779f1cc865575f8ea1b2503ee818))': dependencies: '@better-fetch/fetch': 1.1.21 - better-auth: 1.5.6(f5eede22a65d6cd0c93a8bf1a87b70c5) + better-auth: 1.5.6(bfb0779f1cc865575f8ea1b2503ee818) fast-xml-parser: 5.5.8 jose: 6.1.3 samlify: 2.10.2 zod: 4.3.5 - '@better-auth/sso@1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1)(better-auth@1.5.6(aac79383f71d2c0e811dbd569d97ebd4))(better-call@1.3.2(zod@4.3.6))': + '@better-auth/sso@1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1)(better-auth@1.5.6(778471f5f7178e7ab9fe0c8426d67ae9))(better-call@1.3.2(zod@4.3.6))': dependencies: - '@better-auth/core': 1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0) + '@better-auth/core': 1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0) '@better-auth/utils': 0.3.1 '@better-fetch/fetch': 1.1.21 - better-auth: 1.5.6(aac79383f71d2c0e811dbd569d97ebd4) + better-auth: 1.5.6(778471f5f7178e7ab9fe0c8426d67ae9) better-call: 1.3.2(zod@4.3.6) fast-xml-parser: 5.5.8 jose: 6.1.3 @@ -30665,9 +31152,9 @@ snapshots: tldts: 6.1.86 zod: 4.3.6 - '@better-auth/telemetry@1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))': + '@better-auth/telemetry@1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))': dependencies: - '@better-auth/core': 1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0) + '@better-auth/core': 1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0) '@better-auth/utils': 0.3.1 '@better-fetch/fetch': 1.1.21 @@ -30808,12 +31295,12 @@ snapshots: react-dom: 19.2.3(react@19.2.3) tslib: 2.8.1 - '@clerk/express@1.3.53(express@5.0.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@clerk/express@1.3.53(express@5.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@clerk/backend': 1.25.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@clerk/shared': 3.47.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@clerk/types': 4.48.0 - express: 5.0.1 + express: 5.2.1 tslib: 2.4.1 transitivePeerDependencies: - react @@ -30876,6 +31363,14 @@ snapshots: dependencies: '@clickhouse/client-common': 1.18.2 + '@cloudflare/ai-chat@0.4.4(@ai-sdk/react@3.0.51(react@19.2.3)(zod@3.25.20))(agents@0.11.0)(ai@6.0.68(zod@3.25.20))(react@19.2.3)(zod@3.25.20)': + dependencies: + '@ai-sdk/react': 3.0.51(react@19.2.3)(zod@3.25.20) + agents: 0.11.0(@ai-sdk/react@3.0.51(react@19.2.3)(zod@3.25.20))(@babel/core@7.28.0)(@babel/runtime@7.28.3)(@cloudflare/ai-chat@0.4.4)(@cloudflare/workers-types@4.20260416.2)(ai@6.0.68(zod@3.25.20))(react@19.2.3)(rolldown@1.0.0-rc.16)(vite@6.4.2(@types/node@22.15.13)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.77.8)(sugarss@4.0.1(postcss@8.5.8))(terser@5.31.6)(tsx@4.16.2)(yaml@2.8.3))(zod@3.25.20) + ai: 6.0.68(zod@3.25.20) + react: 19.2.3 + zod: 3.25.20 + '@cloudflare/kv-asset-handler@0.4.2': {} '@cloudflare/unenv-preset@2.14.0(unenv@2.0.0-rc.24)(workerd@1.20260302.0)': @@ -30899,6 +31394,8 @@ snapshots: '@cloudflare/workerd-windows-64@1.20260302.0': optional: true + '@cloudflare/workers-types@4.20260416.2': {} + '@codemirror/autocomplete@6.18.3(@codemirror/language@6.11.1)(@codemirror/state@6.4.1)(@codemirror/view@6.34.3)(@lezer/common@1.2.3)': dependencies: '@codemirror/language': 6.11.1 @@ -31509,6 +32006,12 @@ snapshots: '@emnapi/wasi-threads': 1.0.2 tslib: 2.8.1 + '@emnapi/core@1.9.2': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + '@emnapi/runtime@1.4.3': dependencies: tslib: 2.8.1 @@ -31518,10 +32021,20 @@ snapshots: dependencies: tslib: 2.8.1 + '@emnapi/runtime@1.9.2': + dependencies: + tslib: 2.8.1 + optional: true + '@emnapi/wasi-threads@1.0.2': dependencies: tslib: 2.8.1 + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 + optional: true + '@emotion/babel-plugin@11.10.6': dependencies: '@babel/helper-module-imports': 7.21.4 @@ -32145,6 +32658,10 @@ snapshots: dependencies: '@hapi/hoek': 11.0.7 + '@hono/node-server@1.19.14(hono@4.12.14)': + dependencies: + hono: 4.12.14 + '@hookform/devtools@4.3.1(@types/react@19.2.8)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@emotion/react': 11.10.6(@types/react@19.2.8)(react@19.2.3) @@ -33408,6 +33925,30 @@ snapshots: '@microsoft/tsdoc@0.15.0': {} + '@modelcontextprotocol/sdk@1.29.0(@cfworker/json-schema@4.1.1)(zod@3.25.20)': + dependencies: + '@hono/node-server': 1.19.14(hono@4.12.14) + ajv: 8.18.0 + ajv-formats: 3.0.1(ajv@8.18.0) + content-type: 1.0.5 + cors: 2.8.5 + cross-spawn: 7.0.5 + eventsource: 3.0.7 + eventsource-parser: 3.0.6 + express: 5.2.1 + express-rate-limit: 8.3.2(express@5.2.1) + hono: 4.12.14 + jose: 6.1.3 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 3.25.20 + zod-to-json-schema: 3.25.1(zod@3.25.20) + optionalDependencies: + '@cfworker/json-schema': 4.1.1 + transitivePeerDependencies: + - supports-color + '@mole-inc/bin-wrapper@8.0.1': dependencies: bin-check: 4.1.0 @@ -33502,6 +34043,13 @@ snapshots: '@emnapi/runtime': 1.7.1 '@tybys/wasm-util': 0.9.0 + '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': + dependencies: + '@emnapi/core': 1.9.2 + '@emnapi/runtime': 1.9.2 + '@tybys/wasm-util': 0.10.1 + optional: true + '@nestjs/axios@3.0.3(@nestjs/common@10.4.18(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(axios@1.15.0)(rxjs@7.8.1)': dependencies: '@nestjs/common': 10.4.18(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) @@ -33949,10 +34497,10 @@ snapshots: tslib: 2.8.1 yargs-parser: 21.1.1 - '@nx/eslint@21.3.11(@babel/traverse@7.28.0)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))(@zkochan/js-yaml@0.0.7)(eslint@9.39.4(jiti@2.6.1))(nx@21.3.11(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15)))': + '@nx/eslint@21.3.11(@babel/traverse@7.29.0)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))(@zkochan/js-yaml@0.0.7)(eslint@9.39.4(jiti@2.6.1))(nx@21.3.11(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15)))': dependencies: '@nx/devkit': 21.3.11(nx@21.3.11(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))) - '@nx/js': 21.3.11(@babel/traverse@7.28.0)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))(nx@21.3.11(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))) + '@nx/js': 21.3.11(@babel/traverse@7.29.0)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))(nx@21.3.11(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))) eslint: 9.39.4(jiti@2.6.1) semver: 7.7.4 tslib: 2.8.1 @@ -33968,12 +34516,12 @@ snapshots: - supports-color - verdaccio - '@nx/jest@21.3.11(@babel/traverse@7.28.0)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.15.13)(babel-plugin-macros@3.1.0)(esbuild-register@3.5.0(esbuild@0.27.3))(nx@21.3.11(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15)))(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.15.13)(typescript@5.6.2))(typescript@5.6.2)': + '@nx/jest@21.3.11(@babel/traverse@7.29.0)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.15.13)(babel-plugin-macros@3.1.0)(esbuild-register@3.5.0(esbuild@0.27.3))(nx@21.3.11(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15)))(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.15.13)(typescript@5.6.2))(typescript@5.6.2)': dependencies: '@jest/reporters': 30.0.5 '@jest/test-result': 30.0.5 '@nx/devkit': 21.3.11(nx@21.3.11(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))) - '@nx/js': 21.3.11(@babel/traverse@7.28.0)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))(nx@21.3.11(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))) + '@nx/js': 21.3.11(@babel/traverse@7.29.0)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))(nx@21.3.11(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))) '@phenomnomnominal/tsquery': 5.0.1(typescript@5.6.2) identity-obj-proxy: 3.0.0 jest-config: 30.0.5(@types/node@22.15.13)(babel-plugin-macros@3.1.0)(esbuild-register@3.5.0(esbuild@0.27.3))(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.15.13)(typescript@5.6.2)) @@ -34000,7 +34548,7 @@ snapshots: - typescript - verdaccio - '@nx/js@20.1.2(@babel/traverse@7.28.0)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.15.13)(nx@20.1.2(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15)))(typescript@5.6.2)(verdaccio@5.31.0(encoding@0.1.13)(typanion@3.14.0))': + '@nx/js@20.1.2(@babel/traverse@7.29.0)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.15.13)(nx@20.1.2(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15)))(typescript@5.6.2)(verdaccio@5.31.0(encoding@0.1.13)(typanion@3.14.0))': dependencies: '@babel/core': 7.28.0 '@babel/plugin-proposal-decorators': 7.24.7(@babel/core@7.28.0) @@ -34014,7 +34562,7 @@ snapshots: '@zkochan/js-yaml': 0.0.7 babel-plugin-const-enum: 1.2.0(@babel/core@7.28.0) babel-plugin-macros: 2.8.0 - babel-plugin-transform-typescript-metadata: 0.3.2(@babel/core@7.28.0)(@babel/traverse@7.28.0) + babel-plugin-transform-typescript-metadata: 0.3.2(@babel/core@7.28.0)(@babel/traverse@7.29.0) chalk: 4.1.2 columnify: 1.6.0 detect-port: 1.5.1 @@ -34045,7 +34593,7 @@ snapshots: - supports-color - typescript - '@nx/js@21.3.11(@babel/traverse@7.28.0)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))(nx@21.3.11(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15)))': + '@nx/js@21.3.11(@babel/traverse@7.29.0)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))(nx@21.3.11(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15)))': dependencies: '@babel/core': 7.28.0 '@babel/plugin-proposal-decorators': 7.24.7(@babel/core@7.28.0) @@ -34059,7 +34607,7 @@ snapshots: '@zkochan/js-yaml': 0.0.7 babel-plugin-const-enum: 1.2.0(@babel/core@7.28.0) babel-plugin-macros: 3.1.0 - babel-plugin-transform-typescript-metadata: 0.3.2(@babel/core@7.28.0)(@babel/traverse@7.28.0) + babel-plugin-transform-typescript-metadata: 0.3.2(@babel/core@7.28.0)(@babel/traverse@7.29.0) chalk: 4.1.2 columnify: 1.6.0 detect-port: 1.5.1 @@ -34144,12 +34692,12 @@ snapshots: '@nx/nx-win32-x64-msvc@21.3.11': optional: true - '@nx/plugin@21.3.11(@babel/traverse@7.28.0)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.15.13)(@zkochan/js-yaml@0.0.7)(babel-plugin-macros@3.1.0)(esbuild-register@3.5.0(esbuild@0.27.3))(eslint@9.39.4(jiti@2.6.1))(nx@21.3.11(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15)))(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.15.13)(typescript@5.6.2))(typescript@5.6.2)': + '@nx/plugin@21.3.11(@babel/traverse@7.29.0)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.15.13)(@zkochan/js-yaml@0.0.7)(babel-plugin-macros@3.1.0)(esbuild-register@3.5.0(esbuild@0.27.3))(eslint@9.39.4(jiti@2.6.1))(nx@21.3.11(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15)))(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.15.13)(typescript@5.6.2))(typescript@5.6.2)': dependencies: '@nx/devkit': 21.3.11(nx@21.3.11(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))) - '@nx/eslint': 21.3.11(@babel/traverse@7.28.0)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))(@zkochan/js-yaml@0.0.7)(eslint@9.39.4(jiti@2.6.1))(nx@21.3.11(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))) - '@nx/jest': 21.3.11(@babel/traverse@7.28.0)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.15.13)(babel-plugin-macros@3.1.0)(esbuild-register@3.5.0(esbuild@0.27.3))(nx@21.3.11(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15)))(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.15.13)(typescript@5.6.2))(typescript@5.6.2) - '@nx/js': 21.3.11(@babel/traverse@7.28.0)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))(nx@21.3.11(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))) + '@nx/eslint': 21.3.11(@babel/traverse@7.29.0)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))(@zkochan/js-yaml@0.0.7)(eslint@9.39.4(jiti@2.6.1))(nx@21.3.11(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))) + '@nx/jest': 21.3.11(@babel/traverse@7.29.0)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.15.13)(babel-plugin-macros@3.1.0)(esbuild-register@3.5.0(esbuild@0.27.3))(nx@21.3.11(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15)))(ts-node@10.9.2(@swc/core@1.7.26(@swc/helpers@0.5.15))(@types/node@22.15.13)(typescript@5.6.2))(typescript@5.6.2) + '@nx/js': 21.3.11(@babel/traverse@7.29.0)(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))(nx@21.3.11(@swc-node/register@1.10.10(@swc/core@1.7.26(@swc/helpers@0.5.15))(@swc/types@0.1.12)(typescript@5.6.2))(@swc/core@1.7.26(@swc/helpers@0.5.15))) tslib: 2.8.1 transitivePeerDependencies: - '@babel/traverse' @@ -35667,6 +36215,8 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.5.0(@opentelemetry/api@1.9.0) + '@oxc-project/types@0.126.0': {} + '@oxc-resolver/binding-darwin-arm64@5.3.0': optional: true @@ -38509,8 +39059,68 @@ snapshots: lodash: 4.18.1 lodash-es: 4.18.1 + '@rolldown/binding-android-arm64@1.0.0-rc.16': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.0-rc.16': + optional: true + + '@rolldown/binding-darwin-x64@1.0.0-rc.16': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.0-rc.16': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.16': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.16': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.16': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.16': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.16': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.16': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.0-rc.16': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.0-rc.16': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.0-rc.16': + dependencies: + '@emnapi/core': 1.9.2 + '@emnapi/runtime': 1.9.2 + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.16': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.16': + optional: true + + '@rolldown/plugin-babel@0.2.3(@babel/core@7.28.0)(@babel/runtime@7.28.3)(rolldown@1.0.0-rc.16)(vite@6.4.2(@types/node@22.15.13)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.77.8)(sugarss@4.0.1(postcss@8.5.8))(terser@5.31.6)(tsx@4.16.2)(yaml@2.8.3))': + dependencies: + '@babel/core': 7.28.0 + picomatch: 4.0.4 + rolldown: 1.0.0-rc.16 + optionalDependencies: + '@babel/runtime': 7.28.3 + vite: 6.4.2(@types/node@22.15.13)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.77.8)(sugarss@4.0.1(postcss@8.5.8))(terser@5.31.6)(tsx@4.16.2)(yaml@2.8.3) + '@rolldown/pluginutils@1.0.0-beta.27': {} + '@rolldown/pluginutils@1.0.0-rc.16': {} + '@rollup/plugin-commonjs@22.0.2(rollup@2.80.0)': dependencies: '@rollup/pluginutils': 3.1.0(rollup@2.80.0) @@ -41303,6 +41913,11 @@ snapshots: tslib: 2.8.1 optional: true + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + '@tybys/wasm-util@0.9.0': dependencies: tslib: 2.8.1 @@ -43107,6 +43722,36 @@ snapshots: dependencies: humanize-ms: 1.2.1 + agents@0.11.0(@ai-sdk/react@3.0.51(react@19.2.3)(zod@3.25.20))(@babel/core@7.28.0)(@babel/runtime@7.28.3)(@cloudflare/ai-chat@0.4.4)(@cloudflare/workers-types@4.20260416.2)(ai@6.0.68(zod@3.25.20))(react@19.2.3)(rolldown@1.0.0-rc.16)(vite@6.4.2(@types/node@22.15.13)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.77.8)(sugarss@4.0.1(postcss@8.5.8))(terser@5.31.6)(tsx@4.16.2)(yaml@2.8.3))(zod@3.25.20): + dependencies: + '@babel/plugin-proposal-decorators': 7.29.0(@babel/core@7.28.0) + '@cfworker/json-schema': 4.1.1 + '@modelcontextprotocol/sdk': 1.29.0(@cfworker/json-schema@4.1.1)(zod@3.25.20) + '@rolldown/plugin-babel': 0.2.3(@babel/core@7.28.0)(@babel/runtime@7.28.3)(rolldown@1.0.0-rc.16)(vite@6.4.2(@types/node@22.15.13)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.77.8)(sugarss@4.0.1(postcss@8.5.8))(terser@5.31.6)(tsx@4.16.2)(yaml@2.8.3)) + ai: 6.0.68(zod@3.25.20) + cron-schedule: 6.0.0 + json-schema: 0.4.0 + json-schema-to-typescript: 15.0.4 + mimetext: 3.0.28 + nanoid: 5.1.9 + partyserver: 0.4.1(@cloudflare/workers-types@4.20260416.2) + partysocket: 1.1.16(react@19.2.3) + picomatch: 4.0.4 + react: 19.2.3 + yargs: 18.0.0 + zod: 3.25.20 + optionalDependencies: + '@ai-sdk/react': 3.0.51(react@19.2.3)(zod@3.25.20) + '@cloudflare/ai-chat': 0.4.4(@ai-sdk/react@3.0.51(react@19.2.3)(zod@3.25.20))(agents@0.11.0)(ai@6.0.68(zod@3.25.20))(react@19.2.3)(zod@3.25.20) + vite: 6.4.2(@types/node@22.15.13)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.77.8)(sugarss@4.0.1(postcss@8.5.8))(terser@5.31.6)(tsx@4.16.2)(yaml@2.8.3) + transitivePeerDependencies: + - '@babel/core' + - '@babel/plugin-transform-runtime' + - '@babel/runtime' + - '@cloudflare/workers-types' + - rolldown + - supports-color + aggregate-error@3.1.0: dependencies: clean-stack: 2.2.0 @@ -43120,6 +43765,14 @@ snapshots: '@opentelemetry/api': 1.9.0 zod: 4.3.5 + ai@6.0.49(zod@3.25.20): + dependencies: + '@ai-sdk/gateway': 3.0.22(zod@3.25.20) + '@ai-sdk/provider': 3.0.5 + '@ai-sdk/provider-utils': 4.0.9(zod@3.25.20) + '@opentelemetry/api': 1.9.0 + zod: 3.25.20 + ai@6.0.49(zod@4.3.5): dependencies: '@ai-sdk/gateway': 3.0.22(zod@4.3.5) @@ -43167,7 +43820,6 @@ snapshots: ajv-formats@3.0.1(ajv@8.18.0): optionalDependencies: ajv: 8.18.0 - optional: true ajv-keywords@3.5.2(ajv@6.14.0): dependencies: @@ -43740,12 +44392,12 @@ snapshots: transitivePeerDependencies: - supports-color - babel-plugin-transform-typescript-metadata@0.3.2(@babel/core@7.28.0)(@babel/traverse@7.28.0): + babel-plugin-transform-typescript-metadata@0.3.2(@babel/core@7.28.0)(@babel/traverse@7.29.0): dependencies: '@babel/core': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 optionalDependencies: - '@babel/traverse': 7.28.0 + '@babel/traverse': 7.29.0 babel-preset-current-node-syntax@1.0.1(@babel/core@7.28.0): dependencies: @@ -43889,15 +44541,15 @@ snapshots: jsonpointer: 5.0.1 leven: 3.1.0 - better-auth@1.5.6(aac79383f71d2c0e811dbd569d97ebd4): + better-auth@1.5.6(778471f5f7178e7ab9fe0c8426d67ae9): dependencies: - '@better-auth/core': 1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0) - '@better-auth/drizzle-adapter': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1) - '@better-auth/kysely-adapter': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1)(kysely@0.28.14) - '@better-auth/memory-adapter': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1) - '@better-auth/mongo-adapter': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1)(mongodb@6.21.0(@aws-sdk/credential-providers@3.637.0(@aws-sdk/client-sso-oidc@3.637.0(@aws-sdk/client-sts@3.637.0)))(gcp-metadata@5.3.0(encoding@0.1.13))(socks@2.8.7)) - '@better-auth/prisma-adapter': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1) - '@better-auth/telemetry': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0)) + '@better-auth/core': 1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0) + '@better-auth/drizzle-adapter': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1) + '@better-auth/kysely-adapter': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1)(kysely@0.28.14) + '@better-auth/memory-adapter': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1) + '@better-auth/mongo-adapter': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1)(mongodb@6.21.0(@aws-sdk/credential-providers@3.637.0(@aws-sdk/client-sso-oidc@3.637.0(@aws-sdk/client-sts@3.637.0)))(gcp-metadata@5.3.0(encoding@0.1.13))(socks@2.8.7)) + '@better-auth/prisma-adapter': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1) + '@better-auth/telemetry': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0)) '@better-auth/utils': 0.3.1 '@better-fetch/fetch': 1.1.21 '@noble/ciphers': 2.1.1 @@ -43921,15 +44573,15 @@ snapshots: - '@cloudflare/workers-types' - '@opentelemetry/api' - better-auth@1.5.6(f5eede22a65d6cd0c93a8bf1a87b70c5): + better-auth@1.5.6(bfb0779f1cc865575f8ea1b2503ee818): dependencies: - '@better-auth/core': 1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0) - '@better-auth/drizzle-adapter': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1) - '@better-auth/kysely-adapter': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1)(kysely@0.28.14) - '@better-auth/memory-adapter': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1) - '@better-auth/mongo-adapter': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1)(mongodb@6.21.0(@aws-sdk/credential-providers@3.637.0(@aws-sdk/client-sso-oidc@3.637.0(@aws-sdk/client-sts@3.637.0)))(gcp-metadata@5.3.0(encoding@0.1.13))(socks@2.8.7)) - '@better-auth/prisma-adapter': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1) - '@better-auth/telemetry': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0)) + '@better-auth/core': 1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0) + '@better-auth/drizzle-adapter': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1) + '@better-auth/kysely-adapter': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1)(kysely@0.28.14) + '@better-auth/memory-adapter': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1) + '@better-auth/mongo-adapter': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1)(mongodb@6.21.0(@aws-sdk/credential-providers@3.637.0(@aws-sdk/client-sso-oidc@3.637.0(@aws-sdk/client-sts@3.637.0)))(gcp-metadata@5.3.0(encoding@0.1.13))(socks@2.8.7)) + '@better-auth/prisma-adapter': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0))(@better-auth/utils@0.3.1) + '@better-auth/telemetry': 1.5.6(@better-auth/core@1.5.6(@better-auth/utils@0.3.1)(@better-fetch/fetch@1.1.21)(@cloudflare/workers-types@4.20260416.2)(@opentelemetry/api@1.9.0)(better-call@1.3.2(zod@4.3.6))(jose@6.1.3)(kysely@0.28.14)(nanostores@1.2.0)) '@better-auth/utils': 0.3.1 '@better-fetch/fetch': 1.1.21 '@noble/ciphers': 2.1.1 @@ -44645,6 +45297,12 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + cliui@9.0.1: + dependencies: + string-width: 7.2.0 + strip-ansi: 7.1.0 + wrap-ansi: 9.0.2 + clone-deep@4.0.1: dependencies: is-plain-object: 2.0.4 @@ -44964,6 +45622,8 @@ snapshots: dependencies: browserslist: 4.28.1 + core-js-pure@3.49.0: {} + core-js@2.6.12: {} core-js@3.35.0: {} @@ -45064,6 +45724,8 @@ snapshots: dependencies: luxon: 3.4.4 + cron-schedule@6.0.0: {} + cron@3.1.7: dependencies: '@types/luxon': 3.4.2 @@ -45573,7 +46235,6 @@ snapshots: ms: 2.1.3 optionalDependencies: supports-color: 8.1.1 - optional: true debug@4.3.1(supports-color@8.1.1): dependencies: @@ -46033,6 +46694,8 @@ snapshots: emittery@0.8.1: {} + emoji-regex@10.6.0: {} + emoji-regex@7.0.3: {} emoji-regex@8.0.0: {} @@ -46497,6 +47160,10 @@ snapshots: eventsource-parser@3.0.6: {} + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.0.6 + execa@0.11.0: dependencies: cross-spawn: 6.0.6 @@ -46614,6 +47281,11 @@ snapshots: express-rate-limit@5.5.1: {} + express-rate-limit@8.3.2(express@5.2.1): + dependencies: + express: 5.2.1 + ip-address: 10.1.0 + express@4.21.2: dependencies: accepts: 1.3.8 @@ -46687,6 +47359,39 @@ snapshots: transitivePeerDependencies: - supports-color + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.2 + content-disposition: 1.0.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3(supports-color@8.1.1) + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.0 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.15.0 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.1.0 + serve-static: 2.2.1 + statuses: 2.0.2 + type-is: 2.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + ext-list@2.2.2: dependencies: mime-db: 1.53.0 @@ -46938,6 +47643,17 @@ snapshots: transitivePeerDependencies: - supports-color + finalhandler@2.1.1: + dependencies: + debug: 4.4.3(supports-color@8.1.1) + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + find-cache-dir@3.3.2: dependencies: commondir: 1.0.1 @@ -47956,6 +48672,8 @@ snapshots: dependencies: react-is: 16.13.1 + hono@4.12.14: {} + hosted-git-info@2.8.9: {} hosted-git-info@4.1.0: @@ -49842,6 +50560,8 @@ snapshots: joycon@3.1.1: {} + js-base64@3.7.8: {} + js-cookie@3.0.1: {} js-cookie@3.0.5: {} @@ -50023,12 +50743,26 @@ snapshots: '@babel/runtime': 7.28.3 ts-algebra: 2.0.0 + json-schema-to-typescript@15.0.4: + dependencies: + '@apidevtools/json-schema-ref-parser': 11.6.4 + '@types/json-schema': 7.0.15 + '@types/lodash': 4.17.20 + is-glob: 4.0.3 + js-yaml: 4.1.1 + lodash: 4.18.1 + minimist: 1.2.6 + prettier: 3.3.3 + tinyglobby: 0.2.14 + json-schema-to-zod@2.7.0: {} json-schema-traverse@0.4.1: {} json-schema-traverse@1.0.0: {} + json-schema-typed@8.0.2: {} + json-schema@0.4.0: {} json-stable-stringify-without-jsonify@1.0.1: {} @@ -51463,6 +52197,8 @@ snapshots: mime-db@1.53.0: {} + mime-db@1.54.0: {} + mime-types@2.1.35: dependencies: mime-db: 1.52.0 @@ -51471,6 +52207,10 @@ snapshots: dependencies: mime-db: 1.53.0 + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + mime@1.6.0: {} mime@2.6.0: {} @@ -51482,6 +52222,13 @@ snapshots: addressparser: 1.0.1 encoding: 0.1.13 + mimetext@3.0.28: + dependencies: + '@babel/runtime': 7.28.3 + '@babel/runtime-corejs3': 7.29.2 + js-base64: 3.7.8 + mime-types: 2.1.35 + mimic-fn@1.2.0: {} mimic-fn@2.1.0: {} @@ -51874,6 +52621,8 @@ snapshots: nanoid@5.1.6: {} + nanoid@5.1.9: {} + nanostores@1.2.0: {} napi-postinstall@0.3.3: {} @@ -51896,7 +52645,7 @@ snapshots: needle@3.2.0: dependencies: - debug: 3.2.7(supports-color@5.5.0) + debug: 3.2.7(supports-color@8.1.1) iconv-lite: 0.6.3 sax: 1.5.0 transitivePeerDependencies: @@ -52913,8 +53662,19 @@ snapshots: parseurl@1.3.3: {} + partyserver@0.4.1(@cloudflare/workers-types@4.20260416.2): + dependencies: + '@cloudflare/workers-types': 4.20260416.2 + nanoid: 5.1.9 + partysocket@0.0.17: {} + partysocket@1.1.16(react@19.2.3): + dependencies: + event-target-polyfill: 0.0.4 + optionalDependencies: + react: 19.2.3 + partysocket@1.1.4: dependencies: event-target-polyfill: 0.0.4 @@ -53144,6 +53904,8 @@ snapshots: optionalDependencies: nice-napi: 1.0.2 + pkce-challenge@5.0.1: {} + pkg-conf@2.1.0: dependencies: find-up: 2.1.0 @@ -53226,7 +53988,7 @@ snapshots: portfinder@1.0.32: dependencies: async: 2.6.4 - debug: 3.2.7(supports-color@5.5.0) + debug: 3.2.7(supports-color@8.1.1) mkdirp: 0.5.6 transitivePeerDependencies: - supports-color @@ -54879,6 +55641,27 @@ snapshots: robust-predicates@3.0.2: {} + rolldown@1.0.0-rc.16: + dependencies: + '@oxc-project/types': 0.126.0 + '@rolldown/pluginutils': 1.0.0-rc.16 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.0-rc.16 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.16 + '@rolldown/binding-darwin-x64': 1.0.0-rc.16 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.16 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.16 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.16 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.16 + '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.16 + '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.16 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.16 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.16 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.16 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.16 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.16 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.16 + rollup@2.80.0: optionalDependencies: fsevents: 2.3.3 @@ -54931,6 +55714,16 @@ snapshots: parseurl: 1.3.3 path-to-regexp: 8.4.0 + router@2.2.0: + dependencies: + debug: 4.4.3(supports-color@8.1.1) + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.4.0 + transitivePeerDependencies: + - supports-color + rrdom@2.0.0-alpha.16: dependencies: rrweb-snapshot: 2.0.0-alpha.16 @@ -55165,6 +55958,22 @@ snapshots: transitivePeerDependencies: - supports-color + send@1.2.1: + dependencies: + debug: 4.4.3(supports-color@8.1.1) + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.1 + mime-types: 3.0.2 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + sentence-case@2.1.1: dependencies: no-case: 2.3.2 @@ -55196,6 +56005,15 @@ snapshots: transitivePeerDependencies: - supports-color + serve-static@2.2.1: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.1 + transitivePeerDependencies: + - supports-color + set-blocking@2.0.0: {} set-cookie-parser@2.7.2: {} @@ -55827,6 +56645,12 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.1.0 + string-width@7.2.0: + dependencies: + emoji-regex: 10.6.0 + get-east-asian-width: 1.4.0 + strip-ansi: 7.1.0 + string.fromcodepoint@0.2.1: {} string.prototype.padend@3.1.4: @@ -58430,7 +59254,7 @@ snapshots: workerpool@6.2.1: {} - wrangler@4.68.1: + wrangler@4.68.1(@cloudflare/workers-types@4.20260416.2): dependencies: '@cloudflare/kv-asset-handler': 0.4.2 '@cloudflare/unenv-preset': 2.14.0(unenv@2.0.0-rc.24)(workerd@1.20260302.0) @@ -58441,6 +59265,7 @@ snapshots: unenv: 2.0.0-rc.24 workerd: 1.20260302.0 optionalDependencies: + '@cloudflare/workers-types': 4.20260416.2 fsevents: 2.3.3 transitivePeerDependencies: - bufferutil @@ -58475,6 +59300,12 @@ snapshots: string-width: 5.1.2 strip-ansi: 7.1.0 + wrap-ansi@9.0.2: + dependencies: + ansi-styles: 6.2.1 + string-width: 7.2.0 + strip-ansi: 7.1.0 + wrappy@1.0.2: {} write-file-atomic@3.0.3: @@ -58597,6 +59428,8 @@ snapshots: yargs-parser@21.1.1: {} + yargs-parser@22.0.0: {} + yargs-unparser@2.0.0: dependencies: camelcase: 6.3.0 @@ -58651,6 +59484,15 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + yargs@18.0.0: + dependencies: + cliui: 9.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + string-width: 7.2.0 + y18n: 5.0.8 + yargs-parser: 22.0.0 + yauzl@2.10.0: dependencies: buffer-crc32: 0.2.13