SDKの概要

Vonage Cloud Runtime SDKはすべてのプラットフォーム・プロバイダへの主要なインターフェイスです。Node.jsとPythonで利用可能です。

ランタイム パッケージ 最小バージョン 最新バージョン 備考
Node.js @vonage/vcr-sdk 2.0.0 2.1.5 SDK >=2.1.0 は Node.js 22 (Active LTS) を必要とします。
パイソン vonage_cloud_runtime 2.0.0 2.1.5

について vcr シングルトン

SDKは vcr すべての操作のエントリーポイントとなるシングルトン。

Node.js:

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

パイソン

from vonage_cloud_runtime.vcr import VCR
vcr = VCR()

について vcr オブジェクトは以下のメソッドを提供する:

方法 説明
vcr.createSession(ttl?) オプションでTTLを秒単位で指定して新しいセッションを作成する(デフォルト:7日)
vcr.createSessionWithId(id) 特定のIDでセッションを作成する
vcr.getSessionById(id) IDで既存のセッションを取得する
vcr.getSessionFromRequest(req) HTTPリクエストからセッションを取り出す
vcr.getGlobalSession() グローバルセッションの取得 (すべてのリクエストで共有)
vcr.getInstanceState() インスタンスレベルの状態を取得する(インスタンス内のセッション間で共有される)
vcr.getAccountState() アカウントレベルの状態を取得する(アカウント内のすべてのアプリケーションで共有される)
vcr.getAppUrl() 実行中のアプリケーションの公開URLを取得する。
vcr.createVonageToken(params) Vonage API認証用の署名付きJWTを作成する
vcr.verifyAuth(token) 認証トークンのベリファイ
vcr.unsubscribe(id, provider?) プロバイダーの購読を解除する

セッション

プロバイダーを初期化するには、セッションが必要である。すべてのプロバイダのコンストラクタは、最初の引数としてセッションを取ります。

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();

パイソン

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()

セッションのプロパティとメソッド:

説明
session.id セッション固有の識別子
session.getToken() セッションの認証トークンを取得する
session.createUUID() 新しいUUIDを生成する
session.log(level, message, context?) 構造化されたコンテキストでメッセージを記録する

セッション・スコーピング - 重要なガイダンス

警告だ: vcr.createSession() を生成する。 泡沫夢幻 セッションIDは、それが呼び出されるたびに使用される。そのセッションの下に保存されたデータは(セッションIDを経由して new State(session))は、そのセッションIDを持っている場合のみアクセスできる。もし vcr.createSession() をグローバル/モジュール・スコープで使用し、State、 各レプリカは異なるセッションを作成するそしてデータはサイロ化され、他のレプリカやリクエストからはアクセスできなくなる。これはステートレスアーキテクチャを壊すことになる。

ルール

  • 決して コール vcr.createSession() をグローバル・アプリ・スコープで初期化し、Stateや共有データ・アクセスが必要な他のプロバイダーを初期化する。
  • レプリカ間で状態を共有する場合使用する vcr.getInstanceState() (または vcr.getAccountState() アプリ横断データ用)。
  • リクエストごと、または会話ごとの状態の場合使用する vcr.createSessionWithId(id) を持つ。 決定論的 リクエストコンテキストからIDを取得する。 conversation_uuid 音声コールバックの場合は送信者の電話番号、SMS コールバックの場合は送信者の電話番号、ユーザ ID です。これにより、レプリカやリクエスト間で同じセッションを取得できるようになります。
  • vcr.getGlobalSession() はインスタンス全体のサブスクリプションを登録するためのものです (例えば voice.onCall(), messages.onMessage()).それは 違う 州代表の汎用セッションとして使用される。
// 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');
});

参照 ステートレス・アーキテクチャ を参照されたい。

プロバイダーの初期化

すべてのプロバイダーは、コンストラクターにセッションを渡すという同じパターンに従っている。

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);

パイソン

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)

ステート・スコープ

VCRは3段階の状態を提供する:

スコープ アクセス方法 視認性
セッションの状態 new State(session) 特定のセッションに隔離される
インスタンス状態 vcr.getInstanceState() 同一インスタンス内の全セッションで共有
Accountの状態 vcr.getAccountState() 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();

参照 ステートレス・アーキテクチャ 各スコープを使用する際のガイダンスについては

認証

受信リクエストのベリファイ

用途 vcr.verifyAuth(token) を使用して、受信リクエストのトークンを検証します:

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' });
  }
});

Vonageトークンの作成

用途 vcr.createVonageToken(params) を使用して、Vonage API 認証用の署名付き JWT を生成します:

const token = vcr.createVonageToken({
  exp: Math.floor(Date.now() / 1000) + 3600, // 1-hour expiry
  aclPaths: { '/*/users/**': {} },            // optional ACL paths
  subject: 'user-123',                        // optional subject
});
パラメータ タイプ 必須 説明
exp ナンバー はい トークンの有効期限をUnixタイムスタンプ(秒)で指定。
aclPaths レコード<文字列, 任意 いいえ ACLパスの制限
subject ストリング いいえ トークン・サブジェクト(ユーザー識別子など)

ユーティリティ・メソッド

vcr.getAppUrl()

実行中のVCRインスタンスの公開URLを返します。これは VCR_INSTANCE_PUBLIC_URL 環境変数。

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

vcr.unsubscribe(id, provider?)

プロバイダのサブスクリプションからのコールバックの受信を停止する:

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

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

典型的なアプリケーション構造

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)

重要だ: サーバーは常に 0.0.0.0ではない。 localhost または 127.0.0.1.VCRは内部プロキシを経由してインバウンドトラフィックをルーティングするので、ループバックインターフェースをリッスンするだけではアプリケーションに到達できません。