Descripción general del SDK

El SDK de Vonage Cloud Runtime es la interfaz principal para todos los proveedores de plataformas. Está disponible para Node.js y Python.

Duración Paquete Versión mínima Última versión Notas
Node.js @vonage/vcr-sdk 2.0.0 2.1.5 SDK >=2.1.0 requiere Node.js 22 (Active LTS)
Python vonage_cloud_runtime 2.0.0 2.1.5

El vcr Singleton

El SDK exporta un vcr que es el punto de entrada para todas las operaciones.

Node.js:

import { vcr } from '@vonage/vcr-sdk';

Python:

from vonage_cloud_runtime.vcr import VCR
vcr = VCR()

El vcr proporciona los siguientes métodos:

Método Descripción
vcr.createSession(ttl?) Crear una nueva sesión con TTL opcional en segundos (por defecto: 7 días)
vcr.createSessionWithId(id) Crear una sesión con un ID específico
vcr.getSessionById(id) Recuperar una sesión existente por ID
vcr.getSessionFromRequest(req) Extraer la sesión de una solicitud HTTP entrante
vcr.getGlobalSession() Obtener la sesión global (compartida por todas las solicitudes)
vcr.getInstanceState() Obtener el estado a nivel de instancia (compartido entre sesiones dentro de la instancia)
vcr.getAccountState() Obtener el estado de la cuenta (compartido por todas las aplicaciones de la cuenta)
vcr.getAppUrl() Obtener la URL pública de la aplicación en ejecución
vcr.createVonageToken(params) Crear un JWT firmado para la autenticación de la API de Vonage
vcr.verifyAuth(token) Verificar un token de autenticación
vcr.unsubscribe(id, provider?) Cancelar la suscripción a un proveedor

Sesiones

Se necesitan sesiones para inicializar cualquier proveedor. El constructor de cada proveedor toma una sesión como primer argumento.

Node.js:

import { vcr } from '@vonage/vcr-sdk';

// New session with default 7-day TTL
const session = vcr.createSession();

// New session with a 1-hour TTL
const shortSession = vcr.createSession(3600);

// Session with a specific ID (useful for correlating with a user or call)
const userSession = vcr.createSessionWithId('user-123');

// Extract session from an incoming request
const reqSession = vcr.getSessionFromRequest(req);

// Global session — shared singleton across the entire instance
const globalSession = vcr.getGlobalSession();

Python:

from vonage_cloud_runtime.vcr import VCR
vcr = VCR()

session = vcr.createSession()           # default 7-day TTL
session = vcr.createSession(3600)       # 1-hour TTL
session = vcr.createSessionWithId('user-123')
session = vcr.getSessionFromRequest(req)
session = vcr.getGlobalSession()

Propiedades y métodos de la sesión:

Descripción
session.id El identificador único de la sesión
session.getToken() Obtener el token de autenticación de la sesión
session.createUUID() Generar un nuevo UUID
session.log(level, message, context?) Registrar un mensaje con contexto estructurado

Ámbito de la sesión: orientaciones fundamentales

Advertencia: vcr.createSession() genera un aleatorio, efímero ID de sesión cada vez que se llama. Los datos almacenados en esa sesión (mediante new State(session)) solo es accesible si dispones de ese ID de sesión concreto. Si llamas a vcr.createSession() en el ámbito global/módulo y utilizarlo con State, Cada réplica creará una sesión diferente., y los datos quedarán aislados y serán inaccesibles para otras réplicas o solicitudes. Esto rompe la arquitectura sin estado.

Reglas:

  • Nunca llamada vcr.createSession() en el ámbito global de la aplicación para inicializar State u otros proveedores que necesiten acceso a datos compartidos.
  • Para el estado compartido entre réplicas, utiliza vcr.getInstanceState() (o vcr.getAccountState() para datos entre aplicaciones).
  • Para el estado por solicitud o por conversación, utiliza vcr.createSessionWithId(id) con un determinista ID del contexto de la solicitud — como, por ejemplo, conversation_uuid a partir de una llamada de retorno de voz, del número de teléfono del remitente en una llamada de retorno por SMS o de un identificador de usuario. Esto garantiza que se pueda recuperar la misma sesión en todas las réplicas y solicitudes.
  • vcr.getGlobalSession() está pensado para registrar suscripciones a nivel de instancia (por ejemplo, voice.onCall(), messages.onMessage()). Debería no utilizarse como sesión de uso general para State.
