@whereby.com/assistant-sdk 0.0.0-canary-20250912144626 → 0.0.0-canary-20250916140846

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.cjs CHANGED
@@ -30,9 +30,11 @@ function _interopNamespaceDefault(e) {
30
30
 
31
31
  var dotenv__namespace = /*#__PURE__*/_interopNamespaceDefault(dotenv);
32
32
 
33
- const ASSISTANT_JOIN_SUCCESS = "ASSISTANT_JOIN_SUCCESS";
33
+ const TRIGGER_EVENT_SUCCESS = "trigger_event_success";
34
34
 
35
35
  const AUDIO_STREAM_READY = "AUDIO_STREAM_READY";
36
+ const ASSISTANT_JOINED_ROOM = "ASSISTANT_JOINED_ROOM";
37
+ const ASSISTANT_LEFT_ROOM = "ASSISTANT_LEFT_ROOM";
36
38
 
37
39
  /******************************************************************************
38
40
  Copyright (c) Microsoft Corporation.
@@ -516,6 +518,15 @@ class Assistant extends EventEmitter {
516
518
  this.mediaStream = null;
517
519
  this.audioSource = null;
518
520
  this.combinedStream = null;
521
+ this.roomUrl = null;
522
+ this.handleConnectionStatusChange = (status) => {
523
+ if (status === "connected") {
524
+ this.emit(ASSISTANT_JOINED_ROOM, { roomUrl: this.roomUrl || "" });
525
+ }
526
+ if (["left", "kicked"].includes(status)) {
527
+ this.emit(ASSISTANT_LEFT_ROOM, { roomUrl: this.roomUrl || "" });
528
+ }
529
+ };
519
530
  this.assistantKey = assistantKey;
520
531
  this.client = new core.WherebyClient();
521
532
  this.roomConnection = this.client.getRoomConnection();
@@ -540,6 +551,7 @@ class Assistant extends EventEmitter {
540
551
  const audioMixer = new AudioMixer(handleStreamReady);
541
552
  this.combinedStream = audioMixer.getCombinedAudioStream();
542
553
  this.roomConnection.subscribeToRemoteParticipants(audioMixer.handleRemoteParticipants.bind(audioMixer));
554
+ this.roomConnection.subscribeToConnectionStatus(this.handleConnectionStatusChange);
543
555
  }
544
556
  }
545
557
  joinRoom(roomUrl) {
@@ -547,6 +559,7 @@ class Assistant extends EventEmitter {
547
559
  if (this.mediaStream) {
548
560
  yield this.localMedia.startMedia(this.mediaStream);
549
561
  }
562
+ this.roomUrl = roomUrl;
550
563
  this.roomConnection.initialize({
551
564
  localMediaOptions: {
552
565
  audio: false,
@@ -649,7 +662,7 @@ function buildRoomUrl(roomPath, wherebySubdomain, baseDomain = "whereby.com") {
649
662
  return `https://${wherebyDomain}${roomPath}`;
650
663
  }
651
664
 
652
- const webhookRouter = (webhookTriggers, emitter, assistantKey, startCombinedAudioStream = false, startLocalMedia = false) => {
665
+ const webhookRouter = (webhookTriggers, emitter) => {
653
666
  const router = express.Router();
654
667
  const jsonParser = bodyParser.json();
655
668
  router.get("/", (_, res) => {
@@ -657,15 +670,31 @@ const webhookRouter = (webhookTriggers, emitter, assistantKey, startCombinedAudi
657
670
  res.end();
658
671
  });
659
672
  router.post("/", jsonParser, (req, res) => {
660
- var _a;
673
+ var _a, _b, _c, _d, _e, _f, _g, _h;
661
674
  assert(req.body, "message body is required");
662
675
  assert("type" in req.body, "webhook type is required");
663
- const shouldTriggerOnReceivedWebhook = (_a = webhookTriggers[req.body.type]) === null || _a === void 0 ? void 0 : _a.call(webhookTriggers, req.body);
676
+ let shouldTriggerOnReceivedWebhook = false;
677
+ switch (req.body.type) {
678
+ case "room.client.joined":
679
+ shouldTriggerOnReceivedWebhook =
680
+ (_b = (_a = webhookTriggers["room.client.joined"]) === null || _a === void 0 ? void 0 : _a.call(webhookTriggers, req.body)) !== null && _b !== void 0 ? _b : false;
681
+ break;
682
+ case "room.client.left":
683
+ shouldTriggerOnReceivedWebhook =
684
+ (_d = (_c = webhookTriggers["room.client.left"]) === null || _c === void 0 ? void 0 : _c.call(webhookTriggers, req.body)) !== null && _d !== void 0 ? _d : false;
685
+ break;
686
+ case "room.session.started":
687
+ shouldTriggerOnReceivedWebhook =
688
+ (_f = (_e = webhookTriggers["room.session.started"]) === null || _e === void 0 ? void 0 : _e.call(webhookTriggers, req.body)) !== null && _f !== void 0 ? _f : false;
689
+ break;
690
+ case "room.session.ended":
691
+ shouldTriggerOnReceivedWebhook =
692
+ (_h = (_g = webhookTriggers["room.session.ended"]) === null || _g === void 0 ? void 0 : _g.call(webhookTriggers, req.body)) !== null && _h !== void 0 ? _h : false;
693
+ break;
694
+ }
664
695
  if (shouldTriggerOnReceivedWebhook) {
665
696
  const roomUrl = buildRoomUrl(req.body.data.roomName, req.body.data.subdomain);
666
- const assistant = new Assistant({ assistantKey, startCombinedAudioStream, startLocalMedia });
667
- assistant.joinRoom(roomUrl);
668
- emitter.emit(ASSISTANT_JOIN_SUCCESS, { roomUrl, triggerWebhook: req.body, assistant });
697
+ emitter.emit(TRIGGER_EVENT_SUCCESS, { roomUrl, triggerWebhook: req.body });
669
698
  }
670
699
  res.status(200);
671
700
  res.end();
@@ -673,17 +702,14 @@ const webhookRouter = (webhookTriggers, emitter, assistantKey, startCombinedAudi
673
702
  return router;
674
703
  };
675
704
  class Trigger extends EventEmitter.EventEmitter {
676
- constructor({ webhookTriggers = {}, port = 8080, assistantKey, startCombinedAudioStream, startLocalMedia, }) {
705
+ constructor({ webhookTriggers = {}, port = 8080 }) {
677
706
  super();
678
707
  this.webhookTriggers = webhookTriggers;
679
708
  this.port = port;
680
- this.assistantKey = assistantKey;
681
- this.startCombinedAudioStream = startCombinedAudioStream !== null && startCombinedAudioStream !== void 0 ? startCombinedAudioStream : false;
682
- this.startLocalMedia = startLocalMedia !== null && startLocalMedia !== void 0 ? startLocalMedia : false;
683
709
  }
684
710
  start() {
685
711
  const app = express();
686
- const router = webhookRouter(this.webhookTriggers, this, this.assistantKey, this.startCombinedAudioStream, this.startLocalMedia);
712
+ const router = webhookRouter(this.webhookTriggers, this);
687
713
  app.use(router);
688
714
  const server = app.listen(this.port, () => {
689
715
  // console.log(`Bot trigger server now running on port[${this.port}]`);
@@ -694,9 +720,11 @@ class Trigger extends EventEmitter.EventEmitter {
694
720
  }
695
721
  }
696
722
 
697
- exports.ASSISTANT_JOIN_SUCCESS = ASSISTANT_JOIN_SUCCESS;
723
+ exports.ASSISTANT_JOINED_ROOM = ASSISTANT_JOINED_ROOM;
724
+ exports.ASSISTANT_LEFT_ROOM = ASSISTANT_LEFT_ROOM;
698
725
  exports.AUDIO_STREAM_READY = AUDIO_STREAM_READY;
699
726
  exports.Assistant = Assistant;
700
727
  exports.AudioSink = AudioSink;
701
728
  exports.AudioSource = AudioSource;
729
+ exports.TRIGGER_EVENT_SUCCESS = TRIGGER_EVENT_SUCCESS;
702
730
  exports.Trigger = Trigger;
package/dist/index.d.cts CHANGED
@@ -36,50 +36,8 @@ declare global {
36
36
  }
37
37
  }
38
38
 
39
- declare const AUDIO_STREAM_READY = "AUDIO_STREAM_READY";
40
- type AssistantEvents = {
41
- [AUDIO_STREAM_READY]: [{
42
- stream: MediaStream;
43
- track: MediaStreamTrack;
44
- }];
45
- };
46
-
47
- type AssistantOptions = {
48
- assistantKey: string;
49
- startCombinedAudioStream?: boolean;
50
- startLocalMedia?: boolean;
51
- };
52
- declare class Assistant extends EventEmitter<AssistantEvents> {
53
- private assistantKey;
54
- private client;
55
- private roomConnection;
56
- private localMedia;
57
- private mediaStream;
58
- private audioSource;
59
- private combinedStream;
60
- constructor({ assistantKey, startCombinedAudioStream, startLocalMedia }: AssistantOptions);
61
- joinRoom(roomUrl: string): Promise<void>;
62
- startLocalMedia(): void;
63
- getLocalMediaStream(): MediaStream | null;
64
- getLocalAudioSource(): wrtc__default.nonstandard.RTCAudioSource | null;
65
- getRoomConnection(): RoomConnectionClient;
66
- getCombinedAudioStream(): MediaStream | null;
67
- getRemoteParticipants(): RemoteParticipantState[];
68
- startCloudRecording(): void;
69
- stopCloudRecording(): void;
70
- sendChatMessage(message: string): void;
71
- spotlightParticipant(participantId: string): void;
72
- removeSpotlight(participantId: string): void;
73
- requestAudioEnable(participantId: string, enable: boolean): void;
74
- requestVideoEnable(participantId: string, enable: boolean): void;
75
- acceptWaitingParticipant(participantId: string): void;
76
- rejectWaitingParticipant(participantId: string): void;
77
- subscribeToRemoteParticipants(callback: (participants: RemoteParticipantState[]) => void): () => void;
78
- subscribeToChatMessages(callback: (messages: ChatMessage[]) => void): () => void;
79
- }
80
-
81
39
  type WebhookType = "room.client.joined" | "room.client.left" | "room.session.started" | "room.session.ended";
82
- declare const ASSISTANT_JOIN_SUCCESS = "ASSISTANT_JOIN_SUCCESS";
40
+ declare const TRIGGER_EVENT_SUCCESS = "trigger_event_success";
83
41
  interface WherebyWebhookBase {
84
42
  type: WebhookType;
85
43
  apiVersion: "1.0";
@@ -117,37 +75,82 @@ interface WherebyWebhookRoomSessionEnded extends WherebyWebhookBase {
117
75
  data: WherebyWebhookInRoom;
118
76
  }
119
77
  type TriggerEvents = {
120
- [ASSISTANT_JOIN_SUCCESS]: [{
78
+ [TRIGGER_EVENT_SUCCESS]: [{
121
79
  roomUrl: string;
122
80
  triggerWebhook: WherebyWebhookType;
123
- assistant: Assistant;
124
81
  }];
125
82
  };
126
83
  type WherebyWebhookType = WherebyWebhookRoomClientJoined | WherebyWebhookRoomClientLeft | WherebyWebhookRoomSessionStarted | WherebyWebhookRoomSessionEnded;
127
84
  type WherebyWebhookTriggerTypes = {
128
- "room.client.joined": WherebyWebhookBase;
129
- "room.client.left": WherebyWebhookBase;
85
+ "room.client.joined": WherebyWebhookRoomClientJoined;
86
+ "room.client.left": WherebyWebhookRoomClientLeft;
130
87
  "room.session.started": WherebyWebhookRoomSessionStarted;
131
- "room.session.ended": WherebyWebhookBase;
88
+ "room.session.ended": WherebyWebhookRoomSessionEnded;
132
89
  };
133
90
  type WherebyWebhookTriggers = Partial<{
134
91
  [Type in keyof WherebyWebhookTriggerTypes]: (data: WherebyWebhookTriggerTypes[Type]) => boolean;
135
92
  }>;
136
93
 
137
- interface TriggerOptions {
138
- webhookTriggers: WherebyWebhookTriggers;
139
- port?: number;
94
+ declare const AUDIO_STREAM_READY = "AUDIO_STREAM_READY";
95
+ declare const ASSISTANT_JOINED_ROOM = "ASSISTANT_JOINED_ROOM";
96
+ declare const ASSISTANT_LEFT_ROOM = "ASSISTANT_LEFT_ROOM";
97
+ type AssistantEvents = {
98
+ [ASSISTANT_JOINED_ROOM]: [{
99
+ roomUrl: string;
100
+ }];
101
+ [ASSISTANT_LEFT_ROOM]: [{
102
+ roomUrl: string;
103
+ }];
104
+ [AUDIO_STREAM_READY]: [{
105
+ stream: MediaStream;
106
+ track: MediaStreamTrack;
107
+ }];
108
+ };
109
+
110
+ type AssistantOptions = {
140
111
  assistantKey: string;
141
112
  startCombinedAudioStream?: boolean;
142
113
  startLocalMedia?: boolean;
114
+ };
115
+ declare class Assistant extends EventEmitter<AssistantEvents> {
116
+ private assistantKey;
117
+ private client;
118
+ private roomConnection;
119
+ private localMedia;
120
+ private mediaStream;
121
+ private audioSource;
122
+ private combinedStream;
123
+ private roomUrl;
124
+ constructor({ assistantKey, startCombinedAudioStream, startLocalMedia }: AssistantOptions);
125
+ private handleConnectionStatusChange;
126
+ joinRoom(roomUrl: string): Promise<void>;
127
+ startLocalMedia(): void;
128
+ getLocalMediaStream(): MediaStream | null;
129
+ getLocalAudioSource(): wrtc__default.nonstandard.RTCAudioSource | null;
130
+ getRoomConnection(): RoomConnectionClient;
131
+ getCombinedAudioStream(): MediaStream | null;
132
+ getRemoteParticipants(): RemoteParticipantState[];
133
+ startCloudRecording(): void;
134
+ stopCloudRecording(): void;
135
+ sendChatMessage(message: string): void;
136
+ spotlightParticipant(participantId: string): void;
137
+ removeSpotlight(participantId: string): void;
138
+ requestAudioEnable(participantId: string, enable: boolean): void;
139
+ requestVideoEnable(participantId: string, enable: boolean): void;
140
+ acceptWaitingParticipant(participantId: string): void;
141
+ rejectWaitingParticipant(participantId: string): void;
142
+ subscribeToRemoteParticipants(callback: (participants: RemoteParticipantState[]) => void): () => void;
143
+ subscribeToChatMessages(callback: (messages: ChatMessage[]) => void): () => void;
144
+ }
145
+
146
+ interface TriggerOptions {
147
+ webhookTriggers: WherebyWebhookTriggers;
148
+ port?: number;
143
149
  }
144
150
  declare class Trigger extends EventEmitter$1<TriggerEvents> {
145
151
  private webhookTriggers;
146
152
  private port;
147
- private assistantKey;
148
- private startCombinedAudioStream;
149
- private startLocalMedia;
150
- constructor({ webhookTriggers, port, assistantKey, startCombinedAudioStream, startLocalMedia, }: TriggerOptions);
153
+ constructor({ webhookTriggers, port }: TriggerOptions);
151
154
  start(): void;
152
155
  }
153
156
 
@@ -166,4 +169,5 @@ declare class AudioSink extends wrtc__default.nonstandard.RTCAudioSink {
166
169
  }) => void): () => void;
167
170
  }
168
171
 
169
- export { ASSISTANT_JOIN_SUCCESS, AUDIO_STREAM_READY, Assistant, AudioSink, AudioSource, Trigger };
172
+ export { ASSISTANT_JOINED_ROOM, ASSISTANT_LEFT_ROOM, AUDIO_STREAM_READY, Assistant, AudioSink, AudioSource, TRIGGER_EVENT_SUCCESS, Trigger };
173
+ export type { AssistantEvents };
package/dist/index.d.mts CHANGED
@@ -36,50 +36,8 @@ declare global {
36
36
  }
37
37
  }
38
38
 
39
- declare const AUDIO_STREAM_READY = "AUDIO_STREAM_READY";
40
- type AssistantEvents = {
41
- [AUDIO_STREAM_READY]: [{
42
- stream: MediaStream;
43
- track: MediaStreamTrack;
44
- }];
45
- };
46
-
47
- type AssistantOptions = {
48
- assistantKey: string;
49
- startCombinedAudioStream?: boolean;
50
- startLocalMedia?: boolean;
51
- };
52
- declare class Assistant extends EventEmitter<AssistantEvents> {
53
- private assistantKey;
54
- private client;
55
- private roomConnection;
56
- private localMedia;
57
- private mediaStream;
58
- private audioSource;
59
- private combinedStream;
60
- constructor({ assistantKey, startCombinedAudioStream, startLocalMedia }: AssistantOptions);
61
- joinRoom(roomUrl: string): Promise<void>;
62
- startLocalMedia(): void;
63
- getLocalMediaStream(): MediaStream | null;
64
- getLocalAudioSource(): wrtc__default.nonstandard.RTCAudioSource | null;
65
- getRoomConnection(): RoomConnectionClient;
66
- getCombinedAudioStream(): MediaStream | null;
67
- getRemoteParticipants(): RemoteParticipantState[];
68
- startCloudRecording(): void;
69
- stopCloudRecording(): void;
70
- sendChatMessage(message: string): void;
71
- spotlightParticipant(participantId: string): void;
72
- removeSpotlight(participantId: string): void;
73
- requestAudioEnable(participantId: string, enable: boolean): void;
74
- requestVideoEnable(participantId: string, enable: boolean): void;
75
- acceptWaitingParticipant(participantId: string): void;
76
- rejectWaitingParticipant(participantId: string): void;
77
- subscribeToRemoteParticipants(callback: (participants: RemoteParticipantState[]) => void): () => void;
78
- subscribeToChatMessages(callback: (messages: ChatMessage[]) => void): () => void;
79
- }
80
-
81
39
  type WebhookType = "room.client.joined" | "room.client.left" | "room.session.started" | "room.session.ended";
82
- declare const ASSISTANT_JOIN_SUCCESS = "ASSISTANT_JOIN_SUCCESS";
40
+ declare const TRIGGER_EVENT_SUCCESS = "trigger_event_success";
83
41
  interface WherebyWebhookBase {
84
42
  type: WebhookType;
85
43
  apiVersion: "1.0";
@@ -117,37 +75,82 @@ interface WherebyWebhookRoomSessionEnded extends WherebyWebhookBase {
117
75
  data: WherebyWebhookInRoom;
118
76
  }
119
77
  type TriggerEvents = {
120
- [ASSISTANT_JOIN_SUCCESS]: [{
78
+ [TRIGGER_EVENT_SUCCESS]: [{
121
79
  roomUrl: string;
122
80
  triggerWebhook: WherebyWebhookType;
123
- assistant: Assistant;
124
81
  }];
125
82
  };
126
83
  type WherebyWebhookType = WherebyWebhookRoomClientJoined | WherebyWebhookRoomClientLeft | WherebyWebhookRoomSessionStarted | WherebyWebhookRoomSessionEnded;
127
84
  type WherebyWebhookTriggerTypes = {
128
- "room.client.joined": WherebyWebhookBase;
129
- "room.client.left": WherebyWebhookBase;
85
+ "room.client.joined": WherebyWebhookRoomClientJoined;
86
+ "room.client.left": WherebyWebhookRoomClientLeft;
130
87
  "room.session.started": WherebyWebhookRoomSessionStarted;
131
- "room.session.ended": WherebyWebhookBase;
88
+ "room.session.ended": WherebyWebhookRoomSessionEnded;
132
89
  };
133
90
  type WherebyWebhookTriggers = Partial<{
134
91
  [Type in keyof WherebyWebhookTriggerTypes]: (data: WherebyWebhookTriggerTypes[Type]) => boolean;
135
92
  }>;
136
93
 
137
- interface TriggerOptions {
138
- webhookTriggers: WherebyWebhookTriggers;
139
- port?: number;
94
+ declare const AUDIO_STREAM_READY = "AUDIO_STREAM_READY";
95
+ declare const ASSISTANT_JOINED_ROOM = "ASSISTANT_JOINED_ROOM";
96
+ declare const ASSISTANT_LEFT_ROOM = "ASSISTANT_LEFT_ROOM";
97
+ type AssistantEvents = {
98
+ [ASSISTANT_JOINED_ROOM]: [{
99
+ roomUrl: string;
100
+ }];
101
+ [ASSISTANT_LEFT_ROOM]: [{
102
+ roomUrl: string;
103
+ }];
104
+ [AUDIO_STREAM_READY]: [{
105
+ stream: MediaStream;
106
+ track: MediaStreamTrack;
107
+ }];
108
+ };
109
+
110
+ type AssistantOptions = {
140
111
  assistantKey: string;
141
112
  startCombinedAudioStream?: boolean;
142
113
  startLocalMedia?: boolean;
114
+ };
115
+ declare class Assistant extends EventEmitter<AssistantEvents> {
116
+ private assistantKey;
117
+ private client;
118
+ private roomConnection;
119
+ private localMedia;
120
+ private mediaStream;
121
+ private audioSource;
122
+ private combinedStream;
123
+ private roomUrl;
124
+ constructor({ assistantKey, startCombinedAudioStream, startLocalMedia }: AssistantOptions);
125
+ private handleConnectionStatusChange;
126
+ joinRoom(roomUrl: string): Promise<void>;
127
+ startLocalMedia(): void;
128
+ getLocalMediaStream(): MediaStream | null;
129
+ getLocalAudioSource(): wrtc__default.nonstandard.RTCAudioSource | null;
130
+ getRoomConnection(): RoomConnectionClient;
131
+ getCombinedAudioStream(): MediaStream | null;
132
+ getRemoteParticipants(): RemoteParticipantState[];
133
+ startCloudRecording(): void;
134
+ stopCloudRecording(): void;
135
+ sendChatMessage(message: string): void;
136
+ spotlightParticipant(participantId: string): void;
137
+ removeSpotlight(participantId: string): void;
138
+ requestAudioEnable(participantId: string, enable: boolean): void;
139
+ requestVideoEnable(participantId: string, enable: boolean): void;
140
+ acceptWaitingParticipant(participantId: string): void;
141
+ rejectWaitingParticipant(participantId: string): void;
142
+ subscribeToRemoteParticipants(callback: (participants: RemoteParticipantState[]) => void): () => void;
143
+ subscribeToChatMessages(callback: (messages: ChatMessage[]) => void): () => void;
144
+ }
145
+
146
+ interface TriggerOptions {
147
+ webhookTriggers: WherebyWebhookTriggers;
148
+ port?: number;
143
149
  }
144
150
  declare class Trigger extends EventEmitter$1<TriggerEvents> {
145
151
  private webhookTriggers;
146
152
  private port;
147
- private assistantKey;
148
- private startCombinedAudioStream;
149
- private startLocalMedia;
150
- constructor({ webhookTriggers, port, assistantKey, startCombinedAudioStream, startLocalMedia, }: TriggerOptions);
153
+ constructor({ webhookTriggers, port }: TriggerOptions);
151
154
  start(): void;
152
155
  }
153
156
 
@@ -166,4 +169,5 @@ declare class AudioSink extends wrtc__default.nonstandard.RTCAudioSink {
166
169
  }) => void): () => void;
167
170
  }
168
171
 
169
- export { ASSISTANT_JOIN_SUCCESS, AUDIO_STREAM_READY, Assistant, AudioSink, AudioSource, Trigger };
172
+ export { ASSISTANT_JOINED_ROOM, ASSISTANT_LEFT_ROOM, AUDIO_STREAM_READY, Assistant, AudioSink, AudioSource, TRIGGER_EVENT_SUCCESS, Trigger };
173
+ export type { AssistantEvents };
package/dist/index.d.ts CHANGED
@@ -36,50 +36,8 @@ declare global {
36
36
  }
37
37
  }
38
38
 
39
- declare const AUDIO_STREAM_READY = "AUDIO_STREAM_READY";
40
- type AssistantEvents = {
41
- [AUDIO_STREAM_READY]: [{
42
- stream: MediaStream;
43
- track: MediaStreamTrack;
44
- }];
45
- };
46
-
47
- type AssistantOptions = {
48
- assistantKey: string;
49
- startCombinedAudioStream?: boolean;
50
- startLocalMedia?: boolean;
51
- };
52
- declare class Assistant extends EventEmitter<AssistantEvents> {
53
- private assistantKey;
54
- private client;
55
- private roomConnection;
56
- private localMedia;
57
- private mediaStream;
58
- private audioSource;
59
- private combinedStream;
60
- constructor({ assistantKey, startCombinedAudioStream, startLocalMedia }: AssistantOptions);
61
- joinRoom(roomUrl: string): Promise<void>;
62
- startLocalMedia(): void;
63
- getLocalMediaStream(): MediaStream | null;
64
- getLocalAudioSource(): wrtc__default.nonstandard.RTCAudioSource | null;
65
- getRoomConnection(): RoomConnectionClient;
66
- getCombinedAudioStream(): MediaStream | null;
67
- getRemoteParticipants(): RemoteParticipantState[];
68
- startCloudRecording(): void;
69
- stopCloudRecording(): void;
70
- sendChatMessage(message: string): void;
71
- spotlightParticipant(participantId: string): void;
72
- removeSpotlight(participantId: string): void;
73
- requestAudioEnable(participantId: string, enable: boolean): void;
74
- requestVideoEnable(participantId: string, enable: boolean): void;
75
- acceptWaitingParticipant(participantId: string): void;
76
- rejectWaitingParticipant(participantId: string): void;
77
- subscribeToRemoteParticipants(callback: (participants: RemoteParticipantState[]) => void): () => void;
78
- subscribeToChatMessages(callback: (messages: ChatMessage[]) => void): () => void;
79
- }
80
-
81
39
  type WebhookType = "room.client.joined" | "room.client.left" | "room.session.started" | "room.session.ended";
82
- declare const ASSISTANT_JOIN_SUCCESS = "ASSISTANT_JOIN_SUCCESS";
40
+ declare const TRIGGER_EVENT_SUCCESS = "trigger_event_success";
83
41
  interface WherebyWebhookBase {
84
42
  type: WebhookType;
85
43
  apiVersion: "1.0";
@@ -117,37 +75,82 @@ interface WherebyWebhookRoomSessionEnded extends WherebyWebhookBase {
117
75
  data: WherebyWebhookInRoom;
118
76
  }
119
77
  type TriggerEvents = {
120
- [ASSISTANT_JOIN_SUCCESS]: [{
78
+ [TRIGGER_EVENT_SUCCESS]: [{
121
79
  roomUrl: string;
122
80
  triggerWebhook: WherebyWebhookType;
123
- assistant: Assistant;
124
81
  }];
125
82
  };
126
83
  type WherebyWebhookType = WherebyWebhookRoomClientJoined | WherebyWebhookRoomClientLeft | WherebyWebhookRoomSessionStarted | WherebyWebhookRoomSessionEnded;
127
84
  type WherebyWebhookTriggerTypes = {
128
- "room.client.joined": WherebyWebhookBase;
129
- "room.client.left": WherebyWebhookBase;
85
+ "room.client.joined": WherebyWebhookRoomClientJoined;
86
+ "room.client.left": WherebyWebhookRoomClientLeft;
130
87
  "room.session.started": WherebyWebhookRoomSessionStarted;
131
- "room.session.ended": WherebyWebhookBase;
88
+ "room.session.ended": WherebyWebhookRoomSessionEnded;
132
89
  };
133
90
  type WherebyWebhookTriggers = Partial<{
134
91
  [Type in keyof WherebyWebhookTriggerTypes]: (data: WherebyWebhookTriggerTypes[Type]) => boolean;
135
92
  }>;
136
93
 
137
- interface TriggerOptions {
138
- webhookTriggers: WherebyWebhookTriggers;
139
- port?: number;
94
+ declare const AUDIO_STREAM_READY = "AUDIO_STREAM_READY";
95
+ declare const ASSISTANT_JOINED_ROOM = "ASSISTANT_JOINED_ROOM";
96
+ declare const ASSISTANT_LEFT_ROOM = "ASSISTANT_LEFT_ROOM";
97
+ type AssistantEvents = {
98
+ [ASSISTANT_JOINED_ROOM]: [{
99
+ roomUrl: string;
100
+ }];
101
+ [ASSISTANT_LEFT_ROOM]: [{
102
+ roomUrl: string;
103
+ }];
104
+ [AUDIO_STREAM_READY]: [{
105
+ stream: MediaStream;
106
+ track: MediaStreamTrack;
107
+ }];
108
+ };
109
+
110
+ type AssistantOptions = {
140
111
  assistantKey: string;
141
112
  startCombinedAudioStream?: boolean;
142
113
  startLocalMedia?: boolean;
114
+ };
115
+ declare class Assistant extends EventEmitter<AssistantEvents> {
116
+ private assistantKey;
117
+ private client;
118
+ private roomConnection;
119
+ private localMedia;
120
+ private mediaStream;
121
+ private audioSource;
122
+ private combinedStream;
123
+ private roomUrl;
124
+ constructor({ assistantKey, startCombinedAudioStream, startLocalMedia }: AssistantOptions);
125
+ private handleConnectionStatusChange;
126
+ joinRoom(roomUrl: string): Promise<void>;
127
+ startLocalMedia(): void;
128
+ getLocalMediaStream(): MediaStream | null;
129
+ getLocalAudioSource(): wrtc__default.nonstandard.RTCAudioSource | null;
130
+ getRoomConnection(): RoomConnectionClient;
131
+ getCombinedAudioStream(): MediaStream | null;
132
+ getRemoteParticipants(): RemoteParticipantState[];
133
+ startCloudRecording(): void;
134
+ stopCloudRecording(): void;
135
+ sendChatMessage(message: string): void;
136
+ spotlightParticipant(participantId: string): void;
137
+ removeSpotlight(participantId: string): void;
138
+ requestAudioEnable(participantId: string, enable: boolean): void;
139
+ requestVideoEnable(participantId: string, enable: boolean): void;
140
+ acceptWaitingParticipant(participantId: string): void;
141
+ rejectWaitingParticipant(participantId: string): void;
142
+ subscribeToRemoteParticipants(callback: (participants: RemoteParticipantState[]) => void): () => void;
143
+ subscribeToChatMessages(callback: (messages: ChatMessage[]) => void): () => void;
144
+ }
145
+
146
+ interface TriggerOptions {
147
+ webhookTriggers: WherebyWebhookTriggers;
148
+ port?: number;
143
149
  }
144
150
  declare class Trigger extends EventEmitter$1<TriggerEvents> {
145
151
  private webhookTriggers;
146
152
  private port;
147
- private assistantKey;
148
- private startCombinedAudioStream;
149
- private startLocalMedia;
150
- constructor({ webhookTriggers, port, assistantKey, startCombinedAudioStream, startLocalMedia, }: TriggerOptions);
153
+ constructor({ webhookTriggers, port }: TriggerOptions);
151
154
  start(): void;
152
155
  }
153
156
 
@@ -166,4 +169,5 @@ declare class AudioSink extends wrtc__default.nonstandard.RTCAudioSink {
166
169
  }) => void): () => void;
167
170
  }
168
171
 
169
- export { ASSISTANT_JOIN_SUCCESS, AUDIO_STREAM_READY, Assistant, AudioSink, AudioSource, Trigger };
172
+ export { ASSISTANT_JOINED_ROOM, ASSISTANT_LEFT_ROOM, AUDIO_STREAM_READY, Assistant, AudioSink, AudioSource, TRIGGER_EVENT_SUCCESS, Trigger };
173
+ export type { AssistantEvents };
package/dist/index.mjs CHANGED
@@ -9,9 +9,11 @@ import bodyParser from 'body-parser';
9
9
  import { networkInterfaces } from 'os';
10
10
  import * as dotenv from 'dotenv';
11
11
 
12
- const ASSISTANT_JOIN_SUCCESS = "ASSISTANT_JOIN_SUCCESS";
12
+ const TRIGGER_EVENT_SUCCESS = "trigger_event_success";
13
13
 
14
14
  const AUDIO_STREAM_READY = "AUDIO_STREAM_READY";
15
+ const ASSISTANT_JOINED_ROOM = "ASSISTANT_JOINED_ROOM";
16
+ const ASSISTANT_LEFT_ROOM = "ASSISTANT_LEFT_ROOM";
15
17
 
16
18
  /******************************************************************************
17
19
  Copyright (c) Microsoft Corporation.
@@ -495,6 +497,15 @@ class Assistant extends EventEmitter$1 {
495
497
  this.mediaStream = null;
496
498
  this.audioSource = null;
497
499
  this.combinedStream = null;
500
+ this.roomUrl = null;
501
+ this.handleConnectionStatusChange = (status) => {
502
+ if (status === "connected") {
503
+ this.emit(ASSISTANT_JOINED_ROOM, { roomUrl: this.roomUrl || "" });
504
+ }
505
+ if (["left", "kicked"].includes(status)) {
506
+ this.emit(ASSISTANT_LEFT_ROOM, { roomUrl: this.roomUrl || "" });
507
+ }
508
+ };
498
509
  this.assistantKey = assistantKey;
499
510
  this.client = new WherebyClient();
500
511
  this.roomConnection = this.client.getRoomConnection();
@@ -519,6 +530,7 @@ class Assistant extends EventEmitter$1 {
519
530
  const audioMixer = new AudioMixer(handleStreamReady);
520
531
  this.combinedStream = audioMixer.getCombinedAudioStream();
521
532
  this.roomConnection.subscribeToRemoteParticipants(audioMixer.handleRemoteParticipants.bind(audioMixer));
533
+ this.roomConnection.subscribeToConnectionStatus(this.handleConnectionStatusChange);
522
534
  }
523
535
  }
524
536
  joinRoom(roomUrl) {
@@ -526,6 +538,7 @@ class Assistant extends EventEmitter$1 {
526
538
  if (this.mediaStream) {
527
539
  yield this.localMedia.startMedia(this.mediaStream);
528
540
  }
541
+ this.roomUrl = roomUrl;
529
542
  this.roomConnection.initialize({
530
543
  localMediaOptions: {
531
544
  audio: false,
@@ -628,7 +641,7 @@ function buildRoomUrl(roomPath, wherebySubdomain, baseDomain = "whereby.com") {
628
641
  return `https://${wherebyDomain}${roomPath}`;
629
642
  }
630
643
 
631
- const webhookRouter = (webhookTriggers, emitter, assistantKey, startCombinedAudioStream = false, startLocalMedia = false) => {
644
+ const webhookRouter = (webhookTriggers, emitter) => {
632
645
  const router = express.Router();
633
646
  const jsonParser = bodyParser.json();
634
647
  router.get("/", (_, res) => {
@@ -636,15 +649,31 @@ const webhookRouter = (webhookTriggers, emitter, assistantKey, startCombinedAudi
636
649
  res.end();
637
650
  });
638
651
  router.post("/", jsonParser, (req, res) => {
639
- var _a;
652
+ var _a, _b, _c, _d, _e, _f, _g, _h;
640
653
  assert(req.body, "message body is required");
641
654
  assert("type" in req.body, "webhook type is required");
642
- const shouldTriggerOnReceivedWebhook = (_a = webhookTriggers[req.body.type]) === null || _a === void 0 ? void 0 : _a.call(webhookTriggers, req.body);
655
+ let shouldTriggerOnReceivedWebhook = false;
656
+ switch (req.body.type) {
657
+ case "room.client.joined":
658
+ shouldTriggerOnReceivedWebhook =
659
+ (_b = (_a = webhookTriggers["room.client.joined"]) === null || _a === void 0 ? void 0 : _a.call(webhookTriggers, req.body)) !== null && _b !== void 0 ? _b : false;
660
+ break;
661
+ case "room.client.left":
662
+ shouldTriggerOnReceivedWebhook =
663
+ (_d = (_c = webhookTriggers["room.client.left"]) === null || _c === void 0 ? void 0 : _c.call(webhookTriggers, req.body)) !== null && _d !== void 0 ? _d : false;
664
+ break;
665
+ case "room.session.started":
666
+ shouldTriggerOnReceivedWebhook =
667
+ (_f = (_e = webhookTriggers["room.session.started"]) === null || _e === void 0 ? void 0 : _e.call(webhookTriggers, req.body)) !== null && _f !== void 0 ? _f : false;
668
+ break;
669
+ case "room.session.ended":
670
+ shouldTriggerOnReceivedWebhook =
671
+ (_h = (_g = webhookTriggers["room.session.ended"]) === null || _g === void 0 ? void 0 : _g.call(webhookTriggers, req.body)) !== null && _h !== void 0 ? _h : false;
672
+ break;
673
+ }
643
674
  if (shouldTriggerOnReceivedWebhook) {
644
675
  const roomUrl = buildRoomUrl(req.body.data.roomName, req.body.data.subdomain);
645
- const assistant = new Assistant({ assistantKey, startCombinedAudioStream, startLocalMedia });
646
- assistant.joinRoom(roomUrl);
647
- emitter.emit(ASSISTANT_JOIN_SUCCESS, { roomUrl, triggerWebhook: req.body, assistant });
676
+ emitter.emit(TRIGGER_EVENT_SUCCESS, { roomUrl, triggerWebhook: req.body });
648
677
  }
649
678
  res.status(200);
650
679
  res.end();
@@ -652,17 +681,14 @@ const webhookRouter = (webhookTriggers, emitter, assistantKey, startCombinedAudi
652
681
  return router;
653
682
  };
654
683
  class Trigger extends EventEmitter {
655
- constructor({ webhookTriggers = {}, port = 8080, assistantKey, startCombinedAudioStream, startLocalMedia, }) {
684
+ constructor({ webhookTriggers = {}, port = 8080 }) {
656
685
  super();
657
686
  this.webhookTriggers = webhookTriggers;
658
687
  this.port = port;
659
- this.assistantKey = assistantKey;
660
- this.startCombinedAudioStream = startCombinedAudioStream !== null && startCombinedAudioStream !== void 0 ? startCombinedAudioStream : false;
661
- this.startLocalMedia = startLocalMedia !== null && startLocalMedia !== void 0 ? startLocalMedia : false;
662
688
  }
663
689
  start() {
664
690
  const app = express();
665
- const router = webhookRouter(this.webhookTriggers, this, this.assistantKey, this.startCombinedAudioStream, this.startLocalMedia);
691
+ const router = webhookRouter(this.webhookTriggers, this);
666
692
  app.use(router);
667
693
  const server = app.listen(this.port, () => {
668
694
  // console.log(`Bot trigger server now running on port[${this.port}]`);
@@ -673,4 +699,4 @@ class Trigger extends EventEmitter {
673
699
  }
674
700
  }
675
701
 
676
- export { ASSISTANT_JOIN_SUCCESS, AUDIO_STREAM_READY, Assistant, AudioSink, AudioSource, Trigger };
702
+ export { ASSISTANT_JOINED_ROOM, ASSISTANT_LEFT_ROOM, AUDIO_STREAM_READY, Assistant, AudioSink, AudioSource, TRIGGER_EVENT_SUCCESS, Trigger };
@@ -9,9 +9,11 @@ import bodyParser from 'body-parser';
9
9
  import { networkInterfaces } from 'os';
10
10
  import * as dotenv from 'dotenv';
11
11
 
12
- const ASSISTANT_JOIN_SUCCESS = "ASSISTANT_JOIN_SUCCESS";
12
+ const TRIGGER_EVENT_SUCCESS = "trigger_event_success";
13
13
 
14
14
  const AUDIO_STREAM_READY = "AUDIO_STREAM_READY";
15
+ const ASSISTANT_JOINED_ROOM = "ASSISTANT_JOINED_ROOM";
16
+ const ASSISTANT_LEFT_ROOM = "ASSISTANT_LEFT_ROOM";
15
17
 
16
18
  /******************************************************************************
17
19
  Copyright (c) Microsoft Corporation.
@@ -495,6 +497,15 @@ class Assistant extends EventEmitter$1 {
495
497
  this.mediaStream = null;
496
498
  this.audioSource = null;
497
499
  this.combinedStream = null;
500
+ this.roomUrl = null;
501
+ this.handleConnectionStatusChange = (status) => {
502
+ if (status === "connected") {
503
+ this.emit(ASSISTANT_JOINED_ROOM, { roomUrl: this.roomUrl || "" });
504
+ }
505
+ if (["left", "kicked"].includes(status)) {
506
+ this.emit(ASSISTANT_LEFT_ROOM, { roomUrl: this.roomUrl || "" });
507
+ }
508
+ };
498
509
  this.assistantKey = assistantKey;
499
510
  this.client = new WherebyClient();
500
511
  this.roomConnection = this.client.getRoomConnection();
@@ -519,6 +530,7 @@ class Assistant extends EventEmitter$1 {
519
530
  const audioMixer = new AudioMixer(handleStreamReady);
520
531
  this.combinedStream = audioMixer.getCombinedAudioStream();
521
532
  this.roomConnection.subscribeToRemoteParticipants(audioMixer.handleRemoteParticipants.bind(audioMixer));
533
+ this.roomConnection.subscribeToConnectionStatus(this.handleConnectionStatusChange);
522
534
  }
523
535
  }
524
536
  joinRoom(roomUrl) {
@@ -526,6 +538,7 @@ class Assistant extends EventEmitter$1 {
526
538
  if (this.mediaStream) {
527
539
  yield this.localMedia.startMedia(this.mediaStream);
528
540
  }
541
+ this.roomUrl = roomUrl;
529
542
  this.roomConnection.initialize({
530
543
  localMediaOptions: {
531
544
  audio: false,
@@ -628,7 +641,7 @@ function buildRoomUrl(roomPath, wherebySubdomain, baseDomain = "whereby.com") {
628
641
  return `https://${wherebyDomain}${roomPath}`;
629
642
  }
630
643
 
631
- const webhookRouter = (webhookTriggers, emitter, assistantKey, startCombinedAudioStream = false, startLocalMedia = false) => {
644
+ const webhookRouter = (webhookTriggers, emitter) => {
632
645
  const router = express.Router();
633
646
  const jsonParser = bodyParser.json();
634
647
  router.get("/", (_, res) => {
@@ -636,15 +649,31 @@ const webhookRouter = (webhookTriggers, emitter, assistantKey, startCombinedAudi
636
649
  res.end();
637
650
  });
638
651
  router.post("/", jsonParser, (req, res) => {
639
- var _a;
652
+ var _a, _b, _c, _d, _e, _f, _g, _h;
640
653
  assert(req.body, "message body is required");
641
654
  assert("type" in req.body, "webhook type is required");
642
- const shouldTriggerOnReceivedWebhook = (_a = webhookTriggers[req.body.type]) === null || _a === void 0 ? void 0 : _a.call(webhookTriggers, req.body);
655
+ let shouldTriggerOnReceivedWebhook = false;
656
+ switch (req.body.type) {
657
+ case "room.client.joined":
658
+ shouldTriggerOnReceivedWebhook =
659
+ (_b = (_a = webhookTriggers["room.client.joined"]) === null || _a === void 0 ? void 0 : _a.call(webhookTriggers, req.body)) !== null && _b !== void 0 ? _b : false;
660
+ break;
661
+ case "room.client.left":
662
+ shouldTriggerOnReceivedWebhook =
663
+ (_d = (_c = webhookTriggers["room.client.left"]) === null || _c === void 0 ? void 0 : _c.call(webhookTriggers, req.body)) !== null && _d !== void 0 ? _d : false;
664
+ break;
665
+ case "room.session.started":
666
+ shouldTriggerOnReceivedWebhook =
667
+ (_f = (_e = webhookTriggers["room.session.started"]) === null || _e === void 0 ? void 0 : _e.call(webhookTriggers, req.body)) !== null && _f !== void 0 ? _f : false;
668
+ break;
669
+ case "room.session.ended":
670
+ shouldTriggerOnReceivedWebhook =
671
+ (_h = (_g = webhookTriggers["room.session.ended"]) === null || _g === void 0 ? void 0 : _g.call(webhookTriggers, req.body)) !== null && _h !== void 0 ? _h : false;
672
+ break;
673
+ }
643
674
  if (shouldTriggerOnReceivedWebhook) {
644
675
  const roomUrl = buildRoomUrl(req.body.data.roomName, req.body.data.subdomain);
645
- const assistant = new Assistant({ assistantKey, startCombinedAudioStream, startLocalMedia });
646
- assistant.joinRoom(roomUrl);
647
- emitter.emit(ASSISTANT_JOIN_SUCCESS, { roomUrl, triggerWebhook: req.body, assistant });
676
+ emitter.emit(TRIGGER_EVENT_SUCCESS, { roomUrl, triggerWebhook: req.body });
648
677
  }
649
678
  res.status(200);
650
679
  res.end();
@@ -652,17 +681,14 @@ const webhookRouter = (webhookTriggers, emitter, assistantKey, startCombinedAudi
652
681
  return router;
653
682
  };
654
683
  class Trigger extends EventEmitter {
655
- constructor({ webhookTriggers = {}, port = 8080, assistantKey, startCombinedAudioStream, startLocalMedia, }) {
684
+ constructor({ webhookTriggers = {}, port = 8080 }) {
656
685
  super();
657
686
  this.webhookTriggers = webhookTriggers;
658
687
  this.port = port;
659
- this.assistantKey = assistantKey;
660
- this.startCombinedAudioStream = startCombinedAudioStream !== null && startCombinedAudioStream !== void 0 ? startCombinedAudioStream : false;
661
- this.startLocalMedia = startLocalMedia !== null && startLocalMedia !== void 0 ? startLocalMedia : false;
662
688
  }
663
689
  start() {
664
690
  const app = express();
665
- const router = webhookRouter(this.webhookTriggers, this, this.assistantKey, this.startCombinedAudioStream, this.startLocalMedia);
691
+ const router = webhookRouter(this.webhookTriggers, this);
666
692
  app.use(router);
667
693
  const server = app.listen(this.port, () => {
668
694
  // console.log(`Bot trigger server now running on port[${this.port}]`);
@@ -673,4 +699,4 @@ class Trigger extends EventEmitter {
673
699
  }
674
700
  }
675
701
 
676
- export { ASSISTANT_JOIN_SUCCESS, AUDIO_STREAM_READY, Assistant, AudioSink, AudioSource, Trigger };
702
+ export { ASSISTANT_JOINED_ROOM, ASSISTANT_LEFT_ROOM, AUDIO_STREAM_READY, Assistant, AudioSink, AudioSource, TRIGGER_EVENT_SUCCESS, Trigger };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@whereby.com/assistant-sdk",
3
3
  "description": "Assistant SDK for whereby.com",
4
4
  "author": "Whereby AS",
5
- "version": "0.0.0-canary-20250912144626",
5
+ "version": "0.0.0-canary-20250916140846",
6
6
  "license": "MIT",
7
7
  "files": [
8
8
  "dist",
@@ -47,8 +47,6 @@
47
47
  }
48
48
  },
49
49
  "devDependencies": {
50
- "body-parser": "2.2.0",
51
- "express": "5.1.0",
52
50
  "eslint": "^9.29.0",
53
51
  "prettier": "^3.5.3",
54
52
  "typescript": "^5.8.3",
@@ -60,10 +58,13 @@
60
58
  },
61
59
  "dependencies": {
62
60
  "@roamhq/wrtc": "github:whereby/node-webrtc#patch/rtc_audio_source",
61
+ "@types/web": "^0.0.267",
62
+ "body-parser": "2.2.0",
63
63
  "dotenv": "^16.4.5",
64
+ "express": "5.1.0",
64
65
  "uuid": "^11.0.3",
65
66
  "ws": "^8.18.0",
66
- "@whereby.com/core": "0.0.0-canary-20250912144626"
67
+ "@whereby.com/core": "0.0.0-canary-20250916140846"
67
68
  },
68
69
  "prettier": "@whereby.com/prettier-config",
69
70
  "scripts": {