@defcomm/meetingsdk 0.5.6 → 0.5.8

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/index.d.mts CHANGED
@@ -143,6 +143,49 @@ type LiveTranscript = {
143
143
  end_ms?: number | null;
144
144
  timestamp: string;
145
145
  };
146
+ type TranscriptSegment = {
147
+ id: string;
148
+ transcript_session_id: string;
149
+ room_id: string;
150
+ participant_id: string;
151
+ speaker_name?: string | null;
152
+ sequence: number;
153
+ text: string;
154
+ offset_ms?: number | null;
155
+ start_ms?: number | null;
156
+ end_ms?: number | null;
157
+ created_at: string;
158
+ };
159
+ type TranscriptSession = {
160
+ id: string;
161
+ room_id: string;
162
+ status: string;
163
+ started_at: string;
164
+ finalized_at?: string | null;
165
+ };
166
+ type MeetingSummary = {
167
+ transcript_session_id: string;
168
+ room_id: string;
169
+ status: string;
170
+ overview?: string | null;
171
+ topics: string[];
172
+ decisions: string[];
173
+ action_items: string[];
174
+ important_moments: Array<{
175
+ timestamp_ms?: number | null;
176
+ title?: string | null;
177
+ description?: string | null;
178
+ }>;
179
+ error?: string | null;
180
+ created_at: string;
181
+ updated_at: string;
182
+ };
183
+ type TranscriptResponse = {
184
+ room_id: string;
185
+ session: TranscriptSession | null;
186
+ segments: TranscriptSegment[];
187
+ summary: MeetingSummary | null;
188
+ };
146
189
  type NetworkQuality = {
147
190
  participant_id: string;
148
191
  quality: "excellent" | "good" | "fair" | "poor" | string;
@@ -291,6 +334,10 @@ declare class VideoSDKCore {
291
334
  getRoom(roomCode: string): Promise<any>;
292
335
  getJoinState(roomCode: string): Promise<JoinState>;
293
336
  deleteRoom(roomCode: string): Promise<any>;
337
+ getTranscript(roomCode: string, sessionId?: string): Promise<TranscriptResponse>;
338
+ getMeetingSummary(roomCode: string, sessionId: string): Promise<{
339
+ summary: MeetingSummary | null;
340
+ }>;
294
341
  joinMeeting(config: Omit<MeetingConfig, "participantId">): Promise<void>;
295
342
  private connect;
296
343
  private createSFUClient;
@@ -368,6 +415,10 @@ type MeetingContextValue = {
368
415
  }) => Promise<any>;
369
416
  getRoom: (roomCode: string) => Promise<any>;
370
417
  deleteRoom: (roomCode: string) => Promise<any>;
418
+ getTranscript: (roomCode: string, sessionId?: string) => Promise<TranscriptResponse>;
419
+ getMeetingSummary: (roomCode: string, sessionId: string) => Promise<{
420
+ summary: MeetingSummary | null;
421
+ }>;
371
422
  toggleMic: () => void;
372
423
  toggleCam: () => void;
373
424
  startScreenShare: () => Promise<MediaStream | null>;
@@ -453,6 +504,10 @@ declare const useMeeting: (handlers?: {
453
504
  }) => Promise<any>;
454
505
  getRoom: (roomCode: string) => Promise<any>;
455
506
  deleteRoom: (roomCode: string) => Promise<any>;
507
+ getTranscript: (roomCode: string, sessionId?: string) => Promise<TranscriptResponse>;
508
+ getMeetingSummary: (roomCode: string, sessionId: string) => Promise<{
509
+ summary: MeetingSummary | null;
510
+ }>;
456
511
  toggleMic: () => void;
457
512
  toggleCam: () => void;
458
513
  startScreenShare: () => Promise<MediaStream | null>;
@@ -590,4 +645,4 @@ declare function usePubSub<T extends PubSubTopic>(topic: T, options?: {
590
645
  onMessageReceived?: (message: PubSubMessage<PubSubTopicConfig[T]["message"]>) => void;
591
646
  }): PubSubHandleForTopic<T>;
592
647
 
593
- export { ActiveSpeakerDetector, type ChatInput, type LiveTranscript, type MeetingConfig, MeetingProvider, MeetingState, type NetworkQuality, type Participant, type ParticipantInfo, type PubSubHandle, type PubSubHandleForTopic, type PubSubMessage, type PubSubTopic, type PubSubTopicConfig, type Reaction, type RecordingInfo, type SFUConnectionState, type TrackInfo, VideoSDKCore, useLiveTranscript, useLocalParticipant, useMeeting, useMeetingContext, useMeetingPreview, useNetworkQuality, useParticipants, usePubSub, useRemoteMedia };
648
+ export { ActiveSpeakerDetector, type ChatInput, type LiveTranscript, type MeetingConfig, MeetingProvider, MeetingState, type MeetingSummary, type NetworkQuality, type Participant, type ParticipantInfo, type PubSubHandle, type PubSubHandleForTopic, type PubSubMessage, type PubSubTopic, type PubSubTopicConfig, type Reaction, type RecordingInfo, type SFUConnectionState, type TrackInfo, type TranscriptResponse, type TranscriptSegment, type TranscriptSession, VideoSDKCore, useLiveTranscript, useLocalParticipant, useMeeting, useMeetingContext, useMeetingPreview, useNetworkQuality, useParticipants, usePubSub, useRemoteMedia };
package/dist/index.d.ts CHANGED
@@ -143,6 +143,49 @@ type LiveTranscript = {
143
143
  end_ms?: number | null;
144
144
  timestamp: string;
145
145
  };
146
+ type TranscriptSegment = {
147
+ id: string;
148
+ transcript_session_id: string;
149
+ room_id: string;
150
+ participant_id: string;
151
+ speaker_name?: string | null;
152
+ sequence: number;
153
+ text: string;
154
+ offset_ms?: number | null;
155
+ start_ms?: number | null;
156
+ end_ms?: number | null;
157
+ created_at: string;
158
+ };
159
+ type TranscriptSession = {
160
+ id: string;
161
+ room_id: string;
162
+ status: string;
163
+ started_at: string;
164
+ finalized_at?: string | null;
165
+ };
166
+ type MeetingSummary = {
167
+ transcript_session_id: string;
168
+ room_id: string;
169
+ status: string;
170
+ overview?: string | null;
171
+ topics: string[];
172
+ decisions: string[];
173
+ action_items: string[];
174
+ important_moments: Array<{
175
+ timestamp_ms?: number | null;
176
+ title?: string | null;
177
+ description?: string | null;
178
+ }>;
179
+ error?: string | null;
180
+ created_at: string;
181
+ updated_at: string;
182
+ };
183
+ type TranscriptResponse = {
184
+ room_id: string;
185
+ session: TranscriptSession | null;
186
+ segments: TranscriptSegment[];
187
+ summary: MeetingSummary | null;
188
+ };
146
189
  type NetworkQuality = {
147
190
  participant_id: string;
148
191
  quality: "excellent" | "good" | "fair" | "poor" | string;
@@ -291,6 +334,10 @@ declare class VideoSDKCore {
291
334
  getRoom(roomCode: string): Promise<any>;
292
335
  getJoinState(roomCode: string): Promise<JoinState>;
293
336
  deleteRoom(roomCode: string): Promise<any>;
337
+ getTranscript(roomCode: string, sessionId?: string): Promise<TranscriptResponse>;
338
+ getMeetingSummary(roomCode: string, sessionId: string): Promise<{
339
+ summary: MeetingSummary | null;
340
+ }>;
294
341
  joinMeeting(config: Omit<MeetingConfig, "participantId">): Promise<void>;
295
342
  private connect;
296
343
  private createSFUClient;
@@ -368,6 +415,10 @@ type MeetingContextValue = {
368
415
  }) => Promise<any>;
369
416
  getRoom: (roomCode: string) => Promise<any>;
370
417
  deleteRoom: (roomCode: string) => Promise<any>;
418
+ getTranscript: (roomCode: string, sessionId?: string) => Promise<TranscriptResponse>;
419
+ getMeetingSummary: (roomCode: string, sessionId: string) => Promise<{
420
+ summary: MeetingSummary | null;
421
+ }>;
371
422
  toggleMic: () => void;
372
423
  toggleCam: () => void;
373
424
  startScreenShare: () => Promise<MediaStream | null>;
@@ -453,6 +504,10 @@ declare const useMeeting: (handlers?: {
453
504
  }) => Promise<any>;
454
505
  getRoom: (roomCode: string) => Promise<any>;
455
506
  deleteRoom: (roomCode: string) => Promise<any>;
507
+ getTranscript: (roomCode: string, sessionId?: string) => Promise<TranscriptResponse>;
508
+ getMeetingSummary: (roomCode: string, sessionId: string) => Promise<{
509
+ summary: MeetingSummary | null;
510
+ }>;
456
511
  toggleMic: () => void;
457
512
  toggleCam: () => void;
458
513
  startScreenShare: () => Promise<MediaStream | null>;
@@ -590,4 +645,4 @@ declare function usePubSub<T extends PubSubTopic>(topic: T, options?: {
590
645
  onMessageReceived?: (message: PubSubMessage<PubSubTopicConfig[T]["message"]>) => void;
591
646
  }): PubSubHandleForTopic<T>;
592
647
 
593
- export { ActiveSpeakerDetector, type ChatInput, type LiveTranscript, type MeetingConfig, MeetingProvider, MeetingState, type NetworkQuality, type Participant, type ParticipantInfo, type PubSubHandle, type PubSubHandleForTopic, type PubSubMessage, type PubSubTopic, type PubSubTopicConfig, type Reaction, type RecordingInfo, type SFUConnectionState, type TrackInfo, VideoSDKCore, useLiveTranscript, useLocalParticipant, useMeeting, useMeetingContext, useMeetingPreview, useNetworkQuality, useParticipants, usePubSub, useRemoteMedia };
648
+ export { ActiveSpeakerDetector, type ChatInput, type LiveTranscript, type MeetingConfig, MeetingProvider, MeetingState, type MeetingSummary, type NetworkQuality, type Participant, type ParticipantInfo, type PubSubHandle, type PubSubHandleForTopic, type PubSubMessage, type PubSubTopic, type PubSubTopicConfig, type Reaction, type RecordingInfo, type SFUConnectionState, type TrackInfo, type TranscriptResponse, type TranscriptSegment, type TranscriptSession, VideoSDKCore, useLiveTranscript, useLocalParticipant, useMeeting, useMeetingContext, useMeetingPreview, useNetworkQuality, useParticipants, usePubSub, useRemoteMedia };
package/dist/index.js CHANGED
@@ -472,11 +472,7 @@ var SFUClient = class {
472
472
  this.trackToSource = /* @__PURE__ */ new Map();
473
473
  this.localTrackIds = /* @__PURE__ */ new Map();
474
474
  this.subscriberStatsTimer = null;
475
- this.liveTranscriptionActive = false;
476
- this.liveTranscriptionSequence = 0;
477
- this.liveTranscriptionStartedAt = 0;
478
- this.liveTranscriptionRecorder = null;
479
- this.liveTranscriptionLoopPromise = null;
475
+ this.liveTranscriptionSeen = false;
480
476
  this.networkProfile = null;
481
477
  this.heartbeatTimer = null;
482
478
  this.apiBase = options.apiBase || "https://api.example.com/api";
@@ -1144,7 +1140,10 @@ var SFUClient = class {
1144
1140
  end_ms: payload.end_ms == null ? null : Number(payload.end_ms),
1145
1141
  timestamp: String(payload.timestamp ?? (/* @__PURE__ */ new Date()).toISOString())
1146
1142
  };
1147
- if (transcript.text.trim()) this.onLiveTranscript(transcript);
1143
+ if (transcript.text.trim()) {
1144
+ this.liveTranscriptionSeen = true;
1145
+ this.onLiveTranscript(transcript);
1146
+ }
1148
1147
  break;
1149
1148
  }
1150
1149
  case "network_quality": {
@@ -1825,119 +1824,63 @@ var SFUClient = class {
1825
1824
  }
1826
1825
  });
1827
1826
  }
