From b8f38531f0e8f4a4848fbcb901e9a534c421b16d Mon Sep 17 00:00:00 2001 From: Dave Horton Date: Tue, 7 Apr 2026 10:59:47 -0400 Subject: [PATCH 1/2] refactor schema --- .github/workflows/publish-mcp.yml | 35 - AGENTS.md | 279 +- docs/components/recognizer.md | 78 - docs/components/synthesizer.md | 27 - docs/guides/session-commands.md | 417 --- docs/verbs/conference.md | 51 - docs/verbs/deepgram_s2s.md | 108 - docs/verbs/dial.md | 8 - docs/verbs/listen.md | 71 - docs/verbs/pipeline.md | 475 --- docs/verbs/stream.md | 5 - examples/bedrock-pipeline.ts | 267 ++ mcp-server/package-lock.json | 2682 ----------------- mcp-server/package.json | 57 - mcp-server/src/index.ts | 89 - mcp-server/src/resources.ts | 142 - mcp-server/src/tools.ts | 198 -- mcp-server/tsconfig.json | 20 - mcp-server/tsup.config.ts | 12 - schema/callbacks/amd.schema.json | 50 - schema/callbacks/base.schema.json | 29 - schema/callbacks/call-status.schema.json | 22 - .../callbacks/conference-status.schema.json | 24 - schema/callbacks/conference-wait.schema.json | 11 - schema/callbacks/conference.schema.json | 11 - schema/callbacks/dequeue.schema.json | 19 - schema/callbacks/dial-dtmf.schema.json | 18 - schema/callbacks/dial-hold.schema.json | 22 - schema/callbacks/dial-refer.schema.json | 28 - schema/callbacks/dial.schema.json | 31 - schema/callbacks/enqueue-wait.schema.json | 17 - schema/callbacks/enqueue.schema.json | 27 - schema/callbacks/gather-partial.schema.json | 54 - schema/callbacks/gather.schema.json | 60 - schema/callbacks/listen.schema.json | 21 - schema/callbacks/llm.schema.json | 30 - schema/callbacks/message.schema.json | 35 - schema/callbacks/pipeline-turn.schema.json | 109 - schema/callbacks/play.schema.json | 36 - schema/callbacks/session-new.schema.json | 143 - .../callbacks/session-reconnect.schema.json | 9 - schema/callbacks/session-redirect.schema.json | 38 - schema/callbacks/sip-refer-event.schema.json | 20 - schema/callbacks/sip-refer.schema.json | 22 - schema/callbacks/sip-request.schema.json | 27 - .../transcribe-translation.schema.json | 24 - schema/callbacks/transcribe.schema.json | 46 - .../callbacks/tts-streaming-event.schema.json | 77 - schema/callbacks/verb-status.schema.json | 57 - schema/components/actionHook.schema.json | 36 - .../actionHookDelayAction.schema.json | 37 - schema/components/amd.schema.json | 68 - schema/components/auth.schema.json | 18 - .../components/bidirectionalAudio.schema.json | 22 - schema/components/fillerNoise.schema.json | 25 - schema/components/llm-base.schema.json | 94 - .../recognizer-assemblyAiOptions.schema.json | 66 - .../recognizer-awsOptions.schema.json | 52 - .../recognizer-azureOptions.schema.json | 32 - .../recognizer-cobaltOptions.schema.json | 34 - .../recognizer-customOptions.schema.json | 27 - .../recognizer-deepgramOptions.schema.json | 147 - .../recognizer-elevenlabsOptions.schema.json | 39 - .../recognizer-gladiaOptions.schema.json | 8 - .../recognizer-googleOptions.schema.json | 35 - .../recognizer-houndifyOptions.schema.json | 53 - .../recognizer-ibmOptions.schema.json | 54 - .../recognizer-nuanceOptions.schema.json | 150 - .../recognizer-nvidiaOptions.schema.json | 39 - .../recognizer-openaiOptions.schema.json | 59 - .../recognizer-sonioxOptions.schema.json | 46 - ...recognizer-speechmaticsOptions.schema.json | 100 - .../recognizer-verbioOptions.schema.json | 46 - schema/components/recognizer.schema.json | 216 -- schema/components/synthesizer.schema.json | 82 - schema/components/target.schema.json | 105 - schema/components/vad.schema.json | 48 - schema/jambonz-app.schema.json | 112 - schema/verbs/alert.schema.json | 34 - schema/verbs/answer.schema.json | 22 - schema/verbs/conference.schema.json | 107 - schema/verbs/config.schema.json | 218 -- schema/verbs/deepgram_s2s.schema.json | 81 - schema/verbs/dequeue.schema.json | 51 - schema/verbs/dial.schema.json | 187 -- schema/verbs/dialogflow.schema.json | 148 - schema/verbs/dtmf.schema.json | 49 - schema/verbs/dub.schema.json | 103 - schema/verbs/elevenlabs_s2s.schema.json | 81 - schema/verbs/enqueue.schema.json | 53 - schema/verbs/gather.schema.json | 188 -- schema/verbs/google_s2s.schema.json | 42 - schema/verbs/hangup.schema.json | 36 - schema/verbs/leave.schema.json | 22 - schema/verbs/listen.schema.json | 127 - schema/verbs/llm.schema.json | 44 - schema/verbs/message.schema.json | 82 - schema/verbs/openai_s2s.schema.json | 42 - schema/verbs/pause.schema.json | 36 - schema/verbs/pipeline.schema.json | 240 -- schema/verbs/play.schema.json | 96 - schema/verbs/redirect.schema.json | 34 - schema/verbs/s2s.schema.json | 39 - schema/verbs/say.schema.json | 107 - schema/verbs/sip-decline.schema.json | 58 - schema/verbs/sip-refer.schema.json | 58 - schema/verbs/sip-request.schema.json | 54 - schema/verbs/stream.schema.json | 103 - schema/verbs/tag.schema.json | 41 - schema/verbs/transcribe.schema.json | 57 - schema/verbs/ultravox_s2s.schema.json | 41 - typescript/package-lock.json | 13 +- typescript/package.json | 6 +- typescript/src/validator.ts | 144 +- typescript/test/schema-drift.test.ts | 4 +- typescript/test/validator.test.ts | 8 +- typescript/test/webhook.test.ts | 8 +- 117 files changed, 350 insertions(+), 10502 deletions(-) delete mode 100644 .github/workflows/publish-mcp.yml delete mode 100644 docs/components/recognizer.md delete mode 100644 docs/components/synthesizer.md delete mode 100644 docs/guides/session-commands.md delete mode 100644 docs/verbs/conference.md delete mode 100644 docs/verbs/deepgram_s2s.md delete mode 100644 docs/verbs/dial.md delete mode 100644 docs/verbs/listen.md delete mode 100644 docs/verbs/pipeline.md delete mode 100644 docs/verbs/stream.md create mode 100644 examples/bedrock-pipeline.ts delete mode 100644 mcp-server/package-lock.json delete mode 100644 mcp-server/package.json delete mode 100644 mcp-server/src/index.ts delete mode 100644 mcp-server/src/resources.ts delete mode 100644 mcp-server/src/tools.ts delete mode 100644 mcp-server/tsconfig.json delete mode 100644 mcp-server/tsup.config.ts delete mode 100644 schema/callbacks/amd.schema.json delete mode 100644 schema/callbacks/base.schema.json delete mode 100644 schema/callbacks/call-status.schema.json delete mode 100644 schema/callbacks/conference-status.schema.json delete mode 100644 schema/callbacks/conference-wait.schema.json delete mode 100644 schema/callbacks/conference.schema.json delete mode 100644 schema/callbacks/dequeue.schema.json delete mode 100644 schema/callbacks/dial-dtmf.schema.json delete mode 100644 schema/callbacks/dial-hold.schema.json delete mode 100644 schema/callbacks/dial-refer.schema.json delete mode 100644 schema/callbacks/dial.schema.json delete mode 100644 schema/callbacks/enqueue-wait.schema.json delete mode 100644 schema/callbacks/enqueue.schema.json delete mode 100644 schema/callbacks/gather-partial.schema.json delete mode 100644 schema/callbacks/gather.schema.json delete mode 100644 schema/callbacks/listen.schema.json delete mode 100644 schema/callbacks/llm.schema.json delete mode 100644 schema/callbacks/message.schema.json delete mode 100644 schema/callbacks/pipeline-turn.schema.json delete mode 100644 schema/callbacks/play.schema.json delete mode 100644 schema/callbacks/session-new.schema.json delete mode 100644 schema/callbacks/session-reconnect.schema.json delete mode 100644 schema/callbacks/session-redirect.schema.json delete mode 100644 schema/callbacks/sip-refer-event.schema.json delete mode 100644 schema/callbacks/sip-refer.schema.json delete mode 100644 schema/callbacks/sip-request.schema.json delete mode 100644 schema/callbacks/transcribe-translation.schema.json delete mode 100644 schema/callbacks/transcribe.schema.json delete mode 100644 schema/callbacks/tts-streaming-event.schema.json delete mode 100644 schema/callbacks/verb-status.schema.json delete mode 100644 schema/components/actionHook.schema.json delete mode 100644 schema/components/actionHookDelayAction.schema.json delete mode 100644 schema/components/amd.schema.json delete mode 100644 schema/components/auth.schema.json delete mode 100644 schema/components/bidirectionalAudio.schema.json delete mode 100644 schema/components/fillerNoise.schema.json delete mode 100644 schema/components/llm-base.schema.json delete mode 100644 schema/components/recognizer-assemblyAiOptions.schema.json delete mode 100644 schema/components/recognizer-awsOptions.schema.json delete mode 100644 schema/components/recognizer-azureOptions.schema.json delete mode 100644 schema/components/recognizer-cobaltOptions.schema.json delete mode 100644 schema/components/recognizer-customOptions.schema.json delete mode 100644 schema/components/recognizer-deepgramOptions.schema.json delete mode 100644 schema/components/recognizer-elevenlabsOptions.schema.json delete mode 100644 schema/components/recognizer-gladiaOptions.schema.json delete mode 100644 schema/components/recognizer-googleOptions.schema.json delete mode 100644 schema/components/recognizer-houndifyOptions.schema.json delete mode 100644 schema/components/recognizer-ibmOptions.schema.json delete mode 100644 schema/components/recognizer-nuanceOptions.schema.json delete mode 100644 schema/components/recognizer-nvidiaOptions.schema.json delete mode 100644 schema/components/recognizer-openaiOptions.schema.json delete mode 100644 schema/components/recognizer-sonioxOptions.schema.json delete mode 100644 schema/components/recognizer-speechmaticsOptions.schema.json delete mode 100644 schema/components/recognizer-verbioOptions.schema.json delete mode 100644 schema/components/recognizer.schema.json delete mode 100644 schema/components/synthesizer.schema.json delete mode 100644 schema/components/target.schema.json delete mode 100644 schema/components/vad.schema.json delete mode 100644 schema/jambonz-app.schema.json delete mode 100644 schema/verbs/alert.schema.json delete mode 100644 schema/verbs/answer.schema.json delete mode 100644 schema/verbs/conference.schema.json delete mode 100644 schema/verbs/config.schema.json delete mode 100644 schema/verbs/deepgram_s2s.schema.json delete mode 100644 schema/verbs/dequeue.schema.json delete mode 100644 schema/verbs/dial.schema.json delete mode 100644 schema/verbs/dialogflow.schema.json delete mode 100644 schema/verbs/dtmf.schema.json delete mode 100644 schema/verbs/dub.schema.json delete mode 100644 schema/verbs/elevenlabs_s2s.schema.json delete mode 100644 schema/verbs/enqueue.schema.json delete mode 100644 schema/verbs/gather.schema.json delete mode 100644 schema/verbs/google_s2s.schema.json delete mode 100644 schema/verbs/hangup.schema.json delete mode 100644 schema/verbs/leave.schema.json delete mode 100644 schema/verbs/listen.schema.json delete mode 100644 schema/verbs/llm.schema.json delete mode 100644 schema/verbs/message.schema.json delete mode 100644 schema/verbs/openai_s2s.schema.json delete mode 100644 schema/verbs/pause.schema.json delete mode 100644 schema/verbs/pipeline.schema.json delete mode 100644 schema/verbs/play.schema.json delete mode 100644 schema/verbs/redirect.schema.json delete mode 100644 schema/verbs/s2s.schema.json delete mode 100644 schema/verbs/say.schema.json delete mode 100644 schema/verbs/sip-decline.schema.json delete mode 100644 schema/verbs/sip-refer.schema.json delete mode 100644 schema/verbs/sip-request.schema.json delete mode 100644 schema/verbs/stream.schema.json delete mode 100644 schema/verbs/tag.schema.json delete mode 100644 schema/verbs/transcribe.schema.json delete mode 100644 schema/verbs/ultravox_s2s.schema.json diff --git a/.github/workflows/publish-mcp.yml b/.github/workflows/publish-mcp.yml deleted file mode 100644 index c7ded39..0000000 --- a/.github/workflows/publish-mcp.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Publish @jambonz/mcp-schema-server - -on: - push: - tags: - - 'mcp-v*' - workflow_dispatch: - -jobs: - publish: - runs-on: ubuntu-latest - permissions: - contents: read - id-token: write - steps: - - uses: actions/checkout@v5 - - - uses: actions/setup-node@v5 - with: - node-version: 22 - registry-url: https://registry.npmjs.org - - - name: Install dependencies - working-directory: mcp-server - run: npm ci - - - name: Build - working-directory: mcp-server - run: npm run build - - - name: Publish - working-directory: mcp-server - run: npm publish --access public --provenance - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/AGENTS.md b/AGENTS.md index c175011..ddc7f62 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,100 +1,14 @@ -# jambonz Agent Toolkit +# @jambonz/sdk — Node.js SDK Guide -jambonz is an open-source CPaaS (Communications Platform as a Service) for building voice and messaging applications. It handles telephony infrastructure — SIP, carriers, phone numbers, media processing — so you can focus on application logic. +This guide covers the @jambonz/sdk TypeScript/JavaScript SDK. For the language-agnostic jambonz verb model and protocol reference, see the AGENTS.md in the @jambonz/schema package or use the jambonz MCP server: + +- **Remote**: `https://mcp-server.jambonz.app/mcp` +- **Tools**: `jambonz_developer_toolkit` (full guide + schema index), `get_jambonz_schema` (individual verb/component schemas) ## Before You Start — Ask the User Before generating any jambonz application code, ask the user: **"Do you prefer TypeScript or JavaScript?"** Then generate all code examples in their chosen language. If they don't have a preference, default to TypeScript. -## Server Versions - -jambonz has two editions: **v0.9.x (open source)** and **v10.x (commercial)**. Always target the commercial version (v10.x). All verb schemas and features are available. - -## How jambonz Applications Work - -A jambonz application controls phone calls by returning **arrays of verbs** — JSON instructions that execute sequentially. The runtime processes each verb in order: speak text, play audio, collect input, dial a number, connect to an AI model, etc. - -### The Webhook Lifecycle - -1. An incoming call arrives. jambonz invokes your application's URL with call details (caller, called number, SIP headers, etc.). -2. Your application returns a JSON array of verbs. -3. jambonz executes the verbs in order. -4. When a verb with an `actionHook` completes (e.g. `gather` collects speech input), jambonz invokes the actionHook URL with the result. -5. The actionHook response (a new verb array) replaces the remaining verb stack. -6. This continues until the call ends or a `hangup` verb is executed. - -### Transport Modes - -jambonz supports two transport modes for delivering verb arrays: - -- **Webhook (HTTP)**: Your server receives HTTP POST requests with call data and returns JSON verb arrays in the response body. Stateless and simple. Good for IVR menus, call routing, and straightforward flows. -- **WebSocket**: Your server maintains a persistent websocket connection with jambonz. Verb arrays are sent as JSON messages in both directions. Required for real-time features like LLM conversations, audio streaming, and event-driven flows. - -The verb schemas and JSON structure are identical in both modes. The difference is the transport. - -### When to Use Which - -- **Webhook**: Simple IVR, call routing, voicemail, basic gather-and-respond patterns. -- **WebSocket**: LLM-powered voice agents, real-time audio streaming, complex conversational flows, anything requiring bidirectional communication, or asynchronous logic, or streaming tts. - -**IMPORTANT**: Any application that uses a speech-to-speech verb (`openai_s2s`, `google_s2s`, `deepgram_s2s`, `ultravox_s2s`, `elevenlabs_s2s`, `s2s`, or `pipeline`) MUST use WebSocket transport, not webhooks. These verbs require persistent bidirectional communication for real-time audio and events. Always use `createEndpoint` from `@jambonz/sdk/websocket` for s2s applications. - -## Schema - -The complete verb schema is at `schema/jambonz-app.schema.json`. This is a JSON Schema (draft 2020-12) that defines the structure of a jambonz application. - -Individual verb schemas are in `schema/verbs/`. Shared component types (synthesizer, recognizer, target, etc.) are in `schema/components/`. - -## Core Verbs - -### Audio & Speech -- **say** — Speak text using TTS. Supports SSML, streaming, multiple voices. -- **play** — Play an audio file from a URL. -- **gather** — Collect speech (STT) and/or DTMF input. The workhorse for interactive menus and voice input. - -### AI & Real-time -- **openai_s2s** / **google_s2s** / **deepgram_s2s** / **ultravox_s2s** — Connect the caller to a vendor-specific LLM for real-time voice conversation. These are the **preferred** verbs when the vendor is known. Each handles the full STT→LLM→TTS pipeline with the vendor pre-set. -- **elevenlabs_s2s** — Connect the caller to an ElevenLabs Conversational AI agent. **Unlike other s2s vendors**, ElevenLabs requires a pre-configured `agent_id` (created in the ElevenLabs dashboard) rather than a model and messages. See [ElevenLabs S2S specifics](#elevenlabs-s2s-specifics) below. -- **s2s** — Generic LLM voice conversation verb. Use only when the vendor is determined at runtime (e.g. from an env var). Requires `vendor` to be specified. -- **pipeline** — Higher-level voice AI pipeline with integrated turn detection. -- **dialogflow** — Connect the caller to a Google Dialogflow agent (ES, CX, or CES). -- **stream** — Stream raw audio to a websocket endpoint for custom processing. -- **transcribe** — Real-time call transcription sent to a webhook. - -### Call Control -- **dial** — Place an outbound call and bridge it to the current caller. -- **conference** — Multi-party conference room. -- **enqueue** / **dequeue** — Call queuing. -- **hangup** — End the call. -- **redirect** — Transfer control to a different webhook. -- **pause** — Wait for a specified duration. - -### SIP -- **sip:decline** — Reject an incoming call with a SIP error. -- **sip:request** — Send a SIP request within the dialog. -- **sip:refer** — Transfer the call via SIP REFER. - -### Utility -- **config** — Set session-level defaults (TTS vendor/voice, STT vendor, VAD, etc.). -- **tag** — Attach metadata to the call. -- **dtmf** — Send DTMF tones. -- **dub** — Mix auxiliary audio tracks into the call. -- **message** — Send SMS/MMS. -- **alert** — Send a SIP 180 with Alert-Info. -- **answer** — Explicitly answer the call. -- **leave** — Leave a conference or queue. - -### Verb Synonyms and Shortcuts - -**IMPORTANT — Code generation rules:** - -1. **Always use `stream`, never `listen`** — they are synonyms; `stream` is the preferred name. -2. **Always use the vendor-specific shortcut when the LLM vendor is known** — use `openai_s2s`, `google_s2s`, `elevenlabs_s2s`, `deepgram_s2s`, or `ultravox_s2s`. Do NOT use `llm` or `s2s` with a `vendor` property when a shortcut exists. -3. **Use `s2s` (not `llm`) when the vendor is dynamic** — e.g. the vendor comes from an env var or runtime config. Both `s2s` and `llm` are synonyms, but prefer `s2s`. -4. **Never use `llm` in generated code** — it is a legacy name. Use either a vendor shortcut or `s2s`. - -The same rules apply to SDK method calls: use `.openai_s2s(opts)`, `.deepgram_s2s(opts)`, etc. instead of `.llm({ vendor: 'openai', ... })`. Use `.stream(opts)` instead of `.listen(opts)`. - ## Using the @jambonz/sdk **IMPORTANT**: Always use the `@jambonz/sdk` package (version 0.1.x+) to build jambonz applications. The older packages `@jambonz/node-client-ws` and `@jambonz/node-client` are **deprecated and replaced** by `@jambonz/sdk`. Do NOT use those old packages. Do NOT build apps with raw JSON verb arrays and plain Express/WS — use `@jambonz/sdk`. @@ -295,135 +209,6 @@ await client.calls.redirect(callSid, 'https://example.com/new-flow'); await client.calls.update(callSid, { call_status: 'completed' }); ``` -## Common Patterns (Raw JSON) - -These are the raw JSON verb arrays that the SDK generates. You should use the SDK verb methods above, but these show the underlying structure for reference. - -### Simple Greeting and Gather -```json -[ - { "verb": "say", "text": "Welcome. Press 1 for sales, 2 for support." }, - { "verb": "gather", "input": ["digits"], "numDigits": 1, "actionHook": "/menu" } -] -``` - -### LLM Voice Agent -```json -[ - { - "verb": "config", - "synthesizer": { "vendor": "elevenlabs", "voice": "EXAVITQu4vr4xnSDxMaL" }, - "recognizer": { "vendor": "deepgram", "language": "en-US" } - }, - { - "verb": "openai_s2s", - "model": "gpt-4o", - "llmOptions": { - "messages": [{ "role": "system", "content": "You are a helpful assistant." }] - }, - "actionHook": "/llm-done", - "toolHook": "/tool-call" - } -] -``` - -### ElevenLabs S2S Specifics - -ElevenLabs works differently from other s2s vendors. Instead of passing a model and system prompt, you create a **Conversational AI agent** in the ElevenLabs dashboard and pass the `agent_id` to jambonz. The agent's voice, personality, tools, and LLM configuration are all managed on the ElevenLabs side. - -**Key differences from other s2s verbs:** -- `auth` requires `agent_id` (required) and optionally `api_key` (enables signed WebSocket URLs) -- `model` is NOT used — the model is configured in the ElevenLabs agent -- `llmOptions` should be an empty object `{}` (do NOT pass `messages` or `temperature`) -- `llmOptions.conversation_initiation_client_data` can optionally send data to the agent at conversation start -- Always include `eventHook` and `events: ['all']` — omitting eventHook causes errors on the server - -```json -[ - { - "verb": "elevenlabs_s2s", - "auth": { - "agent_id": "your-agent-id", - "api_key": "your-api-key" - }, - "llmOptions": {}, - "actionHook": "/s2s-complete", - "eventHook": "/event", - "events": ["all"] - } -] -``` - -SDK example: -```typescript -session - .elevenlabs_s2s({ - auth: { agent_id: agentId, api_key: apiKey }, - llmOptions: {}, - actionHook: '/s2s-complete', - eventHook: '/event', - events: ['all'], - }) - .send(); -``` - -### Dial with Fallback -```json -[ - { "verb": "say", "text": "Connecting you now." }, - { - "verb": "dial", - "target": [{ "type": "phone", "number": "+15085551212" }], - "answerOnBridge": true, - "timeout": 30, - "actionHook": "/dial-result" - }, - { "verb": "say", "text": "The agent is unavailable. Goodbye." }, - { "verb": "hangup" } -] -``` - -### Call Queue -```json -[ - { "verb": "say", "text": "All agents are busy. You are in the queue." }, - { - "verb": "enqueue", - "name": "support", - "waitHook": "/hold-music", - "actionHook": "/queue-exit" - } -] -``` - -## ActionHook Payloads - -When a verb completes, jambonz invokes the `actionHook` URL (webhook) or sends an event (WebSocket) with result data. Every actionHook payload includes these base fields: - -| Field | Description | -|-------|-------------| -| `call_sid` | Unique identifier for this call | -| `account_sid` | Your account identifier | -| `application_sid` | The application handling this call | -| `direction` | `inbound` or `outbound` | -| `from` | Caller phone number or SIP URI | -| `to` | Called phone number or SIP URI | -| `call_id` | SIP Call-ID | -| `call_status` | Current call state (`trying`, `ringing`, `early-media`, `in-progress`, `completed`, `failed`, `busy`, `no-answer`) | -| `sip_status` | SIP response code (e.g. `200`, `486`) | - -### Verb-Specific Payload Fields - -**gather**: `speech` (object with `alternatives[].transcript`), `digits` (string), `reason` (`speechDetected`, `dtmfDetected`, `timeout`) - -**dial**: `dial_call_sid`, `dial_call_status`, `dial_sip_status`, `dial_sbc_callid`, `duration` - -**llm**: `completion_reason` (`normal`, `timeout`, `error`), `llm_usage` (token counts) - -**enqueue**: `queue_result` (`dequeued`, `hangup`, `error`) - -**transcribe**: `transcription` (object with transcript text) - ## Application Environment Variables jambonz has a built-in mechanism for application configuration that is **always preferred over `process.env`**. It works in two required steps: @@ -588,32 +373,6 @@ Key capabilities: - **LLM tool output** — `toolOutput()` — return tool call results to the pipeline verb's LLM. - **Cascaded voice AI agents** — build your own STT→LLM→TTS loop using `config` (ttsStream + bargeIn) + `sendTtsTokens()`. Full control over LLM interaction and conversation history. -## WebSocket Protocol - -### Message Types (jambonz → app) - -| Type | Description | -|------|-------------| -| `session:new` | New call session established. Contains call details. | -| `session:redirect` | Call was redirected to this app. | -| `verb:hook` | An actionHook fired (e.g. gather completed). Contains `hook` (the actionHook name) and `data` (the payload). The SDK emits this as `session.on('/hookName', handler)`. Respond with `.reply()`. | -| `verb:status` | Informational verb status notification (no reply needed). | -| `call:status` | Call state changed (e.g. `completed`). | -| `llm:tool-call` | LLM requested a tool/function call. | -| `llm:event` | LLM lifecycle event (connected, tokens, etc.). | -| `tts:tokens-result` | Ack for a TTS token streaming message. | -| `tts:streaming-event` | TTS streaming lifecycle event (e.g. user interruption). | - -### Message Types (app → jambonz) - -| Type | Description | -|------|-------------| -| `ack` | Acknowledge a received message. Include verbs in the `data` array to replace the current verb stack. | -| `command` | Send a command (e.g. inject a verb, control recording). | -| `llm:tool-output` | Return the result of a tool call to the LLM. | -| `tts:tokens` | Stream TTS text tokens for incremental speech synthesis. | -| `tts:flush` | Signal end of a TTS token stream. | - ### Session Events (SDK) The SDK `Session` object emits events for common message types: @@ -820,14 +579,6 @@ session.injectRecord('stopCallRecording'); **Important**: The `dial` verb must use `anchorMedia: true` for recording to work during bridged calls. Without media anchoring, audio doesn't flow through the jambonz media server. -## REST API - -jambonz provides a REST API for platform management and active call control. The API client is available in the SDK at `@jambonz/sdk/client`. - -Key resources: -- **Calls** — Create outbound calls, query active calls, modify in-progress calls (redirect, whisper, mute, hangup) -- **Messages** — Send SMS/MMS messages - ## Code Structure ### Single File (default) @@ -840,9 +591,9 @@ For applications with 3+ routes or significant per-route logic, split into a `sr ``` src/ - app.ts ← entry point: server setup, route registration + app.ts <- entry point: server setup, route registration routes/ - incoming.ts ← handler for one endpoint/path + incoming.ts <- handler for one endpoint/path hold-music.ts queue-exit.ts ``` @@ -940,9 +691,9 @@ svc.on('session:new', (session) => { ### When to Split -- **1-2 routes, simple logic** → single file -- **3+ routes or substantial per-route logic** → `src/app.ts` + `src/routes/` -- **Shared config, prompts, or utilities** → `src/config.ts`, `src/prompts.ts`, etc. +- **1-2 routes, simple logic** -> single file +- **3+ routes or substantial per-route logic** -> `src/app.ts` + `src/routes/` +- **Shared config, prompts, or utilities** -> `src/config.ts`, `src/prompts.ts`, etc. When in doubt, start with a single file. It's easy to split later. @@ -962,13 +713,3 @@ Complete working examples are in the `examples/` directory: - **queue-with-hold** — Call queue with hold music and agent dequeue (webhook + WebSocket) - **call-recording** — Mid-call recording control via REST API and inject commands (webhook + WebSocket) - **realtime-translator** — Bridges two parties with real-time speech translation using STT, Google Translate, and TTS dub tracks. Multi-file example with `src/routes/` structure (WebSocket) - -## Key Concepts - -- **Verb**: A JSON object with a `verb` property that tells jambonz what to do. Verbs execute sequentially. -- **ActionHook**: A webhook URL that jambonz calls when a verb completes. Returns the next verb array. Payload includes call details and verb-specific results. -- **Synthesizer**: TTS configuration (vendor, voice, language). -- **Recognizer**: STT configuration (vendor, language, model). -- **Target**: A call destination (phone number, SIP URI, registered user, Teams user). -- **Session**: A single phone call. Session-level settings (set via `config`) persist across verbs. -- **Inject Command**: Asynchronous mid-call modification (WebSocket). Executes immediately without replacing the verb stack. diff --git a/docs/components/recognizer.md b/docs/components/recognizer.md deleted file mode 100644 index 4c8dfc1..0000000 --- a/docs/components/recognizer.md +++ /dev/null @@ -1,78 +0,0 @@ -## Vendor documentation links - -Refer to vendor documentation for supported models and languages. - -**Important**: jambonz requires real-time streaming STT. When choosing a model, ensure it supports real-time/streaming transcription. Models that only support batch transcription cannot be used. - -### Deepgram -- When using Deepgram default to the latest nova model (e.g. nova-3) -- [Models & Languages Overview](https://developers.deepgram.com/docs/models-languages-overview) - -### Google - -- [Supported Languages](https://cloud.google.com/speech-to-text/docs/speech-to-text-supported-languages) - -### Microsoft Azure - -- [Language and Voice Support](https://learn.microsoft.com/en-us/azure/ai-services/speech-service/language-support) - -### AWS Transcribe - -- [Supported Languages](https://docs.aws.amazon.com/transcribe/latest/dg/supported-languages.html) - -### IBM Watson - -- [Models and Languages](https://cloud.ibm.com/docs/speech-to-text?topic=speech-to-text-models-ng) - -### AssemblyAI - -- [Supported Languages](https://www.assemblyai.com/docs/getting-started/supported-languages) - -#### Prompting (Universal-3 Pro) - -AssemblyAI's Universal-3 Pro streaming model supports a `prompt` parameter that guides transcription behavior around punctuation, disfluencies, formatting, and domain-specific terminology. The default prompt achieves strong turn detection accuracy out of the box — only customize if needed, and start by extending the default rather than replacing it. - -- See [Prompting guide](https://www.assemblyai.com/docs/streaming/universal-3-pro/prompting) - -jambonz has an autogeneratePrompt recognizer setting which when used with AssemblyAI universal-3 pro streaming will automatically create the prompt for a gather verb based on the text in a nested say property. See [here](../../examples/assemblyai-autogenerate-prompt/) for details. - -A `keyterms` array can boost recognition of specific names, brands, or technical terms. This can be updated mid-stream, making it useful for voice agent scenarios where context changes during the call. - -- See [Keyterms guide](https://www.assemblyai.com/docs/streaming/keyterms-prompting) - -### OpenAI (Whisper) - -- [Speech to Text Guide](https://platform.openai.com/docs/guides/speech-to-text) - -### Nvidia Riva - -- [ASR Overview](https://docs.nvidia.com/deeplearning/riva/user-guide/docs/asr/asr-overview.html) - -### Speechmatics - -- [Transcription Languages](https://docs.speechmatics.com/speech-to-text/languages#transcription-languages) - -#### Voice Agent (Preview) - -Speechmatics offers a Voice Agent API (currently in preview) that provides low-latency conversational AI capabilities. When using the Voice Agent API, set the `host` and `profile` properties in `speechmaticsOptions`: - -- `host` - the Speechmatics Voice Agent endpoint URL -- `profile` - one of `adaptive`, `agile`, `smart`, or `external` - -See [Voice Agent API documentation](https://docs.speechmatics.com/private/voice-agent-api#introduction) for details. - -### Soniox - -- [STT Models](https://soniox.com/docs/stt/models) - -### Verbio - -- [Supported Languages](https://www.verbio.com/supported-languages) - -### Gladia - -- [Supported Languages](https://docs.gladia.io/chapters/language/supported-languages) - -### Nuance - -- [ASR gRPC API](https://docs.mix.nuance.com/asr-grpc/v1/) (Nuance is now part of Microsoft; Azure Speech Service is the successor) diff --git a/docs/components/synthesizer.md b/docs/components/synthesizer.md deleted file mode 100644 index fc79587..0000000 --- a/docs/components/synthesizer.md +++ /dev/null @@ -1,27 +0,0 @@ -## Vendor documentation links - -Refer to vendor documentation for supported models, voices, and vendor-specific options. - -### Deepgram - -- [TTS Models](https://developers.deepgram.com/docs/tts-models) - -### Google - -- [Supported Voices and Languages](https://cloud.google.com/text-to-speech/docs/voices) - -### Microsoft Azure - -- [Language and Voice Support](https://learn.microsoft.com/en-us/azure/ai-services/speech-service/language-support?tabs=tts) - -### AWS Polly - -- [Available Voices](https://docs.aws.amazon.com/polly/latest/dg/voicelist.html) - -### ElevenLabs - -- [Models](https://elevenlabs.io/docs/overview/models) - -### Cartesia - -- [TTS Models](https://docs.cartesia.ai/build-with-cartesia/tts-models) diff --git a/docs/guides/session-commands.md b/docs/guides/session-commands.md deleted file mode 100644 index f11d88d..0000000 --- a/docs/guides/session-commands.md +++ /dev/null @@ -1,417 +0,0 @@ -# Session Commands - -Session commands are async operations you can perform at any time during an active WebSocket call. They are not verbs — they don't go in the verb array and don't execute sequentially. Instead, they're SDK method calls that send commands over the WebSocket immediately. - -## TTS Token Streaming - -TTS token streaming lets your app pipe text to jambonz incrementally — as tokens arrive from an LLM — rather than waiting for the full response. jambonz buffers the text, breaks it into natural chunks (sentence boundaries), and streams each chunk to the TTS engine. The caller hears the first sentence while the LLM is still generating the rest. - -**This is different from `autoStreamTts`**. `autoStreamTts` is a jambonz-internal optimization: when a `say` verb has its complete text, jambonz streams the *audio* playback as TTS chunks arrive rather than waiting for full synthesis. Token streaming is app-level: your app sends *text* tokens incrementally via `sendTtsTokens()` while the LLM is still generating. - -### Setup - -Enable TTS streaming via the `config` verb before sending tokens: - -```typescript -session - .config({ - ttsStream: { enable: true }, - synthesizer: { vendor: 'elevenlabs', voice: 'EXAVITQu4vr4xnSDxMaL' }, // ElevenLabs requires voice ID, not name - }) - .say({ text: 'Hi there, how can I help you?' }) - .send(); -``` - -The `ttsStream.enable: true` setting opens a persistent connection to the TTS engine. You can optionally specify a different synthesizer in `ttsStream` to use a different vendor/voice for streaming than the session default. - -### Methods - -```typescript -// Send text tokens as they arrive from the LLM -await session.sendTtsTokens(tokenText); - -// Signal end of the current response — flushes any buffered text -session.flushTtsTokens(); - -// Discard all buffered tokens (e.g. on user interruption) -session.clearTtsTokens(); - -// Check if jambonz has signalled backpressure -if (session.isTtsPaused) { /* wait before sending more */ } -``` - -`sendTtsTokens()` returns a Promise that resolves when jambonz acknowledges receipt. If the buffer is full, jambonz returns a `full` status and the SDK automatically pauses until a `tts:stream_resumed` event arrives. - -### Events - -```typescript -session.on('tts:stream_open', () => { /* vendor connection established */ }); -session.on('tts:stream_paused', () => { /* backpressure: stop sending tokens */ }); -session.on('tts:stream_resumed', () => { /* backpressure released: resume sending */ }); -session.on('tts:stream_closed', () => { /* TTS stream ended */ }); -session.on('tts:user_interrupt', () => { /* user barged in — stop LLM, clear tokens */ }); -``` - -### Tracking What Was Actually Spoken (`trackTtsPlayout`) - -When `trackTtsPlayout: true` is set in the `config` verb, jambonz uses word-level alignment data from the TTS engine to track exactly which words were played out to the caller. This requires a TTS vendor that supports alignment (currently ElevenLabs). - -When the caller interrupts mid-response, jambonz fires a `tts:streaming-event` with: -```json -{ "event_type": "tts_spoken", "text": "only the words actually heard", "bargein": true } -``` - -On normal completion (no interruption): -```json -{ "event_type": "tts_spoken", "text": "the full response text", "bargein": false } -``` - -This is critical for maintaining accurate conversation history with the LLM — record only what the caller actually heard, not the full generated response that may have been cut short. - -See the `callback:tts-streaming-event` schema for the full event payload. - -## Inject Commands - -Inject commands modify an active call without replacing the verb stack. They execute immediately alongside whatever verb is currently running. - -### Recording - -```typescript -// Start recording -session.injectRecord('startCallRecording', { siprecServerURL: 'sip:recorder@example.com' }); - -// Stop recording -session.injectRecord('stopCallRecording'); - -// Pause/resume -session.injectRecord('pauseCallRecording'); -session.injectRecord('resumeCallRecording'); -``` - -### Mute / Unmute - -```typescript -session.injectMute('mute'); -session.injectMute('unmute'); -``` - -### Whisper - -Inject a verb to play to one party (e.g. a supervisor message to the agent): - -```typescript -session.injectWhisper({ verb: 'say', text: 'You have 5 minutes remaining.' }); -``` - -### DTMF - -```typescript -session.injectDtmf('1'); -session.injectDtmf('1234#'); -``` - -### Audio Stream Control - -Pause or resume an active `listen`/`stream` verb: - -```typescript -session.injectListenStatus('pause'); -session.injectListenStatus('resume'); -``` - -### Tag (Metadata) - -Attach arbitrary metadata to the call: - -```typescript -session.injectTag({ supervisor: 'jane', priority: 'high' }); -``` - -### Redirect - -Transfer call control to a different webhook: - -```typescript -session.injectCommand('redirect', { call_hook: '/new-flow' }); -``` - -### Generic Command - -For any command not covered by a specific method: - -```typescript -session.injectCommand('commandName', { ...data }); -``` - -## Pipeline Update - -The `updatePipeline()` method sends mid-conversation updates to an active `pipeline` verb. Four operation types are supported: - -### Update Instructions - -Replace the LLM system prompt while the conversation is in progress: - -```typescript -session.updatePipeline({ - type: 'update_instructions', - instructions: 'You are now a billing support agent. Help the caller with invoice questions.', -}); -``` - -### Inject Context - -Append messages to the LLM conversation history (e.g. CRM data retrieved after the call started): - -```typescript -session.updatePipeline({ - type: 'inject_context', - messages: [ - { role: 'system', content: 'Customer account #12345: Gold tier, 3 open tickets.' }, - ], -}); -``` - -### Update Tools - -Replace the tool set available to the LLM: - -```typescript -session.updatePipeline({ - type: 'update_tools', - tools: [ - { - type: 'function', - function: { - name: 'transfer_call', - description: 'Transfer the caller to a specialist', - parameters: { type: 'object', properties: { department: { type: 'string' } } }, - }, - }, - ], -}); -``` - -### Generate Reply - -Prompt the LLM to generate a new response. If the pipeline is not idle, the request is queued and executes when the current turn completes. Use `interrupt: true` to cancel the current response and generate immediately. - -```typescript -// Simple prompt -session.updatePipeline({ - type: 'generate_reply', - user_input: 'The customer just entered their account number: 12345', -}); - -// With one-shot instructions -session.updatePipeline({ - type: 'generate_reply', - user_input: 'Customer is asking about refunds', - instructions: 'Be empathetic and offer a 20% discount before processing a refund.', -}); - -// Interrupt current response and generate a new one -session.updatePipeline({ - type: 'generate_reply', - user_input: 'Urgent: supervisor override', - interrupt: true, -}); -``` - -## LLM Tool Output - -When using the `pipeline` verb with a `toolHook`, tool call requests arrive as events. Return results with: - -```typescript -session.on('/tool-hook', (evt: Record) => { - const { tool_call_id, name, arguments: args } = evt; - - // Process the tool call... - const result = { temperature: 72, unit: 'F' }; - - // Return the result to the LLM - session.toolOutput(tool_call_id, result).reply(); -}); -``` - -The result is stringified and fed back to the LLM as the tool response. - -## Building a Cascaded Voice AI Agent - -The **pipeline** verb is the simplest way to build a voice AI agent — jambonz manages everything. But when you need full control over the LLM interaction (custom tool handling, conversation history management, multiple LLM providers, etc.), build a **cascaded agent**: your app handles STT transcripts and LLM calls directly, piping responses back via TTS token streaming. - -### Architecture - -``` -config (ttsStream + bargeIn) → say (greeting) - ↓ -bargeIn fires '/speech-detected' with transcript - ↓ -App calls LLM with streaming → tokens arrive - ↓ -sendTtsTokens() pipes each token to jambonz → TTS plays audio - ↓ -flushTtsTokens() when LLM finishes → caller hears full response - ↓ -User speaks again → bargeIn fires → repeat -``` - -The key mechanism is the `bargeIn` actionHook on the `config` verb. When enabled with `sticky: true`, it persists across all verbs. Whenever the caller speaks, the `/speech-detected` hook fires with the speech transcript — even while TTS is playing (which triggers an interruption). Your app then calls the LLM and streams the response back. - -### When to Use Cascaded vs Pipeline - -| | Pipeline verb | Cascaded agent | -|---|---|---| -| **STT/LLM/TTS** | jambonz orchestrates all three | App owns the LLM; jambonz handles STT and TTS | -| **Turn detection** | Built-in (Krisp or STT-native) | App manages via bargeIn actionHook | -| **Tool calls** | Via toolHook | App handles directly in LLM loop | -| **Conversation history** | jambonz manages internally | App manages — full control | -| **Complexity** | Low — one verb | Higher — app manages LLM streaming and history | -| **Use when** | Standard voice AI agent | Custom LLM logic, multiple providers, precise history control | - -### Example (TypeScript) - -```typescript -import Anthropic from '@anthropic-ai/sdk'; -import http from 'http'; -import { createEndpoint } from '@jambonz/sdk/websocket'; - -const server = http.createServer(); -const makeService = createEndpoint({ server, port: 3000 }); -const svc = makeService({ path: '/' }); - -svc.on('session:new', (session) => { - const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY }); - const messages: Array<{ role: 'user' | 'assistant'; content: string }> = []; - let assistantResponse = ''; - let userInterrupt = false; - - session - .on('/speech-detected', async (evt: Record) => { - const { speech } = evt; - session.reply(); // Acknowledge immediately - - if (speech?.is_final) { - const { transcript } = speech.alternatives[0]; - messages.push({ role: 'user', content: transcript }); - userInterrupt = false; - - const stream = await client.messages.create({ - model: 'claude-sonnet-4-20250514', - max_tokens: 1024, - system: 'You are a helpful voice assistant. Keep answers concise.', - messages, - stream: true, - }); - - for await (const event of stream) { - if (userInterrupt) { - messages.push({ role: 'assistant', content: `${assistantResponse}...` }); - assistantResponse = ''; - break; - } - if ((event as any).delta?.text) { - const tokens = (event as any).delta.text; - assistantResponse += tokens; - session.sendTtsTokens(tokens).catch(console.error); - } else if (event.type === 'message_stop') { - session.flushTtsTokens(); - messages.push({ role: 'assistant', content: assistantResponse }); - assistantResponse = ''; - } - } - } - }) - .on('tts:user_interrupt', () => { - userInterrupt = true; - }); - - session - .config({ - ttsStream: { enable: true }, - bargeIn: { - enable: true, - sticky: true, - minBargeinWordCount: 1, - actionHook: '/speech-detected', - input: ['speech'], - }, - }) - .say({ text: 'Hi there, how can I help you today?' }) - .send(); -}); -``` - -### Example (JavaScript) - -```javascript -const Anthropic = require('@anthropic-ai/sdk'); -const http = require('node:http'); -const { createEndpoint } = require('@jambonz/sdk/websocket'); - -const server = http.createServer(); -const makeService = createEndpoint({ server, port: 3000 }); -const svc = makeService({ path: '/' }); - -svc.on('session:new', (session) => { - const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY }); - const messages = []; - let assistantResponse = ''; - let userInterrupt = false; - - session - .on('/speech-detected', async (evt) => { - const { speech } = evt; - session.reply(); - - if (speech?.is_final) { - const { transcript } = speech.alternatives[0]; - messages.push({ role: 'user', content: transcript }); - userInterrupt = false; - - const stream = await client.messages.create({ - model: 'claude-sonnet-4-20250514', - max_tokens: 1024, - system: 'You are a helpful voice assistant. Keep answers concise.', - messages, - stream: true, - }); - - for await (const event of stream) { - if (userInterrupt) { - messages.push({ role: 'assistant', content: `${assistantResponse}...` }); - assistantResponse = ''; - break; - } - if (event.delta?.text) { - const tokens = event.delta.text; - assistantResponse += tokens; - session.sendTtsTokens(tokens).catch(console.error); - } else if (event.type === 'message_stop') { - session.flushTtsTokens(); - messages.push({ role: 'assistant', content: assistantResponse }); - assistantResponse = ''; - } - } - } - }) - .on('tts:user_interrupt', () => { - userInterrupt = true; - }); - - session - .config({ - ttsStream: { enable: true }, - bargeIn: { - enable: true, - sticky: true, - minBargeinWordCount: 1, - actionHook: '/speech-detected', - input: ['speech'], - }, - }) - .say({ text: 'Hi there, how can I help you today?' }) - .send(); -}); -``` - -See the `examples/llm-streaming/` directory for the complete working example. diff --git a/docs/verbs/conference.md b/docs/verbs/conference.md deleted file mode 100644 index fd027d3..0000000 --- a/docs/verbs/conference.md +++ /dev/null @@ -1,51 +0,0 @@ -## Conference auto-destroy behavior - -A conference is created when the first participant with `startConferenceOnEnter: true` joins. It is destroyed when the last participant leaves — you do not need to explicitly clean it up. - -If you want a specific participant (e.g. a moderator) to end the conference for everyone when they leave, set `endConferenceOnExit: true` on that participant only. - -## PIN-based conferences - -A common pattern is to collect a PIN via `gather` and use it as the conference name. This lets multiple independent conferences share one application: - -```typescript -session.conference({ - name: `pin-${digits}`, - beep: true, - startConferenceOnEnter: true, - actionHook: '/conference-done', -}); -``` - -## Waiting room (hold music) - -If `startConferenceOnEnter` is `false` for a participant, they wait silently until someone with `startConferenceOnEnter: true` joins. Use `waitHook` to play hold music while they wait: - -```typescript -session.conference({ - name: 'team-call', - startConferenceOnEnter: false, - waitHook: '/hold-music', -}); -``` - -The `waitHook` handler should return `say` or `play` verbs. jambonz will loop them until the conference starts. - -## statusHook events - -Subscribe to events via `statusEvents` and receive them at `statusHook`. Available events: `join`, `leave`, `start-talking`, `stop-talking`. - -The payload includes `event`, `conferenceSid` (the conference name), and `members` (current participant count). Your handler must reply — in WebSocket mode, call `session.reply()` even if you have no verbs to send. - -## actionHook fires on exit - -The `actionHook` fires when this participant leaves the conference (either by hanging up or being removed). Return verbs to continue the call, or `hangup` to end it: - -```typescript -session.on('/conference-done', () => { - session - .say({ text: 'You have left the conference. Goodbye.' }) - .hangup() - .reply(); -}); -``` diff --git a/docs/verbs/deepgram_s2s.md b/docs/verbs/deepgram_s2s.md deleted file mode 100644 index 6785f2e..0000000 --- a/docs/verbs/deepgram_s2s.md +++ /dev/null @@ -1,108 +0,0 @@ -## Deepgram Voice Agent configuration - -See [Deepgram Voice Agent Settings documentation](https://developers.deepgram.com/docs/voice-agent-settings) for the full configuration reference. - -The Deepgram Voice Agent API does **not** have its own LLM — it delegates to an external LLM provider (OpenAI, Anthropic, etc.) via a "think" provider. The `model` property on the verb is **not used**. Instead, all configuration goes inside `llmOptions.Settings`. - -### Required structure - -The `llmOptions` must contain a `Settings` object with this structure: - -```json -{ - "verb": "deepgram_s2s", - "auth": { "apiKey": "your-deepgram-api-key" }, - "llmOptions": { - "Settings": { - "agent": { - "think": { - "provider": { - "type": "open_ai", - "model": "gpt-4o" - }, - "prompt": "You are a helpful customer service agent." - }, - "speak": { - "provider": { - "type": "deepgram", - "model": "aura-2-thalia-en" - } - } - } - } - }, - "actionHook": "/agent-complete" -} -``` - -### Key differences from other s2s verbs - -- **No top-level `model`** — the LLM model is inside `Settings.agent.think.provider.model` -- **No `messages` array** — the system prompt goes in `Settings.agent.think.prompt` -- **Think provider `type`** — use `"open_ai"` (with underscore), `"anthropic"`, `"groq"`, etc. -- **Speak provider** — controls the TTS voice. Use `"deepgram"` type with an Aura model name like `"aura-2-thalia-en"` -- **Do NOT confuse Deepgram TTS voice names (e.g. `aura-asteria-en`) with LLM model names** — they are completely different - -### Common think provider types - -| type | Example models | -|------|---------------| -| `open_ai` | `gpt-4o`, `gpt-4o-mini` | -| `anthropic` | `claude-sonnet-4-20250514` | -| `groq` | `llama-3.3-70b-versatile` | - -### SDK example - -```typescript -session - .deepgram_s2s({ - auth: { apiKey: deepgramApiKey }, - llmOptions: { - Settings: { - agent: { - think: { - provider: { type: 'open_ai', model: 'gpt-4o' }, - prompt: 'You are a helpful assistant.', - }, - speak: { - provider: { type: 'deepgram', model: 'aura-2-thalia-en' }, - }, - }, - }, - }, - actionHook: '/agent-complete', - }) - .send(); -``` - -### Tool/function support - -Deepgram Voice Agent supports function calling. Define functions in `Settings.agent.think.functions`: - -```json -{ - "Settings": { - "agent": { - "think": { - "provider": { "type": "open_ai", "model": "gpt-4o" }, - "prompt": "You help users check order status.", - "functions": [ - { - "name": "check_order", - "description": "Look up an order by ID", - "parameters": { - "type": "object", - "properties": { - "order_id": { "type": "string" } - }, - "required": ["order_id"] - } - } - ] - } - } - } -} -``` - -Function call results are returned via the `toolHook` webhook or WebSocket `llm:tool-call` event. diff --git a/docs/verbs/dial.md b/docs/verbs/dial.md deleted file mode 100644 index 2136bdf..0000000 --- a/docs/verbs/dial.md +++ /dev/null @@ -1,8 +0,0 @@ -## Generating ringback tones with tone_stream - -The `dialMusic` property is an optional property that can be used to generate audio towards the A party while we are outdialing the B party and get a 180 Ringing from B. In that case, we may want to play ringback tone or a message to the A party until we gert an answer or a 183 with early media. - -Besides an http(s) URL, the value can also be a FreeSWITCH `tone_stream://` URIs in addition to audio file URLs. Use the `L=` parameter to repeat the tone pattern (`L=-1` is not supported; use a finite count like `L=20`): - -- **US ringback**: `tone_stream://L=20;%(2000,4000,440,480)` -- **UK ringback**: `tone_stream://L=20;%(400,200,400,450);%(400,2000,400,450)` diff --git a/docs/verbs/listen.md b/docs/verbs/listen.md deleted file mode 100644 index c03eb99..0000000 --- a/docs/verbs/listen.md +++ /dev/null @@ -1,71 +0,0 @@ -## Bidirectional audio modes - -The listen verb supports two bidirectional audio modes, controlled by the `bidirectionalAudio` property: - -**Non-streaming** (default) — send complete audio clips as base64 via `playAudio()`: -```typescript -session.listen({ - url: '/audio', - actionHook: '/listen-done', - // bidirectionalAudio not needed — non-streaming is the default -}); -``` -Use `stream.playAudio(base64, { audioContentType: 'raw', sampleRate: 8000 })` to play audio back. Up to 10 clips can be queued. Each clip triggers a `playDone` event when finished. - -**Streaming** — send raw L16 PCM binary frames via `sendAudio()`: -```typescript -session.listen({ - url: '/audio', - actionHook: '/listen-done', - bidirectionalAudio: { - enabled: true, - streaming: true, - sampleRate: 8000, - }, -}); -``` -Use `stream.sendAudio(pcmBuffer)` to stream audio continuously. This is required for real-time audio processing (e.g. AI voice agents, echo, audio manipulation). - -## Marks (synchronization markers) - -Marks let you track when streamed audio has been played out to the caller. They work **only in streaming mode** — you must set `bidirectionalAudio: { enabled: true, streaming: true }`. - -The pattern: stream audio via `sendAudio()`, then call `sendMark(name)`. When the audio preceding the mark finishes playing, jambonz sends back a mark event with `event: 'playout'`. - -```typescript -stream.sendAudio(pcmChunk1); -stream.sendMark('after-chunk-1'); // fires when pcmChunk1 finishes playing - -stream.on('mark', (evt) => { - // evt.name = 'after-chunk-1' - // evt.event = 'playout' or 'cleared' -}); -``` - -Use `stream.clearMarks()` to cancel all pending marks — they fire with `event: 'cleared'` instead of `'playout'`. - -**Common mistake**: marks silently fail without `bidirectionalAudio.streaming: true`. Without it there is no playout buffer, so marks are accepted but never fire. - -## Relative URLs - -The `url` property accepts relative paths. jambonz connects the audio WebSocket back to the same server: - -```typescript -session.listen({ url: '/audio', actionHook: '/listen-done' }); -``` - -This avoids hardcoding hostnames. Use `makeService.audio({ path: '/audio' })` to register the audio handler on the same endpoint. - -## Path separation - -The control WebSocket and audio WebSocket must use **different paths**. If both are registered on the same path (e.g. `/`), audio routes take priority and steal control connections. - -```typescript -// Correct — separate paths -const svc = makeService({ path: '/' }); -const audioSvc = makeService.audio({ path: '/audio' }); - -// Wrong — same path causes conflicts -const svc = makeService({ path: '/' }); -const audioSvc = makeService.audio({ path: '/' }); // steals control connections -``` diff --git a/docs/verbs/pipeline.md b/docs/verbs/pipeline.md deleted file mode 100644 index e035aab..0000000 --- a/docs/verbs/pipeline.md +++ /dev/null @@ -1,475 +0,0 @@ -## Overview - -The pipeline verb orchestrates a complete voice AI agent by wiring together three separate components — STT, LLM, and TTS — with integrated turn detection. Unlike the s2s verbs (where a single vendor handles everything), pipeline lets you mix and match: e.g. Deepgram for STT, Anthropic for the LLM, and Cartesia for TTS. - -Pipeline manages the full conversational turn cycle: -1. User speaks → STT produces a transcript -2. Turn detection decides the user is done speaking -3. Transcript is sent to the LLM -4. LLM response tokens stream to TTS -5. TTS audio plays back to the caller -6. If the user barges in, TTS stops and a new turn begins - -## Turn detection - -The `turnDetection` property controls how the pipeline decides the user has finished speaking. - -**`"stt"` (default)** — Uses the STT vendor's native end-of-utterance signal. For most vendors this is silence-based. Some vendors have smarter built-in turn detection: -- **deepgramflux** — Acoustic + semantic turn detection (Deepgram's "Flux" model) -- **assemblyai** — Native turn-taking with `u3-rt-pro` model -- **speechmatics** — Built-in turn detection - -These vendors always use their native detection regardless of the `turnDetection` setting. - -**`"krisp"`** — Uses the Krisp acoustic end-of-turn model, which analyzes speech patterns rather than just silence. Good for natural conversation where users pause mid-thought. Can be tuned: - -```json -{ - "turnDetection": { - "mode": "krisp", - "threshold": 0.3 - } -} -``` - -Lower threshold = faster turn transitions (more aggressive). Default is 0.5. - -**IMPORTANT NOTE**: you must have a krisp API key in order to utilize this module on a self-hosted jambonz system. Please contact us at support@jambonz.org if you need more details. - -## Early generation (speculative preflight) - -Early generation speculatively sends the transcript to the LLM *before* end-of-turn is confirmed. If the transcript matches when the turn does end, buffered tokens are released immediately — shaving off the LLM prompt time. If the user keeps talking and the transcript changes, the speculative response is discarded. This is a latency optimization with no correctness downside. - -There are two ways early generation is triggered: - -- **Krisp turn detection** — Set `earlyGeneration: true` to opt in. Krisp emits an early signal that triggers the speculative LLM prompt before final end-of-turn confirmation. -- **Deepgram Flux** — Early generation happens automatically. Flux emits a native `EagerEndOfTurn` event that triggers preflight regardless of the `earlyGeneration` setting. - -For other STT vendors with native turn-taking (assemblyai, speechmatics), early generation is not available — they don't emit a preflight signal. - -## Noise isolation - -The `noiseIsolation` property enables server-side noise cancellation on the call audio. By default it filters the inbound (caller) audio, improving STT accuracy in noisy environments. It can also be configured to filter outbound audio via the `direction` option. Two vendors are available: - -- **`"krisp"`** — Krisp's proprietary noise cancellation. Requires a Krisp API key on self-hosted systems. -- **`"rnnoise"`** — Open-source RNNoise-based noise cancellation. No API key required. - -Shorthand (default settings): - -```json -{ - "noiseIsolation": "krisp" -} -``` - -Detailed configuration: - -```json -{ - "noiseIsolation": { - "mode": "krisp", - "level": 80, - "direction": "read" - } -} -``` - -- `mode` — Vendor: `"krisp"` or `"rnnoise"`. -- `level` — Suppression level 0–100. Higher values are more aggressive. Default: 100. -- `direction` — `"read"` filters caller audio (default), `"write"` filters outbound audio. -- `model` — Optional model name override. - -Noise isolation can also be enabled/disabled mid-call via the `config` verb, the REST LCC API, or a WebSocket inject command (`noiseIsolation:status`). - -## Barge-in - -By default, users can interrupt the assistant while it's speaking. The `bargeIn` object controls this: - -```json -{ - "bargeIn": { - "enable": true, - "minSpeechDuration": 0.5, - "sticky": false - } -} -``` - -- `minSpeechDuration` — Seconds of speech required to confirm an interruption. Prevents brief noises from cutting off the assistant. Default: 0.5. -- `sticky` — If true, once the user interrupts, the assistant does not resume speaking the interrupted response. - -## eventHook events - -The `eventHook` receives real-time events during the conversation. In WebSocket mode, listen for these with `session.on('/your-event-hook', handler)`. - -| Event type | Description | Key fields | -|---|---|---| -| `user_transcript` | User speech recognized | `transcript` | -| `agent_response` | Assistant reply text | `response` | -| `user_interruption` | User barged in | — | -| `turn_end` | End-of-turn summary | `transcript`, `response`, `interrupted`, `latency` | - -The `turn_end` event is the most useful for observability. It includes per-component latency metrics (STT, LLM, TTS) in milliseconds. See the `callback:pipeline-turn` schema for the full payload structure. - -## toolHook (function calling) - -When the LLM requests a tool/function call, the pipeline sends a request to the `toolHook` with: - -```json -{ - "tool_call_id": "call_abc123", - "name": "get_weather", - "arguments": { "city": "Portland" } -} -``` - -The `arguments` field is already parsed (an object, not a JSON string). - -**Webhook response**: Return the tool result in the HTTP response body as JSON. The result is stringified and fed back to the LLM. - -**WebSocket**: The tool call arrives as an event on the hook path. Respond by calling `session.toolOutput(tool_call_id, result).reply()`. - -## MCP servers (external tools) - -Instead of (or in addition to) defining tools inline via `llmOptions.tools` and handling them with `toolHook`, you can connect to external MCP servers. The pipeline connects to each server at startup via SSE transport, discovers available tools, and makes them available to the LLM alongside any inline tools. - -```json -{ - "verb": "pipeline", - "mcpServers": [ - { - "url": "https://livescoremcp.com/sse" - } - ], - "llm": { - "vendor": "openai", - "model": "gpt-4.1", - "llmOptions": { - "messages": [ - { "role": "system", "content": "You are a sports assistant. Use available tools to look up live scores and fixtures when asked." } - ] - } - }, - "stt": { "vendor": "deepgram", "language": "en-US" }, - "tts": { "vendor": "cartesia", "voice": "sonic-english" } -} -``` - -The [LiveScore MCP server](https://livescoremcp.com/) is a free, public MCP server that exposes tools for live football scores, fixtures, team stats, and player data. The pipeline discovers these tools automatically at startup — no need to define tool schemas in `llmOptions.tools`. A caller can simply ask "what football matches are on right now?" and the LLM will use the `get_live_scores` tool to fetch real-time data. - -If an MCP server requires authentication, pass credentials in the `auth` property: - -```json -{ - "mcpServers": [ - { - "url": "https://mcp.example.com/sse", - "auth": { - "apiKey": "your-api-key-here" - } - } - ] -} -``` - -**How tool dispatch works**: When the LLM requests a tool call, the pipeline checks MCP servers first. If the tool name matches one discovered from an MCP server, the call is dispatched there directly and the result is fed back to the LLM. If no MCP server provides the tool, it falls through to the `toolHook` webhook. You can use both MCP servers and `toolHook` together — MCP handles the tools it knows about, and `toolHook` handles the rest. - -**TypeScript example** — a pipeline agent with the LiveScore MCP server: - -```typescript -session - .pipeline({ - stt: { vendor: 'deepgram', language: 'en-US' }, - tts: { vendor: 'cartesia', voice: 'sonic-english' }, - llm: { - vendor: 'openai', - model: 'gpt-4.1', - llmOptions: { - messages: [ - { role: 'system', content: 'You are a sports assistant. Use available tools to answer questions about football scores, fixtures, and teams.' }, - ], - }, - }, - mcpServers: [ - { url: 'https://livescoremcp.com/sse' }, - // To use a server that requires auth: - // { url: 'https://mcp.example.com/sse', auth: { apiKey: 'your-key' } }, - ], - turnDetection: 'krisp', - actionHook: '/pipeline-complete', - }) - .send(); -``` - -## Mid-conversation updates - -The pipeline supports asynchronous updates while a conversation is in progress. These let you change the agent's behavior, inject new context, modify available tools, or trigger a new LLM response — without interrupting the current verb stack. - -Updates can be sent via: -- **WebSocket**: `session.updatePipeline(data)` (sends a `pipeline:update` command) -- **REST API**: `client.calls.updatePipeline(callSid, data)` (sends `pipeline_update` in the PUT body) - -### update_instructions - -Replace the LLM system prompt mid-conversation. Useful when the conversation transitions to a different topic or agent persona. - -```typescript -// WebSocket -session.updatePipeline({ - type: 'update_instructions', - instructions: 'You are now a billing support agent. Help the caller with invoice questions.', -}); - -// REST -await client.calls.updatePipeline(callSid, { - type: 'update_instructions', - instructions: 'You are now a billing support agent. Help the caller with invoice questions.', -}); -``` - -### inject_context - -Append messages to the LLM conversation history. Useful for injecting CRM data, call notes, or other context retrieved after the call started. - -```typescript -session.updatePipeline({ - type: 'inject_context', - messages: [ - { role: 'system', content: 'Customer account #12345: Gold tier, 3 open tickets.' }, - ], -}); -``` - -### update_tools - -Replace the tool set available to the LLM. The new tools take effect on the next LLM turn. - -```typescript -session.updatePipeline({ - type: 'update_tools', - tools: [ - { - type: 'function', - function: { - name: 'transfer_call', - description: 'Transfer the caller to a specialist', - parameters: { type: 'object', properties: { department: { type: 'string' } } }, - }, - }, - ], -}); -``` - -### generate_reply - -Prompt the LLM to generate a new response. If the pipeline is currently idle, the prompt executes immediately. If the pipeline is busy (e.g. the assistant is speaking), the request is queued and executes when the current turn completes. - -Use `interrupt: true` to cancel the current response and generate immediately — useful for supervisor overrides or urgent context changes. - -```typescript -// Simple prompt -session.updatePipeline({ - type: 'generate_reply', - user_input: 'The customer just entered their account number: 12345', -}); - -// With one-shot instructions -session.updatePipeline({ - type: 'generate_reply', - user_input: 'Customer is asking about refunds', - instructions: 'Be empathetic and offer a 20% discount before processing a refund.', -}); - -// Interrupt current response -session.updatePipeline({ - type: 'generate_reply', - user_input: 'Urgent: supervisor override', - interrupt: true, -}); -``` - -## LLM configuration - -The `llm` property is the only required field. It configures the text-to-text LLM: - -```json -{ - "llm": { - "vendor": "openai", - "model": "gpt-4.1", - "llmOptions": { - "messages": [ - { "role": "system", "content": "You are a helpful voice assistant." } - ], - "tools": [ - { - "type": "function", - "function": { - "name": "get_weather", - "description": "Get current weather for a city", - "parameters": { - "type": "object", - "properties": { - "city": { "type": "string" } - }, - "required": ["city"] - } - } - } - ] - } - } -} -``` - -For Anthropic models, use `"vendor": "anthropic"` and structure messages accordingly (Anthropic uses `"role": "user"` for the system-level instruction). - -## Greeting - -By default (`greeting: true`), the pipeline prompts the LLM to generate an initial greeting before the user speaks. Set `greeting: false` if you want the agent to wait silently for the user to speak first. - -## Complete example (TypeScript) - -A pipeline voice agent using Deepgram STT, OpenAI LLM, and Cartesia TTS with Krisp turn detection. Exposes multiple endpoints with different STT/TTS combinations: - -```typescript -import * as http from 'node:http'; -import { createEndpoint, Session } from '@jambonz/sdk/websocket'; - -const envVars = { - OPENAI_MODEL: { - type: 'string' as const, - description: 'OpenAI model to use', - default: 'gpt-4.1-mini', - }, - SYSTEM_PROMPT: { - type: 'string' as const, - description: 'System prompt for the voice agent', - uiHint: 'textarea' as const, - default: 'You are a helpful voice AI assistant. Your responses are concise and conversational.', - }, -}; - -function handleSession(session: Session) { - const model = session.data.env_vars?.OPENAI_MODEL || 'gpt-4.1-mini'; - const systemPrompt = session.data.env_vars?.SYSTEM_PROMPT || envVars.SYSTEM_PROMPT.default; - - session.on('/pipeline-event', (evt: Record) => { - if (evt.type === 'turn_end') { - const { transcript, response, interrupted, latency } = evt as Record; - console.log('turn_end', JSON.stringify({ transcript, response, interrupted, latency }, null, 2)); - } - }); - - session.on('/pipeline-complete', () => { - session.hangup().reply(); - }); - - session - .pipeline({ - stt: { - vendor: 'deepgram', - language: 'multi', - deepgramOptions: { model: 'nova-3-general' }, - }, - tts: { - vendor: 'cartesia', - voice: '9626c31c-bec5-4cca-baa8-f8ba9e84c8bc', - }, - llm: { - vendor: 'openai', - model, - llmOptions: { - messages: [{ role: 'system', content: systemPrompt }], - }, - }, - turnDetection: 'krisp', - earlyGeneration: true, - bargeIn: { enable: true }, - eventHook: '/pipeline-event', - actionHook: '/pipeline-complete', - }) - .send(); -} - -const port = parseInt(process.env.PORT || '3000', 10); -const server = http.createServer(); -const makeService = createEndpoint({ server, port, envVars }); - -const svc = makeService({ path: '/' }); -svc.on('session:new', (session) => handleSession(session)); -``` - -## Complete example (JavaScript) - -The same agent in plain JavaScript: - -```javascript -const http = require('node:http'); -const { createEndpoint } = require('@jambonz/sdk/websocket'); - -const envVars = { - OPENAI_MODEL: { - type: 'string', - description: 'OpenAI model to use', - default: 'gpt-4.1-mini', - }, - SYSTEM_PROMPT: { - type: 'string', - description: 'System prompt for the voice agent', - uiHint: 'textarea', - default: 'You are a helpful voice AI assistant. Your responses are concise and conversational.', - }, -}; - -function handleSession(session) { - const model = session.data.env_vars?.OPENAI_MODEL || 'gpt-4.1-mini'; - const systemPrompt = session.data.env_vars?.SYSTEM_PROMPT || envVars.SYSTEM_PROMPT.default; - - session.on('/pipeline-event', (evt) => { - if (evt.type === 'turn_end') { - const { transcript, response, interrupted, latency } = evt; - console.log('turn_end', JSON.stringify({ transcript, response, interrupted, latency }, null, 2)); - } - }); - - session.on('/pipeline-complete', () => { - session.hangup().reply(); - }); - - session - .pipeline({ - stt: { - vendor: 'deepgram', - language: 'multi', - deepgramOptions: { model: 'nova-3-general' }, - }, - tts: { - vendor: 'cartesia', - voice: '9626c31c-bec5-4cca-baa8-f8ba9e84c8bc', - }, - llm: { - vendor: 'openai', - model, - llmOptions: { - messages: [{ role: 'system', content: systemPrompt }], - }, - }, - turnDetection: 'krisp', - earlyGeneration: true, - bargeIn: { enable: true }, - eventHook: '/pipeline-event', - actionHook: '/pipeline-complete', - }) - .send(); -} - -const port = parseInt(process.env.PORT || '3000', 10); -const server = http.createServer(); -const makeService = createEndpoint({ server, port, envVars }); - -const svc = makeService({ path: '/' }); -svc.on('session:new', (session) => handleSession(session)); - -console.log(`jambonz voice agent listening on port ${port}`); -``` diff --git a/docs/verbs/stream.md b/docs/verbs/stream.md deleted file mode 100644 index 4264037..0000000 --- a/docs/verbs/stream.md +++ /dev/null @@ -1,5 +0,0 @@ -## stream is a synonym for listen - -The `stream` verb is functionally identical to `listen` — they share the same implementation, the same properties, and the same audio WebSocket protocol. Use whichever name reads better in your application. - -All tips for the `listen` verb apply equally to `stream`: bidirectional audio modes, marks, relative URLs, and path separation. See the listen verb usage guide for full details. diff --git a/examples/bedrock-pipeline.ts b/examples/bedrock-pipeline.ts new file mode 100644 index 0000000..f9272ed --- /dev/null +++ b/examples/bedrock-pipeline.ts @@ -0,0 +1,267 @@ +import * as http from 'node:http'; +import pino from 'pino'; +import { createEndpoint, Session } from '@jambonz/sdk/websocket'; + +const logger = pino({ level: process.env.LOG_LEVEL || 'info' }); + +const envVars = { + LLM_VENDOR: { + type: 'string' as const, + description: 'LLM vendor (openai, bedrock, anthropic, google)', + default: 'openai', + }, + LLM_MODEL: { + type: 'string' as const, + description: 'LLM model to use', + default: 'gpt-4.1-mini', + }, + CARTESIA_VOICE: { + type: 'string' as const, + description: 'Cartesia voice ID', + default: '9626c31c-bec5-4cca-baa8-f8ba9e84c8bc', + }, + ELEVENLABS_VOICE: { + type: 'string' as const, + description: 'ElevenLabs voice id', + default: 'hpp4J3VqNfWAUOO0d1Us', + }, + SYSTEM_PROMPT: { + type: 'string' as const, + description: 'System prompt for the voice agent', + uiHint: 'textarea' as const, + default: [ + 'You are a helpful voice AI assistant.', + 'The user is interacting with you via voice,', + 'even if you perceive the conversation as text.', + 'You eagerly assist users with their questions', + 'by providing information from your extensive knowledge.', + 'Your responses are concise, to the point,', + 'and use natural spoken English with proper punctuation.', + 'Never use markdown, bullet points, numbered lists,', + 'emojis, asterisks, or any special formatting.', + 'You are curious, friendly, and have a sense of humor.', + 'When the conversation begins,', + 'greet the user in a helpful and friendly manner.', + ].join(' '), + }, +}; + +interface SttConfig { + vendor: string; + language?: string; + deepgramOptions?: Record; + assemblyAiOptions?: Record; + speechmaticsOptions?: Record; +} + +interface TtsConfig { + vendor: string; + voiceEnvVar: string; + options?: Record; +} + +interface PipelineOptions { + stt: SttConfig; + tts: TtsConfig; + turnDetection: 'krisp' | 'stt'; + noiseIsolation?: 'krisp' | 'rnnoise'; +} + +function handleSession(session: Session, opts: PipelineOptions) { + const log = logger.child({ call_sid: session.callSid }); + const llmVendor = session.data.env_vars?.LLM_VENDOR || 'openai'; + const model = session.data.env_vars?.LLM_MODEL || 'gpt-4.1-mini'; + const voice = session.data.env_vars?.[opts.tts.voiceEnvVar] + || envVars[opts.tts.voiceEnvVar as keyof typeof envVars]?.default; + const systemPrompt = session.data.env_vars?.SYSTEM_PROMPT || envVars.SYSTEM_PROMPT.default; + + /* Demo: update_tools mid-conversation to add web search capability. + After the user's second question (turn_end #2), inject a web_search tool. + The agent starts without web search, so early questions get stale answers. + Once the tool is added, the agent can search the web via Tavily. */ + let turnCount = 0; + let toolsInjected = false; + + session.on('/pipeline-event', (evt: Record) => { + log.info({payload: evt}, `pipeline event: ${evt.type}`); + + if (evt.type === 'turn_end') { + turnCount++; + if (turnCount === 2 && !toolsInjected) { + toolsInjected = true; + log.info('injecting web_search tool'); + session.updatePipeline({ + type: 'update_tools', + tools: [ + { + type: 'function', + function: { + name: 'web_search', + description: 'Search the web for current information. Use this when the user asks about recent events, product releases, or anything that may be newer than your training data.', + parameters: { + type: 'object', + properties: { + query: { + type: 'string', + description: 'The search query', + }, + }, + required: ['query'], + }, + }, + }, + ], + }); + session.updatePipeline({ + type: 'inject_context', + messages: [ + { + role: 'system', + content: 'You now have access to a web_search tool. When the user asks about current products, recent releases, or anything that might be newer than your training data, use the web_search tool to get up-to-date information.', + }, + ], + }); + } + } + }); + + session.on('/tool-call', async (evt: Record) => { + log.info({payload: evt}, 'tool call received'); + if (evt.name === 'web_search') { + const args = evt.arguments as Record; + const query = args?.query || ''; + log.info({query}, 'searching Tavily'); + try { + const res = await fetch('https://api.tavily.com/search', { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({ + api_key: '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', + query, + max_results: 3, + search_depth: 'basic', + }), + }); + const data = await res.json() as {results?: Array<{title: string; content: string; url: string}>}; + const results = (data.results || []).map( + (r: {title: string; content: string; url: string}) => `${r.title}: ${r.content}` + ).join('\n\n'); + log.info({results}, 'Tavily results'); + session.sendToolOutput(evt.tool_call_id as string, results || 'No results found.'); + } catch (err) { + log.error({err}, 'Tavily search failed'); + session.sendToolOutput(evt.tool_call_id as string, 'Web search failed. Please try again.'); + } + } + }); + + session.on('/pipeline-complete', (evt: Record) => { + log.info({payload: evt}, 'pipeline completed'); + session.hangup().reply(); + }); + + session + .pipeline({ + stt: opts.stt, + tts: { + vendor: opts.tts.vendor, + voice, + ...opts.tts.options && { options: opts.tts.options }, + }, + llm: { + vendor: llmVendor, + model, + llmOptions: { + messages: [ + { role: 'system', content: systemPrompt }, + ], + }, + }, + turnDetection: opts.turnDetection, + ...opts.noiseIsolation && { noiseIsolation: opts.noiseIsolation }, + earlyGeneration: true, + bargeIn: { + enable: true, + }, + eventHook: '/pipeline-event', + toolHook: '/tool-call', + actionHook: '/pipeline-complete', + }) + .send(); +} + +const port = parseInt(process.env.PORT || '3000', 10); +const server = http.createServer(); +const makeService = createEndpoint({ server, port, envVars }); + +/* Deepgram nova-3 + Krisp turn detection */ +const svc = makeService({ path: '/' }); +svc.on('session:new', (session) => { + handleSession(session, { + stt: { + vendor: 'deepgram', + language: 'multi', + deepgramOptions: { model: 'nova-3-general' }, + }, + tts: { vendor: 'cartesia', voiceEnvVar: 'CARTESIA_VOICE' }, + turnDetection: 'krisp', + }); +}); + +/* Deepgram Flux + native turn detection */ +const fluxSvc = makeService({ path: '/flux' }); +fluxSvc.on('session:new', (session) => { + handleSession(session, { + stt: { vendor: 'deepgramflux' }, + tts: { vendor: 'cartesia', voiceEnvVar: 'CARTESIA_VOICE' }, + turnDetection: 'stt', + }); +}); + +/* AssemblyAI u3-rt-pro + native turn detection */ +const aaiSvc = makeService({ path: '/aai' }); +aaiSvc.on('session:new', (session) => { + handleSession(session, { + stt: { + vendor: 'assemblyai', + assemblyAiOptions: { + languageDetection: true, + }, + }, + tts: { vendor: 'cartesia', voiceEnvVar: 'CARTESIA_VOICE' }, + turnDetection: 'stt', + }); +}); + +/* Deepgram nova-3 + Krisp turn detection + ElevenLabs TTS */ +const elSvc = makeService({ path: '/elevenlabs' }); +elSvc.on('session:new', (session) => { + handleSession(session, { + stt: { + vendor: 'deepgram', + language: 'multi', + deepgramOptions: { model: 'nova-3-general' }, + }, + tts: { + vendor: 'elevenlabs', + voiceEnvVar: 'ELEVENLABS_VOICE', + options: { model_id: 'eleven_flash_v2_5' }, + }, + turnDetection: 'krisp', + }); +}); + +/* Speechmatics preview + native turn detection */ +const smSvc = makeService({ path: '/speechmatics' }); +smSvc.on('session:new', (session) => { + handleSession(session, { + stt: { + vendor: 'speechmaticspreview', + language: 'en', + }, + tts: { vendor: 'cartesia', voiceEnvVar: 'CARTESIA_VOICE' }, + turnDetection: 'stt', + }); +}); + +logger.info({ port }, 'jambonz voice agent listening'); diff --git a/mcp-server/package-lock.json b/mcp-server/package-lock.json deleted file mode 100644 index 867f4e3..0000000 --- a/mcp-server/package-lock.json +++ /dev/null @@ -1,2682 +0,0 @@ -{ - "name": "@jambonz/mcp-schema-server", - "version": "0.1.30", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@jambonz/mcp-schema-server", - "version": "0.1.30", - "license": "MIT", - "dependencies": { - "@modelcontextprotocol/sdk": "^1.12.0", - "express": "^5.2.1" - }, - "bin": { - "jambonz-mcp": "dist/index.js" - }, - "devDependencies": { - "@types/express": "^5.0.6", - "@types/node": "^22.0.0", - "tsup": "^8.3.0", - "typescript": "^5.6.0", - "zod": "^3.25.0" - }, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "zod": "^3.25.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", - "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", - "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", - "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", - "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", - "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", - "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", - "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", - "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", - "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", - "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", - "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", - "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", - "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", - "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", - "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", - "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", - "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", - "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", - "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", - "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", - "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", - "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", - "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", - "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", - "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", - "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@hono/node-server": { - "version": "1.19.11", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.11.tgz", - "integrity": "sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==", - "license": "MIT", - "engines": { - "node": ">=18.14.1" - }, - "peerDependencies": { - "hono": "^4" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@modelcontextprotocol/sdk": { - "version": "1.26.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.26.0.tgz", - "integrity": "sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==", - "license": "MIT", - "dependencies": { - "@hono/node-server": "^1.19.9", - "ajv": "^8.17.1", - "ajv-formats": "^3.0.1", - "content-type": "^1.0.5", - "cors": "^2.8.5", - "cross-spawn": "^7.0.5", - "eventsource": "^3.0.2", - "eventsource-parser": "^3.0.0", - "express": "^5.2.1", - "express-rate-limit": "^8.2.1", - "hono": "^4.11.4", - "jose": "^6.1.3", - "json-schema-typed": "^8.0.2", - "pkce-challenge": "^5.0.0", - "raw-body": "^3.0.0", - "zod": "^3.25 || ^4.0", - "zod-to-json-schema": "^3.25.1" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@cfworker/json-schema": "^4.1.1", - "zod": "^3.25 || ^4.0" - }, - "peerDependenciesMeta": { - "@cfworker/json-schema": { - "optional": true - }, - "zod": { - "optional": false - } - } - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", - "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", - "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", - "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", - "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", - "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", - "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", - "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", - "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", - "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", - "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", - "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", - "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", - "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", - "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", - "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", - "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", - "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", - "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", - "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", - "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", - "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", - "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", - "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", - "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", - "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@types/body-parser": { - "version": "1.19.6", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", - "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/express": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz", - "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^5.0.0", - "@types/serve-static": "^2" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.1.tgz", - "integrity": "sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "node_modules/@types/http-errors": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", - "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "22.19.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.11.tgz", - "integrity": "sha512-BH7YwL6rA93ReqeQS1c4bsPpcfOmJasG+Fkr6Y59q83f9M1WcBRHR2vM+P9eOisYRcN3ujQoiZY8uk5W+1WL8w==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@types/qs": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.0.tgz", - "integrity": "sha512-JawvT8iBVWpzTrz3EGw9BTQFg3BQNmwERdKE22vlTxawwtbyUSlMppvZYKLZzB5zgACXdXxbD3m1bXaMqP/9ow==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/send": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", - "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/http-errors": "*", - "@types/node": "*" - } - }, - "node_modules/accepts": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", - "license": "MIT", - "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true, - "license": "MIT" - }, - "node_modules/body-parser": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", - "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", - "license": "MIT", - "dependencies": { - "bytes": "^3.1.2", - "content-type": "^1.0.5", - "debug": "^4.4.3", - "http-errors": "^2.0.0", - "iconv-lite": "^0.7.0", - "on-finished": "^2.4.1", - "qs": "^6.14.1", - "raw-body": "^3.0.1", - "type-is": "^2.0.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/bundle-require": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-5.1.0.tgz", - "integrity": "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "load-tsconfig": "^0.2.3" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "peerDependencies": { - "esbuild": ">=0.18" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/confbox": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", - "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/consola": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", - "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.18.0 || >=16.10.0" - } - }, - "node_modules/content-disposition": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", - "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "license": "MIT", - "engines": { - "node": ">=6.6.0" - } - }, - "node_modules/cors": { - "version": "2.8.6", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", - "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", - "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/esbuild": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", - "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.3", - "@esbuild/android-arm": "0.27.3", - "@esbuild/android-arm64": "0.27.3", - "@esbuild/android-x64": "0.27.3", - "@esbuild/darwin-arm64": "0.27.3", - "@esbuild/darwin-x64": "0.27.3", - "@esbuild/freebsd-arm64": "0.27.3", - "@esbuild/freebsd-x64": "0.27.3", - "@esbuild/linux-arm": "0.27.3", - "@esbuild/linux-arm64": "0.27.3", - "@esbuild/linux-ia32": "0.27.3", - "@esbuild/linux-loong64": "0.27.3", - "@esbuild/linux-mips64el": "0.27.3", - "@esbuild/linux-ppc64": "0.27.3", - "@esbuild/linux-riscv64": "0.27.3", - "@esbuild/linux-s390x": "0.27.3", - "@esbuild/linux-x64": "0.27.3", - "@esbuild/netbsd-arm64": "0.27.3", - "@esbuild/netbsd-x64": "0.27.3", - "@esbuild/openbsd-arm64": "0.27.3", - "@esbuild/openbsd-x64": "0.27.3", - "@esbuild/openharmony-arm64": "0.27.3", - "@esbuild/sunos-x64": "0.27.3", - "@esbuild/win32-arm64": "0.27.3", - "@esbuild/win32-ia32": "0.27.3", - "@esbuild/win32-x64": "0.27.3" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventsource": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", - "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", - "license": "MIT", - "dependencies": { - "eventsource-parser": "^3.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/eventsource-parser": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", - "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/express": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", - "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", - "license": "MIT", - "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.2.1", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", - "cookie": "^0.7.1", - "cookie-signature": "^1.2.1", - "debug": "^4.4.0", - "depd": "^2.0.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "finalhandler": "^2.1.0", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "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.14.0", - "range-parser": "^1.2.1", - "router": "^2.2.0", - "send": "^1.1.0", - "serve-static": "^2.2.0", - "statuses": "^2.0.1", - "type-is": "^2.0.1", - "vary": "^1.1.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express-rate-limit": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.3.1.tgz", - "integrity": "sha512-D1dKN+cmyPWuvB+G2SREQDzPY1agpBIcTa9sJxOPMCNeH3gwzhqJRDWCXW3gg0y//+LQ/8j52JbMROWyrKdMdw==", - "license": "MIT", - "dependencies": { - "ip-address": "10.1.0" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/express-rate-limit" - }, - "peerDependencies": { - "express": ">= 4.11" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "license": "MIT" - }, - "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/finalhandler": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", - "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "on-finished": "^2.4.1", - "parseurl": "^1.3.3", - "statuses": "^2.0.1" - }, - "engines": { - "node": ">= 18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/fix-dts-default-cjs-exports": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fix-dts-default-cjs-exports/-/fix-dts-default-cjs-exports-1.0.1.tgz", - "integrity": "sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "magic-string": "^0.30.17", - "mlly": "^1.7.4", - "rollup": "^4.34.8" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hono": { - "version": "4.12.7", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.7.tgz", - "integrity": "sha512-jq9l1DM0zVIvsm3lv9Nw9nlJnMNPOcAtsbsgiUhWcFzPE99Gvo6yRTlszSLLYacMeQ6quHD6hMfId8crVHvexw==", - "license": "MIT", - "engines": { - "node": ">=16.9.0" - } - }, - "node_modules/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", - "license": "MIT", - "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/iconv-lite": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", - "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/ip-address": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", - "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/jose": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz", - "integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/joycon": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", - "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, - "node_modules/json-schema-typed": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", - "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", - "license": "BSD-2-Clause" - }, - "node_modules/lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, - "license": "MIT" - }, - "node_modules/load-tsconfig": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/load-tsconfig/-/load-tsconfig-0.2.5.tgz", - "integrity": "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/merge-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/mlly": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", - "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.15.0", - "pathe": "^2.0.3", - "pkg-types": "^1.3.1", - "ufo": "^1.6.1" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-to-regexp": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", - "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pirates": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", - "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkce-challenge": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", - "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", - "license": "MIT", - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/pkg-types": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", - "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "confbox": "^0.1.8", - "mlly": "^1.7.4", - "pathe": "^2.0.1" - } - }, - "node_modules/postcss-load-config": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", - "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "lilconfig": "^3.1.1" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "jiti": ">=1.21.0", - "postcss": ">=8.0.9", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - }, - "postcss": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/qs": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz", - "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", - "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.7.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/rollup": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", - "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.8" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.59.0", - "@rollup/rollup-android-arm64": "4.59.0", - "@rollup/rollup-darwin-arm64": "4.59.0", - "@rollup/rollup-darwin-x64": "4.59.0", - "@rollup/rollup-freebsd-arm64": "4.59.0", - "@rollup/rollup-freebsd-x64": "4.59.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", - "@rollup/rollup-linux-arm-musleabihf": "4.59.0", - "@rollup/rollup-linux-arm64-gnu": "4.59.0", - "@rollup/rollup-linux-arm64-musl": "4.59.0", - "@rollup/rollup-linux-loong64-gnu": "4.59.0", - "@rollup/rollup-linux-loong64-musl": "4.59.0", - "@rollup/rollup-linux-ppc64-gnu": "4.59.0", - "@rollup/rollup-linux-ppc64-musl": "4.59.0", - "@rollup/rollup-linux-riscv64-gnu": "4.59.0", - "@rollup/rollup-linux-riscv64-musl": "4.59.0", - "@rollup/rollup-linux-s390x-gnu": "4.59.0", - "@rollup/rollup-linux-x64-gnu": "4.59.0", - "@rollup/rollup-linux-x64-musl": "4.59.0", - "@rollup/rollup-openbsd-x64": "4.59.0", - "@rollup/rollup-openharmony-arm64": "4.59.0", - "@rollup/rollup-win32-arm64-msvc": "4.59.0", - "@rollup/rollup-win32-ia32-msvc": "4.59.0", - "@rollup/rollup-win32-x64-gnu": "4.59.0", - "@rollup/rollup-win32-x64-msvc": "4.59.0", - "fsevents": "~2.3.2" - } - }, - "node_modules/router": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "depd": "^2.0.0", - "is-promise": "^4.0.0", - "parseurl": "^1.3.3", - "path-to-regexp": "^8.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, - "node_modules/send": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", - "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.3", - "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" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/serve-static": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", - "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", - "license": "MIT", - "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.2.0" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/source-map": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", - "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">= 12" - } - }, - "node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/sucrase": { - "version": "3.35.1", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", - "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "tinyglobby": "^0.2.11", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/tinyexec": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", - "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true, - "license": "MIT", - "bin": { - "tree-kill": "cli.js" - } - }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/tsup": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.5.1.tgz", - "integrity": "sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==", - "dev": true, - "license": "MIT", - "dependencies": { - "bundle-require": "^5.1.0", - "cac": "^6.7.14", - "chokidar": "^4.0.3", - "consola": "^3.4.0", - "debug": "^4.4.0", - "esbuild": "^0.27.0", - "fix-dts-default-cjs-exports": "^1.0.0", - "joycon": "^3.1.1", - "picocolors": "^1.1.1", - "postcss-load-config": "^6.0.1", - "resolve-from": "^5.0.0", - "rollup": "^4.34.8", - "source-map": "^0.7.6", - "sucrase": "^3.35.0", - "tinyexec": "^0.3.2", - "tinyglobby": "^0.2.11", - "tree-kill": "^1.2.2" - }, - "bin": { - "tsup": "dist/cli-default.js", - "tsup-node": "dist/cli-node.js" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@microsoft/api-extractor": "^7.36.0", - "@swc/core": "^1", - "postcss": "^8.4.12", - "typescript": ">=4.5.0" - }, - "peerDependenciesMeta": { - "@microsoft/api-extractor": { - "optional": true - }, - "@swc/core": { - "optional": true - }, - "postcss": { - "optional": true - }, - "typescript": { - "optional": true - } - } - }, - "node_modules/type-is": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", - "license": "MIT", - "dependencies": { - "content-type": "^1.0.5", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/ufo": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", - "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, - "node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zod-to-json-schema": { - "version": "3.25.1", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", - "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", - "license": "ISC", - "peerDependencies": { - "zod": "^3.25 || ^4" - } - } - } -} diff --git a/mcp-server/package.json b/mcp-server/package.json deleted file mode 100644 index 8ee1540..0000000 --- a/mcp-server/package.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "name": "@jambonz/mcp-schema-server", - "version": "0.1.30", - "description": "MCP server that provides jambonz verb schemas and documentation as resources", - "author": "Dave Horton", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/jambonz/node-sdk.git", - "directory": "mcp-server" - }, - "homepage": "https://github.com/jambonz/node-sdk#readme", - "keywords": [ - "jambonz", - "mcp", - "model-context-protocol", - "schema", - "voip", - "ai-agent" - ], - "type": "module", - "bin": { - "jambonz-mcp": "./dist/index.js" - }, - "main": "./dist/index.js", - "types": "./dist/index.d.ts", - "files": [ - "dist", - "schema", - "docs", - "AGENTS.md" - ], - "scripts": { - "build": "tsup", - "dev": "tsup --watch", - "typecheck": "tsc --noEmit", - "prepack": "cp -r ../schema . && cp -r ../docs . && cp ../AGENTS.md .", - "prepublishOnly": "npm run build" - }, - "dependencies": { - "@modelcontextprotocol/sdk": "^1.12.0", - "express": "^5.2.1" - }, - "peerDependencies": { - "zod": "^3.25.0" - }, - "devDependencies": { - "@types/express": "^5.0.6", - "@types/node": "^22.0.0", - "tsup": "^8.3.0", - "typescript": "^5.6.0", - "zod": "^3.25.0" - }, - "engines": { - "node": ">=18.0.0" - } -} diff --git a/mcp-server/src/index.ts b/mcp-server/src/index.ts deleted file mode 100644 index fb40371..0000000 --- a/mcp-server/src/index.ts +++ /dev/null @@ -1,89 +0,0 @@ -/** - * jambonz MCP Schema Server - * - * Serves jambonz verb schemas and documentation as MCP resources. - * Designed for AI agents that build jambonz voice applications. - * - * Usage: - * npx @jambonz/mcp-schema-server # stdio (Claude Desktop, etc) - * npx @jambonz/mcp-schema-server --http # HTTP on port 3000 - * npx @jambonz/mcp-schema-server --http --port 8080 # HTTP on custom port - * PORT=8080 npx @jambonz/mcp-schema-server --http # port via env var - */ - -import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; -import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; -import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; -import express from 'express'; -import { registerResources } from './resources.js'; -import { registerTools } from './tools.js'; - -function createServer(): McpServer { - const server = new McpServer({ - name: 'jambonz-schema-server', - version: '0.1.0', - }); - registerResources(server); - registerTools(server); - return server; -} - -const args = process.argv.slice(2); -const httpMode = args.includes('--http'); -const portArgIdx = args.indexOf('--port'); -const port = portArgIdx !== -1 && args[portArgIdx + 1] - ? parseInt(args[portArgIdx + 1], 10) - : parseInt(process.env.PORT || '3000', 10); - -if (httpMode) { - const app = express(); - app.use(express.json()); - - app.post('/mcp', async (req, res) => { - const server = createServer(); - try { - const transport = new StreamableHTTPServerTransport({ - sessionIdGenerator: undefined, - }); - await server.connect(transport); - await transport.handleRequest(req, res, req.body); - res.on('close', () => { - transport.close(); - server.close(); - }); - } catch (error) { - console.error('Error handling MCP request:', error); - if (!res.headersSent) { - res.status(500).json({ - jsonrpc: '2.0', - error: { code: -32603, message: 'Internal server error' }, - id: null, - }); - } - } - }); - - app.get('/mcp', (_req, res) => { - res.status(405).json({ - jsonrpc: '2.0', - error: { code: -32000, message: 'Method not allowed.' }, - id: null, - }); - }); - - app.delete('/mcp', (_req, res) => { - res.status(405).json({ - jsonrpc: '2.0', - error: { code: -32000, message: 'Method not allowed.' }, - id: null, - }); - }); - - app.listen(port, () => { - console.log(`jambonz MCP schema server (HTTP) listening on port ${port}`); - }); -} else { - const server = createServer(); - const transport = new StdioServerTransport(); - await server.connect(transport); -} diff --git a/mcp-server/src/resources.ts b/mcp-server/src/resources.ts deleted file mode 100644 index 3278928..0000000 --- a/mcp-server/src/resources.ts +++ /dev/null @@ -1,142 +0,0 @@ -/** - * Registers jambonz schema files and documentation as MCP resources. - */ - -import { readFileSync, readdirSync } from 'fs'; -import { resolve, basename, dirname } from 'path'; -import { fileURLToPath } from 'url'; -import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; - -/** Locate the schema directory. Checks: - * 1. Bundled in npm package: mcp-server/schema/ (copied by prepack) - * 2. Development: sibling to mcp-server/ at node-sdk/schema/ - */ -function findSchemaDir(): string { - const __dirname = dirname(fileURLToPath(import.meta.url)); - const candidates = [ - resolve(__dirname, '../schema'), // npm: mcp-server/schema/ - resolve(__dirname, '../../schema'), // dev: from dist/ or src/ - resolve(__dirname, '../../../schema'), // dev: nested - ]; - for (const dir of candidates) { - try { - readdirSync(dir); - return dir; - } catch { - // continue - } - } - throw new Error('Could not locate schema directory'); -} - -/** Locate AGENTS.md. Checks: - * 1. Bundled in npm package: mcp-server/AGENTS.md (copied by prepack) - * 2. Development: sibling to mcp-server/ at node-sdk/AGENTS.md - */ -function findAgentsMd(): string { - const __dirname = dirname(fileURLToPath(import.meta.url)); - const candidates = [ - resolve(__dirname, '../AGENTS.md'), // npm: mcp-server/AGENTS.md - resolve(__dirname, '../../AGENTS.md'), // dev: from dist/ or src/ - resolve(__dirname, '../../../AGENTS.md'), // dev: nested - ]; - for (const path of candidates) { - try { - readFileSync(path, 'utf-8'); - return path; - } catch { - // continue - } - } - throw new Error('Could not locate AGENTS.md'); -} - -export function registerResources(server: McpServer): void { - const schemaDir = findSchemaDir(); - const agentsMdPath = findAgentsMd(); - - // 1. AGENTS.md — the main documentation resource - server.resource( - 'agents-guide', - 'jambonz://docs/agents-guide', - { - description: 'jambonz Agent Toolkit guide — explains the verb model, transport modes, core verbs, and common patterns', - mimeType: 'text/markdown', - }, - async (uri) => ({ - contents: [{ - uri: uri.href, - text: readFileSync(agentsMdPath, 'utf-8'), - mimeType: 'text/markdown', - }], - }), - ); - - // 2. Root application schema - const appSchemaPath = resolve(schemaDir, 'jambonz-app.schema.json'); - server.resource( - 'app-schema', - 'jambonz://schema/jambonz-app', - { - description: 'Root JSON Schema for a jambonz application — an array of verbs', - mimeType: 'application/schema+json', - }, - async (uri) => ({ - contents: [{ - uri: uri.href, - text: readFileSync(appSchemaPath, 'utf-8'), - mimeType: 'application/schema+json', - }], - }), - ); - - // 3. Verb schemas - const verbsDir = resolve(schemaDir, 'verbs'); - const verbFiles = readdirSync(verbsDir).filter((f) => f.endsWith('.schema.json')); - - for (const file of verbFiles) { - const verbName = basename(file, '.schema.json'); - const filePath = resolve(verbsDir, file); - - server.resource( - `verb-${verbName}`, - `jambonz://schema/verbs/${verbName}`, - { - description: `JSON Schema for the "${verbName}" verb`, - mimeType: 'application/schema+json', - }, - async (uri) => ({ - contents: [{ - uri: uri.href, - text: readFileSync(filePath, 'utf-8'), - mimeType: 'application/schema+json', - }], - }), - ); - } - - // 4. Component schemas - const componentsDir = resolve(schemaDir, 'components'); - const componentFiles = readdirSync(componentsDir).filter((f) => f.endsWith('.schema.json')); - - for (const file of componentFiles) { - const componentName = basename(file, '.schema.json'); - const filePath = resolve(componentsDir, file); - - server.resource( - `component-${componentName}`, - `jambonz://schema/components/${componentName}`, - { - description: `JSON Schema for the "${componentName}" component`, - mimeType: 'application/schema+json', - }, - async (uri) => ({ - contents: [{ - uri: uri.href, - text: readFileSync(filePath, 'utf-8'), - mimeType: 'application/schema+json', - }], - }), - ); - } -} diff --git a/mcp-server/src/tools.ts b/mcp-server/src/tools.ts deleted file mode 100644 index 051bba5..0000000 --- a/mcp-server/src/tools.ts +++ /dev/null @@ -1,198 +0,0 @@ -/** - * Registers MCP tools for jambonz schema and documentation access. - * - * Two tools: - * 1. jambonz_developer_toolkit — returns the full guide (AGENTS.md) plus - * a verb/component/callback/guide index. - * 2. get_jambonz_schema — returns the full JSON Schema for a single verb, - * component, or callback on demand. If a usage guide exists in docs/verbs/ - * it is appended automatically. Also supports guide: for fetching - * in-depth markdown guides from docs/guides/. - */ - -import { readFileSync, readdirSync, existsSync } from 'fs'; -import { resolve, basename, dirname } from 'path'; -import { fileURLToPath } from 'url'; -import { z } from 'zod'; -import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; - -/** Locate the schema directory. */ -function findSchemaDir(): string { - const __dirname = dirname(fileURLToPath(import.meta.url)); - const candidates = [ - resolve(__dirname, '../schema'), - resolve(__dirname, '../../schema'), - resolve(__dirname, '../../../schema'), - ]; - for (const dir of candidates) { - try { - readdirSync(dir); - return dir; - } catch { - // continue - } - } - throw new Error('Could not locate schema directory'); -} - -/** Locate AGENTS.md. */ -function findAgentsMd(): string { - const __dirname = dirname(fileURLToPath(import.meta.url)); - const candidates = [ - resolve(__dirname, '../AGENTS.md'), - resolve(__dirname, '../../AGENTS.md'), - resolve(__dirname, '../../../AGENTS.md'), - ]; - for (const path of candidates) { - try { - readFileSync(path, 'utf-8'); - return path; - } catch { - // continue - } - } - throw new Error('Could not locate AGENTS.md'); -} - -/** Locate the docs directory (optional — may not exist). */ -function findDocsDir(): string | null { - const __dirname = dirname(fileURLToPath(import.meta.url)); - const candidates = [ - resolve(__dirname, '../docs'), - resolve(__dirname, '../../docs'), - resolve(__dirname, '../../../docs'), - ]; - for (const dir of candidates) { - if (existsSync(dir)) return dir; - } - return null; -} - -/** List schema files in a directory, returning names without .schema.json suffix. */ -function listSchemas(dir: string, exclude: string[] = []): string[] { - if (!existsSync(dir)) return []; - return readdirSync(dir) - .filter((f) => f.endsWith('.schema.json')) - .map((f) => basename(f, '.schema.json')) - .filter((n) => !exclude.includes(n)); -} - -/** List markdown guides in a directory, returning names without .md suffix. */ -function listGuides(dir: string): string[] { - if (!existsSync(dir)) return []; - return readdirSync(dir) - .filter((f) => f.endsWith('.md')) - .map((f) => basename(f, '.md')); -} - -export function registerTools(server: McpServer): void { - const schemaDir = findSchemaDir(); - const agentsMdPath = findAgentsMd(); - const docsDir = findDocsDir(); - - const verbsDir = resolve(schemaDir, 'verbs'); - const componentsDir = resolve(schemaDir, 'components'); - const callbacksDir = resolve(schemaDir, 'callbacks'); - const guidesDir = docsDir ? resolve(docsDir, 'guides') : null; - - const verbNames = listSchemas(verbsDir); - const componentNames = listSchemas(componentsDir); - const callbackNames = listSchemas(callbacksDir, ['base']); - const guideNames = guidesDir ? listGuides(guidesDir) : []; - - // Build the index suffix (static — names don't change at runtime) - const indexParts = [ - '\n---\n', - '# Available JSON Schemas\n', - 'Use the get_jambonz_schema tool to fetch the full JSON Schema for any verb or component listed below.\n', - `\n## Verbs\n${verbNames.join(', ')}\n`, - `\n## Components\n${componentNames.join(', ')}\n`, - ]; - if (callbackNames.length > 0) { - indexParts.push( - `\n## Callbacks (actionHook payloads)\n${callbackNames.join(', ')}\n` - ); - } - if (guideNames.length > 0) { - indexParts.push( - `\n## Guides\nIn-depth documentation on specific topics. Fetch with \`guide:\`.\n${guideNames.join(', ')}\n` - ); - } - const indexSuffix = indexParts.join('\n'); - - // Tool 1: Guide + index (reads AGENTS.md fresh each call for development) - server.tool( - 'jambonz_developer_toolkit', - 'REQUIRED: You MUST call this tool before writing ANY jambonz code. Returns the complete jambonz developer guide covering: the @jambonz/sdk TypeScript SDK (WebhookResponse, WsSession, JambonzClient REST API, verb builder), verb model, webhook and WebSocket transports, actionHook payloads, mid-call control, recording, and working code examples. Also lists all available verb and component schemas.', - {}, - async () => ({ - content: [{ - type: 'text' as const, - text: readFileSync(agentsMdPath, 'utf-8') + indexSuffix, - }], - }), - ); - - // Tool 2: Individual schema lookup - const allNames = [ - ...verbNames.map((n) => `verb:${n}`), - ...componentNames.map((n) => `component:${n}`), - ...callbackNames.map((n) => `callback:${n}`), - ...guideNames.map((n) => `guide:${n}`), - ]; - server.tool( - 'get_jambonz_schema', - `Get the full JSON Schema for a jambonz verb or component. Available: ${allNames.join(', ')}`, - { name: z.string().describe('The verb or component name (e.g. "say", "gather", "dial", "recognizer", "synthesizer")') }, - async ({ name }) => { - // Strip optional prefix (e.g. "verb:say" -> "say", "component:recognizer" -> "recognizer") - const prefixMatch = name.match(/^(verb|component|callback|guide):(.*)/); - const bare = prefixMatch ? prefixMatch[2] : name; - - // Guide lookup — guides are markdown files, not JSON schemas - if (prefixMatch?.[1] === 'guide' && guidesDir) { - const guidePath = resolve(guidesDir, `${bare}.md`); - if (existsSync(guidePath)) { - return { content: [{ type: 'text' as const, text: readFileSync(guidePath, 'utf-8') }] }; - } - return { - content: [{ type: 'text' as const, text: `Unknown guide "${bare}". Available guides: ${guideNames.join(', ')}` }], - isError: true, - }; - } - - // All categories in search order - const allCategories = [ - { prefix: 'verb', dir: verbsDir, names: verbNames, docsSubdir: 'verbs' }, - { prefix: 'component', dir: componentsDir, names: componentNames, docsSubdir: 'components' }, - { prefix: 'callback', dir: callbacksDir, names: callbackNames, docsSubdir: 'callbacks' }, - ] as const; - - // If prefix was explicit, only search that category; otherwise search all - const categories = prefixMatch - ? allCategories.filter((c) => c.prefix === prefixMatch[1]) - : allCategories; - - for (const { dir, names, docsSubdir } of categories) { - if ((names as readonly string[]).includes(bare)) { - let text = readFileSync(resolve(dir, `${bare}.schema.json`), 'utf-8'); - - // Append usage docs if available (read fresh each call for easy editing) - if (docsDir) { - const docsPath = resolve(docsDir, docsSubdir, `${bare}.md`); - if (existsSync(docsPath)) { - const docs = readFileSync(docsPath, 'utf-8'); - text += `\n\n---\n# Usage Guide\n\n${docs}`; - } - } - - return { content: [{ type: 'text' as const, text }] }; - } - } - return { - content: [{ type: 'text' as const, text: `Unknown schema "${name}". Available: ${allNames.join(', ')}` }], - isError: true, - }; - }, - ); -} diff --git a/mcp-server/tsconfig.json b/mcp-server/tsconfig.json deleted file mode 100644 index 23f5478..0000000 --- a/mcp-server/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "ESNext", - "moduleResolution": "bundler", - "lib": ["ES2022"], - "outDir": "dist", - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true, - "isolatedModules": true - }, - "include": ["src"], - "exclude": ["node_modules", "dist"] -} diff --git a/mcp-server/tsup.config.ts b/mcp-server/tsup.config.ts deleted file mode 100644 index 367861a..0000000 --- a/mcp-server/tsup.config.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { defineConfig } from 'tsup'; - -export default defineConfig({ - entry: ['src/index.ts'], - format: ['esm'], - dts: true, - clean: true, - sourcemap: true, - banner: { - js: '#!/usr/bin/env node', - }, -}); diff --git a/schema/callbacks/amd.schema.json b/schema/callbacks/amd.schema.json deleted file mode 100644 index 0609548..0000000 --- a/schema/callbacks/amd.schema.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/amd", - "title": "AMD ActionHook Payload", - "description": "Payload sent to the AMD actionHook when an answering machine detection event occurs. Multiple events may fire during a single call (e.g. amd_machine_detected followed by amd_machine_stopped_speaking or amd_tone_detected).", - "allOf": [{ "$ref": "base" }], - "type": "object", - "properties": { - "type": { - "type": "string", - "description": "The AMD event type. IMPORTANT: This field is 'type', NOT 'amd_type'.", - "enum": [ - "amd_human_detected", - "amd_machine_detected", - "amd_no_speech_detected", - "amd_decision_timeout", - "amd_machine_stopped_speaking", - "amd_tone_detected", - "amd_tone_timeout", - "amd_error", - "amd_stopped" - ] - }, - "reason": { - "type": "string", - "description": "Reason for the detection result (e.g. 'short greeting', 'long greeting', 'hint', 'digit count'). Present on amd_human_detected and amd_machine_detected events." - }, - "greeting": { - "type": "string", - "description": "The transcribed greeting text. Present on amd_human_detected and amd_machine_detected events." - }, - "hint": { - "type": "string", - "description": "The voicemail hint that matched, if detection was triggered by hint matching." - }, - "language": { - "type": "string", - "description": "Language code from the transcription (e.g. 'en-US'). Present on amd_human_detected and amd_machine_detected events." - }, - "frequency": { - "type": "number", - "description": "Frequency of the detected beep in Hz. Present on amd_tone_detected events." - }, - "variance": { - "type": "number", - "description": "Frequency variance of the detected beep. Present on amd_tone_detected events." - } - }, - "required": ["type"] -} diff --git a/schema/callbacks/base.schema.json b/schema/callbacks/base.schema.json deleted file mode 100644 index 6457daa..0000000 --- a/schema/callbacks/base.schema.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/base", - "title": "ActionHook Base Payload", - "description": "Common fields present in every actionHook callback payload. All verb-specific callback schemas extend this base.", - "type": "object", - "properties": { - "call_sid": { "type": "string", "description": "Unique identifier for this call." }, - "account_sid": { "type": "string", "description": "Account identifier." }, - "application_sid": { "type": "string", "description": "Application identifier." }, - "direction": { "type": "string", "enum": ["inbound", "outbound"], "description": "Call direction." }, - "from": { "type": "string", "description": "Caller phone number or SIP URI." }, - "to": { "type": "string", "description": "Called phone number or SIP URI." }, - "call_id": { "type": "string", "description": "SIP Call-ID." }, - "sbc_callid": { "type": "string", "description": "SBC-level Call-ID." }, - "call_status": { - "type": "string", - "enum": ["trying", "ringing", "early-media", "in-progress", "completed", "failed", "busy", "no-answer", "queued"], - "description": "Current call state." - }, - "sip_status": { "type": "integer", "description": "SIP response code (e.g. 200, 486)." }, - "sip_reason": { "type": "string", "description": "SIP reason phrase (e.g. 'OK', 'Busy Here')." }, - "trace_id": { "type": "string", "description": "Distributed tracing identifier for correlating logs across jambonz components." }, - "originating_sip_ip": { "type": "string", "description": "IP address of the originating SIP trunk." }, - "originating_sip_trunk_name": { "type": "string", "description": "Name of the originating SIP trunk as configured in jambonz." }, - "api_base_url": { "type": "string", "description": "jambonz REST API base URL. Use this for mid-call control via the REST API." } - }, - "additionalProperties": true -} diff --git a/schema/callbacks/call-status.schema.json b/schema/callbacks/call-status.schema.json deleted file mode 100644 index 8f81897..0000000 --- a/schema/callbacks/call-status.schema.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/call-status", - "title": "Call Status Webhook Payload", - "description": "Payload sent to the call status webhook URL whenever the call state changes (e.g. trying, in-progress, completed). The status webhook is configured at the application level in jambonz. Multiple status events are sent over the life of a call. The final event (completed or failed) includes additional fields like duration and termination cause.", - "allOf": [ - { "$ref": "base" } - ], - "type": "object", - "properties": { - "call_termination_by": { - "type": "string", - "enum": ["caller", "jambonz"], - "description": "Who terminated the call. 'caller' if the remote party hung up, 'jambonz' if the call was ended by the application (e.g. hangup verb, REST API). Present only on the final status event (completed/failed)." - }, - "duration": { - "type": "integer", - "description": "Call duration in seconds. Present only on the final status event (completed/failed)." - } - }, - "additionalProperties": true -} diff --git a/schema/callbacks/conference-status.schema.json b/schema/callbacks/conference-status.schema.json deleted file mode 100644 index 3bded96..0000000 --- a/schema/callbacks/conference-status.schema.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/conference-status", - "title": "Conference StatusHook Payload", - "description": "Payload sent to the conference statusHook when a conference event occurs.", - "allOf": [ - { "$ref": "base" } - ], - "type": "object", - "properties": { - "event": { - "type": "string", - "enum": ["start", "end", "join", "leave", "start-talking", "stop-talking"], - "description": "The conference event that occurred." - }, - "conference_sid": { "type": "string", "description": "Conference identifier (format: conf::)." }, - "friendly_name": { "type": "string", "description": "The conference name as specified in the conference verb." }, - "duration": { "type": "number", "description": "Time in seconds since the conference started." }, - "members": { "type": "integer", "description": "Current number of participants in the conference." }, - "time": { "type": "string", "format": "date-time", "description": "ISO 8601 timestamp of when the event occurred." } - }, - "required": ["event", "conference_sid"], - "additionalProperties": true -} diff --git a/schema/callbacks/conference-wait.schema.json b/schema/callbacks/conference-wait.schema.json deleted file mode 100644 index 3a82a8a..0000000 --- a/schema/callbacks/conference-wait.schema.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/conference-wait", - "title": "Conference WaitHook Payload", - "description": "Payload sent to the conference waitHook while a participant is waiting for the conference to start. The response should contain an array of say, play, and/or pause verbs to play while waiting.", - "allOf": [ - { "$ref": "base" } - ], - "type": "object", - "additionalProperties": true -} diff --git a/schema/callbacks/conference.schema.json b/schema/callbacks/conference.schema.json deleted file mode 100644 index 8f2c0b8..0000000 --- a/schema/callbacks/conference.schema.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/conference", - "title": "Conference ActionHook Payload", - "description": "Payload sent to the conference verb's actionHook when the participant leaves or the conference ends. Contains only the base call info.", - "allOf": [ - { "$ref": "base" } - ], - "type": "object", - "additionalProperties": true -} diff --git a/schema/callbacks/dequeue.schema.json b/schema/callbacks/dequeue.schema.json deleted file mode 100644 index 66f2c46..0000000 --- a/schema/callbacks/dequeue.schema.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/dequeue", - "title": "Dequeue ActionHook Payload", - "description": "Payload sent to the dequeue verb's actionHook when the dequeue operation completes.", - "allOf": [ - { "$ref": "base" } - ], - "type": "object", - "properties": { - "dequeue_result": { - "type": "string", - "enum": ["complete", "timeout", "hangup"], - "description": "Outcome of the dequeue. 'complete' — successfully dequeued and bridged; 'timeout' — no queued caller found; 'hangup' — call hung up during bridge." - } - }, - "required": ["dequeue_result"], - "additionalProperties": true -} diff --git a/schema/callbacks/dial-dtmf.schema.json b/schema/callbacks/dial-dtmf.schema.json deleted file mode 100644 index 64160d7..0000000 --- a/schema/callbacks/dial-dtmf.schema.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/dial-dtmf", - "title": "Dial DtmfHook Payload", - "description": "Payload sent to the dial dtmfHook when DTMF digits matching the configured pattern are detected during a dial.", - "allOf": [ - { "$ref": "base" } - ], - "type": "object", - "properties": { - "dtmf": { - "type": "string", - "description": "The DTMF digit sequence that matched the configured dtmfCapture pattern." - } - }, - "required": ["dtmf"], - "additionalProperties": true -} diff --git a/schema/callbacks/dial-hold.schema.json b/schema/callbacks/dial-hold.schema.json deleted file mode 100644 index ba2589a..0000000 --- a/schema/callbacks/dial-hold.schema.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/dial-hold", - "title": "Dial OnHoldHook Payload", - "description": "Payload sent to the dial onHoldHook when the remote party places the call on hold. The response should contain say, play, and/or pause verbs to play as hold music. The hook is called repeatedly until the hold ends.", - "allOf": [ - { "$ref": "base" } - ], - "type": "object", - "properties": { - "hold_detail": { - "type": "object", - "description": "Details of the hold event.", - "properties": { - "from": { "type": "string", "description": "SIP From header value." }, - "to": { "type": "string", "description": "SIP To header value." } - } - } - }, - "required": ["hold_detail"], - "additionalProperties": true -} diff --git a/schema/callbacks/dial-refer.schema.json b/schema/callbacks/dial-refer.schema.json deleted file mode 100644 index 69c56fd..0000000 --- a/schema/callbacks/dial-refer.schema.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/dial-refer", - "title": "Dial ReferHook Payload", - "description": "Payload sent to the dial referHook when a SIP REFER is received during an active dial. The response can contain new verbs to execute.", - "allOf": [ - { "$ref": "base" } - ], - "type": "object", - "properties": { - "refer_details": { - "type": "object", - "description": "Details of the SIP REFER request. Any custom X-* headers on the REFER are also included as snake_cased properties (e.g. X-Override-Number becomes x_override_number).", - "properties": { - "sip_refer_to": { "type": "string", "description": "Full SIP Refer-To header value." }, - "refer_to_user": { "type": "string", "description": "User part of the Refer-To URI (phone number or SIP user)." }, - "sip_referred_by": { "type": "string", "description": "SIP Referred-By header value, if present." }, - "referred_by_user": { "type": "string", "description": "User part of the Referred-By URI, if present." }, - "sip_user_agent": { "type": "string", "description": "User-Agent header from the REFER request." }, - "referring_call_sid": { "type": "string", "description": "Call SID of the leg that sent the REFER." }, - "referred_call_sid": { "type": "string", "description": "Call SID of the leg being referred." } - }, - "additionalProperties": true - } - }, - "required": ["refer_details"], - "additionalProperties": true -} diff --git a/schema/callbacks/dial.schema.json b/schema/callbacks/dial.schema.json deleted file mode 100644 index 53a1236..0000000 --- a/schema/callbacks/dial.schema.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/dial", - "title": "Dial ActionHook Payload", - "description": "Payload sent to the actionHook when a dial verb completes, either because the dialed party hung up, the call was not answered, or an error occurred.", - "allOf": [ - { "$ref": "base" } - ], - "type": "object", - "properties": { - "dial_call_status": { - "type": "string", - "enum": ["completed", "failed", "busy", "no-answer", "trying", "ringing", "early-media", "in-progress"], - "description": "Final status of the outbound (dialed) call leg." - }, - "dial_sip_status": { - "type": "integer", - "description": "SIP response code from the dialed party (e.g. 200, 486, 487).", - "examples": [200, 486, 487] - }, - "dial_call_sid": { - "type": "string", - "description": "Call SID of the outbound (dialed) call leg." - }, - "dial_sbc_callid": { - "type": "string", - "description": "SBC-level Call-ID for the outbound (dialed) call leg." - } - }, - "additionalProperties": true -} diff --git a/schema/callbacks/enqueue-wait.schema.json b/schema/callbacks/enqueue-wait.schema.json deleted file mode 100644 index b9d46ec..0000000 --- a/schema/callbacks/enqueue-wait.schema.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/enqueue-wait", - "title": "Enqueue WaitHook Payload", - "description": "Payload sent to the enqueue waitHook while a caller is waiting in the queue. The response should contain an array of say, play, pause, and/or leave verbs. Note: this payload is sparse — it contains queue-specific fields plus call_sid and call_id, but NOT the full base payload fields.", - "type": "object", - "properties": { - "queue_sid": { "type": "string", "description": "Queue identifier in the format 'queue:{account_sid}:{queue_name}'." }, - "queue_time": { "type": "integer", "description": "Time in seconds the caller has been waiting in the queue." }, - "queue_size": { "type": "integer", "description": "Total number of callers currently in the queue." }, - "queue_position": { "type": "integer", "description": "Caller's current position in the queue (0-based)." }, - "call_sid": { "type": "string", "description": "Unique identifier for this call." }, - "call_id": { "type": "string", "description": "SIP Call-ID." } - }, - "required": ["queue_sid", "queue_time"], - "additionalProperties": true -} diff --git a/schema/callbacks/enqueue.schema.json b/schema/callbacks/enqueue.schema.json deleted file mode 100644 index 7356e69..0000000 --- a/schema/callbacks/enqueue.schema.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/enqueue", - "title": "Enqueue ActionHook Payload", - "description": "Payload sent to the enqueue actionHook when the enqueue verb completes — i.e. the call was bridged, abandoned, left the queue, or an error occurred.", - "allOf": [ - { "$ref": "base" } - ], - "type": "object", - "properties": { - "queue_sid": { - "type": "string", - "description": "Queue identifier in the format 'queue:{account_sid}:{queue_name}'." - }, - "queue_time": { - "type": "integer", - "description": "Time in seconds the caller spent waiting in the queue." - }, - "queue_result": { - "type": "string", - "enum": ["bridged", "hangup", "leave", "error"], - "description": "Outcome of the enqueue. 'bridged' — call was dequeued and connected; 'hangup' — caller hung up while waiting; 'leave' — caller executed a leave verb from the waitHook; 'error' — an error occurred during bridging." - } - }, - "required": ["queue_sid", "queue_time", "queue_result"], - "additionalProperties": true -} diff --git a/schema/callbacks/gather-partial.schema.json b/schema/callbacks/gather-partial.schema.json deleted file mode 100644 index b110537..0000000 --- a/schema/callbacks/gather-partial.schema.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/gather-partial", - "title": "Gather Partial Transcript Payload", - "description": "Payload sent to the partialResultHook during a gather verb with speech input. Delivers interim (partial) speech recognition results as they arrive, before the gather completes. This hook is informational — the response is ignored and does not replace the verb stack. Note: the base fields use slightly different names than the actionHook payload (e.g. local_sip_address instead of fs_sip_address).", - "type": "object", - "properties": { - "call_sid": { "type": "string", "description": "Unique identifier for this call." }, - "account_sid": { "type": "string", "description": "Account identifier." }, - "application_sid": { "type": "string", "description": "Application identifier." }, - "direction": { "type": "string", "enum": ["inbound", "outbound"], "description": "Call direction." }, - "from": { "type": "string", "description": "Caller phone number or SIP URI." }, - "to": { "type": "string", "description": "Called phone number or SIP URI." }, - "call_id": { "type": "string", "description": "SIP Call-ID." }, - "sbc_callid": { "type": "string", "description": "SBC-level Call-ID." }, - "call_status": { "type": "string", "description": "Current call state." }, - "sip_status": { "type": "integer", "description": "SIP response code." }, - "sip_reason": { "type": "string", "description": "SIP reason phrase." }, - "trace_id": { "type": "string", "description": "Distributed tracing identifier." }, - "b3": { "type": "string", "description": "B3 trace propagation header." }, - "caller_name": { "type": "string", "description": "Caller display name from SIP, if available." }, - "originating_sip_ip": { "type": "string", "description": "IP address of the originating SIP trunk." }, - "originating_sip_trunk_name": { "type": "string", "description": "Name of the originating SIP trunk." }, - "speech": { - "type": "object", - "description": "Interim speech recognition results.", - "properties": { - "language_code": { "type": "string", "description": "Language code used for recognition (e.g. 'en-US')." }, - "channel_tag": { "type": "integer", "description": "Audio channel number." }, - "is_final": { "type": "boolean", "description": "Always false for partial results." }, - "alternatives": { - "type": "array", - "items": { - "type": "object", - "properties": { - "transcript": { "type": "string", "description": "The partial transcript recognized so far." }, - "confidence": { "type": "number", "description": "Confidence score between 0 and 1." } - } - }, - "description": "Array of recognition alternatives, ordered by confidence." - }, - "vendor": { - "type": "object", - "description": "Vendor-specific STT data. Structure varies by provider.", - "properties": { - "name": { "type": "string", "description": "STT vendor name (e.g. 'deepgram', 'google', 'aws')." }, - "evt": { "type": "object", "description": "Raw vendor-specific event payload.", "additionalProperties": true } - } - } - } - } - }, - "additionalProperties": true -} diff --git a/schema/callbacks/gather.schema.json b/schema/callbacks/gather.schema.json deleted file mode 100644 index a3e151c..0000000 --- a/schema/callbacks/gather.schema.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/gather", - "title": "Gather ActionHook Payload", - "description": "Payload sent to the actionHook when a gather verb completes, either due to speech detected, DTMF detected, or timeout.", - "allOf": [ - { "$ref": "base" } - ], - "type": "object", - "properties": { - "reason": { - "type": "string", - "enum": ["speechDetected", "dtmfDetected", "timeout", "error", "stt-low-confidence"], - "description": "The reason the gather completed." - }, - "speech": { - "type": "object", - "description": "Speech recognition results, present when reason is speechDetected.", - "properties": { - "language_code": { "type": "string", "description": "Language code used for recognition (e.g. 'en-US')." }, - "channel_tag": { "type": "integer", "description": "Audio channel number." }, - "is_final": { "type": "boolean", "description": "Whether this is a final (not interim) recognition result." }, - "alternatives": { - "type": "array", - "items": { - "type": "object", - "properties": { - "transcript": { "type": "string", "description": "The recognized transcript." }, - "confidence": { "type": "number", "description": "Confidence score between 0 and 1." } - } - }, - "description": "Array of recognition alternatives, ordered by confidence." - }, - "vendor": { - "type": "object", - "description": "Vendor-specific STT data. Structure varies by provider.", - "properties": { - "name": { "type": "string", "description": "STT vendor name (e.g. 'deepgram', 'google', 'aws')." }, - "evt": { - "description": "Raw vendor-specific event payload. A single object for simple utterances, or an array of objects when jambonz assembles the final transcript from multiple STT segments. Contains provider-specific fields like word-level timestamps, model info, etc.", - "oneOf": [ - { "type": "object", "additionalProperties": true }, - { "type": "array", "items": { "type": "object", "additionalProperties": true } } - ] - } - } - } - } - }, - "digits": { - "type": "string", - "description": "DTMF digits collected, present when reason is dtmfDetected." - }, - "details": { - "type": "object", - "description": "Error information if reason is error." - } - }, - "additionalProperties": true -} diff --git a/schema/callbacks/listen.schema.json b/schema/callbacks/listen.schema.json deleted file mode 100644 index 847d25b..0000000 --- a/schema/callbacks/listen.schema.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/listen", - "title": "Listen ActionHook Payload", - "description": "Payload sent to the listen verb's actionHook when the listen verb completes.", - "allOf": [ - { "$ref": "base" } - ], - "type": "object", - "properties": { - "dial_call_duration": { - "type": "integer", - "description": "Duration of the listen session in seconds, present if recording was active." - }, - "digits": { - "type": "string", - "description": "DTMF digit that ended the listen, present if finishOnKey was configured and pressed." - } - }, - "additionalProperties": true -} diff --git a/schema/callbacks/llm.schema.json b/schema/callbacks/llm.schema.json deleted file mode 100644 index 67e73a5..0000000 --- a/schema/callbacks/llm.schema.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/llm", - "title": "LLM ActionHook Payload", - "description": "Payload sent to the llm verb's actionHook when the LLM session ends. Applies to all LLM providers (OpenAI, Google, ElevenLabs, Ultravox, and generic voice agents).", - "allOf": [ - { "$ref": "base" } - ], - "type": "object", - "properties": { - "completion_reason": { - "type": "string", - "enum": [ - "normal conversation end", - "connection failure", - "disconnect from remote end", - "server failure", - "server error", - "client error calling function", - "client error calling mcp function" - ], - "description": "Reason the LLM session ended." - }, - "error": { - "description": "Error details, present when completion_reason indicates a failure." - } - }, - "required": ["completion_reason"], - "additionalProperties": true -} diff --git a/schema/callbacks/message.schema.json b/schema/callbacks/message.schema.json deleted file mode 100644 index e94aa5f..0000000 --- a/schema/callbacks/message.schema.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/message", - "title": "Message ActionHook Payload", - "description": "Payload sent to the message verb's actionHook with the delivery status of an outbound SMS.", - "allOf": [ - { "$ref": "base" } - ], - "type": "object", - "properties": { - "message_sid": { - "type": "string", - "description": "Unique identifier for the message." - }, - "message_status": { - "type": "string", - "enum": ["success", "failure", "no carriers", "smpp configuration error", "system error"], - "description": "Delivery status of the message." - }, - "carrier": { - "type": "string", - "description": "Name of the carrier used to send the message. Present on success or carrier-level failure." - }, - "carrier_message_id": { - "type": "string", - "description": "Message ID returned by the carrier. Present on success or carrier-level failure." - }, - "message_failure_reason": { - "type": "string", - "description": "Reason for failure. Present when message_status is 'failure' or 'system error'." - } - }, - "required": ["message_sid", "message_status"], - "additionalProperties": true -} diff --git a/schema/callbacks/pipeline-turn.schema.json b/schema/callbacks/pipeline-turn.schema.json deleted file mode 100644 index 10829fe..0000000 --- a/schema/callbacks/pipeline-turn.schema.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/pipeline-turn", - "title": "Pipeline EventHook Events", - "description": "Events sent to the pipeline verb's eventHook during a conversation. These are sent as 'pipeline:event' messages over the WebSocket connection.", - "type": "object", - "oneOf": [ - { - "properties": { - "type": { - "const": "turn_end", - "description": "Sent at the end of each conversational turn." - }, - "transcript": { - "type": "string", - "description": "The user's final speech-to-text transcript for this turn." - }, - "response": { - "type": "string", - "description": "The assistant's text response for this turn. May be trimmed to what was actually spoken if the turn was interrupted and alignment tracking is enabled." - }, - "interrupted": { - "type": "boolean", - "description": "True if the user interrupted the assistant before it finished speaking.", - "default": false - }, - "latency": { - "type": "object", - "description": "Latency metrics for this turn, all in milliseconds. Fields are absent when not applicable.", - "properties": { - "transcriber_latency": { - "type": "integer", - "description": "STT processing latency: time from user stops talking until final transcript received, in milliseconds." - }, - "turn_detection_latency": { - "type": "integer", - "description": "Additional wait after final transcript for end-of-turn detection, in milliseconds. Absent when EOT fires before or with the transcript." - }, - "model_latency": { - "type": "integer", - "description": "LLM latency: time spent waiting for the first LLM token after the system is ready to prompt, in milliseconds. Absent on a preflight hit." - }, - "voice_latency": { - "type": "integer", - "description": "TTS engine latency: time from first text sent to the TTS engine until first audio received back, in milliseconds." - }, - "preflight": { - "type": "object", - "description": "Early generation (preflight) metrics. Only present when earlyGeneration is enabled.", - "properties": { - "result": { - "type": "string", - "enum": ["hit", "miss", "pending"], - "description": "Whether the speculative preflight transcript matched the final transcript ('hit'), did not match ('miss'), or was still in progress ('pending')." - }, - "tokens": { - "type": "integer", - "description": "Number of preflight tokens that were buffered. Only present on a 'hit'." - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - } - }, - "required": ["type", "transcript", "response", "interrupted", "latency"], - "additionalProperties": false - }, - { - "properties": { - "type": { - "const": "user_transcript", - "description": "Sent when the user's final transcript is available and the system is proceeding to prompt the LLM. This indicates the end of the user's speech input for the current turn." - }, - "transcript": { - "type": "string", - "description": "The user's final speech-to-text transcript." - } - }, - "required": ["type", "transcript"], - "additionalProperties": false - }, - { - "properties": { - "type": { - "const": "agent_response", - "description": "Sent when the LLM has finished generating its response for the current turn. Contains the complete response text." - }, - "response": { - "type": "string", - "description": "The assistant's complete text response." - } - }, - "required": ["type", "response"], - "additionalProperties": false - }, - { - "properties": { - "type": { - "const": "user_interruption", - "description": "Sent when the user barges in (interrupts) while the assistant is speaking. This event has no additional data." - } - }, - "required": ["type"], - "additionalProperties": false - } - ] -} diff --git a/schema/callbacks/play.schema.json b/schema/callbacks/play.schema.json deleted file mode 100644 index 30734d0..0000000 --- a/schema/callbacks/play.schema.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/play", - "title": "Play ActionHook Payload", - "description": "Payload sent to the play verb's actionHook when playback completes or fails.", - "allOf": [ - { "$ref": "base" } - ], - "type": "object", - "properties": { - "reason": { - "type": "string", - "enum": ["playCompleted", "playFailed"], - "description": "Outcome of playback. 'playCompleted' on success, 'playFailed' on file-not-found or other error." - }, - "playback_seconds": { - "type": "integer", - "description": "Total playback duration in seconds. Present when reason is 'playCompleted'." - }, - "playback_milliseconds": { - "type": "integer", - "description": "Total playback duration in milliseconds. Present when reason is 'playCompleted'." - }, - "playback_last_offset_pos": { - "type": "string", - "description": "Last offset position in the audio stream. Present when reason is 'playCompleted'." - }, - "status": { - "type": "string", - "enum": ["fail"], - "description": "Set to 'fail' when playback failed (e.g. file not found)." - } - }, - "required": ["reason"], - "additionalProperties": true -} diff --git a/schema/callbacks/session-new.schema.json b/schema/callbacks/session-new.schema.json deleted file mode 100644 index 514913f..0000000 --- a/schema/callbacks/session-new.schema.json +++ /dev/null @@ -1,143 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/session-new", - "title": "Session:new Payload", - "description": "Payload delivered when a new call arrives. For webhook apps this is the initial POST body; for WebSocket apps it is the `data` property of the first `session:new` message. In the @jambonz/sdk WebSocket transport, this data is available as `session.data`.", - "allOf": [ - { "$ref": "base" } - ], - "type": "object", - "properties": { - "caller_name": { - "type": "string", - "description": "Caller display name from the SIP From header." - }, - "caller_id": { - "type": "string", - "description": "Caller ID value (phone number or SIP user)." - }, - "service_provider_sid": { - "type": "string", - "description": "Service provider identifier, if applicable." - }, - "parent_call_sid": { - "type": "string", - "description": "Call SID of the parent call, present when this session was created via the REST API dial (adulting) or when an outbound call leg is promoted to its own session." - }, - "fs_sip_address": { - "type": "string", - "description": "Internal SIP address of the FreeSWITCH media server handling this call." - }, - "fs_public_ip": { - "type": "string", - "description": "Public IP address of the FreeSWITCH media server, if available." - }, - "sip": { - "type": "object", - "description": "The raw SIP INVITE message (drachtio SipRequest object, serialized). Only present for WebSocket and HTTP POST transports (not for HTTP GET). See https://drachtio.org/api#sip-request for the full drachtio SipRequest API.", - "properties": { - "headers": { - "type": "object", - "description": "SIP headers from the INVITE as key-value pairs. Custom headers (X-* headers) from the originating carrier or SIP client are included here. Standard SIP headers like From, To, Contact, Call-ID, Via, etc. are also present.", - "additionalProperties": { "type": "string" }, - "examples": [ - { - "X-Authenticated-User": "retell@sip.example.com", - "X-Override-Number": "+15551234567", - "From": ";tag=abc123", - "To": "", - "Call-ID": "abc123@10.0.0.1" - } - ] - }, - "body": { - "type": "string", - "description": "SIP message body (typically SDP for INVITE)." - }, - "method": { - "type": "string", - "description": "SIP method (always 'INVITE' for session:new)." - }, - "uri": { - "type": "string", - "description": "Request-URI from the SIP INVITE." - }, - "calledNumber": { - "type": "string", - "description": "Phone number extracted from the Request-URI." - }, - "callingNumber": { - "type": "string", - "description": "Calling phone number extracted from P-Asserted-Identity or From header." - }, - "type": { - "type": "string", - "enum": ["request"], - "description": "Always 'request' for an incoming INVITE." - }, - "source": { - "type": "string", - "enum": ["network", "application"], - "description": "Origin of the SIP message." - }, - "source_address": { - "type": "string", - "description": "IP address of the sender." - }, - "source_port": { - "type": ["string", "integer"], - "description": "Port of the sender." - }, - "protocol": { - "type": "string", - "description": "Transport protocol (e.g. 'udp', 'tcp', 'tls', 'wss')." - }, - "payload": { - "type": "array", - "description": "Message body organized into parts; useful for multipart content." - } - } - }, - "env_vars": { - "type": "object", - "description": "Application environment variables configured in the jambonz portal. These are the key-value pairs defined in the application's environment variable schema. In the @jambonz/sdk, access via `session.data.env_vars`.", - "additionalProperties": true, - "examples": [ - { - "RETELL_TRUNK_NAME": "retell-hosted", - "PSTN_TRUNK_NAME": "my-carrier", - "DEFAULT_COUNTRY": "US" - } - ] - }, - "defaults": { - "type": "object", - "description": "Default speech settings for the account (synthesizer and recognizer defaults).", - "properties": { - "synthesizer": { - "type": "object", - "description": "Default TTS settings.", - "properties": { - "vendor": { "type": "string" }, - "language": { "type": "string" }, - "voice": { "type": "string" } - } - }, - "recognizer": { - "type": "object", - "description": "Default STT settings.", - "properties": { - "vendor": { "type": "string" }, - "language": { "type": "string" } - } - } - } - }, - "customerData": { - "type": "object", - "description": "Custom data attached to the call via the REST API when creating an outbound call. Preserved as-is (not snake-cased).", - "additionalProperties": true - } - }, - "additionalProperties": true -} diff --git a/schema/callbacks/session-reconnect.schema.json b/schema/callbacks/session-reconnect.schema.json deleted file mode 100644 index 8f9a69a..0000000 --- a/schema/callbacks/session-reconnect.schema.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/session-reconnect", - "title": "Session:reconnect Payload", - "description": "Payload delivered when a WebSocket client reconnects after a disconnection. The payload is identical to the original session:new payload — it is cached from the initial session setup and replayed on reconnect. This allows the application to restore state without needing to re-fetch call details.", - "allOf": [ - { "$ref": "session-new" } - ] -} diff --git a/schema/callbacks/session-redirect.schema.json b/schema/callbacks/session-redirect.schema.json deleted file mode 100644 index 81dd184..0000000 --- a/schema/callbacks/session-redirect.schema.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/session-redirect", - "title": "Session:redirect Payload", - "description": "Payload delivered when a redirect verb transfers the call to a new application or WebSocket endpoint. Contains only the current call state information — unlike session:new, it does not include defaults, env_vars, sip, or service_provider_sid.", - "allOf": [ - { "$ref": "base" } - ], - "type": "object", - "properties": { - "caller_name": { - "type": "string", - "description": "Caller display name from the SIP From header." - }, - "caller_id": { - "type": "string", - "description": "Caller ID value (phone number or SIP user)." - }, - "parent_call_sid": { - "type": "string", - "description": "Call SID of the parent call, if applicable." - }, - "fs_sip_address": { - "type": "string", - "description": "Internal SIP address of the FreeSWITCH media server handling this call." - }, - "fs_public_ip": { - "type": "string", - "description": "Public IP address of the FreeSWITCH media server, if available." - }, - "customerData": { - "type": "object", - "description": "Custom data attached to the call via the REST API. Preserved as-is (not snake-cased).", - "additionalProperties": true - } - }, - "additionalProperties": true -} diff --git a/schema/callbacks/sip-refer-event.schema.json b/schema/callbacks/sip-refer-event.schema.json deleted file mode 100644 index 241bc53..0000000 --- a/schema/callbacks/sip-refer-event.schema.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/sip-refer-event", - "title": "SIP Refer EventHook Payload", - "description": "Payload sent to the sip-refer eventHook when a SIP NOTIFY is received with transfer status updates.", - "type": "object", - "properties": { - "event": { - "type": "string", - "const": "transfer-status", - "description": "Event type — always 'transfer-status' for REFER notifications." - }, - "call_status": { - "type": "integer", - "description": "SIP status code from the NOTIFY sipfrag body (e.g. 100 for trying, 180 for ringing, 200 for success)." - } - }, - "required": ["event", "call_status"], - "additionalProperties": true -} diff --git a/schema/callbacks/sip-refer.schema.json b/schema/callbacks/sip-refer.schema.json deleted file mode 100644 index 40c66e7..0000000 --- a/schema/callbacks/sip-refer.schema.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/sip-refer", - "title": "SipRefer ActionHook Payload", - "description": "Payload sent to the sip-refer verb's actionHook when the REFER completes. Sent once the REFER response is received, or after a final NOTIFY arrives.", - "allOf": [ - { "$ref": "base" } - ], - "type": "object", - "properties": { - "refer_status": { - "type": "integer", - "description": "SIP status code from the REFER response (e.g. 202 for accepted, 4xx/5xx for failure)." - }, - "final_referred_call_status": { - "type": "integer", - "description": "Final SIP status of the referred call, extracted from a NOTIFY sipfrag. Present only when the REFER was accepted (202) and a final NOTIFY was received." - } - }, - "required": ["refer_status"], - "additionalProperties": true -} diff --git a/schema/callbacks/sip-request.schema.json b/schema/callbacks/sip-request.schema.json deleted file mode 100644 index 435c79e..0000000 --- a/schema/callbacks/sip-request.schema.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/sip-request", - "title": "SipRequest ActionHook Payload", - "description": "Payload sent to the sip-request verb's actionHook after a SIP request (e.g. INFO, NOTIFY) is sent and a response is received.", - "allOf": [ - { "$ref": "base" } - ], - "type": "object", - "properties": { - "result": { - "type": "string", - "enum": ["success", "failed"], - "description": "Whether the SIP request succeeded or failed." - }, - "sip_status": { - "type": "integer", - "description": "SIP response status code. Present when result is 'success'." - }, - "err": { - "type": "string", - "description": "Error message. Present when result is 'failed'." - } - }, - "required": ["result"], - "additionalProperties": true -} diff --git a/schema/callbacks/transcribe-translation.schema.json b/schema/callbacks/transcribe-translation.schema.json deleted file mode 100644 index 859f700..0000000 --- a/schema/callbacks/transcribe-translation.schema.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/transcribe-translation", - "title": "Transcribe TranslationHook Payload", - "description": "Payload sent to the translationHook when a translation result is received.", - "allOf": [ - { "$ref": "base" } - ], - "type": "object", - "properties": { - "translation": { - "type": "object", - "description": "Translation result data.", - "properties": { - "channel": { "type": "integer", "description": "Audio channel number (1 or 2)." }, - "language": { "type": "string", "description": "Target language code for the translation." }, - "translation": { "type": "string", "description": "The translated text." } - }, - "required": ["channel", "language", "translation"] - } - }, - "required": ["translation"], - "additionalProperties": true -} diff --git a/schema/callbacks/transcribe.schema.json b/schema/callbacks/transcribe.schema.json deleted file mode 100644 index e0da88f..0000000 --- a/schema/callbacks/transcribe.schema.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/transcribe", - "title": "Transcribe TranscriptionHook Payload", - "description": "Payload sent to the transcriptionHook when a transcription result is received from the STT engine.", - "allOf": [ - { "$ref": "base" } - ], - "type": "object", - "properties": { - "speech": { - "type": "object", - "description": "Speech recognition results, present when the STT engine returns alternatives.", - "properties": { - "language_code": { "type": "string", "description": "Language code used for recognition (e.g. 'en-US')." }, - "channel_tag": { "type": "integer", "description": "Audio channel number." }, - "is_final": { "type": "boolean", "description": "Whether this is a final (not interim) recognition result." }, - "alternatives": { - "type": "array", - "items": { - "type": "object", - "properties": { - "transcript": { "type": "string", "description": "The recognized transcript." }, - "confidence": { "type": "number", "description": "Confidence score between 0 and 1." } - } - }, - "description": "Array of recognition alternatives, ordered by confidence." - } - } - }, - "speech_event": { - "type": "object", - "description": "Speech event data, present when the STT engine returns a typed event (e.g. end of utterance).", - "properties": { - "type": { "type": "string", "description": "Event type from the STT vendor." } - }, - "additionalProperties": true - }, - "stt_latency_ms": { "type": "string", "description": "STT latency in milliseconds." }, - "stt_talkspurts": { "type": "string", "description": "JSON-encoded array of talkspurt timing data." }, - "stt_start_time": { "type": "string", "description": "STT recognition start time." }, - "stt_stop_time": { "type": "string", "description": "STT recognition stop time." }, - "stt_usage": { "description": "STT usage data from the vendor." } - }, - "additionalProperties": true -} diff --git a/schema/callbacks/tts-streaming-event.schema.json b/schema/callbacks/tts-streaming-event.schema.json deleted file mode 100644 index 6c0d070..0000000 --- a/schema/callbacks/tts-streaming-event.schema.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/tts-streaming-event", - "title": "TTS Streaming Event", - "description": "Events sent to the '/streaming-event' WebSocket endpoint during TTS streaming. These are sent as 'tts:streaming-event' messages. The tts_spoken event is only sent when trackTtsPlayout is enabled via the config verb.", - "type": "object", - "oneOf": [ - { - "properties": { - "event_type": { - "const": "stream_open", - "description": "The TTS streaming connection has been established." - } - }, - "required": ["event_type"], - "additionalProperties": false - }, - { - "properties": { - "event_type": { - "const": "stream_closed", - "description": "The TTS streaming connection has been closed." - } - }, - "required": ["event_type"], - "additionalProperties": false - }, - { - "properties": { - "event_type": { - "const": "stream_paused", - "description": "TTS streaming has been paused." - } - }, - "required": ["event_type"], - "additionalProperties": false - }, - { - "properties": { - "event_type": { - "const": "stream_resumed", - "description": "TTS streaming has been resumed." - } - }, - "required": ["event_type"], - "additionalProperties": false - }, - { - "properties": { - "event_type": { - "const": "user_interruption", - "description": "The user interrupted (barged in) during TTS playout, causing the stream to be cleared." - } - }, - "required": ["event_type"], - "additionalProperties": false - }, - { - "properties": { - "event_type": { - "const": "tts_spoken", - "description": "Reports the actual text that was spoken via TTS. Sent on utterance completion or when the user barges in. Only sent when trackTtsPlayout is enabled via the config verb. Requires a TTS vendor that supports alignment data (e.g. ElevenLabs)." - }, - "text": { - "type": "string", - "description": "The text that was actually spoken before completion or interruption." - }, - "bargein": { - "type": "boolean", - "description": "True if the user barged in (interrupted) before the TTS finished speaking. False if the utterance completed normally." - } - }, - "required": ["event_type", "text", "bargein"], - "additionalProperties": false - } - ] -} diff --git a/schema/callbacks/verb-status.schema.json b/schema/callbacks/verb-status.schema.json deleted file mode 100644 index 2150b6c..0000000 --- a/schema/callbacks/verb-status.schema.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/callbacks/verb-status", - "title": "Verb Status Event", - "description": "Real-time verb lifecycle events sent over WebSocket when notifyEvents is enabled on the session. These are informational — no response is expected.", - "type": "object", - "properties": { - "event": { - "type": "string", - "enum": [ - "starting", - "finished", - "start-playback", - "stop-playback", - "kill-playback", - "dtmf-bargein-detected", - "speech-bargein-detected", - "synthesized-audio" - ], - "description": "The verb lifecycle event." - }, - "verb": { - "type": "string", - "description": "The verb name (e.g. 'say', 'play', 'gather'). Present on synthesized-audio, start-playback, stop-playback, kill-playback, and dtmf/speech-bargein events." - }, - "name": { - "type": "string", - "description": "The verb name. Present on 'starting' and 'finished' events (these use 'name' instead of 'verb')." - }, - "id": { - "type": "string", - "description": "The verb instance id, if one was assigned by the application." - }, - "vendor": { - "type": "string", - "description": "TTS vendor name. Present on synthesized-audio events." - }, - "language": { - "type": "string", - "description": "TTS language code. Present on synthesized-audio events." - }, - "characters": { - "type": "integer", - "description": "Number of characters synthesized. Present on synthesized-audio events when not served from cache." - }, - "elapsed_time": { - "type": "number", - "description": "TTS round-trip time in milliseconds. Present on synthesized-audio events when not served from cache." - }, - "served_from_cache": { - "type": "boolean", - "description": "Whether the TTS audio was served from cache. Present on synthesized-audio events." - } - }, - "required": ["event"], - "additionalProperties": true -} diff --git a/schema/components/actionHook.schema.json b/schema/components/actionHook.schema.json deleted file mode 100644 index 28366b5..0000000 --- a/schema/components/actionHook.schema.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/components/actionHook", - "title": "ActionHook", - "description": "A webhook or websocket callback that jambonz invokes when a verb completes. Reports verb results (e.g. speech recognition from 'gather', dial outcome) and receives the next verbs to execute. In webhook mode: jambonz POSTs to this URL and the HTTP response body is the next verb array. In WebSocket mode: this value becomes an event name emitted on the session — bind session.on('/hookName', (evt) => {...}) and respond with session.reply() (NOT session.send()). The callback payload always includes 'reason' plus verb-specific fields (e.g. 'speech', 'digits' for gather). Can be a simple URL/path string or an object with additional options.", - "oneOf": [ - { - "type": "string", - "format": "uri", - "description": "A URL to invoke. For webhook applications this is an HTTP(S) URL. For websocket applications this is typically a relative path or event name.", - "examples": ["https://myapp.example.com/gather-result", "/gather-result"] - }, - { - "type": "object", - "description": "A hook specification with URL and additional options.", - "properties": { - "url": { - "type": "string", - "format": "uri", - "description": "The URL to invoke." - }, - "method": { - "type": "string", - "description": "The HTTP method to use. Only applies to webhook applications.", - "enum": ["GET", "POST"], - "default": "POST" - }, - "basicAuth": { - "$ref": "auth", - "description": "Basic authentication credentials to include in the request." - } - }, - "required": ["url"] - } - ] -} diff --git a/schema/components/actionHookDelayAction.schema.json b/schema/components/actionHookDelayAction.schema.json deleted file mode 100644 index 607177f..0000000 --- a/schema/components/actionHookDelayAction.schema.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/components/actionHookDelayAction", - "title": "ActionHookDelayAction", - "description": "Configuration for what to do when an actionHook (webhook) takes a long time to respond. Allows playing interim content (e.g. 'please wait' messages, hold music) while waiting for the webhook response, with configurable retry and give-up behavior.", - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Whether to enable delay handling for actionHooks." - }, - "noResponseTimeout": { - "type": "number", - "description": "Time in seconds to wait before executing the delay actions. If the webhook responds before this timeout, the delay actions are skipped.", - "examples": [3, 5] - }, - "noResponseGiveUpTimeout": { - "type": "number", - "description": "Total time in seconds to wait for a webhook response before giving up and executing the giveUpActions.", - "examples": [30, 60] - }, - "retries": { - "type": "number", - "description": "Number of times to retry the delay actions while still waiting for the webhook response." - }, - "actions": { - "type": "array", - "description": "An array of jambonz verbs to execute while waiting for the webhook response. Typically 'say' or 'play' verbs with messages like 'please hold'.", - "items": { "type": "object" } - }, - "giveUpActions": { - "type": "array", - "description": "An array of jambonz verbs to execute if the webhook never responds within the giveUpTimeout. Typically an error message and/or hangup.", - "items": { "type": "object" } - } - } -} diff --git a/schema/components/amd.schema.json b/schema/components/amd.schema.json deleted file mode 100644 index ee175f0..0000000 --- a/schema/components/amd.schema.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/components/amd", - "title": "Answering Machine Detection", - "description": "Configuration for answering machine detection (AMD). Detects whether an outbound or inbound call was answered by a human or a machine. Used as a nested property on the 'config' or 'dial' verb. IMPORTANT: AMD runs asynchronously in the background. When using AMD with the 'config' verb, you MUST follow it with a 'pause' verb (e.g. pause({ length: 25 })) to keep the call alive while AMD detection runs. Without a pause, the call will end immediately after config completes.", - "type": "object", - "properties": { - "actionHook": { - "$ref": "actionHook", - "description": "Webhook to receive AMD events (amd_human_detected, amd_machine_detected, amd_no_speech_detected, amd_decision_timeout, amd_machine_stopped_speaking, amd_tone_detected, amd_error, amd_stopped)." - }, - "thresholdWordCount": { - "type": "number", - "description": "Number of spoken words in a greeting that triggers an amd_machine_detected result.", - "default": 9 - }, - "digitCount": { - "type": "number", - "description": "Number of digits in a greeting to trigger detection. 0 disables digit-based detection.", - "default": 0 - }, - "timers": { - "type": "object", - "description": "Timer settings controlling AMD detection windows.", - "properties": { - "noSpeechTimeoutMs": { - "type": "number", - "description": "Milliseconds to wait for any speech before returning amd_no_speech_detected.", - "default": 5000 - }, - "decisionTimeoutMs": { - "type": "number", - "description": "Milliseconds before returning amd_decision_timeout if no determination is made.", - "default": 15000 - }, - "toneTimeoutMs": { - "type": "number", - "description": "Milliseconds to wait for beep/tone detection.", - "default": 20000 - }, - "greetingCompletionTimeoutMs": { - "type": "number", - "description": "Milliseconds of silence after speech before determining the machine greeting is complete. Automatically reduced to 1000ms if a beep is detected.", - "default": 2000 - } - }, - "additionalProperties": false - }, - "recognizer": { - "$ref": "recognizer", - "description": "Override the STT recognizer used for AMD speech detection. When omitted, AMD uses the session default recognizer with enhancedModel enabled." - } - }, - "required": ["actionHook"], - "examples": [ - { - "actionHook": "/amd-events" - }, - { - "actionHook": "/amd-events", - "thresholdWordCount": 6, - "timers": { - "noSpeechTimeoutMs": 3000, - "decisionTimeoutMs": 10000 - } - } - ] -} diff --git a/schema/components/auth.schema.json b/schema/components/auth.schema.json deleted file mode 100644 index b2fefa3..0000000 --- a/schema/components/auth.schema.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/components/auth", - "title": "Auth", - "description": "Basic authentication credentials, used for authenticating with external services such as websocket endpoints or SIP registrars.", - "type": "object", - "properties": { - "username": { - "type": "string", - "description": "The username for authentication." - }, - "password": { - "type": "string", - "description": "The password for authentication." - } - }, - "required": ["username", "password"] -} diff --git a/schema/components/bidirectionalAudio.schema.json b/schema/components/bidirectionalAudio.schema.json deleted file mode 100644 index 777a9a2..0000000 --- a/schema/components/bidirectionalAudio.schema.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/components/bidirectionalAudio", - "title": "BidirectionalAudio", - "description": "Configuration for bidirectional audio streaming over a websocket connection. When enabled, the remote websocket endpoint can send audio back to jambonz to be played to the caller.", - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Whether to enable bidirectional audio on the websocket connection." - }, - "streaming": { - "type": "boolean", - "description": "If true, audio is streamed continuously rather than sent as complete messages." - }, - "sampleRate": { - "type": "number", - "description": "The sample rate in Hz for bidirectional audio.", - "examples": [8000, 16000, 24000] - } - } -} diff --git a/schema/components/fillerNoise.schema.json b/schema/components/fillerNoise.schema.json deleted file mode 100644 index 37ec5ba..0000000 --- a/schema/components/fillerNoise.schema.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/components/fillerNoise", - "title": "FillerNoise", - "description": "Configuration for playing background filler noise (e.g. keyboard typing, hold music) while the application is processing and the caller would otherwise hear silence. Commonly used during LLM response generation to indicate the system is working.", - "type": "object", - "properties": { - "enable": { - "type": "boolean", - "description": "Whether to enable filler noise." - }, - "url": { - "type": "string", - "format": "uri", - "description": "URL of the audio file to play as filler noise. Should be a short, loopable audio clip.", - "examples": ["https://example.com/sounds/typing.wav"] - }, - "startDelaySecs": { - "type": "number", - "description": "Number of seconds to wait before starting filler noise. Prevents filler noise from playing during brief processing pauses.", - "examples": [1, 2] - } - }, - "required": ["enable"] -} diff --git a/schema/components/llm-base.schema.json b/schema/components/llm-base.schema.json deleted file mode 100644 index 81203d7..0000000 --- a/schema/components/llm-base.schema.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/components/llm-base", - "title": "LLM Base Properties", - "description": "Shared properties for llm, s2s, and vendor-specific s2s verb schemas.", - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "An optional unique identifier for this verb instance." - }, - "vendor": { - "type": "string", - "description": "The LLM vendor to use.", - "examples": ["openai", "anthropic", "google", "groq", "deepseek", "deepgram", "ultravox", "custom"] - }, - "model": { - "type": "string", - "description": "The specific model to use from the vendor.", - "examples": ["gpt-4o", "claude-sonnet-4-20250514", "gemini-2.0-flash"] - }, - "auth": { - "type": "object", - "description": "Authentication credentials for the LLM vendor API.", - "properties": { - "apiKey": { - "type": "string", - "description": "The API key for the LLM vendor." - } - }, - "additionalProperties": true - }, - "connectOptions": { - "type": "object", - "description": "Additional connection options for the LLM vendor, such as custom base URLs or API versions.", - "additionalProperties": true - }, - "llmOptions": { - "type": "object", - "description": "Configuration passed to the LLM including the system prompt, temperature, tools/functions, and other model parameters. The structure varies by vendor but typically includes 'messages' (conversation history), 'temperature', 'tools' (function definitions), and 'maxTokens'.", - "additionalProperties": true, - "examples": [ - { - "messages": [ - { "role": "system", "content": "You are a helpful customer service agent for Acme Corp." } - ], - "temperature": 0.7 - } - ] - }, - "mcpServers": { - "type": "array", - "items": { - "type": "object", - "properties": { - "url": { - "type": "string", - "format": "uri", - "description": "The URL of the MCP server." - }, - "auth": { - "type": "object", - "description": "Authentication for the MCP server.", - "additionalProperties": true - }, - "roots": { - "type": "array", - "items": { "type": "object" }, - "description": "MCP root definitions." - } - }, - "required": ["url"] - }, - "description": "Model Context Protocol servers to connect to. MCP servers provide tools that the LLM can invoke during the conversation." - }, - "actionHook": { - "$ref": "actionHook", - "description": "A webhook invoked when the LLM conversation ends. Receives conversation details and should return the next verbs to execute." - }, - "eventHook": { - "$ref": "actionHook", - "description": "A webhook invoked for real-time events during the LLM conversation (e.g. tool calls, transcription events)." - }, - "toolHook": { - "$ref": "actionHook", - "description": "A webhook invoked when the LLM calls a tool/function. Receives the tool name and arguments, and should return the tool result." - }, - "events": { - "type": "array", - "items": { "type": "string" }, - "description": "List of event types to receive via the eventHook." - } - } -} diff --git a/schema/components/recognizer-assemblyAiOptions.schema.json b/schema/components/recognizer-assemblyAiOptions.schema.json deleted file mode 100644 index 3494d8e..0000000 --- a/schema/components/recognizer-assemblyAiOptions.schema.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/components/recognizer-assemblyAiOptions", - "title": "AssemblyAI Recognizer Options", - "description": "AssemblyAI-specific STT options. Only applies when recognizer vendor is 'assemblyai'.", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "AssemblyAI API key. Overrides credentials configured in jambonz." - }, - "serviceVersion": { - "type": "string", - "enum": ["v2", "v3"], - "description": "AssemblyAI streaming API version." - }, - "speechModel": { - "type": "string", - "description": "AssemblyAI speech model to use for recognition." - }, - "formatTurns": { - "type": "boolean", - "description": "Enable turn-level formatting." - }, - "endOfTurnConfidenceThreshold": { - "type": "number", - "description": "Confidence threshold for end-of-turn detection." - }, - "minEndOfTurnSilenceWhenConfident": { - "type": "number", - "description": "Minimum silence duration (seconds) to trigger end-of-turn when confidence is met." - }, - "maxTurnSilence": { - "type": "number", - "description": "Maximum silence duration (seconds) before forcing end-of-turn." - }, - "minTurnSilence": { - "type": "number", - "description": "Minimum silence duration (seconds) before allowing end-of-turn." - }, - "keyterms": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of key terms to boost in recognition." - }, - "prompt": { - "type": "string", - "description": "Prompt to guide the recognition model." - }, - "languageDetection": { - "type": "boolean", - "description": "Enable automatic language detection." - }, - "vadThreshold": { - "type": "number", - "description": "Voice activity detection threshold." - }, - "inactivityTimeout": { - "type": "number", - "description": "Timeout (seconds) for inactivity before closing the stream." - } - }, - "additionalProperties": false -} diff --git a/schema/components/recognizer-awsOptions.schema.json b/schema/components/recognizer-awsOptions.schema.json deleted file mode 100644 index fe7d53f..0000000 --- a/schema/components/recognizer-awsOptions.schema.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/components/recognizer-awsOptions", - "title": "AWS Recognizer Options", - "description": "AWS Transcribe specific options. Only applies when recognizer vendor is 'aws'.", - "type": "object", - "properties": { - "accessKey": { - "type": "string", - "description": "AWS access key ID. Overrides credentials configured in jambonz." - }, - "secretKey": { - "type": "string", - "description": "AWS secret access key." - }, - "securityToken": { - "type": "string", - "description": "AWS temporary security token (for STS/assumed roles)." - }, - "region": { - "type": "string", - "description": "AWS region for the Transcribe service." - }, - "vocabularyName": { - "type": "string", - "description": "Name of a custom vocabulary to use." - }, - "vocabularyFilterName": { - "type": "string", - "description": "Name of a vocabulary filter to apply." - }, - "vocabularyFilterMethod": { - "type": "string", - "enum": ["remove", "mask", "tag"], - "description": "How filtered vocabulary words should be handled." - }, - "languageModelName": { - "type": "string", - "description": "Name of a custom language model." - }, - "piiEntityTypes": { - "type": "array", - "items": { "type": "string" }, - "description": "PII entity types to identify (e.g. 'BANK_ACCOUNT_NUMBER', 'CREDIT_DEBIT_NUMBER')." - }, - "piiIdentifyEntities": { - "type": "boolean", - "description": "Enable PII entity identification." - } - }, - "additionalProperties": false -} diff --git a/schema/components/recognizer-azureOptions.schema.json b/schema/components/recognizer-azureOptions.schema.json deleted file mode 100644 index 51c4a7d..0000000 --- a/schema/components/recognizer-azureOptions.schema.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/components/recognizer-azureOptions", - "title": "Azure Recognizer Options", - "description": "Azure Speech Services specific options. Only applies when recognizer vendor is 'microsoft'.", - "type": "object", - "properties": { - "speechSegmentationSilenceTimeoutMs": { - "type": "number", - "description": "Silence timeout in milliseconds for speech segmentation." - }, - "postProcessing": { - "type": "string", - "description": "Post-processing mode for transcription results." - }, - "audioLogging": { - "type": "boolean", - "description": "Enable audio logging for diagnostics." - }, - "languageIdMode": { - "type": "string", - "enum": ["AtStart", "Continuous"], - "description": "Language identification mode when using multiple languages." - }, - "speechRecognitionMode": { - "type": "string", - "enum": ["CONVERSATION", "DICTATION", "INTERACTIVE"], - "description": "Speech recognition mode optimized for the interaction type." - } - }, - "additionalProperties": false -} diff --git a/schema/components/recognizer-cobaltOptions.schema.json b/schema/components/recognizer-cobaltOptions.schema.json deleted file mode 100644 index 23a764d..0000000 --- a/schema/components/recognizer-cobaltOptions.schema.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/components/recognizer-cobaltOptions", - "title": "Cobalt Recognizer Options", - "description": "Cobalt-specific STT options. Only applies when recognizer vendor is 'cobalt'.", - "type": "object", - "properties": { - "serverUri": { - "type": "string", - "description": "Cobalt server URI." - }, - "enableConfusionNetwork": { - "type": "boolean", - "description": "Enable confusion network output." - }, - "metadata": { - "type": "string", - "description": "Metadata string to pass to the server." - }, - "compiledContextData": { - "type": "string", - "description": "Compiled context data for biasing recognition." - }, - "wordTimeOffsets": { - "type": "boolean", - "description": "Include word-level timestamps." - }, - "contextToken": { - "type": "string", - "description": "Context token for server-side context." - } - }, - "additionalProperties": false -} diff --git a/schema/components/recognizer-customOptions.schema.json b/schema/components/recognizer-customOptions.schema.json deleted file mode 100644 index e93490f..0000000 --- a/schema/components/recognizer-customOptions.schema.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/components/recognizer-customOptions", - "title": "Custom Recognizer Options", - "description": "Options for custom STT vendors. Only applies when recognizer vendor is 'custom'.", - "type": "object", - "properties": { - "authToken": { - "type": "string", - "description": "Authentication token for the custom STT service." - }, - "uri": { - "type": "string", - "description": "WebSocket URI of the custom STT service." - }, - "sampleRate": { - "type": "number", - "description": "Audio sample rate in Hz." - }, - "options": { - "type": "object", - "description": "Additional vendor-specific options passed through to the custom service.", - "additionalProperties": true - } - }, - "additionalProperties": false -} diff --git a/schema/components/recognizer-deepgramOptions.schema.json b/schema/components/recognizer-deepgramOptions.schema.json deleted file mode 100644 index 13a286e..0000000 --- a/schema/components/recognizer-deepgramOptions.schema.json +++ /dev/null @@ -1,147 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/components/recognizer-deepgramOptions", - "title": "Deepgram Recognizer Options", - "description": "Deepgram-specific STT options. Only applies when recognizer vendor is 'deepgram'.", - "type": "object", - "properties": { - "deepgramSttUri": { - "type": "string", - "description": "Custom Deepgram STT endpoint URI." - }, - "deepgramSttUseTls": { - "type": "boolean", - "description": "Whether to use TLS when connecting to the Deepgram STT endpoint." - }, - "apiKey": { - "type": "string", - "description": "Deepgram API key. Overrides the key configured in jambonz." - }, - "tier": { - "type": "string", - "description": "Deepgram model tier." - }, - "model": { - "type": "string", - "description": "Deepgram model name (e.g. 'nova-2', 'nova-2-general')." - }, - "customModel": { - "type": "string", - "description": "ID of a custom-trained Deepgram model." - }, - "version": { - "type": "string", - "description": "Model version." - }, - "punctuate": { - "type": "boolean", - "description": "Enable automatic punctuation." - }, - "smartFormatting": { - "type": "boolean", - "description": "Enable Deepgram smart formatting (dates, numbers, etc.)." - }, - "noDelay": { - "type": "boolean", - "description": "Disable Deepgram's internal buffering for lower latency." - }, - "profanityFilter": { - "type": "boolean", - "description": "Filter profanity from transcripts." - }, - "redact": { - "type": "string", - "enum": ["pci", "numbers", "true", "ssn"], - "description": "Redact sensitive information from transcripts." - }, - "diarize": { - "type": "boolean", - "description": "Enable speaker diarization." - }, - "diarizeVersion": { - "type": "string", - "description": "Diarization model version." - }, - "ner": { - "type": "boolean", - "description": "Enable named entity recognition." - }, - "multichannel": { - "type": "boolean", - "description": "Enable multichannel processing." - }, - "alternatives": { - "type": "number", - "description": "Number of alternative transcripts to return." - }, - "numerals": { - "type": "boolean", - "description": "Convert spoken numbers to digits." - }, - "search": { - "type": "array", - "items": { "type": "string" }, - "description": "Terms to search for in the transcript." - }, - "replace": { - "type": "array", - "items": { "type": "string" }, - "description": "Terms to replace in the transcript." - }, - "keywords": { - "type": "array", - "items": { "type": "string" }, - "description": "Keywords to boost recognition for." - }, - "keyterms": { - "type": "array", - "items": { "type": "string" }, - "description": "Key terms to boost recognition for." - }, - "endpointing": { - "type": ["boolean", "number"], - "description": "Endpointing sensitivity. Boolean to enable/disable, or number of milliseconds." - }, - "utteranceEndMs": { - "type": "number", - "description": "Milliseconds of silence to detect end of utterance." - }, - "shortUtterance": { - "type": "boolean", - "description": "Optimize for short utterances." - }, - "vadTurnoff": { - "type": "number", - "description": "Milliseconds of silence before VAD turns off." - }, - "tag": { - "type": "string", - "description": "Tag to associate with the request for tracking." - }, - "fillerWords": { - "type": "boolean", - "description": "Include filler words (um, uh) in transcript." - }, - "eotThreshold": { - "type": "number", - "description": "End-of-turn confidence threshold (0-1)." - }, - "eotTimeoutMs": { - "type": "number", - "description": "End-of-turn timeout in milliseconds." - }, - "mipOptOut": { - "type": "boolean", - "description": "Opt out of Deepgram's model improvement program." - }, - "entityPrompt": { - "type": "string", - "description": "Prompt to guide entity detection." - }, - "eagerEotThreshold": { - "type": "number", - "description": "Eager end-of-turn threshold for faster response." - } - }, - "additionalProperties": false -} diff --git a/schema/components/recognizer-elevenlabsOptions.schema.json b/schema/components/recognizer-elevenlabsOptions.schema.json deleted file mode 100644 index 8a55fa4..0000000 --- a/schema/components/recognizer-elevenlabsOptions.schema.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/components/recognizer-elevenlabsOptions", - "title": "ElevenLabs Recognizer Options", - "description": "ElevenLabs-specific STT options. Only applies when recognizer vendor is 'elevenlabs'.", - "type": "object", - "properties": { - "includeTimestamps": { - "type": "boolean", - "description": "Include word-level timestamps in results." - }, - "commitStrategy": { - "type": "string", - "enum": ["manual", "vad"], - "description": "How audio chunks are committed. 'manual' for explicit commits, 'vad' for voice activity detection." - }, - "vadSilenceThresholdSecs": { - "type": "number", - "description": "Silence duration in seconds to trigger VAD commit." - }, - "vadThreshold": { - "type": "number", - "description": "VAD activation threshold." - }, - "minSpeechDurationMs": { - "type": "number", - "description": "Minimum speech duration in milliseconds to accept." - }, - "minSilenceDurationMs": { - "type": "number", - "description": "Minimum silence duration in milliseconds to trigger end of speech." - }, - "enableLogging": { - "type": "boolean", - "description": "Enable server-side logging." - } - }, - "additionalProperties": false -} diff --git a/schema/components/recognizer-gladiaOptions.schema.json b/schema/components/recognizer-gladiaOptions.schema.json deleted file mode 100644 index 06b5f2f..0000000 --- a/schema/components/recognizer-gladiaOptions.schema.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/components/recognizer-gladiaOptions", - "title": "Gladia Recognizer Options", - "description": "Gladia-specific STT options. Only applies when recognizer vendor is 'gladia'. See Gladia API documentation for available options.", - "type": "object", - "additionalProperties": false -} diff --git a/schema/components/recognizer-googleOptions.schema.json b/schema/components/recognizer-googleOptions.schema.json deleted file mode 100644 index 315f510..0000000 --- a/schema/components/recognizer-googleOptions.schema.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/components/recognizer-googleOptions", - "title": "Google Recognizer Options", - "description": "Google Speech-to-Text specific options. Only applies when recognizer vendor is 'google'.", - "type": "object", - "properties": { - "serviceVersion": { - "type": "string", - "enum": ["v1", "v2"], - "description": "Google Speech-to-Text API version." - }, - "recognizerId": { - "type": "string", - "description": "ID of a Google Speech recognizer resource (v2 only)." - }, - "speechStartTimeoutMs": { - "type": "number", - "description": "Timeout in milliseconds to wait for speech to start." - }, - "speechEndTimeoutMs": { - "type": "number", - "description": "Timeout in milliseconds to detect end of speech." - }, - "enableVoiceActivityEvents": { - "type": "boolean", - "description": "Enable voice activity detection events." - }, - "transcriptNormalization": { - "type": "array", - "description": "Array of transcript normalization rules." - } - }, - "additionalProperties": false -} diff --git a/schema/components/recognizer-houndifyOptions.schema.json b/schema/components/recognizer-houndifyOptions.schema.json deleted file mode 100644 index d21857e..0000000 --- a/schema/components/recognizer-houndifyOptions.schema.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/components/recognizer-houndifyOptions", - "title": "Houndify Recognizer Options", - "description": "Houndify-specific STT options. Only applies when recognizer vendor is 'houndify'.", - "type": "object", - "properties": { - "requestInfo": { - "type": "object", - "description": "Houndify RequestInfo object with context data.", - "additionalProperties": true - }, - "sampleRate": { "type": "number", "description": "Audio sample rate in Hz." }, - "latitude": { "type": "number", "description": "User latitude for location-aware queries." }, - "longitude": { "type": "number", "description": "User longitude for location-aware queries." }, - "city": { "type": "string", "description": "User city." }, - "state": { "type": "string", "description": "User state." }, - "country": { "type": "string", "description": "User country." }, - "timeZone": { "type": "string", "description": "User timezone." }, - "domain": { "type": "string", "description": "Houndify domain." }, - "audioEndpoint": { "type": "string", "description": "Custom audio endpoint URL." }, - "maxSilenceSeconds": { "type": "number", "description": "Maximum silence before stopping." }, - "maxSilenceAfterFullQuerySeconds": { "type": "number", "description": "Silence timeout after a complete query." }, - "maxSilenceAfterPartialQuerySeconds": { "type": "number", "description": "Silence timeout after a partial query." }, - "vadSensitivity": { "type": "number", "description": "VAD sensitivity level." }, - "vadTimeout": { "type": "number", "description": "VAD timeout in milliseconds." }, - "vadMode": { "type": "string", "description": "VAD mode." }, - "vadVoiceMs": { "type": "number", "description": "Milliseconds of voice to trigger VAD." }, - "vadSilenceMs": { "type": "number", "description": "Milliseconds of silence to trigger VAD." }, - "vadDebug": { "type": "boolean", "description": "Enable VAD debug logging." }, - "audioFormat": { "type": "string", "description": "Audio format." }, - "enableNoiseReduction": { "type": "boolean", "description": "Enable noise reduction." }, - "enableProfanityFilter": { "type": "boolean", "description": "Filter profanity." }, - "enablePunctuation": { "type": "boolean", "description": "Enable punctuation." }, - "enableCapitalization": { "type": "boolean", "description": "Enable capitalization." }, - "confidenceThreshold": { "type": "number", "description": "Minimum confidence threshold." }, - "enableDisfluencyFilter": { "type": "boolean", "description": "Filter disfluencies (um, uh)." }, - "maxResults": { "type": "number", "description": "Maximum number of results." }, - "enableWordTimestamps": { "type": "boolean", "description": "Include word timestamps." }, - "maxAlternatives": { "type": "number", "description": "Maximum alternative transcripts." }, - "partialTranscriptInterval": { "type": "number", "description": "Interval for partial transcript delivery." }, - "sessionTimeout": { "type": "number", "description": "Session timeout." }, - "connectionTimeout": { "type": "number", "description": "Connection timeout." }, - "customVocabulary": { - "type": "array", - "items": { "type": "string" }, - "description": "Custom vocabulary terms." - }, - "languageModel": { "type": "string", "description": "Language model to use." }, - "audioQueryAbsoluteTimeout": { "type": "number", "description": "Absolute timeout for audio queries." } - }, - "additionalProperties": false -} diff --git a/schema/components/recognizer-ibmOptions.schema.json b/schema/components/recognizer-ibmOptions.schema.json deleted file mode 100644 index 6f9b0ae..0000000 --- a/schema/components/recognizer-ibmOptions.schema.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/components/recognizer-ibmOptions", - "title": "IBM Recognizer Options", - "description": "IBM Watson Speech-to-Text specific options. Only applies when recognizer vendor is 'ibm'.", - "type": "object", - "properties": { - "sttApiKey": { - "type": "string", - "description": "IBM STT API key. Overrides credentials configured in jambonz." - }, - "sttRegion": { - "type": "string", - "description": "IBM STT region." - }, - "ttsApiKey": { - "type": "string", - "description": "IBM TTS API key." - }, - "ttsRegion": { - "type": "string", - "description": "IBM TTS region." - }, - "instanceId": { - "type": "string", - "description": "IBM Watson instance ID." - }, - "model": { - "type": "string", - "description": "Recognition model name." - }, - "languageCustomizationId": { - "type": "string", - "description": "ID of a custom language model." - }, - "acousticCustomizationId": { - "type": "string", - "description": "ID of a custom acoustic model." - }, - "baseModelVersion": { - "type": "string", - "description": "Base model version to use." - }, - "watsonMetadata": { - "type": "string", - "description": "Customer ID metadata for data labeling." - }, - "watsonLearningOptOut": { - "type": "boolean", - "description": "Opt out of IBM data collection for service improvements." - } - }, - "additionalProperties": false -} diff --git a/schema/components/recognizer-nuanceOptions.schema.json b/schema/components/recognizer-nuanceOptions.schema.json deleted file mode 100644 index c484c26..0000000 --- a/schema/components/recognizer-nuanceOptions.schema.json +++ /dev/null @@ -1,150 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/components/recognizer-nuanceOptions", - "title": "Nuance Recognizer Options", - "description": "Nuance Mix specific options. Only applies when recognizer vendor is 'nuance'.", - "type": "object", - "properties": { - "clientId": { - "type": "string", - "description": "Nuance Mix client ID." - }, - "secret": { - "type": "string", - "description": "Nuance Mix client secret." - }, - "kryptonEndpoint": { - "type": "string", - "description": "Custom Nuance Krypton endpoint URL." - }, - "topic": { - "type": "string", - "description": "Recognition topic (domain)." - }, - "utteranceDetectionMode": { - "type": "string", - "enum": ["single", "multiple", "disabled"], - "description": "How utterance boundaries are detected." - }, - "punctuation": { - "type": "boolean", - "description": "Enable automatic punctuation." - }, - "profanityFilter": { - "type": "boolean", - "description": "Filter profanity from results." - }, - "includeTokenization": { - "type": "boolean", - "description": "Include tokenization data in results." - }, - "discardSpeakerAdaptation": { - "type": "boolean", - "description": "Discard speaker adaptation data." - }, - "suppressCallRecording": { - "type": "boolean", - "description": "Suppress call recording on the Nuance side." - }, - "maskLoadFailures": { - "type": "boolean", - "description": "Mask resource load failures." - }, - "suppressInitialCapitalization": { - "type": "boolean", - "description": "Suppress initial capitalization of results." - }, - "allowZeroBaseLmWeight": { - "type": "boolean", - "description": "Allow zero base language model weight." - }, - "filterWakeupWord": { - "type": "boolean", - "description": "Filter wakeup words from results." - }, - "resultType": { - "type": "string", - "enum": ["final", "partial", "immutable_partial"], - "description": "Type of results to return." - }, - "noInputTimeoutMs": { - "type": "number", - "description": "Timeout in milliseconds before no-input event." - }, - "recognitionTimeoutMs": { - "type": "number", - "description": "Maximum recognition duration in milliseconds." - }, - "utteranceEndSilenceMs": { - "type": "number", - "description": "Silence duration in milliseconds to detect end of utterance." - }, - "maxHypotheses": { - "type": "number", - "description": "Maximum number of recognition hypotheses to return." - }, - "speechDomain": { - "type": "string", - "description": "Speech domain for optimized recognition." - }, - "formatting": { - "type": "object", - "description": "Formatting options for recognition results.", - "properties": { - "scheme": { "type": "string", "description": "Formatting scheme name." }, - "options": { "type": "object", "description": "Scheme-specific formatting options." } - }, - "required": ["scheme", "options"] - }, - "clientData": { - "type": "object", - "description": "Custom client data to pass to Nuance.", - "additionalProperties": true - }, - "userId": { - "type": "string", - "description": "User ID for speaker adaptation." - }, - "speechDetectionSensitivity": { - "type": "number", - "description": "Speech detection sensitivity (0-1)." - }, - "resources": { - "type": "array", - "description": "Array of Nuance recognition resources (grammars, wordsets, etc.).", - "items": { - "type": "object", - "properties": { - "externalReference": { - "type": "object", - "description": "External resource reference.", - "properties": { - "type": { - "type": "string", - "enum": ["undefined_resource_type", "wordset", "compiled_wordset", "domain_lm", "speaker_profile", "grammar", "settings"] - }, - "uri": { "type": "string" }, - "maxLoadFailures": { "type": "boolean" }, - "requestTimeoutMs": { "type": "number" }, - "headers": { "type": "object" } - } - }, - "inlineWordset": { "type": "string", "description": "Inline wordset JSON string." }, - "builtin": { "type": "string", "description": "Built-in grammar name." }, - "inlineGrammar": { "type": "string", "description": "Inline SRGS grammar." }, - "wakeupWord": { "type": "array", "items": { "type": "string" }, "description": "Wakeup words." }, - "weightName": { - "type": "string", - "enum": ["defaultWeight", "lowest", "low", "medium", "high", "highest"] - }, - "weightValue": { "type": "number" }, - "reuse": { - "type": "string", - "enum": ["undefined_reuse", "low_reuse", "high_reuse"] - } - } - } - } - }, - "additionalProperties": false -} diff --git a/schema/components/recognizer-nvidiaOptions.schema.json b/schema/components/recognizer-nvidiaOptions.schema.json deleted file mode 100644 index 15131f9..0000000 --- a/schema/components/recognizer-nvidiaOptions.schema.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/components/recognizer-nvidiaOptions", - "title": "NVIDIA Recognizer Options", - "description": "NVIDIA Riva specific options. Only applies when recognizer vendor is 'nvidia'.", - "type": "object", - "properties": { - "rivaUri": { - "type": "string", - "description": "NVIDIA Riva server URI." - }, - "maxAlternatives": { - "type": "number", - "description": "Maximum number of alternative transcripts." - }, - "profanityFilter": { - "type": "boolean", - "description": "Filter profanity from results." - }, - "punctuation": { - "type": "boolean", - "description": "Enable automatic punctuation." - }, - "wordTimeOffsets": { - "type": "boolean", - "description": "Include word-level timestamps." - }, - "verbatimTranscripts": { - "type": "boolean", - "description": "Return verbatim (unformatted) transcripts." - }, - "customConfiguration": { - "type": "object", - "description": "Custom Riva configuration parameters.", - "additionalProperties": true - } - }, - "additionalProperties": false -} diff --git a/schema/components/recognizer-openaiOptions.schema.json b/schema/components/recognizer-openaiOptions.schema.json deleted file mode 100644 index 7ae4a2d..0000000 --- a/schema/components/recognizer-openaiOptions.schema.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/components/recognizer-openaiOptions", - "title": "OpenAI Recognizer Options", - "description": "OpenAI Whisper/Realtime specific STT options. Only applies when recognizer vendor is 'openai'.", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "OpenAI API key. Overrides credentials configured in jambonz." - }, - "model": { - "type": "string", - "description": "OpenAI STT model name." - }, - "prompt": { - "type": "string", - "description": "Prompt to guide the recognition model." - }, - "promptTemplates": { - "type": "object", - "description": "Templates for dynamic prompt generation.", - "properties": { - "hintsTemplate": { "type": "string", "description": "Template for injecting hints into the prompt." }, - "conversationHistoryTemplate": { "type": "string", "description": "Template for injecting conversation history." } - } - }, - "language": { - "type": "string", - "description": "Language code for recognition." - }, - "input_audio_noise_reduction": { - "type": "string", - "enum": ["near_field", "far_field"], - "description": "Input audio noise reduction mode." - }, - "turn_detection": { - "type": "object", - "description": "Turn detection configuration for the OpenAI Realtime API.", - "properties": { - "type": { - "type": "string", - "enum": ["none", "server_vad", "semantic_vad"], - "description": "Turn detection strategy." - }, - "eagerness": { - "type": "string", - "enum": ["low", "medium", "high", "auto"], - "description": "How eagerly the model should respond." - }, - "threshold": { "type": "number", "description": "VAD activation threshold (0-1)." }, - "prefix_padding_ms": { "type": "number", "description": "Milliseconds of audio to include before detected speech." }, - "silence_duration_ms": { "type": "number", "description": "Milliseconds of silence to detect end of speech." } - }, - "required": ["type"] - } - }, - "additionalProperties": false -} diff --git a/schema/components/recognizer-sonioxOptions.schema.json b/schema/components/recognizer-sonioxOptions.schema.json deleted file mode 100644 index fe6dced..0000000 --- a/schema/components/recognizer-sonioxOptions.schema.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/components/recognizer-sonioxOptions", - "title": "Soniox Recognizer Options", - "description": "Soniox-specific STT options. Only applies when recognizer vendor is 'soniox'.", - "type": "object", - "properties": { - "apiKey": { - "type": "string", - "description": "Soniox API key." - }, - "model": { - "type": "string", - "description": "Soniox recognition model." - }, - "endpointDetection": { - "type": "boolean", - "description": "Enable endpoint detection." - }, - "profanityFilter": { - "type": "boolean", - "description": "Filter profanity from results." - }, - "speechContext": { - "type": "string", - "description": "Speech context for improved recognition." - }, - "clientRequestReference": { - "type": "string", - "description": "Client request reference for tracking." - }, - "storage": { - "type": "object", - "description": "Soniox storage configuration for persisting transcripts.", - "properties": { - "id": { "type": "string", "description": "Storage ID." }, - "title": { "type": "string", "description": "Storage title." }, - "disableStoreAudio": { "type": "boolean", "description": "Disable audio storage." }, - "disableStoreTranscript": { "type": "boolean", "description": "Disable transcript storage." }, - "disableSearch": { "type": "boolean", "description": "Disable search indexing." }, - "metadata": { "type": "object", "description": "Custom metadata.", "additionalProperties": true } - } - } - }, - "additionalProperties": false -} diff --git a/schema/components/recognizer-speechmaticsOptions.schema.json b/schema/components/recognizer-speechmaticsOptions.schema.json deleted file mode 100644 index 9fb193f..0000000 --- a/schema/components/recognizer-speechmaticsOptions.schema.json +++ /dev/null @@ -1,100 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/components/recognizer-speechmaticsOptions", - "title": "Speechmatics Recognizer Options", - "description": "Speechmatics-specific STT options. Only applies when recognizer vendor is 'speechmatics'.", - "type": "object", - "properties": { - "host": { - "type": "string", - "description": "Speechmatics host URL." - }, - "profile": { - "type": "string", - "enum": ["adaptive", "agile", "smart", "external"], - "description": "Speechmatics profile." - }, - "transcription_config": { - "type": "object", - "description": "Speechmatics transcription configuration.", - "properties": { - "language": { "type": "string", "description": "Language code." }, - "domain": { "type": "string", "description": "Domain model." }, - "additional_vocab": { "type": "array", "description": "Additional vocabulary entries." }, - "diarization": { "type": "string", "description": "Diarization mode." }, - "speaker_diarization_config": { - "type": "object", - "properties": { - "speaker_sensitivity": { "type": "number" }, - "max_speakers": { "type": "number" } - } - }, - "conversation_config": { - "type": "object", - "properties": { - "end_of_utterance_silence_trigger": { "type": "number" } - } - }, - "enable_partials": { "type": "boolean", "description": "Enable partial transcripts." }, - "max_delay": { "type": "number", "description": "Maximum delay in seconds." }, - "max_delay_mode": { - "type": "string", - "enum": ["fixed", "flexible"], - "description": "Delay mode." - }, - "output_locale": { "type": "string", "description": "Output locale for formatting." }, - "punctuation_overrides": { - "type": "object", - "properties": { - "permitted_marks": { "type": "array", "items": { "type": "string" } }, - "sensitivity": { "type": "number" } - } - }, - "operating_point": { "type": "string", "description": "Operating point (standard or enhanced)." }, - "enable_entities": { "type": "boolean", "description": "Enable entity detection." }, - "audio_filtering_config": { - "type": "object", - "properties": { - "volume_threshold": { "type": "number" } - }, - "required": ["volume_threshold"] - }, - "transcript_filtering_config": { - "type": "object", - "properties": { - "remove_disfluencies": { "type": "boolean" } - }, - "required": ["remove_disfluencies"] - } - } - }, - "translation_config": { - "type": "object", - "description": "Speechmatics translation configuration.", - "properties": { - "target_languages": { - "type": "array", - "items": { "type": "string" }, - "description": "Target languages for translation." - }, - "enable_partials": { "type": "boolean", "description": "Enable partial translations." } - }, - "required": ["target_languages"] - }, - "audio_events_config": { - "type": "object", - "description": "Audio event detection configuration.", - "properties": { - "types": { - "type": "array", - "items": { - "type": "string", - "enum": ["applause", "music", "laughter"] - }, - "description": "Audio event types to detect." - } - } - } - }, - "additionalProperties": false -} diff --git a/schema/components/recognizer-verbioOptions.schema.json b/schema/components/recognizer-verbioOptions.schema.json deleted file mode 100644 index 2b0c883..0000000 --- a/schema/components/recognizer-verbioOptions.schema.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/components/recognizer-verbioOptions", - "title": "Verbio Recognizer Options", - "description": "Verbio-specific STT options. Only applies when recognizer vendor is 'verbio'.", - "type": "object", - "properties": { - "enable_formatting": { - "type": "boolean", - "description": "Enable text formatting of results." - }, - "enable_diarization": { - "type": "boolean", - "description": "Enable speaker diarization." - }, - "topic": { - "type": "number", - "description": "Topic ID for domain-specific recognition." - }, - "inline_grammar": { - "type": "string", - "description": "Inline SRGS grammar for constrained recognition." - }, - "grammar_uri": { - "type": "string", - "description": "URI of an external grammar resource." - }, - "label": { - "type": "string", - "description": "Label for the recognition session." - }, - "recognition_timeout": { - "type": "number", - "description": "Maximum recognition duration in seconds." - }, - "speech_complete_timeout": { - "type": "number", - "description": "Silence duration in seconds after complete speech." - }, - "speech_incomplete_timeout": { - "type": "number", - "description": "Silence duration in seconds after incomplete speech." - } - }, - "additionalProperties": false -} diff --git a/schema/components/recognizer.schema.json b/schema/components/recognizer.schema.json deleted file mode 100644 index f7f3084..0000000 --- a/schema/components/recognizer.schema.json +++ /dev/null @@ -1,216 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/components/recognizer", - "title": "Recognizer", - "description": "Configuration for speech-to-text recognition. Specifies the STT vendor, language, and vendor-specific options. Can be set at the session level via the 'config' verb or overridden per-verb (e.g. on 'gather').", - "type": "object", - "properties": { - "vendor": { - "type": "string", - "description": "The STT vendor to use. Must match a vendor configured in the jambonz platform.", - "examples": ["google", "aws", "microsoft", "deepgram", "nuance", "ibm", "nvidia", "soniox", "cobalt", "assemblyai", "speechmatics", "openai", "houndify", "gladia", "elevenlabs", "verbio", "custom"] - }, - "label": { - "type": "string", - "description": "An optional label identifying a specific credential set for this vendor. Used when multiple credentials are configured for the same vendor." - }, - "language": { - "type": "string", - "description": "The language code for speech recognition, in BCP-47 format.", - "examples": ["en-US", "en-GB", "es-ES", "fr-FR"] - }, - "fallbackVendor": { - "type": "string", - "description": "A backup STT vendor to use if the primary vendor fails or is unavailable." - }, - "fallbackLabel": { - "type": "string", - "description": "Credential label for the fallback vendor." - }, - "fallbackLanguage": { - "type": "string", - "description": "Language code to use with the fallback vendor." - }, - "vad": { - "$ref": "vad", - "description": "Voice activity detection settings for this recognizer." - }, - "autogeneratePrompt": { - "type": "boolean", - "description": "If true, automatically generate a prompt for the STT vendor based on context (e.g. TTS voice, language). Supported by vendors that accept prompts for recognition guidance." - }, - "hints": { - "type": "array", - "items": { "type": "string" }, - "description": "An array of words or phrases that the recognizer should favor. Use this to improve accuracy for domain-specific terminology, product names, or proper nouns.", - "examples": [["jambonz", "drachtio", "SIP", "WebRTC"]] - }, - "hintsBoost": { - "type": "number", - "description": "A boost factor for hint words. Higher values increase the likelihood of recognizing hinted words. Vendor-specific range." - }, - "altLanguages": { - "type": "array", - "items": { "type": "string" }, - "description": "Additional languages the recognizer should listen for simultaneously. Enables multilingual recognition.", - "examples": [["es-ES", "fr-FR"]] - }, - "profanityFilter": { - "type": "boolean", - "description": "If true, the vendor will attempt to filter profanity from transcription results." - }, - "interim": { - "type": "boolean", - "description": "If true, return interim (partial) transcription results as they become available, before the utterance is complete." - }, - "singleUtterance": { - "type": "boolean", - "description": "If true, recognition stops after the first complete utterance is detected." - }, - "dualChannel": { - "type": "boolean", - "description": "If true, send separate audio channels for each call leg (caller and callee) to the recognizer." - }, - "separateRecognitionPerChannel": { - "type": "boolean", - "description": "If true, perform independent recognition on each audio channel. Requires dualChannel." - }, - "punctuation": { - "type": "boolean", - "description": "If true, enable automatic punctuation in transcription results." - }, - "enhancedModel": { - "type": "boolean", - "description": "If true, use an enhanced (premium) recognition model if available from the vendor." - }, - "words": { - "type": "boolean", - "description": "If true, include word-level timing information in transcription results." - }, - "diarization": { - "type": "boolean", - "description": "If true, enable speaker diarization to identify different speakers in the audio." - }, - "diarizationMinSpeakers": { - "type": "number", - "description": "Minimum number of speakers expected. Used to guide the diarization algorithm." - }, - "diarizationMaxSpeakers": { - "type": "number", - "description": "Maximum number of speakers expected. Used to guide the diarization algorithm." - }, - "interactionType": { - "type": "string", - "description": "A hint to the recognizer about the type of interaction, which can improve accuracy.", - "enum": ["unspecified", "discussion", "presentation", "phone_call", "voicemail", "voice_search", "voice_command", "dictation"] - }, - "naicsCode": { - "type": "number", - "description": "North American Industry Classification System code. Some vendors use this to improve domain-specific accuracy." - }, - "identifyChannels": { - "type": "boolean", - "description": "If true, identify and label which channel each transcription segment came from." - }, - "vocabularyName": { - "type": "string", - "description": "Name of a custom vocabulary resource configured at the vendor for improved recognition of specialized terms." - }, - "vocabularyFilterName": { - "type": "string", - "description": "Name of a vocabulary filter configured at the vendor for masking or removing specific words." - }, - "filterMethod": { - "type": "string", - "description": "How filtered vocabulary words should be handled in the transcript.", - "enum": ["remove", "mask", "tag"] - }, - "model": { - "type": "string", - "description": "The specific recognition model to use. Model names are vendor-specific.", - "examples": ["latest_long", "phone_call", "nova-2", "chirp"] - }, - "outputFormat": { - "type": "string", - "description": "The level of detail in recognition results.", - "enum": ["simple", "detailed"] - }, - "profanityOption": { - "type": "string", - "description": "How profanity should be handled in results.", - "enum": ["masked", "removed", "raw"] - }, - "requestSnr": { - "type": "boolean", - "description": "If true, request signal-to-noise ratio information in results." - }, - "initialSpeechTimeoutMs": { - "type": "number", - "description": "Time in milliseconds to wait for initial speech before timing out.", - "examples": [5000] - }, - "azureServiceEndpoint": { - "type": "string", - "description": "Custom Azure Speech Services endpoint URL. Only applies when vendor is 'microsoft'." - }, - "azureSttEndpointId": { - "type": "string", - "description": "Azure custom speech endpoint ID for using a custom-trained model. Only applies when vendor is 'microsoft'." - }, - "asrDtmfTerminationDigit": { - "type": "string", - "description": "A DTMF digit that terminates speech recognition when pressed.", - "examples": ["#"] - }, - "asrTimeout": { - "type": "number", - "description": "Maximum time in seconds to wait for a complete recognition result." - }, - "fastRecognitionTimeout": { - "type": "number", - "description": "Timeout in seconds for fast recognition mode. Shorter timeout for quick responses." - }, - "minConfidence": { - "type": "number", - "description": "Minimum confidence score (0-1) required to accept a recognition result. Results below this threshold are discarded.", - "minimum": 0, - "maximum": 1 - }, - "deepgramOptions": { "$ref": "recognizer-deepgramOptions" }, - "googleOptions": { "$ref": "recognizer-googleOptions" }, - "awsOptions": { "$ref": "recognizer-awsOptions" }, - "azureOptions": { "$ref": "recognizer-azureOptions" }, - "nuanceOptions": { "$ref": "recognizer-nuanceOptions" }, - "ibmOptions": { "$ref": "recognizer-ibmOptions" }, - "nvidiaOptions": { "$ref": "recognizer-nvidiaOptions" }, - "sonioxOptions": { "$ref": "recognizer-sonioxOptions" }, - "cobaltOptions": { "$ref": "recognizer-cobaltOptions" }, - "assemblyAiOptions": { "$ref": "recognizer-assemblyAiOptions" }, - "speechmaticsOptions": { "$ref": "recognizer-speechmaticsOptions" }, - "openaiOptions": { "$ref": "recognizer-openaiOptions" }, - "houndifyOptions": { "$ref": "recognizer-houndifyOptions" }, - "gladiaOptions": { "$ref": "recognizer-gladiaOptions" }, - "elevenlabsOptions": { "$ref": "recognizer-elevenlabsOptions" }, - "verbioOptions": { "$ref": "recognizer-verbioOptions" }, - "customOptions": { "$ref": "recognizer-customOptions" } - }, - "required": ["vendor"], - "examples": [ - { - "vendor": "deepgram", - "language": "en-US", - "deepgramOptions": { - "model": "nova-2", - "smartFormatting": true, - "endpointing": 500 - } - }, - { - "vendor": "google", - "language": "en-US", - "hints": ["jambonz", "drachtio"], - "punctuation": true, - "enhancedModel": true - } - ] -} diff --git a/schema/components/synthesizer.schema.json b/schema/components/synthesizer.schema.json deleted file mode 100644 index c938efc..0000000 --- a/schema/components/synthesizer.schema.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/components/synthesizer", - "title": "Synthesizer", - "description": "Configuration for text-to-speech synthesis. Specifies the TTS vendor, voice, language, and vendor-specific options. Can be set at the session level via the 'config' verb or overridden per-verb (e.g. on 'say').", - "type": "object", - "properties": { - "vendor": { - "type": "string", - "description": "The TTS vendor to use. Must match a vendor configured in the jambonz platform.", - "examples": ["google", "aws", "microsoft", "elevenlabs", "cartesia", "deepgram", "ibm", "nuance", "nvidia", "wellsaid", "whisper", "verbio", "custom"] - }, - "label": { - "type": "string", - "description": "An optional label identifying a specific credential set for this vendor. Used when multiple credentials are configured for the same vendor on the jambonz platform." - }, - "language": { - "type": "string", - "description": "The language code for speech synthesis, in BCP-47 format.", - "examples": ["en-US", "en-GB", "es-ES", "fr-FR", "de-DE"] - }, - "voice": { - "oneOf": [ - { "type": "string" }, - { "type": "object", "additionalProperties": true } - ], - "description": "The voice to use for synthesis. Format varies by vendor: Google uses voice names like 'en-US-Wavenet-D', AWS Polly uses names like 'Joanna', but ElevenLabs and Cartesia require voice IDs (alphanumeric strings like 'EXAVITQu4vr4xnSDxMaL'), not human-readable names. Some vendors accept an object for more complex voice configuration.", - "examples": ["en-US-Wavenet-D", "Joanna", "EXAVITQu4vr4xnSDxMaL"] - }, - "fallbackVendor": { - "type": "string", - "description": "A backup TTS vendor to use if the primary vendor fails or is unavailable." - }, - "fallbackLabel": { - "type": "string", - "description": "Credential label for the fallback vendor." - }, - "fallbackLanguage": { - "type": "string", - "description": "Language code to use with the fallback vendor." - }, - "fallbackVoice": { - "oneOf": [ - { "type": "string" }, - { "type": "object", "additionalProperties": true } - ], - "description": "Voice to use with the fallback vendor." - }, - "engine": { - "type": "string", - "description": "The synthesis engine tier to use. Availability depends on the vendor.", - "enum": ["standard", "neural", "generative", "long-form"] - }, - "gender": { - "type": "string", - "description": "Preferred voice gender. Used by some vendors (e.g. Google) when a specific voice is not specified.", - "enum": ["MALE", "FEMALE", "NEUTRAL"] - }, - "options": { - "type": "object", - "description": "Vendor-specific options passed through to the TTS provider. The structure depends on the vendor being used.", - "additionalProperties": true - } - }, - "required": ["vendor"], - "examples": [ - { - "vendor": "google", - "language": "en-US", - "voice": "en-US-Wavenet-D" - }, - { - "vendor": "elevenlabs", - "voice": "Rachel", - "options": { - "model_id": "eleven_turbo_v2", - "stability": 0.5, - "similarity_boost": 0.75 - } - } - ] -} diff --git a/schema/components/target.schema.json b/schema/components/target.schema.json deleted file mode 100644 index 6268cc6..0000000 --- a/schema/components/target.schema.json +++ /dev/null @@ -1,105 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/components/target", - "title": "Target", - "description": "A call target for the 'dial' verb. Specifies who or what to connect the call to: a phone number (PSTN), a SIP endpoint, a registered user, or a Microsoft Teams user.", - "type": "object", - "properties": { - "type": { - "type": "string", - "description": "The type of target to dial.", - "enum": ["phone", "sip", "user", "teams"] - }, - "number": { - "type": "string", - "description": "The phone number to dial. Required when type is 'phone'. Use E.164 format.", - "examples": ["+15085551212"] - }, - "sipUri": { - "type": "string", - "description": "The SIP URI to dial. Required when type is 'sip'.", - "examples": ["sip:alice@example.com"] - }, - "name": { - "type": "string", - "description": "The registered user name to dial. Required when type is 'user'. Also used as the display name for SIP targets." - }, - "tenant": { - "type": "string", - "description": "The Microsoft Teams tenant ID. Required when type is 'teams'." - }, - "trunk": { - "type": "string", - "description": "The SIP trunk to use for the outbound call. When specified, overrides the default carrier routing." - }, - "confirmHook": { - "oneOf": [ - { "type": "string", "format": "uri" }, - { "$ref": "actionHook" } - ], - "description": "A webhook to invoke when the target answers, before connecting the call. Use this to screen calls, play a whisper prompt, or require the target to press a key to accept." - }, - "method": { - "type": "string", - "description": "The HTTP method to use when invoking the confirmHook.", - "enum": ["GET", "POST"], - "default": "POST" - }, - "headers": { - "type": "object", - "description": "Custom SIP headers to include on the outbound INVITE. Keys are header names, values are header values.", - "additionalProperties": { "type": "string" } - }, - "from": { - "type": "object", - "description": "Override the From header on the outbound SIP INVITE.", - "properties": { - "user": { - "type": "string", - "description": "The user part of the SIP From URI." - }, - "host": { - "type": "string", - "description": "The host part of the SIP From URI." - } - } - }, - "auth": { - "$ref": "auth", - "description": "SIP authentication credentials for the outbound call, if the far end requires digest auth." - }, - "vmail": { - "type": "boolean", - "description": "If true, follow the call into voicemail if the target does not answer." - }, - "overrideTo": { - "type": "string", - "description": "Override the Request-URI on the outbound SIP INVITE. Useful when the Request-URI needs to differ from the To header." - }, - "proxy": { - "type": "string", - "description": "A SIP proxy to route the outbound call through, specified as a SIP URI.", - "examples": ["sip:proxy.example.com"] - } - }, - "required": ["type"], - "examples": [ - { - "type": "phone", - "number": "+15085551212" - }, - { - "type": "sip", - "sipUri": "sip:alice@example.com" - }, - { - "type": "user", - "name": "bob" - }, - { - "type": "teams", - "number": "+15085551212", - "tenant": "a]b]c]d]e" - } - ] -} diff --git a/schema/components/vad.schema.json b/schema/components/vad.schema.json deleted file mode 100644 index d33c75a..0000000 --- a/schema/components/vad.schema.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/components/vad", - "title": "VAD", - "description": "Voice Activity Detection configuration. Controls how jambonz detects the presence or absence of speech on the audio channel. Used to determine speech start/end boundaries for recognition and barge-in.", - "type": "object", - "properties": { - "enable": { - "type": "boolean", - "description": "Whether to enable voice activity detection." - }, - "voiceMs": { - "type": "number", - "description": "Duration of voice activity (in milliseconds) required before speech is considered to have started.", - "examples": [250] - }, - "silenceMs": { - "type": "number", - "description": "Duration of silence (in milliseconds) required before speech is considered to have ended.", - "examples": [1000] - }, - "strategy": { - "type": "string", - "description": "The VAD strategy to use." - }, - "mode": { - "type": "number", - "description": "WebRTC VAD aggressiveness mode (0-3). Higher values are more aggressive at filtering non-speech. Only applies when vendor is 'webrtc'.", - "minimum": 0, - "maximum": 3 - }, - "vendor": { - "type": "string", - "description": "The VAD engine to use.", - "enum": ["webrtc", "silero"] - }, - "threshold": { - "type": "number", - "description": "Speech detection confidence threshold for Silero VAD. Value between 0 and 1, where higher values require greater confidence. Only applies when vendor is 'silero'.", - "minimum": 0, - "maximum": 1 - }, - "speechPadMs": { - "type": "number", - "description": "Padding in milliseconds added before and after detected speech segments. Prevents clipping utterance boundaries. Only applies when vendor is 'silero'." - } - } -} diff --git a/schema/jambonz-app.schema.json b/schema/jambonz-app.schema.json deleted file mode 100644 index 323da09..0000000 --- a/schema/jambonz-app.schema.json +++ /dev/null @@ -1,112 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/jambonz-app", - "title": "jambonz Application", - "description": "A jambonz application is an array of verbs that are executed sequentially to control a phone call. Each verb performs an action: speaking text, playing audio, collecting input, dialing a number, connecting to an AI model, etc. When a webhook (actionHook) is invoked, it must return a new verb array to continue call processing.\n\nThe execution model is simple: verbs execute one after another, top to bottom. When a verb with an actionHook completes (e.g. gather collects input), the actionHook is called and its response replaces the remaining verb stack. If the verb array is exhausted without a hangup, the call is terminated.\n\nThere are two transport modes for delivering verb arrays to jambonz:\n- **Webhook**: Your HTTP server receives POST/GET requests with call data and returns JSON verb arrays in the response body.\n- **WebSocket**: Your server maintains a persistent websocket connection with jambonz and sends/receives verb arrays as JSON messages. Required for real-time features like LLM conversations.\n\nThe verb schemas and JSON structure are identical regardless of transport mode.", - "type": "array", - "items": { - "$ref": "#/$defs/Verb" - }, - "minItems": 1, - "$defs": { - "Verb": { - "oneOf": [ - { "$ref": "verbs/answer" }, - { "$ref": "verbs/alert" }, - { "$ref": "verbs/config" }, - { "$ref": "verbs/say" }, - { "$ref": "verbs/play" }, - { "$ref": "verbs/gather" }, - { "$ref": "verbs/dial" }, - { "$ref": "verbs/listen" }, - { "$ref": "verbs/stream" }, - { "$ref": "verbs/llm" }, - { "$ref": "verbs/s2s" }, - { "$ref": "verbs/openai_s2s" }, - { "$ref": "verbs/google_s2s" }, - { "$ref": "verbs/elevenlabs_s2s" }, - { "$ref": "verbs/deepgram_s2s" }, - { "$ref": "verbs/ultravox_s2s" }, - { "$ref": "verbs/dialogflow" }, - { "$ref": "verbs/pipeline" }, - { "$ref": "verbs/conference" }, - { "$ref": "verbs/transcribe" }, - { "$ref": "verbs/enqueue" }, - { "$ref": "verbs/dequeue" }, - { "$ref": "verbs/dtmf" }, - { "$ref": "verbs/dub" }, - { "$ref": "verbs/hangup" }, - { "$ref": "verbs/leave" }, - { "$ref": "verbs/message" }, - { "$ref": "verbs/pause" }, - { "$ref": "verbs/redirect" }, - { "$ref": "verbs/tag" }, - { "$ref": "verbs/sip:decline" }, - { "$ref": "verbs/sip:request" }, - { "$ref": "verbs/sip:refer" } - ], - "discriminator": { - "propertyName": "verb" - } - } - }, - "examples": [ - [ - { - "verb": "config", - "synthesizer": { "vendor": "elevenlabs", "voice": "EXAVITQu4vr4xnSDxMaL", "language": "en-US" }, - "recognizer": { "vendor": "deepgram", "language": "en-US" } - }, - { - "verb": "say", - "text": "Hello! Welcome to Acme Corp. How can I help you today?" - }, - { - "verb": "gather", - "input": ["speech"], - "actionHook": "/process-input", - "timeout": 15, - "say": { "text": "I'm listening." } - } - ], - [ - { - "verb": "say", - "text": "Please hold while I connect you to an agent." - }, - { - "verb": "dial", - "target": [{ "type": "phone", "number": "+15085551212" }], - "answerOnBridge": true, - "timeout": 30, - "actionHook": "/dial-complete" - }, - { - "verb": "say", - "text": "Sorry, the agent is not available. Please try again later." - }, - { - "verb": "hangup" - } - ], - [ - { - "verb": "config", - "synthesizer": { "vendor": "cartesia", "voice": "sonic-english" }, - "recognizer": { "vendor": "deepgram", "language": "en-US" } - }, - { - "verb": "openai_s2s", - "model": "gpt-4o", - "llmOptions": { - "messages": [ - { "role": "system", "content": "You are a helpful customer service agent for Acme Corp. Be concise and friendly." } - ], - "temperature": 0.7 - }, - "actionHook": "/llm-complete", - "toolHook": "/llm-tool" - } - ] - ] -} diff --git a/schema/verbs/alert.schema.json b/schema/verbs/alert.schema.json deleted file mode 100644 index 3ae3832..0000000 --- a/schema/verbs/alert.schema.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/alert", - "minVersion": "0.9.6", - "title": "Alert", - "description": "Sends a 180 Ringing provisional response with an Alert-Info header. Used to trigger a specific ring tone or alert behavior on the caller's device before the call is answered.", - "type": "object", - "properties": { - "verb": { - "const": "alert" - }, - "id": { - "type": "string", - "description": "An optional unique identifier for this verb instance." - }, - "message": { - "type": "string", - "description": "The value to include in the Alert-Info header.", - "examples": [ - "info=alert-internal", - "http://example.com/ringtone.wav" - ] - } - }, - "required": [ - "message" - ], - "examples": [ - { - "verb": "alert", - "message": "info=alert-internal" - } - ] -} diff --git a/schema/verbs/answer.schema.json b/schema/verbs/answer.schema.json deleted file mode 100644 index dea0b61..0000000 --- a/schema/verbs/answer.schema.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/answer", - "minVersion": "0.9.6", - "title": "Answer", - "description": "Answers an incoming call (sends a 200 OK to the SIP INVITE). Most verbs implicitly answer the call, so this verb is only needed when you want to explicitly control when the call is answered — for example, to play early media before answering.", - "type": "object", - "properties": { - "verb": { - "const": "answer" - }, - "id": { - "type": "string", - "description": "An optional unique identifier for this verb instance." - } - }, - "examples": [ - { - "verb": "answer" - } - ] -} diff --git a/schema/verbs/conference.schema.json b/schema/verbs/conference.schema.json deleted file mode 100644 index 55654d3..0000000 --- a/schema/verbs/conference.schema.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/conference", - "minVersion": "0.9.6", - "title": "Conference", - "description": "Places the caller into a multi-party conference room. Multiple callers in the same named conference can speak to each other. Supports features like muting, recording, waiting rooms, and participant limits.", - "type": "object", - "properties": { - "verb": { - "const": "conference" - }, - "id": { - "type": "string", - "description": "An optional unique identifier for this verb instance." - }, - "name": { - "type": "string", - "description": "The name of the conference room. All callers joining the same named conference are connected together.", - "examples": [ - "team-standup", - "customer-call-12345" - ] - }, - "beep": { - "type": "boolean", - "description": "If true, play a beep when participants join or leave." - }, - "memberTag": { - "type": "string", - "description": "A tag to identify this participant. Can be used to target specific members for actions like muting or whispering." - }, - "speakOnlyTo": { - "type": "string", - "description": "If set, this participant's audio is only heard by the member with the specified memberTag. Creates a private whisper channel." - }, - "startConferenceOnEnter": { - "type": "boolean", - "description": "If true (default), the conference starts when this participant joins. If false, this participant waits silently until a participant with startConferenceOnEnter=true joins." - }, - "endConferenceOnExit": { - "type": "boolean", - "description": "If true, the conference ends for all participants when this participant leaves." - }, - "endConferenceDuration": { - "type": "number", - "description": "Maximum duration of the conference in seconds." - }, - "maxParticipants": { - "type": "number", - "description": "Maximum number of participants allowed in the conference." - }, - "joinMuted": { - "type": "boolean", - "description": "If true, this participant joins the conference muted." - }, - "actionHook": { - "$ref": "../components/actionHook", - "description": "A webhook invoked when this participant leaves the conference." - }, - "waitHook": { - "$ref": "../components/actionHook", - "description": "A webhook invoked while this participant is waiting for the conference to start. Should return verbs to play (e.g. hold music)." - }, - "statusEvents": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of conference events to receive via the statusHook." - }, - "statusHook": { - "$ref": "../components/actionHook", - "description": "A webhook to receive conference status events (joins, leaves, etc.)." - }, - "enterHook": { - "$ref": "../components/actionHook", - "description": "A webhook invoked when this participant first enters the conference." - }, - "record": { - "type": "object", - "description": "Recording configuration for the conference.", - "additionalProperties": true - }, - "listen": { - "type": "object", - "description": "Audio streaming configuration for the conference.", - "additionalProperties": true - }, - "distributeDtmf": { - "type": "boolean", - "description": "If true, DTMF events from this participant are distributed to all other participants." - } - }, - "required": [ - "name" - ], - "examples": [ - { - "verb": "conference", - "name": "team-standup", - "beep": true, - "startConferenceOnEnter": true, - "endConferenceOnExit": false, - "statusHook": "/conference-events" - } - ] -} diff --git a/schema/verbs/config.schema.json b/schema/verbs/config.schema.json deleted file mode 100644 index 0e40c87..0000000 --- a/schema/verbs/config.schema.json +++ /dev/null @@ -1,218 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/config", - "minVersion": "0.9.6", - "title": "Config", - "description": "Sets session-level defaults for the call. Configures default TTS, STT, VAD, recording, streaming, and other session-wide settings. These defaults apply to all subsequent verbs unless overridden at the verb level. Typically the first verb in an application. Can be used multiple times during a call to change settings.", - "type": "object", - "properties": { - "verb": { - "const": "config", - "description": "The verb name." - }, - "id": { - "type": "string", - "description": "An optional unique identifier for this verb instance." - }, - "synthesizer": { - "$ref": "../components/synthesizer", - "description": "Default TTS configuration for the session." - }, - "recognizer": { - "$ref": "../components/recognizer", - "description": "Default STT configuration for the session." - }, - "bargeIn": { - "type": "object", - "description": "Default barge-in configuration. When enabled, callers can interrupt playing prompts with speech or DTMF.", - "properties": { - "enable": { - "type": "boolean" - }, - "sticky": { - "type": "boolean", - "description": "If true, barge-in settings persist across verbs rather than resetting after each verb." - }, - "actionHook": { - "$ref": "../components/actionHook" - }, - "input": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "speech", - "digits" - ] - } - }, - "minBargeinWordCount": { - "type": "number" - } - } - }, - "ttsStream": { - "type": "object", - "description": "Default TTS streaming configuration for the session.", - "properties": { - "enable": { - "type": "boolean" - }, - "synthesizer": { - "$ref": "../components/synthesizer" - } - } - }, - "record": { - "type": "object", - "description": "Session-level call recording configuration.", - "additionalProperties": true - }, - "listen": { - "$ref": "listen", - "description": "Nested listen verb — session-level audio streaming configuration." - }, - "stream": { - "$ref": "stream", - "description": "Nested stream verb — session-level audio streaming configuration. Alias for 'listen'." - }, - "transcribe": { - "$ref": "transcribe", - "description": "Nested transcribe verb — session-level real-time transcription configuration." - }, - "amd": { - "$ref": "../components/amd", - "description": "Session-level answering machine detection configuration." - }, - "fillerNoise": { - "$ref": "../components/fillerNoise", - "description": "Default filler noise configuration for the session." - }, - "vad": { - "$ref": "../components/vad", - "description": "Default voice activity detection configuration for the session." - }, - "notifyEvents": { - "type": "boolean", - "description": "If true, send call events (e.g. DTMF, call status changes) to the application via the status webhook." - }, - "notifySttLatency": { - "type": "boolean", - "description": "If true, include STT latency measurements in webhook payloads." - }, - "reset": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ], - "description": "Reset specific session-level settings to their defaults. Pass a setting name or array of setting names to reset." - }, - "onHoldMusic": { - "type": "string", - "format": "uri", - "description": "URL of an audio file to play when the call is placed on hold." - }, - "actionHookDelayAction": { - "$ref": "../components/actionHookDelayAction", - "description": "Default configuration for handling slow webhook responses." - }, - "sipRequestWithinDialogHook": { - "$ref": "../components/actionHook", - "description": "A webhook to invoke when a SIP request (e.g. INFO, NOTIFY) is received within the dialog." - }, - "boostAudioSignal": { - "oneOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ], - "description": "Boost (or attenuate) the audio signal in dB for the session." - }, - "referHook": { - "$ref": "../components/actionHook", - "description": "A webhook to invoke when a SIP REFER request is received." - }, - "earlyMedia": { - "type": "boolean", - "description": "If true, allow early media (audio before call answer) for the session." - }, - "autoStreamTts": { - "type": "boolean", - "description": "If true, automatically use streaming TTS for all 'say' verbs in the session." - }, - "disableTtsCache": { - "type": "boolean", - "description": "If true, disable TTS caching for the session." - }, - "trackTtsPlayout": { - "type": "boolean", - "description": "If true, report the actual text spoken via TTS. Requires a TTS vendor that supports alignment data (e.g. ElevenLabs). On each utterance completion or interruption, a tts_spoken event is sent to the '/streaming-event' endpoint with fields: 'text' (string — the text actually spoken) and 'bargein' (boolean — true if the user interrupted before TTS finished). See the tts-streaming-event callback schema for full details." - }, - "noiseIsolation": { - "type": "object", - "description": "Noise isolation configuration to reduce background noise on call audio. Defaults to filtering inbound (caller) audio; can also filter outbound audio via the direction option.", - "properties": { - "enable": { - "type": "boolean" - }, - "vendor": { - "type": "string" - }, - "level": { - "type": "number" - }, - "model": { - "type": "string" - } - } - }, - "turnTaking": { - "type": "object", - "description": "Turn-taking detection configuration for conversational AI applications.", - "properties": { - "enable": { - "type": "boolean" - }, - "vendor": { - "type": "string" - }, - "threshold": { - "type": "number" - }, - "model": { - "type": "string" - } - } - } - }, - "required": [], - "examples": [ - { - "verb": "config", - "synthesizer": { - "vendor": "elevenlabs", - "voice": "Rachel", - "language": "en-US" - }, - "recognizer": { - "vendor": "deepgram", - "language": "en-US" - }, - "fillerNoise": { - "enable": true, - "url": "https://example.com/sounds/typing.wav", - "startDelaySecs": 2 - } - } - ] -} diff --git a/schema/verbs/deepgram_s2s.schema.json b/schema/verbs/deepgram_s2s.schema.json deleted file mode 100644 index ffd4054..0000000 --- a/schema/verbs/deepgram_s2s.schema.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/deepgram_s2s", - "minVersion": "10.1.0", - "title": "Deepgram S2S", - "description": "Shortcut for 'llm' with vendor automatically set to 'deepgram'. Connects the caller to a Deepgram model for real-time speech-to-speech voice conversation.", - "type": "object", - "allOf": [ - { - "$ref": "../components/llm-base" - } - ], - "properties": { - "verb": { - "const": "deepgram_s2s", - "description": "The verb name." - }, - "vendor": { - "type": "string", - "const": "deepgram", - "description": "The LLM vendor (always 'deepgram' for this shortcut)." - }, - "llmOptions": { - "type": "object", - "description": "IMPORTANT: Deepgram does NOT use a 'messages' array. The llmOptions must contain a 'Settings' object with 'agent.think' (LLM provider, model, and prompt) and 'agent.speak' (TTS provider and voice model). The system prompt goes in Settings.agent.think.prompt, NOT in messages.", - "additionalProperties": true, - "examples": [ - { - "Settings": { - "agent": { - "think": { - "provider": { - "type": "open_ai", - "model": "gpt-4o" - }, - "prompt": "You are a helpful voice assistant." - }, - "speak": { - "provider": { - "type": "deepgram", - "model": "aura-2-thalia-en" - } - } - } - } - } - ] - } - }, - "required": [ - "llmOptions" - ], - "examples": [ - { - "verb": "deepgram_s2s", - "auth": { - "apiKey": "your-deepgram-api-key" - }, - "llmOptions": { - "Settings": { - "agent": { - "think": { - "provider": { - "type": "open_ai", - "model": "gpt-4o" - }, - "prompt": "You are a helpful voice assistant." - }, - "speak": { - "provider": { - "type": "deepgram", - "model": "aura-2-thalia-en" - } - } - } - } - }, - "actionHook": "/s2s-complete" - } - ] -} diff --git a/schema/verbs/dequeue.schema.json b/schema/verbs/dequeue.schema.json deleted file mode 100644 index b58efe8..0000000 --- a/schema/verbs/dequeue.schema.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/dequeue", - "minVersion": "0.9.6", - "title": "Dequeue", - "description": "Removes a caller from a named queue and bridges them to the current call. Typically used by an agent or operator call flow to connect with the next waiting caller.", - "type": "object", - "properties": { - "verb": { - "const": "dequeue" - }, - "id": { - "type": "string", - "description": "An optional unique identifier for this verb instance." - }, - "name": { - "type": "string", - "description": "The name of the queue to dequeue from.", - "examples": [ - "support", - "sales" - ] - }, - "actionHook": { - "$ref": "../components/actionHook", - "description": "A webhook invoked when the dequeued call ends." - }, - "timeout": { - "type": "number", - "description": "Time in seconds to wait for a caller to be available in the queue." - }, - "beep": { - "type": "boolean", - "description": "If true, play a beep when the calls are connected." - }, - "callSid": { - "type": "string", - "description": "Dequeue a specific call by its call SID, rather than the next caller in line." - } - }, - "required": [ - "name" - ], - "examples": [ - { - "verb": "dequeue", - "name": "support", - "beep": true - } - ] -} diff --git a/schema/verbs/dial.schema.json b/schema/verbs/dial.schema.json deleted file mode 100644 index 54a85af..0000000 --- a/schema/verbs/dial.schema.json +++ /dev/null @@ -1,187 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/dial", - "minVersion": "0.9.6", - "title": "Dial", - "description": "Initiates an outbound call to one or more targets and bridges the caller to the first target that answers. Targets can be phone numbers (PSTN), SIP endpoints, registered users, or Microsoft Teams users. Supports simultaneous ringing, call screening, recording, and DTMF capture during the bridged call.", - "type": "object", - "properties": { - "verb": { - "const": "dial", - "description": "The verb name." - }, - "id": { - "type": "string", - "description": "An optional unique identifier for this verb instance." - }, - "target": { - "type": "array", - "items": { - "$ref": "../components/target" - }, - "description": "One or more call targets to dial. If multiple targets are specified, they are rung simultaneously and the first to answer is connected. The rest are canceled.", - "minItems": 1 - }, - "actionHook": { - "$ref": "../components/actionHook", - "description": "A webhook invoked when the dialed call ends. Receives call disposition details (duration, who hung up, etc.) and should return the next verbs to execute." - }, - "onHoldHook": { - "$ref": "../components/actionHook", - "description": "A webhook invoked when the call is placed on hold. Should return verbs to execute (e.g. play hold music) while the caller is holding." - }, - "answerOnBridge": { - "type": "boolean", - "description": "If true, delay answering the inbound call until the outbound leg is answered. This allows the caller to hear ringing until the target picks up, and avoids billing the caller for unanswered outbound attempts." - }, - "callerId": { - "type": "string", - "description": "The caller ID (phone number) to present on the outbound call. Overrides the default caller ID.", - "examples": [ - "+15085551212" - ] - }, - "callerName": { - "type": "string", - "description": "The caller display name to present on the outbound call." - }, - "confirmHook": { - "$ref": "../components/actionHook", - "description": "A webhook invoked when a target answers, before the call is bridged. Used for call screening — the webhook can return verbs (e.g. a 'say' prompt and 'gather') to confirm the callee wants to accept the call." - }, - "referHook": { - "$ref": "../components/actionHook", - "description": "A webhook invoked when a SIP REFER is received on the bridged call. Allows handling call transfers initiated by the far end." - }, - "dialMusic": { - "type": "string", - "format": "uri", - "description": "URL of an audio file to play to the caller while the outbound call is ringing. Replaces the default ringback tone." - }, - "dtmfCapture": { - "type": "object", - "description": "Configuration for capturing DTMF digits during the bridged call. Keys are DTMF patterns to capture, values are configuration for each.", - "additionalProperties": true - }, - "dtmfHook": { - "$ref": "../components/actionHook", - "description": "A webhook invoked when a captured DTMF pattern is detected during the bridged call." - }, - "headers": { - "type": "object", - "description": "Custom SIP headers to include on the outbound INVITE.", - "additionalProperties": { - "type": "string" - } - }, - "anchorMedia": { - "type": "boolean", - "description": "If true, keep media anchored through the jambonz media server even if a direct media path is possible. Required for features like recording, listen, and DTMF capture during bridged calls." - }, - "exitMediaPath": { - "type": "boolean", - "description": "If true, remove jambonz from the media path after the call is bridged. Reduces latency but disables mid-call features like recording and DTMF capture." - }, - "boostAudioSignal": { - "oneOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ], - "description": "Boost (or attenuate) the audio signal in dB. Positive values increase volume, negative values decrease it.", - "examples": [ - 6, - -3 - ] - }, - "listen": { - "$ref": "listen", - "description": "Nested listen verb — streams audio of the bridged call to a websocket endpoint." - }, - "stream": { - "$ref": "stream", - "description": "Nested stream verb — streams audio of the bridged call. Alias for 'listen'." - }, - "transcribe": { - "$ref": "transcribe", - "description": "Nested transcribe verb — enables real-time transcription of the bridged call." - }, - "timeLimit": { - "type": "number", - "description": "Maximum duration in seconds for the bridged call. The call is automatically hung up when this limit is reached.", - "examples": [ - 3600 - ] - }, - "timeout": { - "type": "number", - "description": "Time in seconds to wait for the target to answer before giving up.", - "examples": [ - 30, - 60 - ] - }, - "proxy": { - "type": "string", - "description": "A SIP proxy to route the outbound call through.", - "examples": [ - "sip:proxy.example.com" - ] - }, - "amd": { - "$ref": "../components/amd", - "description": "Answering machine detection configuration. When enabled, jambonz attempts to determine whether the call was answered by a human or a machine." - }, - "dub": { - "type": "array", - "items": { - "$ref": "dub" - }, - "description": "Nested dub verbs — audio dubbing configuration for mixing additional audio tracks into the bridged call." - }, - "tag": { - "type": "object", - "description": "Arbitrary metadata to attach to this call leg. Included in subsequent webhook invocations and CDRs.", - "additionalProperties": true - }, - "forwardPAI": { - "type": "boolean", - "description": "If true, forward the P-Asserted-Identity header from the inbound call to the outbound call." - } - }, - "required": [ - "target" - ], - "examples": [ - { - "verb": "dial", - "target": [ - { - "type": "phone", - "number": "+15085551212" - } - ], - "answerOnBridge": true, - "timeout": 30, - "actionHook": "/dial-complete" - }, - { - "verb": "dial", - "target": [ - { - "type": "sip", - "sipUri": "sip:alice@example.com" - }, - { - "type": "sip", - "sipUri": "sip:bob@example.com" - } - ], - "confirmHook": "/screen-call", - "timeLimit": 3600 - } - ] -} diff --git a/schema/verbs/dialogflow.schema.json b/schema/verbs/dialogflow.schema.json deleted file mode 100644 index a02b347..0000000 --- a/schema/verbs/dialogflow.schema.json +++ /dev/null @@ -1,148 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/dialogflow", - "minVersion": "0.9.6", - "title": "Dialogflow", - "description": "Connects the caller to a Google Dialogflow agent for a voice conversation. Supports Dialogflow ES, CX, and CES models. The caller speaks and Dialogflow handles intent detection and response generation.", - "type": "object", - "properties": { - "verb": { - "const": "dialogflow", - "description": "The verb name." - }, - "id": { - "type": "string", - "description": "An optional unique identifier for this verb instance." - }, - "credentials": { - "oneOf": [ - { - "type": "object", - "additionalProperties": true - }, - { - "type": "string" - } - ], - "description": "Google service account credentials as a JSON object or stringified JSON." - }, - "project": { - "type": "string", - "description": "The Google Cloud project ID." - }, - "agent": { - "type": "string", - "description": "The Dialogflow agent ID. Required for CX agents." - }, - "environment": { - "type": "string", - "description": "The Dialogflow environment to use." - }, - "region": { - "type": "string", - "description": "The Google Cloud region for the Dialogflow API endpoint." - }, - "model": { - "type": "string", - "enum": [ - "es", - "cx", - "ces" - ], - "description": "The Dialogflow model type: 'es' for Dialogflow ES, 'cx' for Dialogflow CX, 'ces' for Dialogflow CES." - }, - "lang": { - "type": "string", - "description": "The language code for the conversation (e.g. 'en-US')." - }, - "actionHook": { - "$ref": "../components/actionHook", - "description": "A webhook invoked when the Dialogflow session ends." - }, - "eventHook": { - "$ref": "../components/actionHook", - "description": "A webhook invoked for Dialogflow events during the conversation." - }, - "events": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of event types to receive via the eventHook." - }, - "welcomeEvent": { - "type": "string", - "description": "A Dialogflow event to trigger at the start of the conversation (e.g. 'welcome')." - }, - "welcomeEventParams": { - "type": "object", - "description": "Parameters to pass with the welcome event.", - "additionalProperties": true - }, - "noInputTimeout": { - "type": "number", - "description": "Seconds to wait for caller input before triggering the no-input event." - }, - "noInputEvent": { - "type": "string", - "description": "Dialogflow event to trigger when no input is received within the timeout." - }, - "passDtmfAsTextInput": { - "type": "boolean", - "description": "If true, pass DTMF digits to Dialogflow as text input." - }, - "thinkingMusic": { - "type": "string", - "description": "URL of an audio file to play while waiting for Dialogflow to respond." - }, - "tts": { - "$ref": "../components/synthesizer", - "description": "TTS configuration for Dialogflow responses." - }, - "bargein": { - "type": "boolean", - "description": "If true, allow the caller to interrupt Dialogflow responses with speech." - }, - "queryInput": { - "type": "object", - "description": "Initial query input to send to Dialogflow.", - "properties": { - "text": { - "type": "string", - "description": "Text input." - }, - "intent": { - "type": "string", - "description": "Intent to trigger." - }, - "event": { - "type": "string", - "description": "Event to trigger." - }, - "dtmf": { - "type": "string", - "description": "DTMF input." - } - }, - "additionalProperties": false - } - }, - "required": [ - "project", - "credentials", - "lang" - ], - "examples": [ - { - "verb": "dialogflow", - "project": "my-gcp-project", - "credentials": "{\"type\": \"service_account\", \"project_id\": \"my-gcp-project\"}", - "lang": "en-US", - "model": "cx", - "agent": "my-agent-id", - "welcomeEvent": "welcome", - "actionHook": "/dialogflow-action", - "eventHook": "/dialogflow-event" - } - ] -} diff --git a/schema/verbs/dtmf.schema.json b/schema/verbs/dtmf.schema.json deleted file mode 100644 index fe0ea13..0000000 --- a/schema/verbs/dtmf.schema.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/dtmf", - "minVersion": "0.9.6", - "title": "DTMF", - "description": "Sends DTMF tones on the call. Used to interact with IVR systems on the far end, or to signal systems that respond to DTMF.", - "type": "object", - "properties": { - "verb": { - "const": "dtmf" - }, - "id": { - "type": "string", - "description": "An optional unique identifier for this verb instance." - }, - "dtmf": { - "type": "string", - "description": "The DTMF digits to send. Valid characters are 0-9, *, #, and A-D. Use 'w' for a 500ms pause between digits.", - "examples": [ - "1234#", - "1w2w3", - "5551212" - ] - }, - "duration": { - "type": "number", - "description": "Duration in milliseconds for each DTMF tone.", - "default": 500, - "examples": [ - 250, - 500 - ] - } - }, - "required": [ - "dtmf" - ], - "examples": [ - { - "verb": "dtmf", - "dtmf": "1234#" - }, - { - "verb": "dtmf", - "dtmf": "1w2w3w4", - "duration": 250 - } - ] -} diff --git a/schema/verbs/dub.schema.json b/schema/verbs/dub.schema.json deleted file mode 100644 index ca83414..0000000 --- a/schema/verbs/dub.schema.json +++ /dev/null @@ -1,103 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/dub", - "minVersion": "0.9.6", - "title": "Dub", - "description": "Manages audio dubbing tracks on a call. Allows adding, removing, and controlling auxiliary audio tracks that are mixed into the call audio. Used for background music, coaching whispers, or injecting audio from external sources.", - "type": "object", - "properties": { - "verb": { - "const": "dub" - }, - "id": { - "type": "string", - "description": "An optional unique identifier for this verb instance." - }, - "action": { - "type": "string", - "description": "The dubbing action to perform.", - "enum": [ - "addTrack", - "removeTrack", - "silenceTrack", - "playOnTrack", - "sayOnTrack" - ] - }, - "track": { - "type": "string", - "description": "The name of the audio track. Used to reference the track in subsequent dub actions.", - "examples": [ - "background-music", - "coach-whisper" - ] - }, - "play": { - "type": "string", - "format": "uri", - "description": "URL of an audio file to play on the track. Used with 'playOnTrack' action." - }, - "say": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "object", - "additionalProperties": true - } - ], - "description": "Text to synthesize and play on the track. Used with 'sayOnTrack' action. Can be a string or a say configuration object." - }, - "loop": { - "type": "boolean", - "description": "If true, loop the audio on the track continuously." - }, - "gain": { - "oneOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ], - "description": "Audio gain for the track in dB. Use negative values to reduce volume.", - "examples": [ - -10, - 0, - 6 - ] - } - }, - "required": [ - "action", - "track" - ], - "examples": [ - { - "verb": "dub", - "action": "addTrack", - "track": "bgm" - }, - { - "verb": "dub", - "action": "playOnTrack", - "track": "bgm", - "play": "https://example.com/music.mp3", - "loop": true, - "gain": -15 - }, - { - "verb": "dub", - "action": "sayOnTrack", - "track": "coach", - "say": "Ask about their budget" - }, - { - "verb": "dub", - "action": "removeTrack", - "track": "bgm" - } - ] -} diff --git a/schema/verbs/elevenlabs_s2s.schema.json b/schema/verbs/elevenlabs_s2s.schema.json deleted file mode 100644 index c20bbc6..0000000 --- a/schema/verbs/elevenlabs_s2s.schema.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/elevenlabs_s2s", - "minVersion": "10.1.0", - "title": "ElevenLabs S2S", - "description": "Shortcut for 'llm' with vendor automatically set to 'elevenlabs'. Connects the caller to an ElevenLabs Conversational AI agent for real-time speech-to-speech voice conversation. Unlike other s2s vendors, ElevenLabs requires a pre-configured agent_id rather than a model and messages.", - "type": "object", - "allOf": [ - { - "$ref": "../components/llm-base" - } - ], - "properties": { - "verb": { - "const": "elevenlabs_s2s", - "description": "The verb name." - }, - "vendor": { - "type": "string", - "const": "elevenlabs", - "description": "The LLM vendor (always 'elevenlabs' for this shortcut)." - }, - "auth": { - "type": "object", - "description": "Authentication credentials for ElevenLabs. Requires agent_id; api_key is optional (if not provided, an unsigned URL is used).", - "properties": { - "agent_id": { - "type": "string", - "description": "The ElevenLabs Conversational AI agent ID. Required." - }, - "api_key": { - "type": "string", - "description": "The ElevenLabs API key. Optional; when provided, a signed URL is used for the WebSocket connection." - } - }, - "required": [ - "agent_id" - ] - }, - "llmOptions": { - "type": "object", - "description": "Options for the ElevenLabs conversation session.", - "properties": { - "conversation_initiation_client_data": { - "type": "object", - "description": "Optional data sent to the agent when the conversation starts.", - "additionalProperties": true - }, - "input_sample_rate": { - "type": "integer", - "description": "Audio input sample rate in Hz.", - "default": 16000 - }, - "output_sample_rate": { - "type": "integer", - "description": "Audio output sample rate in Hz.", - "default": 16000 - } - }, - "additionalProperties": true - } - }, - "required": [ - "auth" - ], - "examples": [ - { - "verb": "elevenlabs_s2s", - "auth": { - "agent_id": "your-elevenlabs-agent-id", - "api_key": "your-elevenlabs-api-key" - }, - "llmOptions": {}, - "actionHook": "/s2s-complete", - "eventHook": "/event", - "events": [ - "all" - ] - } - ] -} diff --git a/schema/verbs/enqueue.schema.json b/schema/verbs/enqueue.schema.json deleted file mode 100644 index c0cf5df..0000000 --- a/schema/verbs/enqueue.schema.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/enqueue", - "minVersion": "0.9.6", - "title": "Enqueue", - "description": "Places the caller into a named call queue. While in the queue, the caller hears content returned by the waitHook (typically hold music or position announcements). The caller remains in the queue until dequeued by another call or process.", - "type": "object", - "properties": { - "verb": { - "const": "enqueue" - }, - "id": { - "type": "string", - "description": "An optional unique identifier for this verb instance." - }, - "name": { - "type": "string", - "description": "The name of the queue to place the caller in. Queues are created implicitly when first referenced.", - "examples": [ - "support", - "sales" - ] - }, - "actionHook": { - "$ref": "../components/actionHook", - "description": "A webhook invoked when the caller leaves the queue (either dequeued or hung up). Should return the next verbs to execute." - }, - "waitHook": { - "$ref": "../components/actionHook", - "description": "A webhook invoked immediately when the caller enters the queue and periodically while waiting. Should return verbs to play to the caller (e.g. hold music, queue position announcements)." - }, - "priority": { - "type": "number", - "description": "The priority of this caller in the queue. Lower numbers are higher priority and are dequeued first.", - "examples": [ - 1, - 5, - 10 - ] - } - }, - "required": [ - "name" - ], - "examples": [ - { - "verb": "enqueue", - "name": "support", - "waitHook": "/queue-wait", - "actionHook": "/queue-exit" - } - ] -} diff --git a/schema/verbs/gather.schema.json b/schema/verbs/gather.schema.json deleted file mode 100644 index cc08fd5..0000000 --- a/schema/verbs/gather.schema.json +++ /dev/null @@ -1,188 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/gather", - "minVersion": "0.9.6", - "title": "Gather", - "description": "Collects user input via speech (STT) and/or DTMF digits. Optionally plays a prompt (using nested 'say' or 'play') while listening. When input is received, the result is sent to the actionHook which should return the next set of verbs. This is the primary verb for building interactive voice menus and conversational flows.", - "type": "object", - "properties": { - "verb": { - "const": "gather", - "description": "The verb name." - }, - "id": { - "type": "string", - "description": "An optional unique identifier for this verb instance." - }, - "actionHook": { - "$ref": "../components/actionHook", - "description": "Invoked when the gather completes. The payload includes 'reason' ('speechDetected', 'dtmfDetected', or 'timeout'), 'speech' (object with alternatives[].transcript and alternatives[].confidence when reason is speechDetected), and 'digits' (string when reason is dtmfDetected). In webhook mode this is a URL that receives an HTTP POST. In WebSocket mode this is an event name — use session.on('/hookName', (evt) => {...}) and respond with session.reply()." - }, - "input": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "speech", - "digits" - ] - }, - "description": "The types of input to accept. Can include 'speech' (STT), 'digits' (DTMF), or both.", - "default": [ - "digits" - ], - "examples": [ - [ - "speech", - "digits" - ], - [ - "speech" - ], - [ - "digits" - ] - ] - }, - "finishOnKey": { - "type": "string", - "description": "A DTMF key that signals the end of digit input. The key itself is not included in the collected digits.", - "examples": [ - "#", - "*" - ] - }, - "numDigits": { - "type": "number", - "description": "Exact number of DTMF digits to collect. Gather completes automatically when this many digits are received." - }, - "minDigits": { - "type": "number", - "description": "Minimum number of DTMF digits required." - }, - "maxDigits": { - "type": "number", - "description": "Maximum number of DTMF digits to collect." - }, - "interDigitTimeout": { - "type": "number", - "description": "Time in seconds to wait between DTMF digits before considering input complete.", - "examples": [ - 5 - ] - }, - "speechTimeout": { - "type": "number", - "description": "Time in seconds of silence after speech before considering the utterance complete.", - "examples": [ - 2, - 3 - ] - }, - "timeout": { - "type": "number", - "description": "Overall timeout in seconds. If no input is received within this time, the gather completes with no input and the actionHook is invoked.", - "examples": [ - 10, - 30 - ] - }, - "partialResultHook": { - "$ref": "../components/actionHook", - "description": "A webhook to invoke with interim (partial) speech recognition results. Useful for providing real-time feedback or early processing." - }, - "listenDuringPrompt": { - "type": "boolean", - "description": "If true, listen for input while the prompt is playing. If false, only start listening after the prompt finishes.", - "default": true - }, - "dtmfBargein": { - "type": "boolean", - "description": "If true, DTMF input interrupts (barges in on) any playing prompt." - }, - "bargein": { - "type": "boolean", - "description": "If true, speech input interrupts (barges in on) any playing prompt." - }, - "minBargeinWordCount": { - "type": "number", - "description": "Minimum number of words that must be recognized before barge-in is triggered. Prevents brief noises from interrupting prompts.", - "examples": [ - 1, - 2 - ] - }, - "recognizer": { - "$ref": "../components/recognizer", - "description": "Override the session-level STT configuration for this gather." - }, - "say": { - "$ref": "say", - "description": "A nested 'say' verb to use as the prompt. Played to the caller while listening for input." - }, - "play": { - "$ref": "play", - "description": "A nested 'play' verb to use as the prompt. Played to the caller while listening for input." - }, - "fillerNoise": { - "$ref": "../components/fillerNoise", - "description": "Filler noise configuration while waiting for the actionHook to respond." - }, - "actionHookDelayAction": { - "$ref": "../components/actionHookDelayAction", - "description": "Configuration for interim actions while the actionHook is processing." - } - }, - "examples": [ - { - "verb": "gather", - "input": [ - "speech", - "digits" - ], - "actionHook": "/gather-result", - "timeout": 15, - "say": { - "text": "Please say or enter your account number." - } - }, - { - "verb": "gather", - "input": [ - "digits" - ], - "actionHook": "/menu-selection", - "numDigits": 1, - "say": { - "text": "Press 1 for sales, 2 for support, or 3 for billing." - } - }, - { - "verb": "gather", - "input": [ - "speech" - ], - "actionHook": "/process-speech", - "timeout": 20, - "bargein": true, - "recognizer": { - "vendor": "deepgram", - "language": "en-US", - "hints": [ - "account", - "balance", - "transfer", - "payment" - ] - }, - "say": { - "text": "How can I help you today?" - }, - "fillerNoise": { - "enable": true, - "url": "https://example.com/sounds/typing.wav", - "startDelaySecs": 2 - } - } - ] -} diff --git a/schema/verbs/google_s2s.schema.json b/schema/verbs/google_s2s.schema.json deleted file mode 100644 index 2558539..0000000 --- a/schema/verbs/google_s2s.schema.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/google_s2s", - "minVersion": "10.1.0", - "title": "Google S2S", - "description": "Shortcut for 'llm' with vendor automatically set to 'google'. Connects the caller to a Google model for real-time speech-to-speech voice conversation.", - "type": "object", - "allOf": [ - { - "$ref": "../components/llm-base" - } - ], - "properties": { - "verb": { - "const": "google_s2s", - "description": "The verb name." - }, - "vendor": { - "type": "string", - "const": "google", - "description": "The LLM vendor (always 'google' for this shortcut)." - } - }, - "required": [ - "llmOptions" - ], - "examples": [ - { - "verb": "google_s2s", - "model": "gemini-2.0-flash", - "llmOptions": { - "messages": [ - { - "role": "system", - "content": "You are a helpful voice assistant." - } - ] - }, - "actionHook": "/s2s-complete" - } - ] -} diff --git a/schema/verbs/hangup.schema.json b/schema/verbs/hangup.schema.json deleted file mode 100644 index ef96d03..0000000 --- a/schema/verbs/hangup.schema.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/hangup", - "minVersion": "0.9.6", - "title": "Hangup", - "description": "Terminates the call. Optionally includes custom SIP headers on the BYE request.", - "type": "object", - "properties": { - "verb": { - "const": "hangup", - "description": "The verb name." - }, - "id": { - "type": "string", - "description": "An optional unique identifier for this verb instance." - }, - "headers": { - "type": "object", - "description": "Custom SIP headers to include on the BYE request.", - "additionalProperties": { - "type": "string" - } - } - }, - "examples": [ - { - "verb": "hangup" - }, - { - "verb": "hangup", - "headers": { - "X-Reason": "call-complete" - } - } - ] -} diff --git a/schema/verbs/leave.schema.json b/schema/verbs/leave.schema.json deleted file mode 100644 index 523a743..0000000 --- a/schema/verbs/leave.schema.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/leave", - "minVersion": "0.9.6", - "title": "Leave", - "description": "Removes the caller from a conference or queue that they are currently in. Execution continues with the next verb in the application.", - "type": "object", - "properties": { - "verb": { - "const": "leave" - }, - "id": { - "type": "string", - "description": "An optional unique identifier for this verb instance." - } - }, - "examples": [ - { - "verb": "leave" - } - ] -} diff --git a/schema/verbs/listen.schema.json b/schema/verbs/listen.schema.json deleted file mode 100644 index 863fadc..0000000 --- a/schema/verbs/listen.schema.json +++ /dev/null @@ -1,127 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/listen", - "minVersion": "0.9.6", - "title": "Listen", - "description": "Streams real-time call audio to an external websocket endpoint. The remote endpoint receives raw audio and can optionally send audio back (bidirectional). Used for custom speech processing, real-time analysis, AI agent integration, and recording to external systems.", - "type": "object", - "properties": { - "verb": { - "const": "listen", - "description": "The verb name." - }, - "id": { - "type": "string", - "description": "An optional unique identifier for this verb instance." - }, - "url": { - "type": "string", - "format": "uri", - "description": "The websocket URL to stream audio to.", - "examples": [ - "wss://myapp.example.com/audio-stream" - ] - }, - "actionHook": { - "$ref": "../components/actionHook", - "description": "A webhook invoked when the listen session ends. Should return the next verbs to execute." - }, - "wsAuth": { - "$ref": "../components/auth", - "description": "Authentication credentials for the websocket connection." - }, - "mixType": { - "type": "string", - "description": "How to mix the audio channels when streaming. 'mono' sends a single mixed channel, 'stereo' sends caller and callee as separate left/right channels, 'mixed' sends both as a single mixed stream.", - "enum": [ - "mono", - "stereo", - "mixed" - ], - "default": "mono" - }, - "metadata": { - "type": "object", - "description": "Arbitrary metadata to send to the websocket endpoint in the initial connection message.", - "additionalProperties": true - }, - "sampleRate": { - "type": "number", - "description": "The audio sample rate in Hz.", - "examples": [ - 8000, - 16000, - 24000 - ], - "default": 8000 - }, - "finishOnKey": { - "type": "string", - "description": "A DTMF key that ends the listen session when pressed.", - "examples": [ - "#" - ] - }, - "maxLength": { - "type": "number", - "description": "Maximum duration in seconds for the listen session." - }, - "passDtmf": { - "type": "boolean", - "description": "If true, forward DTMF events to the websocket endpoint." - }, - "playBeep": { - "type": "boolean", - "description": "If true, play a beep tone before streaming begins." - }, - "disableBidirectionalAudio": { - "type": "boolean", - "description": "If true, disable receiving audio from the websocket endpoint. Audio flows only from the call to the websocket, not back." - }, - "bidirectionalAudio": { - "$ref": "../components/bidirectionalAudio", - "description": "Fine-grained configuration for bidirectional audio." - }, - "timeout": { - "type": "number", - "description": "Time in seconds to wait for audio activity before ending the listen session." - }, - "transcribe": { - "$ref": "transcribe", - "description": "Nested transcribe verb — enables simultaneous real-time transcription of the audio being streamed." - }, - "earlyMedia": { - "type": "boolean", - "description": "If true, begin streaming audio before the call is formally answered." - }, - "channel": { - "type": "number", - "description": "Specific audio channel to stream. Used when streaming a single channel of a multi-channel call." - } - }, - "required": [ - "url" - ], - "examples": [ - { - "verb": "listen", - "url": "wss://myapp.example.com/audio-stream", - "actionHook": "/listen-complete", - "sampleRate": 16000, - "mixType": "stereo" - }, - { - "verb": "listen", - "url": "wss://myapp.example.com/ai-agent", - "bidirectionalAudio": { - "enabled": true, - "streaming": true, - "sampleRate": 24000 - }, - "metadata": { - "callType": "support", - "language": "en-US" - } - } - ] -} diff --git a/schema/verbs/llm.schema.json b/schema/verbs/llm.schema.json deleted file mode 100644 index e539ba1..0000000 --- a/schema/verbs/llm.schema.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/llm", - "minVersion": "0.9.6", - "title": "LLM", - "description": "Connects the caller to a large language model for a real-time voice conversation. Handles the complete STT → LLM → TTS pipeline, including turn detection, interruption handling, and tool/function calling. The caller speaks naturally and the LLM responds via synthesized speech. This is the primary verb for building AI voice agents on jambonz.", - "type": "object", - "allOf": [ - { - "$ref": "../components/llm-base" - } - ], - "properties": { - "verb": { - "const": "llm", - "description": "The verb name." - } - }, - "required": [ - "vendor", - "llmOptions" - ], - "examples": [ - { - "verb": "llm", - "vendor": "openai", - "model": "gpt-4o", - "auth": { - "apiKey": "sk-..." - }, - "llmOptions": { - "messages": [ - { - "role": "system", - "content": "You are a helpful customer service agent. Be concise and friendly." - } - ], - "temperature": 0.7 - }, - "actionHook": "/llm-complete", - "toolHook": "/llm-tool-call" - } - ] -} diff --git a/schema/verbs/message.schema.json b/schema/verbs/message.schema.json deleted file mode 100644 index 3ad1e7e..0000000 --- a/schema/verbs/message.schema.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/message", - "minVersion": "0.9.6", - "title": "Message", - "description": "Sends an SMS or MMS message. Can be used during a voice call to send a text message to the caller or another party, or as a standalone action.", - "type": "object", - "properties": { - "verb": { - "const": "message" - }, - "id": { - "type": "string", - "description": "An optional unique identifier for this verb instance." - }, - "to": { - "type": "string", - "description": "The destination phone number in E.164 format.", - "examples": [ - "+15085551212" - ] - }, - "from": { - "type": "string", - "description": "The sender phone number in E.164 format. Must be a number provisioned on the jambonz platform.", - "examples": [ - "+15085559876" - ] - }, - "text": { - "type": "string", - "description": "The text content of the message." - }, - "media": { - "oneOf": [ - { - "type": "string", - "format": "uri" - }, - { - "type": "array", - "items": { - "type": "string", - "format": "uri" - } - } - ], - "description": "URL(s) of media to attach to the message (MMS). Can be images, audio, or video.", - "examples": [ - "https://example.com/images/receipt.png" - ] - }, - "carrier": { - "type": "string", - "description": "The messaging carrier to use. If not specified, the default carrier is used." - }, - "account_sid": { - "type": "string", - "description": "The account SID to use for sending. Defaults to the current account." - }, - "message_sid": { - "type": "string", - "description": "An optional message SID for tracking." - }, - "actionHook": { - "$ref": "../components/actionHook", - "description": "A webhook invoked when the message send completes or fails." - } - }, - "required": [ - "to", - "from" - ], - "examples": [ - { - "verb": "message", - "to": "+15085551212", - "from": "+15085559876", - "text": "Your order has been confirmed. Order #12345." - } - ] -} diff --git a/schema/verbs/openai_s2s.schema.json b/schema/verbs/openai_s2s.schema.json deleted file mode 100644 index a9fed5f..0000000 --- a/schema/verbs/openai_s2s.schema.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/openai_s2s", - "minVersion": "10.1.0", - "title": "OpenAI S2S", - "description": "Shortcut for 'llm' with vendor automatically set to 'openai'. Connects the caller to an OpenAI model for real-time speech-to-speech voice conversation.", - "type": "object", - "allOf": [ - { - "$ref": "../components/llm-base" - } - ], - "properties": { - "verb": { - "const": "openai_s2s", - "description": "The verb name." - }, - "vendor": { - "type": "string", - "const": "openai", - "description": "The LLM vendor (always 'openai' for this shortcut)." - } - }, - "required": [ - "llmOptions" - ], - "examples": [ - { - "verb": "openai_s2s", - "model": "gpt-4o-realtime", - "llmOptions": { - "messages": [ - { - "role": "system", - "content": "You are a helpful voice assistant." - } - ] - }, - "actionHook": "/s2s-complete" - } - ] -} diff --git a/schema/verbs/pause.schema.json b/schema/verbs/pause.schema.json deleted file mode 100644 index bc2c50c..0000000 --- a/schema/verbs/pause.schema.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/pause", - "minVersion": "0.9.6", - "title": "Pause", - "description": "Pauses execution for a specified number of seconds. The caller hears silence during the pause. Useful for adding delays between verbs.", - "type": "object", - "properties": { - "verb": { - "const": "pause", - "description": "The verb name." - }, - "id": { - "type": "string", - "description": "An optional unique identifier for this verb instance." - }, - "length": { - "type": "number", - "description": "The duration of the pause in seconds.", - "examples": [ - 1, - 2, - 5 - ] - } - }, - "required": [ - "length" - ], - "examples": [ - { - "verb": "pause", - "length": 2 - } - ] -} diff --git a/schema/verbs/pipeline.schema.json b/schema/verbs/pipeline.schema.json deleted file mode 100644 index 50f478b..0000000 --- a/schema/verbs/pipeline.schema.json +++ /dev/null @@ -1,240 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/pipeline", - "minVersion": "10.1.0", - "title": "Pipeline", - "description": "Configures a complete STT → LLM → TTS voice AI pipeline with integrated turn detection. Provides a higher-level abstraction than manually orchestrating the individual components. Optimized for building voice AI agents with proper turn-taking behavior.", - "type": "object", - "properties": { - "verb": { - "const": "pipeline" - }, - "id": { - "type": "string", - "description": "An optional unique identifier for this verb instance." - }, - "stt": { - "$ref": "../components/recognizer", - "description": "Speech-to-text configuration for the pipeline." - }, - "tts": { - "$ref": "../components/synthesizer", - "description": "Text-to-speech configuration for the pipeline." - }, - "turnDetection": { - "oneOf": [ - { - "type": "string", - "enum": ["stt", "krisp"], - "description": "Turn detection strategy shorthand. 'stt' uses the STT vendor's native signals (silence-based for most vendors; acoustic+semantic for deepgramflux, assemblyai, speechmatics). 'krisp' uses the Krisp acoustic end-of-turn model with default settings." - }, - { - "type": "object", - "description": "Turn detection configuration with tunable parameters.", - "properties": { - "mode": { - "type": "string", - "enum": ["krisp"], - "description": "Turn detection mode. Currently only 'krisp' supports object-form tuning." - }, - "threshold": { - "type": "number", - "minimum": 0, - "maximum": 1, - "description": "Krisp end-of-turn confidence threshold (0.0–1.0). Lower values trigger earlier turn transitions. Default: 0.5" - }, - "model": { - "type": "string", - "description": "Optional Krisp model name override." - } - }, - "required": ["mode"], - "additionalProperties": false - } - ], - "default": "stt", - "description": "Turn detection strategy. Controls when the pipeline decides the user has finished speaking. STT vendors with native turn-taking (deepgramflux, assemblyai, speechmatics) always use their built-in detection regardless of this setting." - }, - "bargeIn": { - "type": "object", - "description": "Controls whether and how the user can interrupt the assistant while it is speaking.", - "properties": { - "enable": { - "type": "boolean", - "description": "Allow the user to interrupt the assistant while it is speaking. Default: true.", - "default": true - }, - "minSpeechDuration": { - "type": "number", - "minimum": 0, - "description": "Seconds of detected speech required before confirming an interruption. Prevents brief noises from cutting off the assistant. Default: 0.5", - "default": 0.5 - }, - "sticky": { - "type": "boolean", - "description": "If true, once the user interrupts the assistant does not resume speaking. Default: false.", - "default": false - } - }, - "additionalProperties": false - }, - "noResponseTimeout": { - "type": "number", - "minimum": 0, - "description": "Seconds to wait after the assistant finishes speaking before prompting the user to respond. 0 disables. Default: 0.", - "default": 0 - }, - "llm": { - "type": "object", - "description": "LLM configuration for the pipeline. See the 'llm' verb schema for details.", - "additionalProperties": true - }, - "actionHook": { - "$ref": "../components/actionHook", - "description": "A webhook invoked when the pipeline ends." - }, - "eventHook": { - "$ref": "../components/actionHook", - "description": "A webhook invoked for pipeline events. Receives event types: 'user_transcript' (user speech recognized), 'agent_response' (assistant reply), 'user_interruption' (barge-in detected), and 'turn_end' (end-of-turn summary with transcript, response, and latency metrics)." - }, - "toolHook": { - "$ref": "../components/actionHook", - "description": "A webhook invoked when the LLM requests a tool/function call. The payload includes the tool name and arguments; the response provides the tool result." - }, - "greeting": { - "type": "boolean", - "description": "Whether the LLM should generate an initial greeting before the user speaks. Default: true.", - "default": true - }, - "earlyGeneration": { - "type": "boolean", - "description": "Enable speculative LLM prompting before end-of-turn is confirmed. When using Krisp turn detection, set this to true to speculatively prompt the LLM before Krisp confirms the turn has ended. If the transcript matches when turn ends, buffered tokens are released immediately — reducing response latency. Note: Deepgram Flux performs early generation automatically via its native EagerEndOfTurn signal regardless of this setting. Default: false.", - "default": false - }, - "noiseIsolation": { - "oneOf": [ - { - "type": "string", - "enum": ["krisp", "rnnoise"], - "description": "Shorthand — enable noise isolation with the specified vendor using default settings." - }, - { - "type": "object", - "description": "Detailed noise isolation configuration.", - "properties": { - "mode": { - "type": "string", - "description": "Noise isolation vendor/mode (e.g. 'krisp')." - }, - "level": { - "type": "number", - "minimum": 0, - "maximum": 100, - "description": "Suppression level 0–100. Default: 100." - }, - "direction": { - "type": "string", - "enum": ["read", "write"], - "description": "Audio direction to apply noise isolation. 'read' filters caller audio, 'write' filters outbound audio. Default: 'read'." - }, - "model": { - "type": "string", - "description": "Optional model name override." - } - }, - "required": ["mode"], - "additionalProperties": false - } - ], - "description": "Enable server-side noise isolation to reduce background noise on call audio. Defaults to filtering inbound (caller) audio; set direction to 'write' for outbound. Useful for improving STT accuracy in noisy environments." - }, - "mcpServers": { - "type": "array", - "items": { - "type": "object", - "properties": { - "url": { - "type": "string", - "format": "uri", - "description": "The URL of the MCP server." - }, - "auth": { - "type": "object", - "description": "Authentication for the MCP server.", - "additionalProperties": true - }, - "roots": { - "type": "array", - "items": { "type": "object" }, - "description": "MCP root definitions." - } - }, - "required": ["url"] - }, - "description": "External MCP servers that provide tools to the LLM. The pipeline connects at startup via SSE, discovers available tools, and makes them callable by the LLM." - } - }, - "required": [ - "llm" - ], - "examples": [ - { - "verb": "pipeline", - "stt": { - "vendor": "deepgram", - "language": "en-US" - }, - "tts": { - "vendor": "cartesia", - "voice": "sonic-english" - }, - "llm": { - "vendor": "openai", - "model": "gpt-4o", - "llmOptions": { - "messages": [ - { - "role": "system", - "content": "You are a helpful voice assistant." - } - ] - } - }, - "turnDetection": "stt", - "actionHook": "/pipeline-complete" - }, - { - "verb": "pipeline", - "stt": { - "vendor": "deepgram", - "language": "en-US" - }, - "tts": { - "vendor": "cartesia", - "voice": "sonic-english" - }, - "llm": { - "vendor": "anthropic", - "model": "claude-opus-4-6", - "llmOptions": { - "messages": [ - { - "role": "user", - "content": "You are a helpful voice assistant." - } - ] - } - }, - "turnDetection": { - "mode": "krisp", - "threshold": 0.3 - }, - "bargeIn": { - "enable": true, - "minSpeechDuration": 0.3, - "sticky": false - }, - "actionHook": "/pipeline-complete" - } - ] -} diff --git a/schema/verbs/play.schema.json b/schema/verbs/play.schema.json deleted file mode 100644 index b193b22..0000000 --- a/schema/verbs/play.schema.json +++ /dev/null @@ -1,96 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/play", - "minVersion": "0.9.6", - "title": "Play", - "description": "Plays an audio file to the caller. Supports WAV and MP3 formats hosted at a URL. Can play a single file or cycle through a list of files.", - "type": "object", - "properties": { - "verb": { - "const": "play", - "description": "The verb name." - }, - "id": { - "type": "string", - "description": "An optional unique identifier for this verb instance." - }, - "url": { - "oneOf": [ - { - "type": "string", - "format": "uri" - }, - { - "type": "array", - "items": { - "type": "string", - "format": "uri" - } - } - ], - "description": "The URL(s) of the audio file(s) to play. Supports WAV and MP3. If an array, files are played in sequence.", - "examples": [ - "https://example.com/sounds/greeting.wav", - [ - "https://example.com/sounds/part1.wav", - "https://example.com/sounds/part2.wav" - ] - ] - }, - "loop": { - "oneOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ], - "description": "Number of times to repeat playback. Use 0 or 'forever' to loop indefinitely until interrupted.", - "examples": [ - 3, - "forever" - ] - }, - "earlyMedia": { - "type": "boolean", - "description": "If true, play the audio as early media before the call is answered." - }, - "seekOffset": { - "oneOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ], - "description": "Start playback at this offset in seconds from the beginning of the file." - }, - "timeoutSecs": { - "oneOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ], - "description": "Maximum time in seconds to play the audio. Playback stops after this duration even if the file has not finished." - }, - "actionHook": { - "$ref": "../components/actionHook", - "description": "A webhook to invoke when playback completes." - } - }, - "required": [ - "url" - ], - "examples": [ - { - "verb": "play", - "url": "https://example.com/sounds/hold-music.mp3", - "loop": "forever" - } - ] -} diff --git a/schema/verbs/redirect.schema.json b/schema/verbs/redirect.schema.json deleted file mode 100644 index 2cd461c..0000000 --- a/schema/verbs/redirect.schema.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/redirect", - "minVersion": "0.9.6", - "title": "Redirect", - "description": "Transfers call control to a different webhook URL. The current verb stack is abandoned and the new webhook's response becomes the active application. Useful for modular application design where different URLs handle different phases of a call.", - "type": "object", - "properties": { - "verb": { - "const": "redirect" - }, - "id": { - "type": "string", - "description": "An optional unique identifier for this verb instance." - }, - "actionHook": { - "$ref": "../components/actionHook", - "description": "The webhook to transfer control to. Must return a new array of verbs." - }, - "statusHook": { - "$ref": "../components/actionHook", - "description": "A webhook to receive call status events after the redirect." - } - }, - "required": [ - "actionHook" - ], - "examples": [ - { - "verb": "redirect", - "actionHook": "/new-handler" - } - ] -} diff --git a/schema/verbs/s2s.schema.json b/schema/verbs/s2s.schema.json deleted file mode 100644 index 935dc13..0000000 --- a/schema/verbs/s2s.schema.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/s2s", - "minVersion": "10.1.0", - "title": "S2S", - "description": "Synonym for 'llm'. Connects the caller to a large language model for a real-time speech-to-speech voice conversation. Requires 'vendor' to be specified explicitly.", - "type": "object", - "allOf": [ - { - "$ref": "../components/llm-base" - } - ], - "properties": { - "verb": { - "const": "s2s", - "description": "The verb name." - } - }, - "required": [ - "vendor", - "llmOptions" - ], - "examples": [ - { - "verb": "s2s", - "vendor": "openai", - "model": "gpt-4o-realtime", - "llmOptions": { - "messages": [ - { - "role": "system", - "content": "You are a helpful voice assistant." - } - ] - }, - "actionHook": "/s2s-complete" - } - ] -} diff --git a/schema/verbs/say.schema.json b/schema/verbs/say.schema.json deleted file mode 100644 index dac059b..0000000 --- a/schema/verbs/say.schema.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/say", - "minVersion": "0.9.6", - "title": "Say", - "description": "Speaks text to the caller using text-to-speech. The text can be plain text or SSML. Optionally streams TTS output incrementally for lower latency. This is one of the most commonly used verbs in jambonz applications.", - "type": "object", - "properties": { - "verb": { - "const": "say", - "description": "The verb name." - }, - "id": { - "type": "string", - "description": "An optional unique identifier for this verb instance. Can be used to reference it in other contexts." - }, - "text": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ], - "description": "The text to speak. Can be plain text or SSML markup. If an array is provided, one entry is selected at random (useful for variety in prompts).", - "examples": [ - "Hello, welcome to our service.", - "Hello welcome.", - [ - "Hello!", - "Hi there!", - "Welcome!" - ] - ] - }, - "instructions": { - "type": "string", - "description": "Natural language instructions to guide TTS expression and delivery. Supported by vendors that offer instruction-based synthesis (e.g. ElevenLabs, some OpenAI models).", - "examples": [ - "Speak in a warm, friendly tone", - "Sound excited and energetic" - ] - }, - "stream": { - "type": "boolean", - "description": "If true, stream TTS audio to the caller incrementally as it is generated, rather than waiting for the complete audio. Reduces time-to-first-byte for long utterances. Requires a vendor that supports streaming synthesis." - }, - "loop": { - "oneOf": [ - { - "type": "number" - }, - { - "type": "string" - } - ], - "description": "Number of times to repeat the speech. Use 0 or 'forever' to loop indefinitely until interrupted.", - "examples": [ - 2, - "forever" - ] - }, - "synthesizer": { - "$ref": "../components/synthesizer", - "description": "Override the session-level TTS configuration for this specific utterance." - }, - "earlyMedia": { - "type": "boolean", - "description": "If true, play the audio as early media (before the call is answered). Used for playing announcements or prompts to the caller before the call is formally connected." - }, - "disableTtsCache": { - "type": "boolean", - "description": "If true, bypass the TTS cache and always generate fresh audio. Useful when the same text should be re-synthesized (e.g. with different SSML or when the voice has been updated)." - }, - "closeStreamOnEmpty": { - "type": "boolean", - "description": "If true, close the TTS stream when an empty text string is received. Only applies when stream is true." - } - }, - "examples": [ - { - "verb": "say", - "text": "Hello, welcome to Acme Corp. How can I help you today?" - }, - { - "verb": "say", - "text": "Please hold while I transfer your call.", - "synthesizer": { - "vendor": "elevenlabs", - "voice": "Rachel" - } - }, - { - "verb": "say", - "text": [ - "Hello!", - "Hi there!", - "Welcome!" - ], - "loop": 1 - } - ] -} diff --git a/schema/verbs/sip-decline.schema.json b/schema/verbs/sip-decline.schema.json deleted file mode 100644 index 2bea669..0000000 --- a/schema/verbs/sip-decline.schema.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/sip:decline", - "minVersion": "0.9.6", - "title": "SIP Decline", - "description": "Rejects an incoming call with a SIP error response. Used to decline calls with a specific status code and reason (e.g. 486 Busy Here, 603 Decline).", - "type": "object", - "properties": { - "verb": { - "const": "sip:decline" - }, - "id": { - "type": "string", - "description": "An optional unique identifier for this verb instance." - }, - "status": { - "type": "number", - "description": "The SIP response status code to send.", - "examples": [ - 486, - 603, - 404, - 480 - ] - }, - "reason": { - "type": "string", - "description": "The SIP reason phrase to include in the response.", - "examples": [ - "Busy Here", - "Decline", - "Not Found" - ] - }, - "headers": { - "type": "object", - "description": "Custom SIP headers to include in the response.", - "additionalProperties": { - "type": "string" - } - } - }, - "required": [ - "status" - ], - "examples": [ - { - "verb": "sip:decline", - "status": 486, - "reason": "Busy Here" - }, - { - "verb": "sip:decline", - "status": 603, - "reason": "Decline" - } - ] -} diff --git a/schema/verbs/sip-refer.schema.json b/schema/verbs/sip-refer.schema.json deleted file mode 100644 index 1909519..0000000 --- a/schema/verbs/sip-refer.schema.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/sip:refer", - "minVersion": "0.9.6", - "title": "SIP Refer", - "description": "Sends a SIP REFER request to transfer the call to another party. Initiates an attended or unattended (blind) transfer.", - "type": "object", - "properties": { - "verb": { - "const": "sip:refer" - }, - "id": { - "type": "string", - "description": "An optional unique identifier for this verb instance." - }, - "referTo": { - "type": "string", - "description": "The SIP URI or phone number to transfer the call to.", - "examples": [ - "sip:alice@example.com", - "+15085551212" - ] - }, - "referredBy": { - "type": "string", - "description": "The SIP URI to use in the Referred-By header." - }, - "referredByDisplayName": { - "type": "string", - "description": "The display name to use in the Referred-By header." - }, - "headers": { - "type": "object", - "description": "Custom SIP headers to include in the REFER request.", - "additionalProperties": { - "type": "string" - } - }, - "actionHook": { - "$ref": "../components/actionHook", - "description": "A webhook invoked when the REFER completes (or fails)." - }, - "eventHook": { - "$ref": "../components/actionHook", - "description": "A webhook invoked for NOTIFY events during the REFER process, providing transfer progress updates." - } - }, - "required": [ - "referTo" - ], - "examples": [ - { - "verb": "sip:refer", - "referTo": "sip:alice@example.com", - "actionHook": "/refer-complete" - } - ] -} diff --git a/schema/verbs/sip-request.schema.json b/schema/verbs/sip-request.schema.json deleted file mode 100644 index 20fc013..0000000 --- a/schema/verbs/sip-request.schema.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/sip:request", - "minVersion": "0.9.6", - "title": "SIP Request", - "description": "Sends a SIP request within the current dialog. Used to send INFO, NOTIFY, or other SIP methods to the remote party during an active call.", - "type": "object", - "properties": { - "verb": { - "const": "sip:request" - }, - "id": { - "type": "string", - "description": "An optional unique identifier for this verb instance." - }, - "method": { - "type": "string", - "description": "The SIP method to send.", - "examples": [ - "INFO", - "NOTIFY", - "MESSAGE" - ] - }, - "body": { - "type": "string", - "description": "The body of the SIP request." - }, - "headers": { - "type": "object", - "description": "Custom SIP headers to include in the request.", - "additionalProperties": { - "type": "string" - } - }, - "actionHook": { - "$ref": "../components/actionHook", - "description": "A webhook invoked when the response to the SIP request is received." - } - }, - "required": [ - "method" - ], - "examples": [ - { - "verb": "sip:request", - "method": "INFO", - "body": "Signal=1\nDuration=250", - "headers": { - "Content-Type": "application/dtmf-relay" - } - } - ] -} diff --git a/schema/verbs/stream.schema.json b/schema/verbs/stream.schema.json deleted file mode 100644 index 9252b00..0000000 --- a/schema/verbs/stream.schema.json +++ /dev/null @@ -1,103 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/stream", - "minVersion": "0.9.6", - "title": "Stream", - "description": "Streams real-time call audio to an external websocket endpoint. Functionally equivalent to 'listen' — this is an alias provided for naming clarity when the intent is audio streaming rather than recording.", - "type": "object", - "properties": { - "verb": { - "const": "stream" - }, - "id": { - "type": "string", - "description": "An optional unique identifier for this verb instance." - }, - "url": { - "type": "string", - "format": "uri", - "description": "The websocket URL to stream audio to." - }, - "actionHook": { - "$ref": "../components/actionHook", - "description": "A webhook invoked when the stream ends." - }, - "wsAuth": { - "$ref": "../components/auth", - "description": "Authentication credentials for the websocket connection." - }, - "mixType": { - "type": "string", - "enum": [ - "mono", - "stereo", - "mixed" - ], - "description": "How to mix audio channels." - }, - "metadata": { - "type": "object", - "description": "Metadata to send with the initial connection.", - "additionalProperties": true - }, - "sampleRate": { - "type": "number", - "description": "Audio sample rate in Hz.", - "examples": [ - 8000, - 16000 - ] - }, - "finishOnKey": { - "type": "string", - "description": "DTMF key that ends the stream." - }, - "maxLength": { - "type": "number", - "description": "Maximum duration in seconds." - }, - "passDtmf": { - "type": "boolean", - "description": "Forward DTMF events to the websocket." - }, - "playBeep": { - "type": "boolean", - "description": "Play a beep before streaming begins." - }, - "disableBidirectionalAudio": { - "type": "boolean", - "description": "Disable receiving audio from the websocket." - }, - "bidirectionalAudio": { - "$ref": "../components/bidirectionalAudio", - "description": "Bidirectional audio configuration." - }, - "timeout": { - "type": "number", - "description": "Inactivity timeout in seconds." - }, - "transcribe": { - "$ref": "transcribe", - "description": "Nested transcribe verb — enables simultaneous real-time transcription of the streamed audio." - }, - "earlyMedia": { - "type": "boolean", - "description": "Stream audio before the call is answered." - }, - "channel": { - "type": "number", - "description": "Specific audio channel to stream. Used when streaming a single channel of a multi-channel call." - } - }, - "required": [ - "url" - ], - "examples": [ - { - "verb": "stream", - "url": "wss://myapp.example.com/audio", - "sampleRate": 16000, - "mixType": "stereo" - } - ] -} diff --git a/schema/verbs/tag.schema.json b/schema/verbs/tag.schema.json deleted file mode 100644 index 610adac..0000000 --- a/schema/verbs/tag.schema.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/tag", - "minVersion": "0.9.6", - "title": "Tag", - "description": "Attaches arbitrary metadata to the current call. Tagged data is included in all subsequent webhook requests and in the call detail record (CDR). Useful for tracking business context, routing decisions, or analytics data through the call lifecycle.", - "type": "object", - "properties": { - "verb": { - "const": "tag" - }, - "id": { - "type": "string", - "description": "An optional unique identifier for this verb instance." - }, - "data": { - "type": "object", - "description": "An object containing the metadata to attach to the call. Keys and values are application-defined.", - "additionalProperties": true, - "examples": [ - { - "customerId": "12345", - "department": "support", - "priority": "high" - } - ] - } - }, - "required": [ - "data" - ], - "examples": [ - { - "verb": "tag", - "data": { - "customerId": "12345", - "intent": "billing-inquiry" - } - } - ] -} diff --git a/schema/verbs/transcribe.schema.json b/schema/verbs/transcribe.schema.json deleted file mode 100644 index 48f1bbf..0000000 --- a/schema/verbs/transcribe.schema.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/transcribe", - "minVersion": "0.9.6", - "title": "Transcribe", - "description": "Enables real-time transcription of the call audio. Transcription results are sent to the transcriptionHook as they are produced. Runs as a background process — subsequent verbs execute immediately while transcription continues.", - "type": "object", - "properties": { - "verb": { - "const": "transcribe" - }, - "id": { - "type": "string", - "description": "An optional unique identifier for this verb instance." - }, - "enable": { - "type": "boolean", - "description": "Enable or disable transcription. Used when transcribe is nested inside a config or dial verb to start or stop background transcription." - }, - "transcriptionHook": { - "type": "string", - "format": "uri", - "description": "The webhook URL to receive transcription results." - }, - "translationHook": { - "type": "string", - "format": "uri", - "description": "The webhook URL to receive translated transcription results." - }, - "recognizer": { - "$ref": "../components/recognizer", - "description": "STT configuration for the transcription." - }, - "earlyMedia": { - "type": "boolean", - "description": "If true, begin transcribing before the call is answered." - }, - "channel": { - "type": "number", - "description": "Specific audio channel to transcribe." - } - }, - "examples": [ - { - "verb": "transcribe", - "transcriptionHook": "https://myapp.example.com/transcription", - "recognizer": { - "vendor": "deepgram", - "language": "en-US", - "deepgramOptions": { - "model": "nova-2", - "smartFormatting": true - } - } - } - ] -} diff --git a/schema/verbs/ultravox_s2s.schema.json b/schema/verbs/ultravox_s2s.schema.json deleted file mode 100644 index 308f7c5..0000000 --- a/schema/verbs/ultravox_s2s.schema.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://jambonz.org/schema/verbs/ultravox_s2s", - "minVersion": "10.1.0", - "title": "Ultravox S2S", - "description": "Shortcut for 'llm' with vendor automatically set to 'ultravox'. Connects the caller to an Ultravox model for real-time speech-to-speech voice conversation.", - "type": "object", - "allOf": [ - { - "$ref": "../components/llm-base" - } - ], - "properties": { - "verb": { - "const": "ultravox_s2s", - "description": "The verb name." - }, - "vendor": { - "type": "string", - "const": "ultravox", - "description": "The LLM vendor (always 'ultravox' for this shortcut)." - } - }, - "required": [ - "llmOptions" - ], - "examples": [ - { - "verb": "ultravox_s2s", - "llmOptions": { - "messages": [ - { - "role": "system", - "content": "You are a helpful voice assistant." - } - ] - }, - "actionHook": "/s2s-complete" - } - ] -} diff --git a/typescript/package-lock.json b/typescript/package-lock.json index 9da8f4c..80c152d 100644 --- a/typescript/package-lock.json +++ b/typescript/package-lock.json @@ -9,6 +9,7 @@ "version": "0.1.32", "license": "MIT", "dependencies": { + "@jambonz/schema": "^0.1.1", "ajv": "^8.17.1", "ws": "^8.18.0" }, @@ -580,6 +581,16 @@ "node": ">=8" } }, + "node_modules/@jambonz/schema": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jambonz/schema/-/schema-0.1.1.tgz", + "integrity": "sha512-T8uWnRJVHmu2z5kVvuqVUr+cuj7ERfA5m6Pfd0as+IhAl7op3E3xIoyRqddO+cEMAtFcbi8ZymbWaFve3z0woQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.17.1", + "debug": "^4.3.4" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -1464,7 +1475,6 @@ "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -1977,7 +1987,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/mz": { diff --git a/typescript/package.json b/typescript/package.json index 950c956..5e72a47 100644 --- a/typescript/package.json +++ b/typescript/package.json @@ -77,11 +77,10 @@ } }, "files": [ - "dist", - "schema" + "dist" ], "scripts": { - "build": "tsup && rm -rf ./schema && cp -r ../schema ./schema", + "build": "tsup", "dev": "tsup --watch", "test": "vitest run", "test:watch": "vitest", @@ -91,6 +90,7 @@ "prepublishOnly": "npm run build" }, "dependencies": { + "@jambonz/schema": "^0.1.1", "ajv": "^8.17.1", "ws": "^8.18.0" }, diff --git a/typescript/src/validator.ts b/typescript/src/validator.ts index ff6b564..3952ffe 100644 --- a/typescript/src/validator.ts +++ b/typescript/src/validator.ts @@ -1,12 +1,13 @@ /** * Schema-based validation using AJV. - * Loads all JSON schemas from schema/ and validates verb arrays and individual verbs. + * Loads all JSON schemas from the @jambonz/schema package. */ import Ajv, { type ValidateFunction, type ErrorObject } from 'ajv'; -import { readFileSync } from 'fs'; -import { resolve, dirname } from 'path'; +import { readFileSync, readdirSync, existsSync } from 'fs'; +import { resolve, dirname, basename } from 'path'; import { fileURLToPath } from 'url'; +import { createRequire } from 'module'; export interface ValidationResult { valid: boolean; @@ -18,107 +19,56 @@ export interface ValidationError { message: string; } -// Schema $id to file path mapping -const COMPONENT_SCHEMAS = [ - 'auth', - 'actionHook', - 'actionHookDelayAction', - 'amd', - 'bidirectionalAudio', - 'fillerNoise', - 'recognizer', - 'recognizer-assemblyAiOptions', - 'recognizer-awsOptions', - 'recognizer-azureOptions', - 'recognizer-cobaltOptions', - 'recognizer-customOptions', - 'recognizer-deepgramOptions', - 'recognizer-elevenlabsOptions', - 'recognizer-gladiaOptions', - 'recognizer-googleOptions', - 'recognizer-houndifyOptions', - 'recognizer-ibmOptions', - 'recognizer-nuanceOptions', - 'recognizer-nvidiaOptions', - 'recognizer-openaiOptions', - 'recognizer-sonioxOptions', - 'recognizer-speechmaticsOptions', - 'recognizer-verbioOptions', - 'llm-base', - 'synthesizer', - 'target', - 'vad', -] as const; - -const VERB_SCHEMAS = [ - 'answer', - 'alert', - 'config', - 'say', - 'play', - 'gather', - 'dial', - 'listen', - 'stream', - 'llm', - 's2s', - 'openai_s2s', - 'google_s2s', - 'elevenlabs_s2s', - 'deepgram_s2s', - 'ultravox_s2s', - 'dialogflow', - 'pipeline', - 'conference', - 'transcribe', - 'enqueue', - 'dequeue', - 'dtmf', - 'dub', - 'hangup', - 'leave', - 'message', - 'pause', - 'redirect', - 'tag', - 'sip-decline', - 'sip-request', - 'sip-refer', -] as const; - -function loadSchema(schemaDir: string, relativePath: string): Record { - const fullPath = resolve(schemaDir, relativePath); - return JSON.parse(readFileSync(fullPath, 'utf-8')) as Record; -} - +/** Locate the @jambonz/schema package directory. */ function findSchemaDir(): string { - // Walk up from this file to find the schema/ directory - // In development: typescript/src/validator.ts -> ../../schema - // In dist: dist/index.js -> ../schema (tsup bundles to package-root/dist/) + // Method 1: use createRequire to resolve the package + try { + const req = createRequire(import.meta.url); + const schemaIndex = req.resolve('@jambonz/schema'); + const dir = resolve(schemaIndex, '..'); + if (existsSync(resolve(dir, 'jambonz-app.schema.json'))) { + return dir; + } + } catch { + // fall through + } + + // Method 2: walk up from this file to find node_modules/@jambonz/schema const currentDir = typeof __dirname !== 'undefined' ? __dirname : dirname(fileURLToPath(import.meta.url)); - // Try relative paths from both src and dist locations - const candidates = [ - resolve(currentDir, '../../schema'), // from typescript/src/ - resolve(currentDir, '../schema'), // from dist/ (tsup bundles to package-root/dist/) - ]; - - for (const candidate of candidates) { - try { - readFileSync(resolve(candidate, 'jambonz-app.schema.json'), 'utf-8'); + let dir = currentDir; + for (let i = 0; i < 10; i++) { + const candidate = resolve(dir, 'node_modules', '@jambonz', 'schema'); + if (existsSync(resolve(candidate, 'jambonz-app.schema.json'))) { return candidate; - } catch { - // try next } + const parent = dirname(dir); + if (parent === dir) break; + dir = parent; } throw new Error( - 'Could not find jambonz schema directory. Ensure the schema/ directory is present alongside the typescript/ directory.' + 'Could not find @jambonz/schema package. Ensure it is installed as a dependency.' ); } +/** Discover schema files in a subdirectory. */ +function discoverSchemas(dir: string): string[] { + try { + return readdirSync(dir) + .filter((f) => f.endsWith('.schema.json')) + .map((f) => basename(f, '.schema.json')); + } catch { + return []; + } +} + +function loadSchema(filePath: string): Record { + return JSON.parse(readFileSync(filePath, 'utf-8')) as Record; +} + export class JambonzValidator { private validateApp: ValidateFunction; private ajv: Ajv; @@ -133,19 +83,21 @@ export class JambonzValidator { }); // Register component schemas first (they are referenced by verb schemas) - for (const name of COMPONENT_SCHEMAS) { - const schema = loadSchema(dir, `components/${name}.schema.json`); + const componentsDir = resolve(dir, 'components'); + for (const name of discoverSchemas(componentsDir)) { + const schema = loadSchema(resolve(componentsDir, `${name}.schema.json`)); this.ajv.addSchema(schema); } // Register verb schemas - for (const name of VERB_SCHEMAS) { - const schema = loadSchema(dir, `verbs/${name}.schema.json`); + const verbsDir = resolve(dir, 'verbs'); + for (const name of discoverSchemas(verbsDir)) { + const schema = loadSchema(resolve(verbsDir, `${name}.schema.json`)); this.ajv.addSchema(schema); } // Compile the root app schema - const appSchema = loadSchema(dir, 'jambonz-app.schema.json'); + const appSchema = loadSchema(resolve(dir, 'jambonz-app.schema.json')); this.validateApp = this.ajv.compile(appSchema); } diff --git a/typescript/test/schema-drift.test.ts b/typescript/test/schema-drift.test.ts index 960a662..6441f23 100644 --- a/typescript/test/schema-drift.test.ts +++ b/typescript/test/schema-drift.test.ts @@ -7,9 +7,11 @@ import { describe, it, expect } from 'vitest'; import { readFileSync, readdirSync } from 'fs'; import { resolve, basename, dirname } from 'path'; import { fileURLToPath } from 'url'; +import { createRequire } from 'module'; +const require = createRequire(import.meta.url); +const schemaDir = resolve(require.resolve('@jambonz/schema'), '..'); const __dirname_test = dirname(fileURLToPath(import.meta.url)); -const schemaDir = resolve(__dirname_test, '../../schema'); const verbsDir = resolve(schemaDir, 'verbs'); const componentsDir = resolve(schemaDir, 'components'); const typesDir = resolve(__dirname_test, '../src/types'); diff --git a/typescript/test/validator.test.ts b/typescript/test/validator.test.ts index 7979229..50e7f72 100644 --- a/typescript/test/validator.test.ts +++ b/typescript/test/validator.test.ts @@ -1,11 +1,11 @@ import { describe, it, expect } from 'vitest'; import { JambonzValidator } from '../src/validator.js'; -import { resolve, dirname } from 'path'; -import { fileURLToPath } from 'url'; +import { resolve } from 'path'; +import { createRequire } from 'module'; import { readFileSync } from 'fs'; -const __dirname_test = dirname(fileURLToPath(import.meta.url)); -const schemaDir = resolve(__dirname_test, '../../schema'); +const require = createRequire(import.meta.url); +const schemaDir = resolve(require.resolve('@jambonz/schema'), '..'); describe('JambonzValidator', () => { const validator = new JambonzValidator(schemaDir); diff --git a/typescript/test/webhook.test.ts b/typescript/test/webhook.test.ts index b4b0e85..4898215 100644 --- a/typescript/test/webhook.test.ts +++ b/typescript/test/webhook.test.ts @@ -2,11 +2,11 @@ import { describe, it, expect, vi } from 'vitest'; import { createHmac } from 'crypto'; import { WebhookResponse } from '../src/webhook/response.js'; import { envVarsMiddleware } from '../src/webhook/env-vars.js'; -import { resolve, dirname } from 'path'; -import { fileURLToPath } from 'url'; +import { resolve } from 'path'; +import { createRequire } from 'module'; -const __dirname_test = dirname(fileURLToPath(import.meta.url)); -const schemaDir = resolve(__dirname_test, '../../schema'); +const require = createRequire(import.meta.url); +const schemaDir = resolve(require.resolve('@jambonz/schema'), '..'); describe('WebhookResponse', () => { it('should build a simple greeting', () => { From f6ae501cc73f99458748e21c4fa2cf94980f9750 Mon Sep 17 00:00:00 2001 From: Dave Horton Date: Tue, 7 Apr 2026 13:51:56 -0400 Subject: [PATCH 2/2] update to latest schema --- typescript/package-lock.json | 641 ++++++++++++++------------- typescript/package.json | 2 +- typescript/test/schema-drift.test.ts | 6 +- 3 files changed, 346 insertions(+), 303 deletions(-) diff --git a/typescript/package-lock.json b/typescript/package-lock.json index 80c152d..5fbd472 100644 --- a/typescript/package-lock.json +++ b/typescript/package-lock.json @@ -9,7 +9,7 @@ "version": "0.1.32", "license": "MIT", "dependencies": { - "@jambonz/schema": "^0.1.1", + "@jambonz/schema": "^0.1.5", "ajv": "^8.17.1", "ws": "^8.18.0" }, @@ -61,9 +61,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "dev": true, "license": "MIT", "dependencies": { @@ -98,9 +98,9 @@ "license": "MIT" }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", - "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", "cpu": [ "ppc64" ], @@ -115,9 +115,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", - "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", "cpu": [ "arm" ], @@ -132,9 +132,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", - "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", "cpu": [ "arm64" ], @@ -149,9 +149,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", - "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", "cpu": [ "x64" ], @@ -166,9 +166,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", - "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", "cpu": [ "arm64" ], @@ -183,9 +183,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", - "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", "cpu": [ "x64" ], @@ -200,9 +200,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", - "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", "cpu": [ "arm64" ], @@ -217,9 +217,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", - "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", "cpu": [ "x64" ], @@ -234,9 +234,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", - "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", "cpu": [ "arm" ], @@ -251,9 +251,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", - "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", "cpu": [ "arm64" ], @@ -268,9 +268,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", - "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", "cpu": [ "ia32" ], @@ -285,9 +285,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", - "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", "cpu": [ "loong64" ], @@ -302,9 +302,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", - "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", "cpu": [ "mips64el" ], @@ -319,9 +319,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", - "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", "cpu": [ "ppc64" ], @@ -336,9 +336,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", - "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", "cpu": [ "riscv64" ], @@ -353,9 +353,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", - "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", "cpu": [ "s390x" ], @@ -370,9 +370,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", - "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", "cpu": [ "x64" ], @@ -387,9 +387,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", - "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", "cpu": [ "arm64" ], @@ -404,9 +404,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", - "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", "cpu": [ "x64" ], @@ -421,9 +421,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", - "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", "cpu": [ "arm64" ], @@ -438,9 +438,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", - "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", "cpu": [ "x64" ], @@ -455,9 +455,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", - "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", "cpu": [ "arm64" ], @@ -472,9 +472,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", - "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", "cpu": [ "x64" ], @@ -489,9 +489,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", - "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", "cpu": [ "arm64" ], @@ -506,9 +506,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", - "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", "cpu": [ "ia32" ], @@ -523,9 +523,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", - "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", "cpu": [ "x64" ], @@ -582,9 +582,9 @@ } }, "node_modules/@jambonz/schema": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jambonz/schema/-/schema-0.1.1.tgz", - "integrity": "sha512-T8uWnRJVHmu2z5kVvuqVUr+cuj7ERfA5m6Pfd0as+IhAl7op3E3xIoyRqddO+cEMAtFcbi8ZymbWaFve3z0woQ==", + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@jambonz/schema/-/schema-0.1.5.tgz", + "integrity": "sha512-50fu8JLug3QPZ1m84D01MddsYutRjSOVgF4wFmYwfivH8BKcQ+fDeRRZcAygIl1AfAVmbpUXQ6J+tYbJY3iC9A==", "license": "MIT", "dependencies": { "ajv": "^8.17.1", @@ -642,9 +642,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", - "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.1.tgz", + "integrity": "sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==", "cpu": [ "arm" ], @@ -656,9 +656,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", - "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.1.tgz", + "integrity": "sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA==", "cpu": [ "arm64" ], @@ -670,9 +670,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", - "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.1.tgz", + "integrity": "sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==", "cpu": [ "arm64" ], @@ -684,9 +684,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", - "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.1.tgz", + "integrity": "sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew==", "cpu": [ "x64" ], @@ -698,9 +698,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", - "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.1.tgz", + "integrity": "sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w==", "cpu": [ "arm64" ], @@ -712,9 +712,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", - "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.1.tgz", + "integrity": "sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g==", "cpu": [ "x64" ], @@ -726,13 +726,16 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", - "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.1.tgz", + "integrity": "sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==", "cpu": [ "arm" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -740,13 +743,16 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", - "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.1.tgz", + "integrity": "sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==", "cpu": [ "arm" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -754,13 +760,16 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", - "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.1.tgz", + "integrity": "sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -768,13 +777,16 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", - "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.1.tgz", + "integrity": "sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -782,13 +794,16 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", - "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.1.tgz", + "integrity": "sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==", "cpu": [ "loong64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -796,13 +811,16 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", - "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.1.tgz", + "integrity": "sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==", "cpu": [ "loong64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -810,13 +828,16 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", - "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.1.tgz", + "integrity": "sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==", "cpu": [ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -824,13 +845,16 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", - "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.1.tgz", + "integrity": "sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==", "cpu": [ "ppc64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -838,13 +862,16 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", - "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.1.tgz", + "integrity": "sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==", "cpu": [ "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -852,13 +879,16 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", - "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.1.tgz", + "integrity": "sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==", "cpu": [ "riscv64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -866,13 +896,16 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", - "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.1.tgz", + "integrity": "sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==", "cpu": [ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -880,13 +913,16 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", - "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.1.tgz", + "integrity": "sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -894,13 +930,16 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", - "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.1.tgz", + "integrity": "sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -908,9 +947,9 @@ ] }, "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", - "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.1.tgz", + "integrity": "sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw==", "cpu": [ "x64" ], @@ -922,9 +961,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", - "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.1.tgz", + "integrity": "sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA==", "cpu": [ "arm64" ], @@ -936,9 +975,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", - "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.1.tgz", + "integrity": "sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g==", "cpu": [ "arm64" ], @@ -950,9 +989,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", - "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.1.tgz", + "integrity": "sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg==", "cpu": [ "ia32" ], @@ -964,9 +1003,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", - "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.1.tgz", + "integrity": "sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg==", "cpu": [ "x64" ], @@ -978,9 +1017,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", - "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.1.tgz", + "integrity": "sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ==", "cpu": [ "x64" ], @@ -1058,9 +1097,9 @@ } }, "node_modules/@types/node": { - "version": "22.19.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.11.tgz", - "integrity": "sha512-BH7YwL6rA93ReqeQS1c4bsPpcfOmJasG+Fkr6Y59q83f9M1WcBRHR2vM+P9eOisYRcN3ujQoiZY8uk5W+1WL8w==", + "version": "22.19.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.17.tgz", + "integrity": "sha512-wGdMcf+vPYM6jikpS/qhg6WiqSV/OhG+jeeHT/KlVqxYfD40iYJf9/AE1uQxVWFvU7MipKRkRv8NSHiCGgPr8Q==", "dev": true, "license": "MIT", "dependencies": { @@ -1245,9 +1284,9 @@ } }, "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", "bin": { @@ -1324,20 +1363,26 @@ } }, "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } }, "node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" } }, "node_modules/bundle-require": { @@ -1533,9 +1578,9 @@ "license": "MIT" }, "node_modules/esbuild": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", - "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -1546,32 +1591,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.3", - "@esbuild/android-arm": "0.27.3", - "@esbuild/android-arm64": "0.27.3", - "@esbuild/android-x64": "0.27.3", - "@esbuild/darwin-arm64": "0.27.3", - "@esbuild/darwin-x64": "0.27.3", - "@esbuild/freebsd-arm64": "0.27.3", - "@esbuild/freebsd-x64": "0.27.3", - "@esbuild/linux-arm": "0.27.3", - "@esbuild/linux-arm64": "0.27.3", - "@esbuild/linux-ia32": "0.27.3", - "@esbuild/linux-loong64": "0.27.3", - "@esbuild/linux-mips64el": "0.27.3", - "@esbuild/linux-ppc64": "0.27.3", - "@esbuild/linux-riscv64": "0.27.3", - "@esbuild/linux-s390x": "0.27.3", - "@esbuild/linux-x64": "0.27.3", - "@esbuild/netbsd-arm64": "0.27.3", - "@esbuild/netbsd-x64": "0.27.3", - "@esbuild/openbsd-arm64": "0.27.3", - "@esbuild/openbsd-x64": "0.27.3", - "@esbuild/openharmony-arm64": "0.27.3", - "@esbuild/sunos-x64": "0.27.3", - "@esbuild/win32-arm64": "0.27.3", - "@esbuild/win32-ia32": "0.27.3", - "@esbuild/win32-x64": "0.27.3" + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" } }, "node_modules/estree-walker": { @@ -1700,6 +1745,39 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/glob/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", + "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -1945,16 +2023,16 @@ "license": "MIT" }, "node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^2.0.2" + "brace-expansion": "^5.0.5" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -1971,16 +2049,16 @@ } }, "node_modules/mlly": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", - "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz", + "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==", "dev": true, "license": "MIT", "dependencies": { - "acorn": "^8.15.0", + "acorn": "^8.16.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", - "ufo": "^1.6.1" + "ufo": "^1.6.3" } }, "node_modules/ms": { @@ -2089,9 +2167,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -2124,9 +2202,9 @@ } }, "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", "dev": true, "funding": [ { @@ -2239,9 +2317,9 @@ } }, "node_modules/rollup": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", - "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.1.tgz", + "integrity": "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==", "dev": true, "license": "MIT", "dependencies": { @@ -2255,31 +2333,31 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.59.0", - "@rollup/rollup-android-arm64": "4.59.0", - "@rollup/rollup-darwin-arm64": "4.59.0", - "@rollup/rollup-darwin-x64": "4.59.0", - "@rollup/rollup-freebsd-arm64": "4.59.0", - "@rollup/rollup-freebsd-x64": "4.59.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", - "@rollup/rollup-linux-arm-musleabihf": "4.59.0", - "@rollup/rollup-linux-arm64-gnu": "4.59.0", - "@rollup/rollup-linux-arm64-musl": "4.59.0", - "@rollup/rollup-linux-loong64-gnu": "4.59.0", - "@rollup/rollup-linux-loong64-musl": "4.59.0", - "@rollup/rollup-linux-ppc64-gnu": "4.59.0", - "@rollup/rollup-linux-ppc64-musl": "4.59.0", - "@rollup/rollup-linux-riscv64-gnu": "4.59.0", - "@rollup/rollup-linux-riscv64-musl": "4.59.0", - "@rollup/rollup-linux-s390x-gnu": "4.59.0", - "@rollup/rollup-linux-x64-gnu": "4.59.0", - "@rollup/rollup-linux-x64-musl": "4.59.0", - "@rollup/rollup-openbsd-x64": "4.59.0", - "@rollup/rollup-openharmony-arm64": "4.59.0", - "@rollup/rollup-win32-arm64-msvc": "4.59.0", - "@rollup/rollup-win32-ia32-msvc": "4.59.0", - "@rollup/rollup-win32-x64-gnu": "4.59.0", - "@rollup/rollup-win32-x64-msvc": "4.59.0", + "@rollup/rollup-android-arm-eabi": "4.60.1", + "@rollup/rollup-android-arm64": "4.60.1", + "@rollup/rollup-darwin-arm64": "4.60.1", + "@rollup/rollup-darwin-x64": "4.60.1", + "@rollup/rollup-freebsd-arm64": "4.60.1", + "@rollup/rollup-freebsd-x64": "4.60.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.1", + "@rollup/rollup-linux-arm-musleabihf": "4.60.1", + "@rollup/rollup-linux-arm64-gnu": "4.60.1", + "@rollup/rollup-linux-arm64-musl": "4.60.1", + "@rollup/rollup-linux-loong64-gnu": "4.60.1", + "@rollup/rollup-linux-loong64-musl": "4.60.1", + "@rollup/rollup-linux-ppc64-gnu": "4.60.1", + "@rollup/rollup-linux-ppc64-musl": "4.60.1", + "@rollup/rollup-linux-riscv64-gnu": "4.60.1", + "@rollup/rollup-linux-riscv64-musl": "4.60.1", + "@rollup/rollup-linux-s390x-gnu": "4.60.1", + "@rollup/rollup-linux-x64-gnu": "4.60.1", + "@rollup/rollup-linux-x64-musl": "4.60.1", + "@rollup/rollup-openbsd-x64": "4.60.1", + "@rollup/rollup-openharmony-arm64": "4.60.1", + "@rollup/rollup-win32-arm64-msvc": "4.60.1", + "@rollup/rollup-win32-ia32-msvc": "4.60.1", + "@rollup/rollup-win32-x64-gnu": "4.60.1", + "@rollup/rollup-win32-x64-msvc": "4.60.1", "fsevents": "~2.3.2" } }, @@ -2528,45 +2606,6 @@ "node": ">=18" } }, - "node_modules/test-exclude/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/test-exclude/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/test-exclude/node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", @@ -2722,17 +2761,17 @@ } }, "node_modules/typedoc": { - "version": "0.28.17", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.28.17.tgz", - "integrity": "sha512-ZkJ2G7mZrbxrKxinTQMjFqsCoYY6a5Luwv2GKbTnBCEgV2ihYm5CflA9JnJAwH0pZWavqfYxmDkFHPt4yx2oDQ==", + "version": "0.28.18", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.28.18.tgz", + "integrity": "sha512-NTWTUOFRQ9+SGKKTuWKUioUkjxNwtS3JDRPVKZAXGHZy2wCA8bdv2iJiyeePn0xkmK+TCCqZFT0X7+2+FLjngA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@gerrit0/mini-shiki": "^3.17.0", + "@gerrit0/mini-shiki": "^3.23.0", "lunr": "^2.3.9", - "markdown-it": "^14.1.0", - "minimatch": "^9.0.5", - "yaml": "^2.8.1" + "markdown-it": "^14.1.1", + "minimatch": "^10.2.4", + "yaml": "^2.8.2" }, "bin": { "typedoc": "bin/typedoc" @@ -2742,7 +2781,7 @@ "pnpm": ">= 10" }, "peerDependencies": { - "typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x" + "typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x || 6.0.x" } }, "node_modules/typescript": { @@ -3505,9 +3544,9 @@ } }, "node_modules/ws": { - "version": "8.19.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", - "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", + "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -3526,9 +3565,9 @@ } }, "node_modules/yaml": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", - "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz", + "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==", "dev": true, "license": "ISC", "bin": { diff --git a/typescript/package.json b/typescript/package.json index 5e72a47..0177f22 100644 --- a/typescript/package.json +++ b/typescript/package.json @@ -90,7 +90,7 @@ "prepublishOnly": "npm run build" }, "dependencies": { - "@jambonz/schema": "^0.1.1", + "@jambonz/schema": "^0.1.5", "ajv": "^8.17.1", "ws": "^8.18.0" }, diff --git a/typescript/test/schema-drift.test.ts b/typescript/test/schema-drift.test.ts index 6441f23..986ec5a 100644 --- a/typescript/test/schema-drift.test.ts +++ b/typescript/test/schema-drift.test.ts @@ -90,7 +90,11 @@ describe('Schema drift detection', () => { const componentsSource = readFileSync(resolve(typesDir, 'components.ts'), 'utf-8'); describe('verb schemas match TypeScript interfaces', () => { - const verbFiles = readdirSync(verbsDir).filter((f) => f.endsWith('.schema.json')); + // rest_dial is an internal server verb — no public TypeScript interface needed + const SKIP_VERBS = ['rest_dial']; + const verbFiles = readdirSync(verbsDir) + .filter((f) => f.endsWith('.schema.json')) + .filter((f) => !SKIP_VERBS.includes(basename(f, '.schema.json'))); for (const file of verbFiles) { const schemaName = basename(file, '.schema.json');