@craftedxp/voice-js 0.4.2 → 0.5.4

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/browser.mjs CHANGED
@@ -1015,6 +1015,204 @@ async function createWebRtcCall(opts) {
1015
1015
  };
1016
1016
  }
1017
1017
 
1018
+ // src/room.ts
1019
+ import {
1020
+ Room,
1021
+ RoomEvent,
1022
+ Track
1023
+ } from "livekit-client";
1024
+
1025
+ // src/roomProtocol.ts
1026
+ var SYSTEM_TOPIC = "system";
1027
+ var TRANSCRIPT_TOPIC = "transcript";
1028
+ var decodeSystem = (bytes) => {
1029
+ try {
1030
+ const v = JSON.parse(new TextDecoder().decode(bytes));
1031
+ if (v && typeof v.kind === "string") return v;
1032
+ return null;
1033
+ } catch {
1034
+ return null;
1035
+ }
1036
+ };
1037
+ var decodeTranscript = (bytes) => {
1038
+ try {
1039
+ const v = JSON.parse(new TextDecoder().decode(bytes));
1040
+ if (v && v.kind === "partial") return v;
1041
+ return null;
1042
+ } catch {
1043
+ return null;
1044
+ }
1045
+ };
1046
+
1047
+ // src/room.ts
1048
+ var identityToPid = (identity) => identity.startsWith("guest:") ? identity.slice("guest:".length) : identity;
1049
+ var joinRoom = async (opts) => {
1050
+ const exchangeUrl = `${opts.apiBase.replace(/\/+$/, "")}/v1/rooms/${encodeURIComponent(
1051
+ opts.roomId
1052
+ )}/join`;
1053
+ const exchangeRes = await fetch(exchangeUrl, {
1054
+ method: "POST",
1055
+ headers: { "Content-Type": "application/json" },
1056
+ body: JSON.stringify({ code: opts.joinCode, name: opts.name })
1057
+ });
1058
+ if (!exchangeRes.ok) {
1059
+ const err = await exchangeRes.json().catch(() => ({}));
1060
+ throw new Error(err.error?.code ?? `join_failed_${exchangeRes.status}`);
1061
+ }
1062
+ const exchange = await exchangeRes.json();
1063
+ const handlers = /* @__PURE__ */ new Map();
1064
+ const emit = (e, payload) => {
1065
+ handlers.get(e)?.forEach((h) => {
1066
+ try {
1067
+ h(payload);
1068
+ } catch {
1069
+ }
1070
+ });
1071
+ };
1072
+ const room = new Room({ adaptiveStream: true, dynacast: true });
1073
+ room.on(
1074
+ RoomEvent.ParticipantConnected,
1075
+ (p) => emit("participant.joined", {
1076
+ participantId: identityToPid(p.identity),
1077
+ name: p.name ?? ""
1078
+ })
1079
+ );
1080
+ room.on(
1081
+ RoomEvent.ParticipantDisconnected,
1082
+ (p) => emit("participant.left", {
1083
+ participantId: identityToPid(p.identity),
1084
+ name: p.name ?? ""
1085
+ })
1086
+ );
1087
+ room.on(RoomEvent.Disconnected, () => emit("room.ended", void 0));
1088
+ room.on(RoomEvent.DataReceived, (data, _participant, _kind, topic) => {
1089
+ if (topic === SYSTEM_TOPIC) {
1090
+ const m = decodeSystem(data);
1091
+ if (m) emit("system.message", m);
1092
+ } else if (topic === TRANSCRIPT_TOPIC) {
1093
+ const m = decodeTranscript(data);
1094
+ if (m) emit("transcript.partial", m);
1095
+ }
1096
+ });
1097
+ const trackKind = (t) => t.kind === Track.Kind.Video ? "video" : "audio";
1098
+ const trackSource = (s) => {
1099
+ switch (s) {
1100
+ case Track.Source.Camera:
1101
+ return "camera";
1102
+ case Track.Source.Microphone:
1103
+ return "microphone";
1104
+ case Track.Source.ScreenShare:
1105
+ return "screen_share";
1106
+ case Track.Source.ScreenShareAudio:
1107
+ return "screen_share_audio";
1108
+ default:
1109
+ return "unknown";
1110
+ }
1111
+ };
1112
+ room.on(
1113
+ RoomEvent.TrackSubscribed,
1114
+ (track, pub, participant) => emit("track.subscribed", {
1115
+ participantId: identityToPid(participant.identity),
1116
+ kind: trackKind(track),
1117
+ source: trackSource(pub.source),
1118
+ track
1119
+ })
1120
+ );
1121
+ room.on(
1122
+ RoomEvent.TrackUnsubscribed,
1123
+ (track, pub, participant) => emit("track.unsubscribed", {
1124
+ participantId: identityToPid(participant.identity),
1125
+ kind: trackKind(track),
1126
+ source: trackSource(pub.source),
1127
+ track
1128
+ })
1129
+ );
1130
+ room.on(
1131
+ RoomEvent.ActiveSpeakersChanged,
1132
+ (speakers) => emit(
1133
+ "active.speakers",
1134
+ speakers.map((p) => identityToPid(p.identity))
1135
+ )
1136
+ );
1137
+ await room.connect(exchange.livekit.url, exchange.livekit.token);
1138
+ return {
1139
+ participantId: exchange.participantId,
1140
+ get participants() {
1141
+ return [...room.remoteParticipants.values()].map((p) => ({
1142
+ participantId: identityToPid(p.identity),
1143
+ name: p.name ?? ""
1144
+ }));
1145
+ },
1146
+ on(event, handler) {
1147
+ const set = handlers.get(event) ?? /* @__PURE__ */ new Set();
1148
+ set.add(handler);
1149
+ handlers.set(event, set);
1150
+ },
1151
+ publishMic: async () => {
1152
+ await room.localParticipant.setMicrophoneEnabled(true);
1153
+ },
1154
+ publishCamera: async () => {
1155
+ await room.localParticipant.setCameraEnabled(true);
1156
+ },
1157
+ setMicEnabled: async (on) => {
1158
+ await room.localParticipant.setMicrophoneEnabled(on);
1159
+ },
1160
+ setCameraEnabled: async (on) => {
1161
+ await room.localParticipant.setCameraEnabled(on);
1162
+ },
1163
+ isMicEnabled: () => room.localParticipant.isMicrophoneEnabled,
1164
+ isCameraEnabled: () => room.localParticipant.isCameraEnabled,
1165
+ getLocalCameraTrack: () => room.localParticipant.getTrackPublication(Track.Source.Camera)?.videoTrack ?? null,
1166
+ getRemoteTracks: () => {
1167
+ const out = [];
1168
+ for (const p of room.remoteParticipants.values()) {
1169
+ for (const pub of p.trackPublications.values()) {
1170
+ const track = pub.track;
1171
+ if (!track) continue;
1172
+ out.push({
1173
+ participantId: identityToPid(p.identity),
1174
+ kind: trackKind(track),
1175
+ source: trackSource(pub.source),
1176
+ track
1177
+ });
1178
+ }
1179
+ }
1180
+ return out;
1181
+ },
1182
+ setScreenShareEnabled: async (on, opts2) => {
1183
+ await room.localParticipant.setScreenShareEnabled(on, { audio: opts2?.audio ?? false });
1184
+ },
1185
+ isScreenShareEnabled: () => room.localParticipant.isScreenShareEnabled,
1186
+ getLocalScreenTrack: () => room.localParticipant.getTrackPublication(Track.Source.ScreenShare)?.videoTrack ?? null,
1187
+ leave: async () => {
1188
+ await room.disconnect();
1189
+ }
1190
+ };
1191
+ };
1192
+
1193
+ // src/incomingCall.ts
1194
+ var parseIncomingCall = (raw) => {
1195
+ if (typeof raw !== "object" || raw === null) {
1196
+ throw new Error("parseIncomingCall: payload must be an object");
1197
+ }
1198
+ const p = raw;
1199
+ if (typeof p.token !== "string" || !p.token.startsWith("ct_")) {
1200
+ throw new Error("parseIncomingCall: missing or invalid `token` (expected a ct_ string)");
1201
+ }
1202
+ if (typeof p.agentId !== "string" || p.agentId.length === 0) {
1203
+ throw new Error("parseIncomingCall: missing `agentId`");
1204
+ }
1205
+ const transport = p.transport === "webrtc" ? "webrtc" : "ws";
1206
+ const out = { token: p.token, agentId: p.agentId, transport };
1207
+ if (transport === "webrtc" && typeof p.webrtcGatewayBase === "string") {
1208
+ out.webrtcGatewayBase = p.webrtcGatewayBase;
1209
+ }
1210
+ if (typeof p.expiresAt === "number") out.expiresAt = p.expiresAt;
1211
+ if (typeof p.agentName === "string") out.agentName = p.agentName;
1212
+ if (typeof p.agentAvatarUrl === "string") out.agentAvatarUrl = p.agentAvatarUrl;
1213
+ return out;
1214
+ };
1215
+
1018
1216
  // src/browser.ts
