streemo-video-call-sdk 0.2.5 → 0.2.7
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.
- package/dist/client.d.ts +2 -2
- package/dist/client.js +161 -0
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +19 -120
- package/dist/index.js +106 -28
- package/dist/index.js.map +1 -1
- package/dist/sdkConfig-DTNZ7Mms.d.ts +165 -0
- package/dist/styles.css +52 -88
- package/package.json +4 -1
- package/dist/sdkConfig-C9Fey7R2.d.ts +0 -42
package/dist/client.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { T as TokenProvider, S as ServerAuthConfig } from './sdkConfig-
|
|
2
|
-
export { a as SDKError, b as SDKErrorCode, c as ServerTokenProviderOptions, d as TokenProviderContext, V as VideoSDKConfig,
|
|
1
|
+
import { T as TokenProvider, S as ServerAuthConfig } from './sdkConfig-DTNZ7Mms.js';
|
|
2
|
+
export { a as SDKError, b as SDKErrorCode, c as ServerTokenProviderOptions, d as StreemoClient, e as StreemoClientOptions, f as TokenProviderContext, V as VideoSDKConfig, g as createServerTokenProvider, h as createStreemoClient, i as defaultApiBaseUrl, j as defaultWsBaseUrlFromApi, k as getVideoSDKConfig, l as initVideoSDK, m as mapSDKErrorToUIMessage } from './sdkConfig-DTNZ7Mms.js';
|
|
3
3
|
|
|
4
4
|
type SignalMessage = {
|
|
5
5
|
type: string;
|
package/dist/client.js
CHANGED
|
@@ -263,10 +263,171 @@ var VideoSignalingClient = class {
|
|
|
263
263
|
this.connected = false;
|
|
264
264
|
}
|
|
265
265
|
};
|
|
266
|
+
|
|
267
|
+
// src/client/StreemoClient.ts
|
|
268
|
+
var StreemoClient = class {
|
|
269
|
+
apiKey;
|
|
270
|
+
userToken;
|
|
271
|
+
user;
|
|
272
|
+
baseUrl;
|
|
273
|
+
wsUrl;
|
|
274
|
+
reconnect;
|
|
275
|
+
ws = null;
|
|
276
|
+
manuallyClosed = false;
|
|
277
|
+
reconnectAttempt = 0;
|
|
278
|
+
listeners = {};
|
|
279
|
+
constructor(options) {
|
|
280
|
+
this.apiKey = options.apiKey;
|
|
281
|
+
this.userToken = options.userToken;
|
|
282
|
+
this.user = options.user;
|
|
283
|
+
this.baseUrl = (options.baseUrl ?? "https://api.streemo.ru").replace(/\/+$/, "");
|
|
284
|
+
const defaultWs = this.baseUrl.replace(/^http/, "ws");
|
|
285
|
+
this.wsUrl = (options.wsUrl ?? defaultWs).replace(/\/+$/, "");
|
|
286
|
+
this.reconnect = options.reconnect ?? true;
|
|
287
|
+
}
|
|
288
|
+
on(event, listener) {
|
|
289
|
+
if (!this.listeners[event]) this.listeners[event] = /* @__PURE__ */ new Set();
|
|
290
|
+
this.listeners[event]?.add(listener);
|
|
291
|
+
return () => this.off(event, listener);
|
|
292
|
+
}
|
|
293
|
+
off(event, listener) {
|
|
294
|
+
this.listeners[event]?.delete(listener);
|
|
295
|
+
}
|
|
296
|
+
emit(event, payload) {
|
|
297
|
+
this.listeners[event]?.forEach((listener) => {
|
|
298
|
+
listener(payload);
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
async connect() {
|
|
302
|
+
if (this.ws && (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING)) return;
|
|
303
|
+
this.manuallyClosed = false;
|
|
304
|
+
await this.openSocket();
|
|
305
|
+
}
|
|
306
|
+
disconnect() {
|
|
307
|
+
this.manuallyClosed = true;
|
|
308
|
+
this.ws?.close();
|
|
309
|
+
this.ws = null;
|
|
310
|
+
this.emit("connected", { connected: false });
|
|
311
|
+
}
|
|
312
|
+
async openSocket() {
|
|
313
|
+
await new Promise((resolve, reject) => {
|
|
314
|
+
const url = `${this.wsUrl}/v1/ws?token=${encodeURIComponent(this.userToken)}&userId=${encodeURIComponent(this.user.id)}`;
|
|
315
|
+
const ws = new WebSocket(url);
|
|
316
|
+
this.ws = ws;
|
|
317
|
+
ws.onopen = () => {
|
|
318
|
+
this.reconnectAttempt = 0;
|
|
319
|
+
this.emit("connected", { connected: true });
|
|
320
|
+
resolve();
|
|
321
|
+
};
|
|
322
|
+
ws.onmessage = (event) => {
|
|
323
|
+
const parsed = JSON.parse(event.data);
|
|
324
|
+
switch (parsed.type) {
|
|
325
|
+
case "message_new":
|
|
326
|
+
case "message_updated":
|
|
327
|
+
this.emit(parsed.type, parsed);
|
|
328
|
+
break;
|
|
329
|
+
case "typing":
|
|
330
|
+
this.emit("typing", parsed);
|
|
331
|
+
break;
|
|
332
|
+
case "presence":
|
|
333
|
+
this.emit("presence", parsed);
|
|
334
|
+
break;
|
|
335
|
+
case "reaction_new":
|
|
336
|
+
this.emit("reaction_new", parsed);
|
|
337
|
+
break;
|
|
338
|
+
default:
|
|
339
|
+
break;
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
ws.onerror = () => {
|
|
343
|
+
reject(new Error("WebSocket connection failed"));
|
|
344
|
+
};
|
|
345
|
+
ws.onclose = () => {
|
|
346
|
+
this.emit("connected", { connected: false });
|
|
347
|
+
if (!this.manuallyClosed && this.reconnect) {
|
|
348
|
+
const backoffMs = Math.min(1e3 * 2 ** this.reconnectAttempt, 15e3);
|
|
349
|
+
this.reconnectAttempt += 1;
|
|
350
|
+
setTimeout(() => {
|
|
351
|
+
void this.openSocket();
|
|
352
|
+
}, backoffMs);
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
buildUrl(path, query) {
|
|
358
|
+
const url = new URL(`${this.baseUrl}${path}`);
|
|
359
|
+
if (query) {
|
|
360
|
+
Object.entries(query).forEach(([key, value]) => {
|
|
361
|
+
if (value !== void 0) url.searchParams.set(key, String(value));
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
return url.toString();
|
|
365
|
+
}
|
|
366
|
+
async request(path, init, query) {
|
|
367
|
+
const response = await fetch(this.buildUrl(path, query), {
|
|
368
|
+
...init,
|
|
369
|
+
headers: {
|
|
370
|
+
Authorization: `Bearer ${this.userToken}`,
|
|
371
|
+
"X-App-Id": this.apiKey,
|
|
372
|
+
"Content-Type": "application/json",
|
|
373
|
+
...init?.headers ?? {}
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
const data = await response.json().catch(() => ({}));
|
|
377
|
+
if (!response.ok) {
|
|
378
|
+
throw new Error(data.error || `HTTP ${response.status}`);
|
|
379
|
+
}
|
|
380
|
+
return data;
|
|
381
|
+
}
|
|
382
|
+
listChannels() {
|
|
383
|
+
return this.request("/v1/channels");
|
|
384
|
+
}
|
|
385
|
+
listMessages(channelId, cursor, limit = 30) {
|
|
386
|
+
return this.request(
|
|
387
|
+
`/v1/channels/${encodeURIComponent(channelId)}/messages`,
|
|
388
|
+
void 0,
|
|
389
|
+
{ cursor, limit }
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
sendMessage(input) {
|
|
393
|
+
return this.request(`/v1/channels/${encodeURIComponent(input.channelId)}/messages`, {
|
|
394
|
+
method: "POST",
|
|
395
|
+
body: JSON.stringify(input)
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
updateMessage(channelId, messageId, text) {
|
|
399
|
+
return this.request(
|
|
400
|
+
`/v1/channels/${encodeURIComponent(channelId)}/messages/${encodeURIComponent(messageId)}`,
|
|
401
|
+
{
|
|
402
|
+
method: "PATCH",
|
|
403
|
+
body: JSON.stringify({ text })
|
|
404
|
+
}
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
deleteMessage(channelId, messageId) {
|
|
408
|
+
return this.request(
|
|
409
|
+
`/v1/channels/${encodeURIComponent(channelId)}/messages/${encodeURIComponent(messageId)}`,
|
|
410
|
+
{ method: "DELETE" }
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
sendTyping(channelId, isTyping) {
|
|
414
|
+
return this.request(`/v1/channels/${encodeURIComponent(channelId)}/typing`, {
|
|
415
|
+
method: "POST",
|
|
416
|
+
body: JSON.stringify({ isTyping })
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
// src/client/createStreemoClient.ts
|
|
422
|
+
function createStreemoClient(options) {
|
|
423
|
+
return new StreemoClient(options);
|
|
424
|
+
}
|
|
266
425
|
export {
|
|
267
426
|
SDKError,
|
|
427
|
+
StreemoClient,
|
|
268
428
|
VideoSignalingClient,
|
|
269
429
|
createServerTokenProvider,
|
|
430
|
+
createStreemoClient,
|
|
270
431
|
defaultApiBaseUrl,
|
|
271
432
|
defaultWsBaseUrlFromApi,
|
|
272
433
|
getVideoSDKConfig,
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/auth.ts","../src/sdkErrors.ts","../src/tokenProvider.ts","../src/sdkConfig.ts","../src/signalingClient.ts"],"sourcesContent":["export type ServerAuthConfig = {\n authToken: string\n clientId?: string\n appId: string\n authHeader?: string\n clientIdHeader?: string\n appIdHeader?: string\n}\n\nexport function buildAuthHeaders(auth: ServerAuthConfig): Record<string, string> {\n const headers: Record<string, string> = {\n [auth.appIdHeader ?? 'X-App-Id']: auth.appId,\n [auth.authHeader ?? 'Authorization']: `Bearer ${auth.authToken}`,\n }\n if (auth.clientId) {\n headers[auth.clientIdHeader ?? 'X-Client-Id'] = auth.clientId\n }\n return headers\n}\n","export type SDKErrorCode =\n | 'invalid_app'\n | 'invalid_client'\n | 'expired_token'\n | 'unauthorized'\n | 'forbidden'\n | 'rate_limited'\n | 'network_error'\n | 'unknown_error'\n\nexport class SDKError extends Error {\n code: SDKErrorCode\n status?: number\n\n constructor(code: SDKErrorCode, message: string, status?: number) {\n super(message)\n this.code = code\n this.status = status\n this.name = 'SDKError'\n }\n}\n\nexport function mapSDKErrorToUIMessage(err: unknown): string {\n if (!(err instanceof SDKError)) {\n return 'Unexpected error while connecting to call server.'\n }\n\n switch (err.code) {\n case 'invalid_app':\n return 'Application is not allowed to use this video service.'\n case 'invalid_client':\n return 'Client is not recognized by video service.'\n case 'expired_token':\n return 'Authorization token is expired. Please sign in again.'\n case 'unauthorized':\n return 'Authorization failed. Please check your credentials.'\n case 'forbidden':\n return 'Access is forbidden for this application/client.'\n case 'rate_limited':\n return 'Organization rate limit exceeded. Please retry later.'\n case 'network_error':\n return 'Network error while connecting to video service.'\n default:\n return err.message || 'Unknown video service error.'\n }\n}\n","import { buildAuthHeaders, type ServerAuthConfig } from './auth'\nimport { SDKError } from './sdkErrors'\n\nexport type TokenProviderContext = {\n roomId: string\n userId: string\n}\n\nexport type TokenProvider = (ctx: TokenProviderContext) => Promise<string>\n\nexport type ServerTokenProviderOptions = {\n apiBaseUrl?: string\n auth: ServerAuthConfig\n externalUserRegisterPath?: string\n joinPathBuilder?: (roomId: string) => string\n tokenPathBuilder?: (roomId: string) => string\n}\n\ntype ServerErrorPayload = {\n error?: string\n message?: string\n}\n\nfunction mapServerError(status: number, serverMessage: string): SDKError {\n const message = serverMessage.toLowerCase()\n if (status === 403 && message.includes('app id')) {\n return new SDKError('invalid_app', 'invalid_app', status)\n }\n if (status === 403 && message.includes('auth token')) {\n return new SDKError('unauthorized', 'invalid_auth_token', status)\n }\n if (status === 403 && message.includes('client id')) {\n return new SDKError('invalid_client', 'invalid_client', status)\n }\n if (status === 401 && message.includes('expired token')) {\n return new SDKError('expired_token', 'expired_token', status)\n }\n if (status === 401) {\n return new SDKError('unauthorized', 'unauthorized', status)\n }\n if (status === 403) {\n return new SDKError('forbidden', 'forbidden', status)\n }\n if (status === 429) {\n return new SDKError('rate_limited', 'rate_limited', status)\n }\n return new SDKError('unknown_error', serverMessage || 'unknown_error', status)\n}\n\nasync function fetchJson<T>(input: RequestInfo | URL, init: RequestInit): Promise<T> {\n let response: Response\n try {\n response = await fetch(input, init)\n } catch {\n throw new SDKError('network_error', 'network_error')\n }\n if (!response.ok) {\n let serverMessage = response.statusText\n try {\n const payload = (await response.json()) as ServerErrorPayload\n serverMessage = payload.error || payload.message || serverMessage\n } catch {\n const text = await response.text()\n if (text) serverMessage = text\n }\n throw mapServerError(response.status, serverMessage)\n }\n return response.json() as Promise<T>\n}\n\nexport function defaultWsBaseUrlFromApi(apiBaseUrl: string): string {\n const normalized = apiBaseUrl.replace(/\\/+$/, '')\n if (normalized.startsWith('https://')) {\n return normalized.replace(/^https:\\/\\//, 'wss://')\n }\n if (normalized.startsWith('http://')) {\n return normalized.replace(/^http:\\/\\//, 'ws://')\n }\n return normalized\n}\n\nexport function defaultApiBaseUrl(): string {\n if (typeof window !== 'undefined' && window.location?.origin) {\n return window.location.origin\n }\n return ''\n}\n\nexport function createServerTokenProvider(options: ServerTokenProviderOptions): TokenProvider {\n const externalUserRegisterPath = options.externalUserRegisterPath ?? '/v1/external-users/register'\n const joinPathBuilder = options.joinPathBuilder ?? ((roomId: string) => `/v1/rooms/${roomId}/join`)\n const tokenPathBuilder = options.tokenPathBuilder ?? ((roomId: string) => `/v1/rooms/${roomId}/token`)\n const externalUserMap = new Map<string, string>()\n\n return async ({ roomId, userId }) => {\n const base = (options.apiBaseUrl || defaultApiBaseUrl()).replace(/\\/+$/, '')\n if (!base) {\n throw new SDKError('unknown_error', 'api_base_url_required')\n }\n const headers = {\n 'Content-Type': 'application/json',\n ...buildAuthHeaders(options.auth),\n }\n\n let internalUserID = externalUserMap.get(userId)\n if (!internalUserID) {\n const registration = await fetchJson<{ userId: string }>(`${base}${externalUserRegisterPath}`, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n externalId: userId,\n }),\n })\n if (!registration.userId) {\n throw new SDKError('unknown_error', 'external_user_registration_failed')\n }\n internalUserID = registration.userId\n externalUserMap.set(userId, internalUserID)\n }\n const roomHeaders = {\n ...headers,\n 'X-Guest-Id': internalUserID,\n }\n\n await fetchJson<{ ok?: boolean }>(`${base}${joinPathBuilder(roomId)}`, {\n method: 'POST',\n headers: roomHeaders,\n body: '{}',\n })\n\n const tokenResponse = await fetchJson<{ token: string }>(`${base}${tokenPathBuilder(roomId)}`, {\n method: 'POST',\n headers: roomHeaders,\n })\n\n if (!tokenResponse.token) {\n throw new Error('Room token is empty')\n }\n return tokenResponse.token\n }\n}\n","import type { ServerAuthConfig } from './auth'\n\nexport type VideoSDKConfig = {\n apiBaseUrl?: string\n wsBaseUrl?: string\n auth?: ServerAuthConfig\n}\n\nconst DEFAULT_API_BASE_URL = 'https://api.streemo.ru'\nconst DEFAULT_WS_BASE_URL = 'wss://api.streemo.ru'\n\nlet globalConfig: VideoSDKConfig = {\n apiBaseUrl: DEFAULT_API_BASE_URL,\n wsBaseUrl: DEFAULT_WS_BASE_URL,\n}\n\nexport function initVideoSDK(config: VideoSDKConfig): void {\n globalConfig = {\n ...globalConfig,\n ...config,\n auth: config.auth ? { ...(globalConfig.auth ?? {}), ...config.auth } : globalConfig.auth,\n }\n}\n\nexport function getVideoSDKConfig(): VideoSDKConfig {\n return globalConfig\n}\n\n","import {\n createServerTokenProvider,\n defaultApiBaseUrl,\n defaultWsBaseUrlFromApi,\n type TokenProvider,\n type TokenProviderContext,\n} from './tokenProvider'\nimport type { ServerAuthConfig } from './auth'\nimport { getVideoSDKConfig } from './sdkConfig'\n\nexport type SignalMessage = {\n type: string\n roomId: string\n userId: string\n targetUserId?: string\n payload?: unknown\n}\n\nexport type SignalingClientConfig = {\n roomId: string\n userId: string\n roomToken?: string\n wsBaseUrl?: string\n tokenProvider?: TokenProvider\n apiBaseUrl?: string\n auth?: ServerAuthConfig\n onOpen?: () => void\n onClose?: (event: CloseEvent) => void\n onError?: (event: Event) => void\n onMessage?: (message: SignalMessage) => void\n}\n\nfunction resolveTokenProvider(config: SignalingClientConfig): TokenProvider | null {\n const sdkConfig = getVideoSDKConfig()\n const apiBaseUrl = config.apiBaseUrl ?? sdkConfig.apiBaseUrl\n const auth = config.auth ?? sdkConfig.auth\n if (config.tokenProvider) return config.tokenProvider\n if (auth) {\n return createServerTokenProvider({\n apiBaseUrl: apiBaseUrl ?? defaultApiBaseUrl(),\n auth,\n })\n }\n return null\n}\n\nasync function resolveRoomToken(config: SignalingClientConfig): Promise<string> {\n if (config.roomToken) return config.roomToken\n const provider = resolveTokenProvider(config)\n if (!provider) {\n throw new Error('roomToken or tokenProvider/apiBaseUrl+auth is required')\n }\n const ctx: TokenProviderContext = {\n roomId: config.roomId,\n userId: config.userId,\n }\n return provider(ctx)\n}\n\nfunction resolveWsBaseUrl(config: SignalingClientConfig): string {\n const sdkConfig = getVideoSDKConfig()\n if (config.wsBaseUrl) return config.wsBaseUrl.replace(/\\/+$/, '')\n if (sdkConfig.wsBaseUrl) return sdkConfig.wsBaseUrl.replace(/\\/+$/, '')\n const apiBaseUrl = config.apiBaseUrl ?? sdkConfig.apiBaseUrl ?? defaultApiBaseUrl()\n if (apiBaseUrl) return defaultWsBaseUrlFromApi(apiBaseUrl)\n throw new Error('wsBaseUrl or apiBaseUrl is required')\n}\n\nexport class VideoSignalingClient {\n private readonly config: SignalingClientConfig\n private ws: WebSocket | null = null\n private connected = false\n\n constructor(config: SignalingClientConfig) {\n this.config = config\n }\n\n isConnected(): boolean {\n return this.connected\n }\n\n async connect(): Promise<void> {\n if (this.ws && (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING)) {\n return\n }\n\n const roomToken = await resolveRoomToken(this.config)\n const wsBase = resolveWsBaseUrl(this.config)\n const wsURL = `${wsBase}/v1/ws?roomId=${encodeURIComponent(this.config.roomId)}&token=${encodeURIComponent(roomToken)}`\n\n await new Promise<void>((resolve, reject) => {\n const ws = new WebSocket(wsURL)\n this.ws = ws\n\n ws.onopen = () => {\n this.connected = true\n this.config.onOpen?.()\n resolve()\n }\n ws.onclose = (event) => {\n this.connected = false\n this.config.onClose?.(event)\n }\n ws.onerror = (event) => {\n this.config.onError?.(event)\n reject(new Error('WebSocket connection error'))\n }\n ws.onmessage = (event) => {\n const message = JSON.parse(event.data) as SignalMessage\n this.config.onMessage?.(message)\n }\n })\n }\n\n send(message: Omit<SignalMessage, 'roomId' | 'userId'>): void {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return\n this.ws.send(\n JSON.stringify({\n roomId: this.config.roomId,\n userId: this.config.userId,\n ...message,\n }),\n )\n }\n\n disconnect(): void {\n this.ws?.close()\n this.ws = null\n this.connected = false\n }\n}\n"],"mappings":";AASO,SAAS,iBAAiB,MAAgD;AAC/E,QAAM,UAAkC;AAAA,IACtC,CAAC,KAAK,eAAe,UAAU,GAAG,KAAK;AAAA,IACvC,CAAC,KAAK,cAAc,eAAe,GAAG,UAAU,KAAK,SAAS;AAAA,EAChE;AACA,MAAI,KAAK,UAAU;AACjB,YAAQ,KAAK,kBAAkB,aAAa,IAAI,KAAK;AAAA,EACvD;AACA,SAAO;AACT;;;ACRO,IAAM,WAAN,cAAuB,MAAM;AAAA,EAClC;AAAA,EACA;AAAA,EAEA,YAAY,MAAoB,SAAiB,QAAiB;AAChE,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,OAAO;AAAA,EACd;AACF;AAEO,SAAS,uBAAuB,KAAsB;AAC3D,MAAI,EAAE,eAAe,WAAW;AAC9B,WAAO;AAAA,EACT;AAEA,UAAQ,IAAI,MAAM;AAAA,IAChB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO,IAAI,WAAW;AAAA,EAC1B;AACF;;;ACtBA,SAAS,eAAe,QAAgB,eAAiC;AACvE,QAAM,UAAU,cAAc,YAAY;AAC1C,MAAI,WAAW,OAAO,QAAQ,SAAS,QAAQ,GAAG;AAChD,WAAO,IAAI,SAAS,eAAe,eAAe,MAAM;AAAA,EAC1D;AACA,MAAI,WAAW,OAAO,QAAQ,SAAS,YAAY,GAAG;AACpD,WAAO,IAAI,SAAS,gBAAgB,sBAAsB,MAAM;AAAA,EAClE;AACA,MAAI,WAAW,OAAO,QAAQ,SAAS,WAAW,GAAG;AACnD,WAAO,IAAI,SAAS,kBAAkB,kBAAkB,MAAM;AAAA,EAChE;AACA,MAAI,WAAW,OAAO,QAAQ,SAAS,eAAe,GAAG;AACvD,WAAO,IAAI,SAAS,iBAAiB,iBAAiB,MAAM;AAAA,EAC9D;AACA,MAAI,WAAW,KAAK;AAClB,WAAO,IAAI,SAAS,gBAAgB,gBAAgB,MAAM;AAAA,EAC5D;AACA,MAAI,WAAW,KAAK;AAClB,WAAO,IAAI,SAAS,aAAa,aAAa,MAAM;AAAA,EACtD;AACA,MAAI,WAAW,KAAK;AAClB,WAAO,IAAI,SAAS,gBAAgB,gBAAgB,MAAM;AAAA,EAC5D;AACA,SAAO,IAAI,SAAS,iBAAiB,iBAAiB,iBAAiB,MAAM;AAC/E;AAEA,eAAe,UAAa,OAA0B,MAA+B;AACnF,MAAI;AACJ,MAAI;AACF,eAAW,MAAM,MAAM,OAAO,IAAI;AAAA,EACpC,QAAQ;AACN,UAAM,IAAI,SAAS,iBAAiB,eAAe;AAAA,EACrD;AACA,MAAI,CAAC,SAAS,IAAI;AAChB,QAAI,gBAAgB,SAAS;AAC7B,QAAI;AACF,YAAM,UAAW,MAAM,SAAS,KAAK;AACrC,sBAAgB,QAAQ,SAAS,QAAQ,WAAW;AAAA,IACtD,QAAQ;AACN,YAAM,OAAO,MAAM,SAAS,KAAK;AACjC,UAAI,KAAM,iBAAgB;AAAA,IAC5B;AACA,UAAM,eAAe,SAAS,QAAQ,aAAa;AAAA,EACrD;AACA,SAAO,SAAS,KAAK;AACvB;AAEO,SAAS,wBAAwB,YAA4B;AAClE,QAAM,aAAa,WAAW,QAAQ,QAAQ,EAAE;AAChD,MAAI,WAAW,WAAW,UAAU,GAAG;AACrC,WAAO,WAAW,QAAQ,eAAe,QAAQ;AAAA,EACnD;AACA,MAAI,WAAW,WAAW,SAAS,GAAG;AACpC,WAAO,WAAW,QAAQ,cAAc,OAAO;AAAA,EACjD;AACA,SAAO;AACT;AAEO,SAAS,oBAA4B;AAC1C,MAAI,OAAO,WAAW,eAAe,OAAO,UAAU,QAAQ;AAC5D,WAAO,OAAO,SAAS;AAAA,EACzB;AACA,SAAO;AACT;AAEO,SAAS,0BAA0B,SAAoD;AAC5F,QAAM,2BAA2B,QAAQ,4BAA4B;AACrE,QAAM,kBAAkB,QAAQ,oBAAoB,CAAC,WAAmB,aAAa,MAAM;AAC3F,QAAM,mBAAmB,QAAQ,qBAAqB,CAAC,WAAmB,aAAa,MAAM;AAC7F,QAAM,kBAAkB,oBAAI,IAAoB;AAEhD,SAAO,OAAO,EAAE,QAAQ,OAAO,MAAM;AACnC,UAAM,QAAQ,QAAQ,cAAc,kBAAkB,GAAG,QAAQ,QAAQ,EAAE;AAC3E,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,SAAS,iBAAiB,uBAAuB;AAAA,IAC7D;AACA,UAAM,UAAU;AAAA,MACd,gBAAgB;AAAA,MAChB,GAAG,iBAAiB,QAAQ,IAAI;AAAA,IAClC;AAEA,QAAI,iBAAiB,gBAAgB,IAAI,MAAM;AAC/C,QAAI,CAAC,gBAAgB;AACnB,YAAM,eAAe,MAAM,UAA8B,GAAG,IAAI,GAAG,wBAAwB,IAAI;AAAA,QAC7F,QAAQ;AAAA,QACR;AAAA,QACA,MAAM,KAAK,UAAU;AAAA,UACnB,YAAY;AAAA,QACd,CAAC;AAAA,MACH,CAAC;AACD,UAAI,CAAC,aAAa,QAAQ;AACxB,cAAM,IAAI,SAAS,iBAAiB,mCAAmC;AAAA,MACzE;AACA,uBAAiB,aAAa;AAC9B,sBAAgB,IAAI,QAAQ,cAAc;AAAA,IAC5C;AACA,UAAM,cAAc;AAAA,MAClB,GAAG;AAAA,MACH,cAAc;AAAA,IAChB;AAEA,UAAM,UAA4B,GAAG,IAAI,GAAG,gBAAgB,MAAM,CAAC,IAAI;AAAA,MACrE,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,MAAM;AAAA,IACR,CAAC;AAED,UAAM,gBAAgB,MAAM,UAA6B,GAAG,IAAI,GAAG,iBAAiB,MAAM,CAAC,IAAI;AAAA,MAC7F,QAAQ;AAAA,MACR,SAAS;AAAA,IACX,CAAC;AAED,QAAI,CAAC,cAAc,OAAO;AACxB,YAAM,IAAI,MAAM,qBAAqB;AAAA,IACvC;AACA,WAAO,cAAc;AAAA,EACvB;AACF;;;ACpIA,IAAM,uBAAuB;AAC7B,IAAM,sBAAsB;AAE5B,IAAI,eAA+B;AAAA,EACjC,YAAY;AAAA,EACZ,WAAW;AACb;AAEO,SAAS,aAAa,QAA8B;AACzD,iBAAe;AAAA,IACb,GAAG;AAAA,IACH,GAAG;AAAA,IACH,MAAM,OAAO,OAAO,EAAE,GAAI,aAAa,QAAQ,CAAC,GAAI,GAAG,OAAO,KAAK,IAAI,aAAa;AAAA,EACtF;AACF;AAEO,SAAS,oBAAoC;AAClD,SAAO;AACT;;;ACMA,SAAS,qBAAqB,QAAqD;AACjF,QAAM,YAAY,kBAAkB;AACpC,QAAM,aAAa,OAAO,cAAc,UAAU;AAClD,QAAM,OAAO,OAAO,QAAQ,UAAU;AACtC,MAAI,OAAO,cAAe,QAAO,OAAO;AACxC,MAAI,MAAM;AACR,WAAO,0BAA0B;AAAA,MAC/B,YAAY,cAAc,kBAAkB;AAAA,MAC5C;AAAA,IACF,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAEA,eAAe,iBAAiB,QAAgD;AAC9E,MAAI,OAAO,UAAW,QAAO,OAAO;AACpC,QAAM,WAAW,qBAAqB,MAAM;AAC5C,MAAI,CAAC,UAAU;AACb,UAAM,IAAI,MAAM,wDAAwD;AAAA,EAC1E;AACA,QAAM,MAA4B;AAAA,IAChC,QAAQ,OAAO;AAAA,IACf,QAAQ,OAAO;AAAA,EACjB;AACA,SAAO,SAAS,GAAG;AACrB;AAEA,SAAS,iBAAiB,QAAuC;AAC/D,QAAM,YAAY,kBAAkB;AACpC,MAAI,OAAO,UAAW,QAAO,OAAO,UAAU,QAAQ,QAAQ,EAAE;AAChE,MAAI,UAAU,UAAW,QAAO,UAAU,UAAU,QAAQ,QAAQ,EAAE;AACtE,QAAM,aAAa,OAAO,cAAc,UAAU,cAAc,kBAAkB;AAClF,MAAI,WAAY,QAAO,wBAAwB,UAAU;AACzD,QAAM,IAAI,MAAM,qCAAqC;AACvD;AAEO,IAAM,uBAAN,MAA2B;AAAA,EACf;AAAA,EACT,KAAuB;AAAA,EACvB,YAAY;AAAA,EAEpB,YAAY,QAA+B;AACzC,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,cAAuB;AACrB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,UAAyB;AAC7B,QAAI,KAAK,OAAO,KAAK,GAAG,eAAe,UAAU,QAAQ,KAAK,GAAG,eAAe,UAAU,aAAa;AACrG;AAAA,IACF;AAEA,UAAM,YAAY,MAAM,iBAAiB,KAAK,MAAM;AACpD,UAAM,SAAS,iBAAiB,KAAK,MAAM;AAC3C,UAAM,QAAQ,GAAG,MAAM,iBAAiB,mBAAmB,KAAK,OAAO,MAAM,CAAC,UAAU,mBAAmB,SAAS,CAAC;AAErH,UAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,YAAM,KAAK,IAAI,UAAU,KAAK;AAC9B,WAAK,KAAK;AAEV,SAAG,SAAS,MAAM;AAChB,aAAK,YAAY;AACjB,aAAK,OAAO,SAAS;AACrB,gBAAQ;AAAA,MACV;AACA,SAAG,UAAU,CAAC,UAAU;AACtB,aAAK,YAAY;AACjB,aAAK,OAAO,UAAU,KAAK;AAAA,MAC7B;AACA,SAAG,UAAU,CAAC,UAAU;AACtB,aAAK,OAAO,UAAU,KAAK;AAC3B,eAAO,IAAI,MAAM,4BAA4B,CAAC;AAAA,MAChD;AACA,SAAG,YAAY,CAAC,UAAU;AACxB,cAAM,UAAU,KAAK,MAAM,MAAM,IAAI;AACrC,aAAK,OAAO,YAAY,OAAO;AAAA,MACjC;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,KAAK,SAAyD;AAC5D,QAAI,CAAC,KAAK,MAAM,KAAK,GAAG,eAAe,UAAU,KAAM;AACvD,SAAK,GAAG;AAAA,MACN,KAAK,UAAU;AAAA,QACb,QAAQ,KAAK,OAAO;AAAA,QACpB,QAAQ,KAAK,OAAO;AAAA,QACpB,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,aAAmB;AACjB,SAAK,IAAI,MAAM;AACf,SAAK,KAAK;AACV,SAAK,YAAY;AAAA,EACnB;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/auth.ts","../src/sdkErrors.ts","../src/tokenProvider.ts","../src/sdkConfig.ts","../src/signalingClient.ts","../src/client/StreemoClient.ts","../src/client/createStreemoClient.ts"],"sourcesContent":["export type ServerAuthConfig = {\n authToken: string\n clientId?: string\n appId: string\n authHeader?: string\n clientIdHeader?: string\n appIdHeader?: string\n}\n\nexport function buildAuthHeaders(auth: ServerAuthConfig): Record<string, string> {\n const headers: Record<string, string> = {\n [auth.appIdHeader ?? 'X-App-Id']: auth.appId,\n [auth.authHeader ?? 'Authorization']: `Bearer ${auth.authToken}`,\n }\n if (auth.clientId) {\n headers[auth.clientIdHeader ?? 'X-Client-Id'] = auth.clientId\n }\n return headers\n}\n","export type SDKErrorCode =\n | 'invalid_app'\n | 'invalid_client'\n | 'expired_token'\n | 'unauthorized'\n | 'forbidden'\n | 'rate_limited'\n | 'network_error'\n | 'unknown_error'\n\nexport class SDKError extends Error {\n code: SDKErrorCode\n status?: number\n\n constructor(code: SDKErrorCode, message: string, status?: number) {\n super(message)\n this.code = code\n this.status = status\n this.name = 'SDKError'\n }\n}\n\nexport function mapSDKErrorToUIMessage(err: unknown): string {\n if (!(err instanceof SDKError)) {\n return 'Unexpected error while connecting to call server.'\n }\n\n switch (err.code) {\n case 'invalid_app':\n return 'Application is not allowed to use this video service.'\n case 'invalid_client':\n return 'Client is not recognized by video service.'\n case 'expired_token':\n return 'Authorization token is expired. Please sign in again.'\n case 'unauthorized':\n return 'Authorization failed. Please check your credentials.'\n case 'forbidden':\n return 'Access is forbidden for this application/client.'\n case 'rate_limited':\n return 'Organization rate limit exceeded. Please retry later.'\n case 'network_error':\n return 'Network error while connecting to video service.'\n default:\n return err.message || 'Unknown video service error.'\n }\n}\n","import { buildAuthHeaders, type ServerAuthConfig } from './auth'\nimport { SDKError } from './sdkErrors'\n\nexport type TokenProviderContext = {\n roomId: string\n userId: string\n}\n\nexport type TokenProvider = (ctx: TokenProviderContext) => Promise<string>\n\nexport type ServerTokenProviderOptions = {\n apiBaseUrl?: string\n auth: ServerAuthConfig\n externalUserRegisterPath?: string\n joinPathBuilder?: (roomId: string) => string\n tokenPathBuilder?: (roomId: string) => string\n}\n\ntype ServerErrorPayload = {\n error?: string\n message?: string\n}\n\nfunction mapServerError(status: number, serverMessage: string): SDKError {\n const message = serverMessage.toLowerCase()\n if (status === 403 && message.includes('app id')) {\n return new SDKError('invalid_app', 'invalid_app', status)\n }\n if (status === 403 && message.includes('auth token')) {\n return new SDKError('unauthorized', 'invalid_auth_token', status)\n }\n if (status === 403 && message.includes('client id')) {\n return new SDKError('invalid_client', 'invalid_client', status)\n }\n if (status === 401 && message.includes('expired token')) {\n return new SDKError('expired_token', 'expired_token', status)\n }\n if (status === 401) {\n return new SDKError('unauthorized', 'unauthorized', status)\n }\n if (status === 403) {\n return new SDKError('forbidden', 'forbidden', status)\n }\n if (status === 429) {\n return new SDKError('rate_limited', 'rate_limited', status)\n }\n return new SDKError('unknown_error', serverMessage || 'unknown_error', status)\n}\n\nasync function fetchJson<T>(input: RequestInfo | URL, init: RequestInit): Promise<T> {\n let response: Response\n try {\n response = await fetch(input, init)\n } catch {\n throw new SDKError('network_error', 'network_error')\n }\n if (!response.ok) {\n let serverMessage = response.statusText\n try {\n const payload = (await response.json()) as ServerErrorPayload\n serverMessage = payload.error || payload.message || serverMessage\n } catch {\n const text = await response.text()\n if (text) serverMessage = text\n }\n throw mapServerError(response.status, serverMessage)\n }\n return response.json() as Promise<T>\n}\n\nexport function defaultWsBaseUrlFromApi(apiBaseUrl: string): string {\n const normalized = apiBaseUrl.replace(/\\/+$/, '')\n if (normalized.startsWith('https://')) {\n return normalized.replace(/^https:\\/\\//, 'wss://')\n }\n if (normalized.startsWith('http://')) {\n return normalized.replace(/^http:\\/\\//, 'ws://')\n }\n return normalized\n}\n\nexport function defaultApiBaseUrl(): string {\n if (typeof window !== 'undefined' && window.location?.origin) {\n return window.location.origin\n }\n return ''\n}\n\nexport function createServerTokenProvider(options: ServerTokenProviderOptions): TokenProvider {\n const externalUserRegisterPath = options.externalUserRegisterPath ?? '/v1/external-users/register'\n const joinPathBuilder = options.joinPathBuilder ?? ((roomId: string) => `/v1/rooms/${roomId}/join`)\n const tokenPathBuilder = options.tokenPathBuilder ?? ((roomId: string) => `/v1/rooms/${roomId}/token`)\n const externalUserMap = new Map<string, string>()\n\n return async ({ roomId, userId }) => {\n const base = (options.apiBaseUrl || defaultApiBaseUrl()).replace(/\\/+$/, '')\n if (!base) {\n throw new SDKError('unknown_error', 'api_base_url_required')\n }\n const headers = {\n 'Content-Type': 'application/json',\n ...buildAuthHeaders(options.auth),\n }\n\n let internalUserID = externalUserMap.get(userId)\n if (!internalUserID) {\n const registration = await fetchJson<{ userId: string }>(`${base}${externalUserRegisterPath}`, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n externalId: userId,\n }),\n })\n if (!registration.userId) {\n throw new SDKError('unknown_error', 'external_user_registration_failed')\n }\n internalUserID = registration.userId\n externalUserMap.set(userId, internalUserID)\n }\n const roomHeaders = {\n ...headers,\n 'X-Guest-Id': internalUserID,\n }\n\n await fetchJson<{ ok?: boolean }>(`${base}${joinPathBuilder(roomId)}`, {\n method: 'POST',\n headers: roomHeaders,\n body: '{}',\n })\n\n const tokenResponse = await fetchJson<{ token: string }>(`${base}${tokenPathBuilder(roomId)}`, {\n method: 'POST',\n headers: roomHeaders,\n })\n\n if (!tokenResponse.token) {\n throw new Error('Room token is empty')\n }\n return tokenResponse.token\n }\n}\n","import type { ServerAuthConfig } from './auth'\n\nexport type VideoSDKConfig = {\n apiBaseUrl?: string\n wsBaseUrl?: string\n auth?: ServerAuthConfig\n}\n\nconst DEFAULT_API_BASE_URL = 'https://api.streemo.ru'\nconst DEFAULT_WS_BASE_URL = 'wss://api.streemo.ru'\n\nlet globalConfig: VideoSDKConfig = {\n apiBaseUrl: DEFAULT_API_BASE_URL,\n wsBaseUrl: DEFAULT_WS_BASE_URL,\n}\n\nexport function initVideoSDK(config: VideoSDKConfig): void {\n globalConfig = {\n ...globalConfig,\n ...config,\n auth: config.auth ? { ...(globalConfig.auth ?? {}), ...config.auth } : globalConfig.auth,\n }\n}\n\nexport function getVideoSDKConfig(): VideoSDKConfig {\n return globalConfig\n}\n\n","import {\n createServerTokenProvider,\n defaultApiBaseUrl,\n defaultWsBaseUrlFromApi,\n type TokenProvider,\n type TokenProviderContext,\n} from './tokenProvider'\nimport type { ServerAuthConfig } from './auth'\nimport { getVideoSDKConfig } from './sdkConfig'\n\nexport type SignalMessage = {\n type: string\n roomId: string\n userId: string\n targetUserId?: string\n payload?: unknown\n}\n\nexport type SignalingClientConfig = {\n roomId: string\n userId: string\n roomToken?: string\n wsBaseUrl?: string\n tokenProvider?: TokenProvider\n apiBaseUrl?: string\n auth?: ServerAuthConfig\n onOpen?: () => void\n onClose?: (event: CloseEvent) => void\n onError?: (event: Event) => void\n onMessage?: (message: SignalMessage) => void\n}\n\nfunction resolveTokenProvider(config: SignalingClientConfig): TokenProvider | null {\n const sdkConfig = getVideoSDKConfig()\n const apiBaseUrl = config.apiBaseUrl ?? sdkConfig.apiBaseUrl\n const auth = config.auth ?? sdkConfig.auth\n if (config.tokenProvider) return config.tokenProvider\n if (auth) {\n return createServerTokenProvider({\n apiBaseUrl: apiBaseUrl ?? defaultApiBaseUrl(),\n auth,\n })\n }\n return null\n}\n\nasync function resolveRoomToken(config: SignalingClientConfig): Promise<string> {\n if (config.roomToken) return config.roomToken\n const provider = resolveTokenProvider(config)\n if (!provider) {\n throw new Error('roomToken or tokenProvider/apiBaseUrl+auth is required')\n }\n const ctx: TokenProviderContext = {\n roomId: config.roomId,\n userId: config.userId,\n }\n return provider(ctx)\n}\n\nfunction resolveWsBaseUrl(config: SignalingClientConfig): string {\n const sdkConfig = getVideoSDKConfig()\n if (config.wsBaseUrl) return config.wsBaseUrl.replace(/\\/+$/, '')\n if (sdkConfig.wsBaseUrl) return sdkConfig.wsBaseUrl.replace(/\\/+$/, '')\n const apiBaseUrl = config.apiBaseUrl ?? sdkConfig.apiBaseUrl ?? defaultApiBaseUrl()\n if (apiBaseUrl) return defaultWsBaseUrlFromApi(apiBaseUrl)\n throw new Error('wsBaseUrl or apiBaseUrl is required')\n}\n\nexport class VideoSignalingClient {\n private readonly config: SignalingClientConfig\n private ws: WebSocket | null = null\n private connected = false\n\n constructor(config: SignalingClientConfig) {\n this.config = config\n }\n\n isConnected(): boolean {\n return this.connected\n }\n\n async connect(): Promise<void> {\n if (this.ws && (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING)) {\n return\n }\n\n const roomToken = await resolveRoomToken(this.config)\n const wsBase = resolveWsBaseUrl(this.config)\n const wsURL = `${wsBase}/v1/ws?roomId=${encodeURIComponent(this.config.roomId)}&token=${encodeURIComponent(roomToken)}`\n\n await new Promise<void>((resolve, reject) => {\n const ws = new WebSocket(wsURL)\n this.ws = ws\n\n ws.onopen = () => {\n this.connected = true\n this.config.onOpen?.()\n resolve()\n }\n ws.onclose = (event) => {\n this.connected = false\n this.config.onClose?.(event)\n }\n ws.onerror = (event) => {\n this.config.onError?.(event)\n reject(new Error('WebSocket connection error'))\n }\n ws.onmessage = (event) => {\n const message = JSON.parse(event.data) as SignalMessage\n this.config.onMessage?.(message)\n }\n })\n }\n\n send(message: Omit<SignalMessage, 'roomId' | 'userId'>): void {\n if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return\n this.ws.send(\n JSON.stringify({\n roomId: this.config.roomId,\n userId: this.config.userId,\n ...message,\n }),\n )\n }\n\n disconnect(): void {\n this.ws?.close()\n this.ws = null\n this.connected = false\n }\n}\n","import type {\r\n PresenceState,\r\n StreemoAttachment,\r\n StreemoChannel,\r\n StreemoMessage,\r\n StreemoReaction,\r\n StreemoUser,\r\n TypingState,\r\n} from '../types/models'\r\n\r\ntype Listener<T> = (event: T) => void\r\n\r\ntype RealtimeEventMap = {\r\n connected: { connected: boolean }\r\n message_new: StreemoMessage\r\n message_updated: StreemoMessage\r\n typing: TypingState\r\n presence: PresenceState\r\n reaction_new: { channelId: string; messageId: string; reaction: StreemoReaction }\r\n}\r\n\r\ntype QueryParams = Record<string, string | number | undefined>\r\n\r\n/** Internal storage uses a generic listener to avoid DTS inference issues with mapped types */\r\ntype AnyListener = Listener<RealtimeEventMap[keyof RealtimeEventMap]>\r\n\r\nexport type StreemoClientOptions = {\r\n apiKey: string\r\n userToken: string\r\n user: StreemoUser\r\n baseUrl?: string\r\n wsUrl?: string\r\n reconnect?: boolean\r\n}\r\n\r\nexport class StreemoClient {\r\n public readonly apiKey: string\r\n public readonly userToken: string\r\n public readonly user: StreemoUser\r\n public readonly baseUrl: string\r\n public readonly wsUrl: string\r\n private readonly reconnect: boolean\r\n\r\n private ws: WebSocket | null = null\r\n private manuallyClosed = false\r\n private reconnectAttempt = 0\r\n private listeners: Partial<Record<keyof RealtimeEventMap, Set<AnyListener>>> = {}\r\n\r\n constructor(options: StreemoClientOptions) {\r\n this.apiKey = options.apiKey\r\n this.userToken = options.userToken\r\n this.user = options.user\r\n this.baseUrl = (options.baseUrl ?? 'https://api.streemo.ru').replace(/\\/+$/, '')\r\n const defaultWs = this.baseUrl.replace(/^http/, 'ws')\r\n this.wsUrl = (options.wsUrl ?? defaultWs).replace(/\\/+$/, '')\r\n this.reconnect = options.reconnect ?? true\r\n }\r\n\r\n on<K extends keyof RealtimeEventMap>(event: K, listener: Listener<RealtimeEventMap[K]>): () => void {\r\n if (!this.listeners[event]) this.listeners[event] = new Set()\r\n this.listeners[event]?.add(listener as Listener<RealtimeEventMap[keyof RealtimeEventMap]>)\r\n return () => this.off(event, listener)\r\n }\r\n\r\n off<K extends keyof RealtimeEventMap>(event: K, listener: Listener<RealtimeEventMap[K]>): void {\r\n this.listeners[event]?.delete(listener as Listener<RealtimeEventMap[keyof RealtimeEventMap]>)\r\n }\r\n\r\n private emit<K extends keyof RealtimeEventMap>(event: K, payload: RealtimeEventMap[K]): void {\r\n this.listeners[event]?.forEach((listener) => {\r\n listener(payload)\r\n })\r\n }\r\n\r\n async connect(): Promise<void> {\r\n if (this.ws && (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING)) return\r\n this.manuallyClosed = false\r\n await this.openSocket()\r\n }\r\n\r\n disconnect(): void {\r\n this.manuallyClosed = true\r\n this.ws?.close()\r\n this.ws = null\r\n this.emit('connected', { connected: false })\r\n }\r\n\r\n private async openSocket(): Promise<void> {\r\n await new Promise<void>((resolve, reject) => {\r\n const url = `${this.wsUrl}/v1/ws?token=${encodeURIComponent(this.userToken)}&userId=${encodeURIComponent(this.user.id)}`\r\n const ws = new WebSocket(url)\r\n this.ws = ws\r\n\r\n ws.onopen = () => {\r\n this.reconnectAttempt = 0\r\n this.emit('connected', { connected: true })\r\n resolve()\r\n }\r\n\r\n ws.onmessage = (event) => {\r\n const parsed = JSON.parse(event.data) as { type: keyof RealtimeEventMap } & Record<string, unknown>\r\n switch (parsed.type) {\r\n case 'message_new':\r\n case 'message_updated':\r\n this.emit(parsed.type, parsed as unknown as StreemoMessage)\r\n break\r\n case 'typing':\r\n this.emit('typing', parsed as unknown as TypingState)\r\n break\r\n case 'presence':\r\n this.emit('presence', parsed as unknown as PresenceState)\r\n break\r\n case 'reaction_new':\r\n this.emit('reaction_new', parsed as unknown as { channelId: string; messageId: string; reaction: StreemoReaction })\r\n break\r\n default:\r\n break\r\n }\r\n }\r\n\r\n ws.onerror = () => {\r\n reject(new Error('WebSocket connection failed'))\r\n }\r\n\r\n ws.onclose = () => {\r\n this.emit('connected', { connected: false })\r\n if (!this.manuallyClosed && this.reconnect) {\r\n const backoffMs = Math.min(1000 * 2 ** this.reconnectAttempt, 15000)\r\n this.reconnectAttempt += 1\r\n setTimeout(() => {\r\n void this.openSocket()\r\n }, backoffMs)\r\n }\r\n }\r\n })\r\n }\r\n\r\n private buildUrl(path: string, query?: QueryParams): string {\r\n const url = new URL(`${this.baseUrl}${path}`)\r\n if (query) {\r\n Object.entries(query).forEach(([key, value]) => {\r\n if (value !== undefined) url.searchParams.set(key, String(value))\r\n })\r\n }\r\n return url.toString()\r\n }\r\n\r\n private async request<T>(path: string, init?: RequestInit, query?: QueryParams): Promise<T> {\r\n const response = await fetch(this.buildUrl(path, query), {\r\n ...init,\r\n headers: {\r\n Authorization: `Bearer ${this.userToken}`,\r\n 'X-App-Id': this.apiKey,\r\n 'Content-Type': 'application/json',\r\n ...(init?.headers ?? {}),\r\n },\r\n })\r\n const data = await response.json().catch(() => ({}))\r\n if (!response.ok) {\r\n throw new Error((data as { error?: string }).error || `HTTP ${response.status}`)\r\n }\r\n return data as T\r\n }\r\n\r\n listChannels(): Promise<{ items: StreemoChannel[] }> {\r\n return this.request<{ items: StreemoChannel[] }>('/v1/channels')\r\n }\r\n\r\n listMessages(channelId: string, cursor?: string, limit = 30): Promise<{ items: StreemoMessage[]; nextCursor?: string; hasMore?: boolean }> {\r\n return this.request<{ items: StreemoMessage[]; nextCursor?: string; hasMore?: boolean }>(\r\n `/v1/channels/${encodeURIComponent(channelId)}/messages`,\r\n undefined,\r\n { cursor, limit },\r\n )\r\n }\r\n\r\n sendMessage(input: {\r\n channelId: string\r\n text: string\r\n parentId?: string\r\n attachments?: StreemoAttachment[]\r\n }): Promise<StreemoMessage> {\r\n return this.request<StreemoMessage>(`/v1/channels/${encodeURIComponent(input.channelId)}/messages`, {\r\n method: 'POST',\r\n body: JSON.stringify(input),\r\n })\r\n }\r\n\r\n updateMessage(channelId: string, messageId: string, text: string): Promise<StreemoMessage> {\r\n return this.request<StreemoMessage>(\r\n `/v1/channels/${encodeURIComponent(channelId)}/messages/${encodeURIComponent(messageId)}`,\r\n {\r\n method: 'PATCH',\r\n body: JSON.stringify({ text }),\r\n },\r\n )\r\n }\r\n\r\n deleteMessage(channelId: string, messageId: string): Promise<{ ok: true }> {\r\n return this.request<{ ok: true }>(\r\n `/v1/channels/${encodeURIComponent(channelId)}/messages/${encodeURIComponent(messageId)}`,\r\n { method: 'DELETE' },\r\n )\r\n }\r\n\r\n sendTyping(channelId: string, isTyping: boolean): Promise<{ ok: true }> {\r\n return this.request<{ ok: true }>(`/v1/channels/${encodeURIComponent(channelId)}/typing`, {\r\n method: 'POST',\r\n body: JSON.stringify({ isTyping }),\r\n })\r\n }\r\n}\r\n","import { StreemoClient, type StreemoClientOptions } from './StreemoClient'\n\n/**\n * Stable factory for app-level client creation.\n * Keeps construction centralized and allows future non-breaking extensions.\n */\nexport function createStreemoClient(options: StreemoClientOptions): StreemoClient {\n return new StreemoClient(options)\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,125 +1,9 @@
|
|
|
1
|
+
import { d as StreemoClient, n as StreemoChannel, o as TypingState, p as StreemoMessage, q as StreemoAttachment, P as PresenceState, T as TokenProvider, S as ServerAuthConfig } from './sdkConfig-DTNZ7Mms.js';
|
|
2
|
+
export { r as Participant, a as SDKError, b as SDKErrorCode, c as ServerTokenProviderOptions, e as StreemoClientOptions, s as StreemoReaction, t as StreemoUser, f as TokenProviderContext, V as VideoSDKConfig, g as createServerTokenProvider, h as createStreemoClient, i as defaultApiBaseUrl, j as defaultWsBaseUrlFromApi, k as getVideoSDKConfig, l as initVideoSDK, m as mapSDKErrorToUIMessage } from './sdkConfig-DTNZ7Mms.js';
|
|
1
3
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
4
|
import * as react from 'react';
|
|
3
5
|
import { PropsWithChildren, Component, ReactNode, ErrorInfo } from 'react';
|
|
4
|
-
|
|
5
|
-
export { a as SDKError, b as SDKErrorCode, c as ServerTokenProviderOptions, d as TokenProviderContext, V as VideoSDKConfig, e as createServerTokenProvider, f as defaultApiBaseUrl, g as defaultWsBaseUrlFromApi, h as getVideoSDKConfig, i as initVideoSDK, m as mapSDKErrorToUIMessage } from './sdkConfig-C9Fey7R2.js';
|
|
6
|
-
|
|
7
|
-
type StreemoUser = {
|
|
8
|
-
id: string;
|
|
9
|
-
name: string;
|
|
10
|
-
image?: string;
|
|
11
|
-
};
|
|
12
|
-
type StreemoAttachment = {
|
|
13
|
-
id: string;
|
|
14
|
-
type: 'image' | 'video' | 'file';
|
|
15
|
-
url: string;
|
|
16
|
-
name?: string;
|
|
17
|
-
};
|
|
18
|
-
type StreemoReaction = {
|
|
19
|
-
type: string;
|
|
20
|
-
userId: string;
|
|
21
|
-
};
|
|
22
|
-
type StreemoMessage = {
|
|
23
|
-
id: string;
|
|
24
|
-
channelId: string;
|
|
25
|
-
text: string;
|
|
26
|
-
userId: string;
|
|
27
|
-
createdAt: string;
|
|
28
|
-
updatedAt?: string;
|
|
29
|
-
parentId?: string;
|
|
30
|
-
attachments?: StreemoAttachment[];
|
|
31
|
-
reactions?: StreemoReaction[];
|
|
32
|
-
deliveryStatus?: 'sending' | 'sent' | 'failed';
|
|
33
|
-
};
|
|
34
|
-
type StreemoChannel = {
|
|
35
|
-
id: string;
|
|
36
|
-
name: string;
|
|
37
|
-
image?: string;
|
|
38
|
-
lastMessageAt?: string;
|
|
39
|
-
unreadCount?: number;
|
|
40
|
-
};
|
|
41
|
-
type TypingState = {
|
|
42
|
-
channelId: string;
|
|
43
|
-
userId: string;
|
|
44
|
-
isTyping: boolean;
|
|
45
|
-
updatedAt: string;
|
|
46
|
-
};
|
|
47
|
-
type PresenceState = {
|
|
48
|
-
userId: string;
|
|
49
|
-
status: 'online' | 'offline' | 'away';
|
|
50
|
-
lastSeenAt?: string;
|
|
51
|
-
};
|
|
52
|
-
type Participant = {
|
|
53
|
-
userId: string;
|
|
54
|
-
userName: string;
|
|
55
|
-
stream?: MediaStream;
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
type Listener<T> = (event: T) => void;
|
|
59
|
-
type RealtimeEventMap = {
|
|
60
|
-
connected: {
|
|
61
|
-
connected: boolean;
|
|
62
|
-
};
|
|
63
|
-
message_new: StreemoMessage;
|
|
64
|
-
message_updated: StreemoMessage;
|
|
65
|
-
typing: TypingState;
|
|
66
|
-
presence: PresenceState;
|
|
67
|
-
reaction_new: {
|
|
68
|
-
channelId: string;
|
|
69
|
-
messageId: string;
|
|
70
|
-
reaction: StreemoReaction;
|
|
71
|
-
};
|
|
72
|
-
};
|
|
73
|
-
type StreemoClientOptions = {
|
|
74
|
-
apiKey: string;
|
|
75
|
-
userToken: string;
|
|
76
|
-
user: StreemoUser;
|
|
77
|
-
baseUrl?: string;
|
|
78
|
-
wsUrl?: string;
|
|
79
|
-
reconnect?: boolean;
|
|
80
|
-
};
|
|
81
|
-
declare class StreemoClient {
|
|
82
|
-
readonly apiKey: string;
|
|
83
|
-
readonly userToken: string;
|
|
84
|
-
readonly user: StreemoUser;
|
|
85
|
-
readonly baseUrl: string;
|
|
86
|
-
readonly wsUrl: string;
|
|
87
|
-
private readonly reconnect;
|
|
88
|
-
private ws;
|
|
89
|
-
private manuallyClosed;
|
|
90
|
-
private reconnectAttempt;
|
|
91
|
-
private listeners;
|
|
92
|
-
constructor(options: StreemoClientOptions);
|
|
93
|
-
on<K extends keyof RealtimeEventMap>(event: K, listener: Listener<RealtimeEventMap[K]>): () => void;
|
|
94
|
-
off<K extends keyof RealtimeEventMap>(event: K, listener: Listener<RealtimeEventMap[K]>): void;
|
|
95
|
-
private emit;
|
|
96
|
-
connect(): Promise<void>;
|
|
97
|
-
disconnect(): void;
|
|
98
|
-
private openSocket;
|
|
99
|
-
private buildUrl;
|
|
100
|
-
private request;
|
|
101
|
-
listChannels(): Promise<{
|
|
102
|
-
items: StreemoChannel[];
|
|
103
|
-
}>;
|
|
104
|
-
listMessages(channelId: string, cursor?: string, limit?: number): Promise<{
|
|
105
|
-
items: StreemoMessage[];
|
|
106
|
-
nextCursor?: string;
|
|
107
|
-
hasMore?: boolean;
|
|
108
|
-
}>;
|
|
109
|
-
sendMessage(input: {
|
|
110
|
-
channelId: string;
|
|
111
|
-
text: string;
|
|
112
|
-
parentId?: string;
|
|
113
|
-
attachments?: StreemoAttachment[];
|
|
114
|
-
}): Promise<StreemoMessage>;
|
|
115
|
-
updateMessage(channelId: string, messageId: string, text: string): Promise<StreemoMessage>;
|
|
116
|
-
deleteMessage(channelId: string, messageId: string): Promise<{
|
|
117
|
-
ok: true;
|
|
118
|
-
}>;
|
|
119
|
-
sendTyping(channelId: string, isTyping: boolean): Promise<{
|
|
120
|
-
ok: true;
|
|
121
|
-
}>;
|
|
122
|
-
}
|
|
6
|
+
export { StreemoThemeProvider, Theme, ThemeMode, ThemeTokens, createTheme, useTheme } from 'streemo-ui-kit-web/theme';
|
|
123
7
|
|
|
124
8
|
type StreemoContextValue = {
|
|
125
9
|
client: StreemoClient;
|
|
@@ -196,6 +80,7 @@ declare function useTyping(channelId: string): {
|
|
|
196
80
|
declare function usePresence(): {
|
|
197
81
|
presenceMap: Record<string, PresenceState>;
|
|
198
82
|
getUserPresence: (userId: string) => PresenceState;
|
|
83
|
+
findUserPresence: (userId: string) => PresenceState;
|
|
199
84
|
};
|
|
200
85
|
|
|
201
86
|
type UseCallParams = {
|
|
@@ -246,6 +131,20 @@ declare function useParticipants(params: UseCallParams): {
|
|
|
246
131
|
leaveCall: () => void;
|
|
247
132
|
};
|
|
248
133
|
|
|
134
|
+
type StreemoEntitlements = {
|
|
135
|
+
operations: {
|
|
136
|
+
createRoom: boolean;
|
|
137
|
+
chatWrite: boolean;
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
type UseEntitlementsResult = {
|
|
141
|
+
entitlements: StreemoEntitlements | null;
|
|
142
|
+
loading: boolean;
|
|
143
|
+
error: string | null;
|
|
144
|
+
refresh: () => Promise<StreemoEntitlements | null>;
|
|
145
|
+
};
|
|
146
|
+
declare function useEntitlements(enabled?: boolean): UseEntitlementsResult;
|
|
147
|
+
|
|
249
148
|
declare function Chat({ children }: PropsWithChildren): react_jsx_runtime.JSX.Element;
|
|
250
149
|
|
|
251
150
|
declare function ChannelList(): react_jsx_runtime.JSX.Element;
|
|
@@ -476,4 +375,4 @@ type VideoCallWidgetProps = {
|
|
|
476
375
|
};
|
|
477
376
|
declare function VideoCallWidget({ roomId, userId, userName, roomToken, wsBaseUrl, tokenProvider, apiBaseUrl, auth, enabled, localLabelSuffix, showChat, }: VideoCallWidgetProps): react_jsx_runtime.JSX.Element;
|
|
478
377
|
|
|
479
|
-
export { AttachmentPreview, Avatar, CallControls, CallRoom, CameraToggle, Channel, ChannelList, ChannelPreview, Chat, type ChatMessage, ChatPanel, type ChatPanelProps, ErrorBoundary, JoinCallButton, LeaveCallButton, LoadingSpinner, Message, MessageInput, MessageList, MuteButton,
|
|
378
|
+
export { AttachmentPreview, Avatar, CallControls, CallRoom, CameraToggle, Channel, ChannelList, ChannelPreview, Chat, type ChatMessage, ChatPanel, type ChatPanelProps, ErrorBoundary, JoinCallButton, LeaveCallButton, LoadingSpinner, Message, MessageInput, MessageList, MuteButton, ParticipantGrid, ParticipantTile, PresenceBadge, PresenceState, ReactionPicker, type RemoteTrackState, ScreenShareButton, ServerAuthConfig, StreemoAttachment, StreemoChannel, StreemoClient, type StreemoEntitlements, StreemoMessage, StreemoProvider, StreemoTheme, type StreemoThemeTokens, Thread, TokenProvider, TypingIndicator, type TypingParticipant, TypingState, type UseWebRTCCallParams, UserStatus, VideoCallWidget, type VideoCallWidgetProps, VideoTile, useCall, useCallRoomContext, useChannel, useChat, useEntitlements, useMessages, useParticipants, usePresence, useStreemoContext, useTyping, useWebRTCCall };
|