payfri-video-sdk 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +123 -92
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,91 +1,112 @@
1
1
  # payfri-video-sdk
2
2
 
3
- SDK del **servicio de video de Payfri**. Integra videollamadas en tu producto en minutos: tu
4
- backend emite tokens contra la API del servicio y tu frontend se une a la llamada — sin implementar
5
- WebRTC ni montar infraestructura de medios propia. Tres entry points con una **separación estricta
6
- de seguridad**:
3
+ SDK oficial del **servicio de video de Payfri**. Integra videollamadas en tu producto sin
4
+ implementar WebRTC ni montar infraestructura de medios.
7
5
 
8
- | Entry | Dónde corre | Credencial que recibe | Para qué |
9
- | --- | --- | --- | --- |
10
- | `payfri-video-sdk/server` | Tu **backend** | **API key** del tenant (secreta) | Crear salas y emitir tokens |
11
- | `payfri-video-sdk/client` | **Navegador** | Solo un **token** de corta duración | Unirse a la llamada (web) |
12
- | `payfri-video-sdk/native` | **React Native** | Solo un **token** de corta duración | Unirse a la llamada (móvil) |
6
+ ## La idea en 30 segundos
13
7
 
14
- > La API key **jamás** debe llegar al navegador ni al dispositivo. Los tipos de `/client` y
15
- > `/native` hacen **imposible** pasarla (no compila), y además hay una verificación en runtime.
8
+ Una videollamada son dos pasos, en dos lugares distintos:
16
9
 
17
- ## Cómo funciona
10
+ 1. **Tu backend** pide un token de acceso al servicio (aquí vive tu **API key**, que es secreta).
11
+ 2. **Tu frontend** (web o móvil) se une a la llamada con ese token (expira; default 1 hora).
18
12
 
19
13
  ```
20
14
  Tu backend ──(API key)──▶ API de video ──▶ { token, livekitUrl }
21
-
22
- └────────── pasa token + livekitUrl ─────────┘
23
-
24
- Navegador / app móvil se une a la llamada con el token
15
+
16
+ └──▶ tu frontend se une a la llamada con { token, livekitUrl }
25
17
  ```
26
18
 
27
- 1. Tu backend usa la API key para pedir un **token de acceso** (`tokens.issue`).
28
- 2. Le pasas `{ token, livekitUrl }` a tu frontend (respuesta de tu propio endpoint).
29
- 3. El frontend se une a la sala con `/client` (web) o `/native` (React Native).
30
-
31
- Los tokens expiran (default **1 hora**, configurable de 60 s a 12 h), así que emite uno nuevo por
32
- participante y por sesión.
33
-
34
- ## Qué necesitas antes de empezar
35
-
36
- Te lo entrega el equipo que administra el servicio de video:
37
-
38
- - **`baseUrl`** — URL de la API de video, p. ej. `https://api.video.tuempresa.com`
39
- - **`apiKey`** — API key de tu tenant (formato `{prefijo}_live_{aleatorio}`). Se muestra **una sola
40
- vez** al crearla: guárdala en un gestor de secretos, nunca en el código.
41
- - **`embedBaseUrl`** (solo para `/native`) — URL de la página embebible, p. ej.
42
- `https://embed.tuempresa.com`
43
- - **Alta de CORS** — pide que agreguen el dominio de tu frontend a los orígenes permitidos de la API.
44
-
45
- Requisitos técnicos: Node 18+ en el backend (usa `fetch` global; en runtimes sin él puedes inyectar
46
- uno propio). El paquete se distribuye en **ESM + CJS con tipos incluidos**.
47
-
48
- ## Instalación
49
-
50
- ```bash
51
- # Backend (emitir tokens) — sin dependencias extra
52
- npm install payfri-video-sdk
53
-
54
- # Navegador (unirse a la llamada) — livekit-client es peer dependency
55
- npm install payfri-video-sdk livekit-client
19
+ El SDK trae un entry point para cada lugar:
56
20
 
57
- # React Native / Expo
58
- npm install payfri-video-sdk react-native-webview
59
- ```
21
+ | Entry | Dónde corre | Recibe | Para qué |
22
+ | --- | --- | --- | --- |
23
+ | `payfri-video-sdk/server` | Tu backend | API key (secreta) | Emitir tokens, administrar salas |
24
+ | `payfri-video-sdk/client` | Navegador | Solo el token | Unirse a la llamada (web, tú pones la UI) |
25
+ | `payfri-video-sdk/native` | React Native | Solo el token | Unirse a la llamada (móvil, UI lista) |
60
26
 