1828
- getLiveTranscriptionMimeType() {
1829
- if (typeof MediaRecorder === "undefined") {
1830
- throw new Error("MediaRecorder is not supported by this browser");
1827
+ /**
1828
+ * Transcription is server-authoritative. The SFU reads the already-published
1829
+ * microphone RTP stream, sends audio to the configured transcription service,
1830
+ * persists final segments, and broadcasts LiveTranscript events.
1831
+ *
1832
+ * These methods remain as compatibility shims for applications that used the
1833
+ * previous browser MediaRecorder-based API. They intentionally do not capture
1834
+ * or upload microphone audio from the browser.
1835
+ */
1836
+ async startLiveTranscription() {
1837
+ if (!this.room) {
1838
+ throw new Error("Cannot start live transcription without a room");
1831
1839
  }
1832
- const candidates = [
1833
- "audio/webm;codecs=opus",
1834
- "audio/webm",
1835
- "audio/ogg;codecs=opus"
1836
- ];
1837
- return candidates.find((type) => MediaRecorder.isTypeSupported(type)) || "";
1838
- }
1839
- async startLiveTranscription(audioTrack, speakerName) {
1840
- if (this.liveTranscriptionActive) return;
1841
- if (!this.room) throw new Error("Cannot start live transcription without a room");
1842
- if (!this.authToken) throw new Error("Cannot start live transcription without an authenticated token");
1843
- if (!audioTrack || audioTrack.kind !== "audio") {
1844
- throw new Error("A live microphone audio track is required");
1845
- }
1846
- const mimeType = this.getLiveTranscriptionMimeType();
1847
- this.liveTranscriptionActive = true;
1848
- this.liveTranscriptionSequence = 0;
1849
- this.liveTranscriptionStartedAt = Date.now();
1850
- const stream = new MediaStream([audioTrack]);
1851
- this.liveTranscriptionLoopPromise = this.runLiveTranscriptionLoop(
1852
- stream,
1853
- mimeType
1854
- ).finally(() => {
1855
- this.liveTranscriptionRecorder = null;
1856
- this.liveTranscriptionLoopPromise = null;
1857
- });
1858
- void speakerName;
1859
- await Promise.resolve();
1840
+ console.info("[Transcript] server-authoritative live transcription is managed by the SFU");
1860
1841
  }
1861
- async captureLiveChunk(stream, mimeType) {
1862
- return new Promise((resolve, reject) => {
1863
- const chunks = [];
1864
- const recorder = mimeType ? new MediaRecorder(stream, { mimeType }) : new MediaRecorder(stream);
1865
- this.liveTranscriptionRecorder = recorder;
1866
- const timeout = setTimeout(() => {
1867
- if (recorder.state !== "inactive") recorder.stop();
1868
- }, 4500);
1869
- recorder.ondataavailable = (event) => {
1870
- if (event.data.size > 0) chunks.push(event.data);
1871
- };
1872
- recorder.onerror = () => {
1873
- clearTimeout(timeout);
1874
- reject(new Error("Live transcription recorder failed"));
1875
- };
1876
- recorder.onstop = () => {
1877
- clearTimeout(timeout);
1878
- this.liveTranscriptionRecorder = null;
1879
- resolve(
1880
- chunks.length ? new Blob(chunks, { type: recorder.mimeType || mimeType || "audio/webm" }) : null
1881
- );
1882
- };
1883
- recorder.start();
1884
- });
1842
+ stopLiveTranscription() {
1843
+ console.info("[Transcript] server-authoritative live transcription remains managed by the SFU");
1885
1844
  }
1886
- async runLiveTranscriptionLoop(stream, mimeType) {
1887
- while (this.liveTranscriptionActive && stream.getAudioTracks()[0]?.readyState === "live") {
1888
- try {
1889
- const blob = await this.captureLiveChunk(stream, mimeType);
1890
- if (!this.liveTranscriptionActive) break;
1891
- if (!blob || blob.size === 0) continue;
1892
- const sequence = this.liveTranscriptionSequence++;
1893
- const offsetMs = Math.max(0, Date.now() - this.liveTranscriptionStartedAt);
1894
- await this.uploadLiveTranscriptionChunk(blob, sequence, offsetMs, mimeType);
1895
- } catch (error) {
1896
- this.onError(error);
1897
- await new Promise((resolve) => setTimeout(resolve, 750));
1898
- }
1899
- }
1845
+ isLiveTranscriptionActive() {
1846
+ return this.liveTranscriptionSeen;
1900
1847
  }
1901
- async uploadLiveTranscriptionChunk(blob, sequence, offsetMs, mimeType) {
1902
- if (!this.room || !this.authToken) return;
1903
- const form = new FormData();
1904
- form.append("sequence", String(sequence));
1905
- form.append("offset_ms", String(offsetMs));
1906
- const extension = mimeType.includes("ogg") || blob.type.includes("ogg") ? "ogg" : "webm";
1907
- form.append("audio", blob, `live-${sequence}.${extension}`);
1848
+ async getTranscript(roomCode, sessionId) {
1849
+ if (!this.authToken) throw new Error("Authentication token is required");
1850
+ const query = sessionId ? `?session_id=${encodeURIComponent(sessionId)}` : "";
1908
1851
  const response = await fetch(
1909
- `${this.apiBase}/rooms/${encodeURIComponent(this.room)}/live-transcription`,
1852
+ `${this.apiBase}/rooms/${encodeURIComponent(roomCode)}/transcript${query}`,
1910
1853
  {
1911
- method: "POST",
1854
+ method: "GET",
1912
1855
  headers: {
1913
1856
  Authorization: `Bearer ${this.authToken}`,
1914
1857
  Accept: "application/json"
1915
- },
1916
- body: form
1858
+ }
1917
1859
  }
1918
1860
  );
1861
+ const text = await response.text();
1919
1862
  if (!response.ok) {
1920
- let detail = `Live transcription request failed: ${response.status}`;
1921
- try {
1922
- const body = await response.json();
1923
- detail = body?.message || body?.detail || detail;
1924
- } catch {
1925
- }
1926
- throw new Error(detail);
1863
+ throw new Error(`Transcript request failed: ${response.status} ${text}`);
1927
1864
  }
1865
+ return JSON.parse(text);
1928
1866
  }
1929
- stopLiveTranscription() {
1930
- this.liveTranscriptionActive = false;
1931
- try {
1932
- if (this.liveTranscriptionRecorder?.state !== "inactive") {
1933
- this.liveTranscriptionRecorder?.stop();
1867
+ async getMeetingSummary(roomCode, sessionId) {
1868
+ if (!this.authToken) throw new Error("Authentication token is required");
1869
+ const response = await fetch(
1870
+ `${this.apiBase}/rooms/${encodeURIComponent(roomCode)}/transcript/${encodeURIComponent(sessionId)}/summary`,
1871
+ {
1872
+ method: "GET",
1873
+ headers: {
1874
+ Authorization: `Bearer ${this.authToken}`,
1875
+ Accept: "application/json"
1876
+ }
1934
1877
  }
1935
- } catch {
1878
+ );
1879
+ const text = await response.text();
1880
+ if (!response.ok) {
1881
+ throw new Error(`Meeting summary request failed: ${response.status} ${text}`);
1936
1882
  }
1937
- this.liveTranscriptionRecorder = null;
1938
- }
1939
- isLiveTranscriptionActive() {
1940
- return this.liveTranscriptionActive;
1883
+ return JSON.parse(text);
1941
1884
  }
1942
1885
  async applyNetworkRecommendation(action) {
1943
1886
  if (!this.videoSender || this.networkProfile === action) return;
@@ -2380,6 +2323,12 @@ var VideoSDKCore = class {
2380
2323
  async deleteRoom(roomCode) {
2381
2324
  return this.sfuClient.deleteRoom(roomCode);
2382
2325
  }
2326
+ async getTranscript(roomCode, sessionId) {
2327
+ return this.sfuClient.getTranscript(roomCode, sessionId);
2328
+ }
2329
+ async getMeetingSummary(roomCode, sessionId) {
2330
+ return this.sfuClient.getMeetingSummary(roomCode, sessionId);
2331
+ }
2383
2332
  // JOIN
2384
2333
  async joinMeeting(config) {
2385
2334
  const { roomId, name, audioMuted = false, videoMuted = false } = config;
@@ -3164,13 +3113,10 @@ var VideoSDKCore = class {
3164
3113
  throw new Error("SFU client is not connected");
3165
3114
  }
3166
3115
  const audioTrack = this.localStream?.getAudioTracks()[0];
3167
- if (!audioTrack) {
3116
+ if (!audioTrack || audioTrack.readyState !== "live") {
3168
3117
  throw new Error("Microphone audio track is not available");
3169
3118
  }
3170
- await this.sfuClient.startLiveTranscription(
3171
- audioTrack,
3172
- this.participantName
3173
- );
3119
+ await this.sfuClient.startLiveTranscription();
3174
3120
  }
3175
3121
  stopLiveTranscription() {
3176
3122
  this.sfuClient?.stopLiveTranscription();
@@ -3436,6 +3382,8 @@ var MeetingProvider = ({
3436
3382
  createRoom: sdk.createRoom.bind(sdk),
3437
3383
  getRoom: sdk.getRoom.bind(sdk),
3438
3384
  deleteRoom: sdk.deleteRoom.bind(sdk),
3385
+ getTranscript: sdk.getTranscript.bind(sdk),
3386
+ getMeetingSummary: sdk.getMeetingSummary.bind(sdk),
3439
3387
  toggleMic: sdk.toggleMic.bind(sdk),
3440
3388
  toggleCam: sdk.toggleCam.bind(sdk),
3441
3389
  startScreenShare: sdk.startScreenShare.bind(sdk),