// WRONG — random session at global scope, state is unreachable by other replicas/requests
const session = vcr.createSession();
const state = new State(session); // Data siloed to this random session

// CORRECT — shared state across all replicas
const state = vcr.getInstanceState();

// CORRECT — per-conversation state using a deterministic ID from a callback
app.post('/onCall', async (req, res) => {
  const session = vcr.createSessionWithId(req.body.conversation_uuid);
  const state = new State(session); // Same conversation_uuid = same state, any replica
  await state.set('step', 'greeting');
});

Véase Arquitectura sin Estado para obtener información detallada.

Inicialización del proveedor

Todos los proveedores siguen el mismo patrón: pasar una sesión al constructor.

Node.js:

import { vcr, State, Queue, Scheduler, Messages, Voice, Assets } from '@vonage/vcr-sdk';

const session = vcr.createSession();

// For shared state across replicas, use getInstanceState() — not new State(session)
const state     = vcr.getInstanceState();
const queue     = new Queue(session);
const scheduler = new Scheduler(session);
const messages  = new Messages(session);
const voice     = new Voice(session);
const assets    = new Assets(session);

Python:

from vonage_cloud_runtime.vcr import VCR
from vonage_cloud_runtime.providers.state.state import State
from vonage_cloud_runtime.providers.queue.queue import Queue
from vonage_cloud_runtime.providers.scheduler.scheduler import Scheduler
from vonage_cloud_runtime.providers.messages.messages import Messages
from vonage_cloud_runtime.providers.voice.voice import Voice
from vonage_cloud_runtime.providers.assets.assets import Assets

vcr = VCR()
session = vcr.createSession()

# For shared state across replicas, use getInstanceState() — not State(session)
state     = vcr.getInstanceState()
queue     = Queue(session)
scheduler = Scheduler(session)
messages  = Messages(session)
voice     = Voice(session)
assets    = Assets(session)

Ámbito estatal

VCR ofrece tres niveles de estado:

Ámbito de aplicación Cómo acceder Visibilidad
Estado de la sesión new State(session) Aislado a la sesión específica
Estado de la instancia vcr.getInstanceState() Compartido entre todas las sesiones de una misma instancia
Estado de la cuenta vcr.getAccountState() Compartido en todas las aplicaciones de la cuenta de Vonage
// Per-user state
const session = vcr.createSessionWithId(userId);
const userState = new State(session);

// Shared across all replicas of this instance
const instanceState = vcr.getInstanceState();

// Shared across all applications in the account
const accountState = vcr.getAccountState();

Véase Arquitectura sin Estado para saber cuándo utilizar cada tipo de alcance.

Autenticación

Verificación de las solicitudes recibidas

Uso vcr.verifyAuth(token) para validar los tokens en las solicitudes entrantes:

app.use((req, res, next) => {
  const token = req.headers.authorization?.replace('Bearer ', '');
  try {
    const decoded = vcr.verifyAuth(token);
    req.user = decoded;
    next();
  } catch (err) {
    res.status(401).json({ error: 'Invalid token' });
  }
});

Creación de tokens de Vonage

Uso vcr.createVonageToken(params) Para generar JWT firmados para la autenticación en la API de Vonage:

const token = vcr.createVonageToken({
  exp: Math.floor(Date.now() / 1000) + 3600, // 1-hour expiry
  aclPaths: { '/*/users/**': {} },            // optional ACL paths
  subject: 'user-123',                        // optional subject
});
Parámetro Tipo Requerido Descripción
exp número Expiración del token como marca de tiempo Unix (segundos)
aclPaths Registro<string, any> No Restricciones de ruta ACL
subject cadena No Sujeto del token (por ejemplo, identificador de usuario)