61
- Todas las peer dependencies son **opcionales**: instala solo lo que exige el entry que uses.
27
+ Dos cosas que conviene saber desde ya:
62
28
 
63
- > `livekit-client` aparece porque el motor de medios del servicio es [LiveKit](https://livekit.io);
64
- > es un detalle interno de implementación solo interactúas con la API del servicio y con este SDK.
29
+ - **Regla de oro:** la API key jamás sale de tu servidor. `/client` y `/native` ni siquiera
30
+ compilan si intentas pasarles una (y lo verifican también en runtime).
31
+ - **El SDK de backend es opcional.** `/server` es un wrapper de conveniencia sobre la API REST del
32
+ servicio. Si prefieres, llama a la API directo con cualquier HTTP client —
33
+ [ejemplo abajo](#sin-sdk-rest-directo).
65
34
 
66
- ---
35
+ ## Inicio rápido
67
36
 
68
- ## Backend`payfri-video-sdk/server`
37
+ **1. En tu backend emite el token:**
69
38
 
70
39
  ```ts
71
40
  import { createVideoClient } from "payfri-video-sdk/server";
72
41
 
73
42
  const video = createVideoClient({
74
43
  baseUrl: process.env.VIDEO_API_BASE_URL!, // https://api.video.tuempresa.com
75
- apiKey: process.env.VIDEO_API_KEY!, // secreta, SOLO en el servidor
44
+ apiKey: process.env.VIDEO_API_KEY!, // secreta, SOLO aquí
76
45
  });
77
46
 
78
- // Emitir un token para un participante (crea la sala si no existe)
47
+ // En tu endpoint (protegido con TU auth):
79
48
  const { token, livekitUrl } = await video.tokens.issue({
80
49
  roomName: "consulta-123",
81
- identity: "doctor-45",
50
+ identity: "doctor-45", // id único de TU usuario
82
51
  displayName: "Dra. López",
83
- createIfMissing: true,
52
+ createIfMissing: true, // crea la sala si no existe
84
53
  });
54
+ // devuelve { token, livekitUrl } a tu frontend
55
+ ```
56
+
57
+ **2a. En el navegador — únete:**
85
58
 
86
- // Devuelve { token, livekitUrl } a tu frontend. NUNCA la apiKey.
59
+ ```ts
60
+ import { joinRoom } from "payfri-video-sdk/client";
61
+
62
+ const handle = await joinRoom({
63
+ token, // desde tu backend
64
+ livekitUrl, // desde tu backend
65
+ container: document.getElementById("call")!,
66
+ });
67
+
68
+ await handle.toggleMic();
69
+ await handle.leave();
87
70
  ```
88
71
 
72
+ **2b. O en React Native — únete:**
73
+
74
+ ```tsx
75
+ import { VideoCall } from "payfri-video-sdk/native";
76
+
77
+ <VideoCall token={token} livekitUrl={livekitUrl} embedBaseUrl="https://embed.tuempresa.com" style={{ flex: 1 }} />;
78
+ ```
79
+
80
+ Eso es todo el flujo. Lo demás es referencia.
81
+
82
+ ## Qué necesitas
83
+
84
+ Te lo entrega el equipo que administra el servicio:
85
+
86
+ - **`baseUrl`** — URL de la API de video
87
+ - **`apiKey`** — la key de tu tenant. Se muestra **una sola vez** al crearla: guárdala en un gestor
88
+ de secretos, nunca en el código
89
+ - **`embedBaseUrl`** — URL de la página de llamada (solo si usas `/native`)
90
+
91
+ Técnico: Node 18+ en el backend (o inyecta tu propio `fetch`). El paquete es ESM + CJS con tipos
92
+ TypeScript incluidos.
93
+
94
+ ## Instalación
95
+
96
+ ```bash
97
+ npm install payfri-video-sdk # backend: suficiente para /server
98
+ npm install payfri-video-sdk livekit-client # web: /client necesita livekit-client
99
+ npm install payfri-video-sdk react-native-webview # móvil: /native necesita el WebView
100
+ ```
101
+
102
+ Las peer dependencies son opcionales: instala solo lo que exige el entry que uses. (`livekit-client`
103
+ aparece porque el motor de medios del servicio es [LiveKit](https://livekit.io) — detalle interno;
104
+ tú solo interactúas con este SDK.)
105
+
106
+ ---
107
+
108
+ ## Referencia: `/server` (backend)
109
+
89
110
  ### `createVideoClient(options)`
90
111
 
91
112
  | Opción | Tipo | Requerido | Descripción |
@@ -148,23 +169,39 @@ try {
148
169
 
149
170
  | `status` | Causa típica |
150
171
  | --- | --- |
172
+ | 400 | Body inválido (revisa `message`) |
151
173
  | 401 | API key inválida o revocada |
152
174
  | 403 | Tenant suspendido |
153
175
  | 404 | Sala inexistente (usa `createIfMissing: true` si aplica) |
154
- | 400 | Body inválido (revisa `message`) |
176
+
177
+ ### Sin SDK: REST directo
178
+
179
+ `/server` solo envuelve la API REST. El mismo token del inicio rápido, con `curl`:
180
+
181
+ ```bash
182
+ curl -X POST "$VIDEO_API_BASE_URL/v1/tokens" \
183
+ -H "Authorization: Bearer $VIDEO_API_KEY" \
184
+ -H "Content-Type: application/json" \
185
+ -d '{"roomName":"consulta-123","identity":"doctor-45","displayName":"Dra. López","createIfMissing":true}'
186
+ # → { "token": "...", "livekitUrl": "wss://...", "roomName": "...", "identity": "...", "expiresAt": "..." }
187
+ ```
188
+
189
+ Endpoints equivalentes: `POST /v1/tokens`, `POST /v1/rooms`, `GET /v1/rooms/:roomName`,
190
+ `DELETE /v1/rooms/:roomName`. Los errores tienen la forma `{ error: { code, message } }`. La
191
+ documentación completa (Swagger) vive en `<baseUrl>/docs`. Úsalo desde cualquier lenguaje —
192
+ el SDK solo es obligatorio si quieres los tipos y el manejo de errores ya resueltos.
155
193
 
156
194
  ---
157
195
 
158
- ## Navegador — `payfri-video-sdk/client`
196
+ ## Referencia: `/client` (navegador)
197
+
198
+ `joinRoom` conecta a la sala y monta los `<video>` en tu contenedor. **La UI es tuya**: tú pones
199
+ los botones y llamas a los métodos del handle.
159
200
 
160
201
  ```ts
161
202
  import { joinRoom } from "payfri-video-sdk/client";
162
203
 
163
- const handle = await joinRoom({
164
- token, // recibido desde TU backend
165
- livekitUrl, // recibido desde TU backend
166
- container: document.getElementById("call")!,
167
- });
204
+ const handle = await joinRoom({ token, livekitUrl, container: document.getElementById("call")! });
168
205
 
169
206
  handle.on("participantJoined", (p) => console.log("entró", p.identity));
170
207
  handle.on("error", (e) => console.error(e));
@@ -178,8 +215,8 @@ await handle.leave(); // salir y liberar recursos
178
215
 
179
216
  | Opción | Tipo | Default | Descripción |
180
217
  | --- | --- | --- | --- |
181
- | `token` | `string` | requerido | Token de acceso emitido por tu backend |
182
- | `livekitUrl` | `string` | requerido | URL `wss` del servidor de medios (la devuelve `tokens.issue`; pásala tal cual) |
218
+ | `token` | `string` | requerido | Token emitido por tu backend |
219
+ | `livekitUrl` | `string` | requerido | URL `wss` del servidor de medios (viene con el token; pásala tal cual) |
183
220
  | `container` | `HTMLElement` | requerido | Elemento donde se montan los videos |
184
221
  | `enableCamera` | `boolean` | `true` | Publicar cámara al conectar |
185
222
  | `enableMicrophone` | `boolean` | `true` | Publicar micrófono al conectar |
@@ -198,30 +235,22 @@ await handle.leave(); // salir y liberar recursos
198
235
 
199
236
  Para casos avanzados, `handle.room` expone el `Room` de `livekit-client` subyacente.
200
237
 
201
- ### Seguridad de tipos
202
-
203
- `joinRoom` **no tiene** campo para la API key. Esto no compila:
204
-
205
- ```ts
206
- // @ts-expect-error — apiKey no existe en JoinRoomOptions
207
- joinRoom({ token, livekitUrl, container, apiKey: "..." });
208
- ```
209
-
210
- Y en runtime, `joinRoom` lanza si detecta `apiKey`/`apiSecret`/`secret` en las opciones.
238
+ > Seguridad: `joinRoom` no tiene campo para la API key — pasarla no compila, y en runtime lanza si
239
+ > detecta `apiKey`/`apiSecret`/`secret` en las opciones.
211
240
 
212
241
  ---
213
242
 
214
- ## React Native — `payfri-video-sdk/native`
243
+ ## Referencia: `/native` (React Native)
215
244
 
216
- Componente `<VideoCall>` que incrusta la videollamada en un `WebView` (carga la página embebible
217
- del servicio). **No requiere `react-native-webrtc`** ni código nativo propio.
245
+ `<VideoCall>` incrusta la llamada **con UI lista** (la página del servicio dentro de un `WebView`).
246
+ No requiere `react-native-webrtc` ni código nativo propio.
218
247
 
219
248
  ```tsx
220
249
  import { VideoCall } from "payfri-video-sdk/native";
221
250
 
222
251
  <VideoCall
223
- token={token} // recibido desde TU backend
224
- livekitUrl={livekitUrl} // recibido desde TU backend
252
+ token={token} // desde tu backend
253
+ livekitUrl={livekitUrl} // desde tu backend
225
254
  embedBaseUrl="https://embed.tuempresa.com"
226
255
  onConnected={() => console.log("conectado")}
227
256
  onLeave={() => navigation.goBack()}
@@ -234,9 +263,9 @@ import { VideoCall } from "payfri-video-sdk/native";
234
263
 
235
264
  | Prop | Tipo | Requerido | Descripción |
236
265
  | --- | --- | --- | --- |
237
- | `token` | `string` | ✅ | Token de acceso emitido por tu backend |
238
- | `livekitUrl` | `string` | ✅ | URL `wss` del servidor de medios (la devuelve `tokens.issue`; pásala tal cual) |
239
- | `embedBaseUrl` | `string` | ✅ | Base de la página embebible (**HTTPS obligatorio**) |
266
+ | `token` | `string` | ✅ | Token emitido por tu backend |
267
+ | `livekitUrl` | `string` | ✅ | URL `wss` del servidor de medios (viene con el token; pásala tal cual) |
268
+ | `embedBaseUrl` | `string` | ✅ | Base de la página de llamada (**HTTPS obligatorio**) |
240
269
  | `theme` | `string` | — | Color de acento para branding (ej. `#4f7cff`) |
241
270
  | `onConnected` | `() => void` | — | La videollamada conectó |
242
271
  | `onDisconnected` | `() => void` | — | El usuario se desconectó o se cerró la sala |
@@ -246,7 +275,7 @@ import { VideoCall } from "payfri-video-sdk/native";
246
275
  | `onError` | `(error: Error) => void` | — | Permisos denegados, token inválido, fallo de sala |
247
276
  | `style` | `StyleProp<ViewStyle>` | — | Estilo del contenedor (default: ocupa todo) |
248
277
 
249
- Igual que `/client`, `VideoCallProps` **no tiene** campo para la API key (no compila si la pasas).
278
+ Igual que `/client`, no existe campo para la API key (no compila si la pasas).
250
279
 
251
280
  ### Permisos de cámara y micrófono
252
281
 
@@ -262,12 +291,15 @@ Igual que `/client`, `VideoCallProps` **no tiene** campo para la API key (no com
262
291
  }
263
292
  ```
264
293
 
265
- El plugin inyecta en el prebuild `NSCameraUsageDescription` / `NSMicrophoneUsageDescription` (iOS)
266
- y `CAMERA` / `RECORD_AUDIO` / `MODIFY_AUDIO_SETTINGS` (Android).
294
+ El plugin inyecta `NSCameraUsageDescription` / `NSMicrophoneUsageDescription` (iOS) y
295
+ `CAMERA` / `RECORD_AUDIO` / `MODIFY_AUDIO_SETTINGS` (Android).
267
296
 
268
297
  **React Native "bare"** (sin Expo) — agrégalos a mano en `Info.plist` y `AndroidManifest.xml`.
269
- En Android, `MODIFY_AUDIO_SETTINGS` es obligatorio: el WebView lo exige junto a `RECORD_AUDIO`
270
- para capturar audio; sin él el micrófono falla con "Could not start audio source".
298
+ En Android, `MODIFY_AUDIO_SETTINGS` es obligatorio: el WebView lo exige junto a `RECORD_AUDIO`;
299
+ sin él el micrófono falla con "Could not start audio source".
300
+
301
+ **Prueba en un dev build en teléfono real** (`npx expo run:android` / `run:ios`) — Expo Go no
302
+ aplica config plugins, así que los permisos no existen ahí.
271
303
 
272
304
  > App de ejemplo completa (Expo):
273
305
  > [`examples/expo-videocall`](https://github.com/Payfri/VideoCallsGateway/tree/main/examples/expo-videocall)
@@ -279,10 +311,9 @@ para capturar audio; sin él el micrófono falla con "Could not start audio sour
279
311
  | Síntoma | Causa probable | Solución |
280
312
  | --- | --- | --- |
281
313
  | `401 UNAUTHORIZED` desde `/server` | API key mal copiada o revocada | Verifica la env var; pide una key nueva si fue revocada |
282
- | CORS bloquea la petición del navegador | Tu dominio no está en la lista de orígenes | Pide el alta de tu dominio al equipo de la plataforma |
283
314
  | "token inválido o expirado" al unirse | El token venció (default 1 h) | Emite un token nuevo por sesión; sube `ttlSeconds` si aplica |
284
315
  | Cámara/micrófono no arrancan (web) | Contexto no seguro | Sirve tu página por **HTTPS** (`getUserMedia` lo exige) |
285
- | Cámara/micrófono no arrancan (RN) | Permisos no declarados | Config plugin (Expo) o permisos manuales (bare) + rebuild |
316
+ | Cámara/micrófono no arrancan (RN) | Permisos no declarados, o Expo Go | Config plugin + dev build (Expo) o permisos manuales (bare) |
286
317
  | `No hay fetch disponible` en `/server` | Node < 18 o runtime sin fetch | Usa Node 18+ o pasa `fetch` en las opciones |
287
318
  | Pantalla en blanco en `<VideoCall>` | `embedBaseUrl` en HTTP o mal apuntada | Debe ser HTTPS y responder la página `/room` |
288
319
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "payfri-video-sdk",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "SDK del microservicio de video: entry /server (apiKey, backend), /client (token, navegador) y /native (token, React Native)",
5
5
  "license": "MIT",
6
6
  "keywords": ["livekit", "video", "webrtc", "react-native", "expo", "sdk"],