1019
1217
  var browserWsFactory = (url) => new globalThis.WebSocket(url);
1020
1218
  var BrowserVoiceFactory = class {
@@ -1072,6 +1270,14 @@ var BrowserVoiceFactory = class {
1072
1270
  await client.start();
1073
1271
  return client;
1074
1272
  };
1273
+ // Multi-party rooms (Phase 7 video).
1274
+ //
1275
+ // The guest's browser calls this with the roomId + joinCode it parsed
1276
+ // out of the invite link. The SDK exchanges the code for a LiveKit
1277
+ // JWT against `${apiBase}/v1/rooms/:roomId/join` (an AUTH-EXEMPT
1278
+ // endpoint — the opaque code is the only credential), then connects
1279
+ // to LiveKit and returns a typed event surface.
1280
+ this.joinRoom = (opts) => joinRoom({ apiBase: this.config.apiBase, ...opts });
1075
1281
  this.config = config;
1076
1282
  }
1077
1283
  };
@@ -1085,6 +1291,8 @@ export {
1085
1291
  createAudioPlayback,
1086
1292
  createProtocolState,
1087
1293
  createReconnectingWebSocket,
1088
- handleServerMessage
1294
+ handleServerMessage,
1295
+ joinRoom,
1296
+ parseIncomingCall
1089
1297
  };
1090
1298
  //# sourceMappingURL=browser.mjs.map