Métodos de utilidad

vcr.getAppUrl()

Devuelve la URL pública de la instancia de VCR en ejecución. Equivale a leer el VCR_INSTANCE_PUBLIC_URL variable de entorno.

const appUrl = vcr.getAppUrl();
// e.g. "https://my-app-dev.use1.runtime.vonage.cloud"

vcr.unsubscribe(id, provider?)

Dejar de recibir callbacks de una suscripción de proveedor:

const subId = await voice.onCall('onCall');

// Later, when you want to stop receiving calls:
await vcr.unsubscribe(subId, 'voice');

Estructura típica de las Applications

Node.js (Express):

import express from 'express';
import { vcr, Voice, Messages, State } from '@vonage/vcr-sdk';

const app = express();
app.use(express.json());

// Use getGlobalSession() for registering instance-wide subscriptions.
// Do NOT use vcr.createSession() here — it creates a random session that
// cannot be shared across replicas or requests.
const globalSession = vcr.getGlobalSession();
const voice = new Voice(globalSession);
const messages = new Messages(globalSession);

await voice.onCall('onCall');
await messages.onMessage('onMessage',
  { type: 'sms', number: process.env.VONAGE_NUMBER },
  { type: 'sms', number: undefined }
);

app.post('/onCall', async (req, res) => {
  // Scope session to the conversation using its unique ID from the callback
  const session = vcr.createSessionWithId(req.body.conversation_uuid);
  const state = new State(session);
  await state.set('status', 'answered');
  res.json([{ action: 'talk', text: 'Hello from VCR!' }]);
});

app.post('/onMessage', async (req, res) => {
  // Scope session to the sender — deterministic, same across replicas
  const session = vcr.createSessionWithId(req.body.from);
  const state = new State(session);
  await state.set('lastMessage', req.body.text);
  res.sendStatus(200);
});

app.get('/_/health', (req, res) => res.sendStatus(200));

// Must bind to 0.0.0.0 — VCR routes traffic via an internal proxy
const port = process.env.VCR_PORT || 8080;
app.listen(port, '0.0.0.0');

Python (FastAPI):

import os
from fastapi import FastAPI, Request
from vonage_cloud_runtime.vcr import VCR
from vonage_cloud_runtime.providers.voice.voice import Voice
from vonage_cloud_runtime.providers.messages.messages import Messages
from vonage_cloud_runtime.providers.state.state import State

app = FastAPI()
vcr = VCR()

# Use getGlobalSession() for registering instance-wide subscriptions.
# Do NOT use vcr.createSession() here — it creates a random session that
# cannot be shared across replicas or requests.
global_session = vcr.getGlobalSession()
voice = Voice(global_session)
messages = Messages(global_session)

@app.on_event("startup")
async def startup():
    await voice.onCall("onCall")
    await messages.onMessage("onMessage",
        {"type": "sms", "number": os.environ.get("VONAGE_NUMBER")},
        {"type": "sms", "number": None}
    )

@app.post("/onCall")
async def on_call(request: Request):
    body = await request.json()
    # Scope session to the conversation using its unique ID from the callback
    session = vcr.createSessionWithId(body.get("conversation_uuid"))
    state = State(session)
    await state.set("status", "answered")
    return [{"action": "talk", "text": "Hello from VCR!"}]

@app.post("/onMessage")
async def on_message(request: Request):
    body = await request.json()
    # Scope session to the sender — deterministic, same across replicas
    session = vcr.createSessionWithId(body.get("from"))
    state = State(session)
    await state.set("lastMessage", body.get("text"))
    return {"status": "ok"}

@app.get("/_/health")
async def health():
    return {"status": "ok"}

if __name__ == "__main__":
    import uvicorn
    port = int(os.environ.get("VCR_PORT", 8080))
    uvicorn.run(app, host="0.0.0.0", port=port)

Importante: Vincule siempre su servidor a 0.0.0.0, no localhost o 127.0.0.1. VCR redirige el tráfico entrante a través de un proxy interno y no se podrá acceder a la aplicación si esta solo escucha en la interfaz de bucle invertido.