@shadowob/sdk 1.1.3 → 1.1.5

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
@@ -34,6 +34,7 @@ __export(index_exports, {
34
34
  SERVER_EVENTS: () => import_shared.SERVER_EVENTS,
35
35
  ShadowClient: () => ShadowClient,
36
36
  ShadowSocket: () => ShadowSocket,
37
+ ShadowVoiceConsumer: () => ShadowVoiceConsumer,
37
38
  channelRoom: () => channelRoom,
38
39
  threadRoom: () => threadRoom,
39
40
  userRoom: () => userRoom
@@ -87,12 +88,13 @@ var ShadowClient = class {
87
88
  const url = `${this.baseUrl}${path}`;
88
89
  const controller = new AbortController();
89
90
  const timeout = setTimeout(() => controller.abort(), 6e4);
91
+ const isFormData = init?.body instanceof FormData;
90
92
  try {
91
93
  const res = await fetch(url, {
92
94
  ...init,
93
95
  signal: init?.signal ?? controller.signal,
94
96
  headers: {
95
- "Content-Type": "application/json",
97
+ ...!isFormData ? { "Content-Type": "application/json" } : {},
96
98
  Authorization: `Bearer ${this.token}`,
97
99
  ...init?.headers
98
100
  }
@@ -217,8 +219,11 @@ var ShadowClient = class {
217
219
  });
218
220
  }
219
221
  // ── Agents ────────────────────────────────────────────────────────────
220
- async listAgents() {
221
- return this.request("/api/agents");
222
+ async listAgents(options) {
223
+ const params = new URLSearchParams();
224
+ if (options?.includeRentals) params.set("includeRentals", "true");
225
+ const query = params.toString();
226
+ return this.request(`/api/agents${query ? `?${query}` : ""}`);
222
227
  }
223
228
  async createAgent(data) {
224
229
  return this.request("/api/agents", {
@@ -334,15 +339,113 @@ var ShadowClient = class {
334
339
  async getServerAccess(serverIdOrSlug) {
335
340
  return this.request(`/api/servers/${serverIdOrSlug}/access`);
336
341
  }
342
+ // ── Server App Integrations ───────────────────────────────────────────
343
+ async listServerApps(serverIdOrSlug) {
344
+ return this.request(`/api/servers/${serverIdOrSlug}/apps`);
345
+ }
346
+ async listServerAppCatalog(serverIdOrSlug) {
347
+ return this.request(`/api/servers/${serverIdOrSlug}/apps/catalog`);
348
+ }
349
+ async discoverServerApp(serverIdOrSlug, data) {
350
+ return this.request(`/api/servers/${serverIdOrSlug}/apps/discover`, {
351
+ method: "POST",
352
+ body: JSON.stringify(data)
353
+ });
354
+ }
355
+ async installServerApp(serverIdOrSlug, data) {
356
+ return this.request(`/api/servers/${serverIdOrSlug}/apps`, {
357
+ method: "POST",
358
+ body: JSON.stringify(data)
359
+ });
360
+ }
361
+ async installServerAppFromCatalog(serverIdOrSlug, catalogEntryId, data = {}) {
362
+ return this.request(
363
+ `/api/servers/${serverIdOrSlug}/apps/catalog/${encodeURIComponent(catalogEntryId)}/install`,
364
+ {
365
+ method: "POST",
366
+ body: JSON.stringify(data)
367
+ }
368
+ );
369
+ }
370
+ async getServerApp(serverIdOrSlug, appKey) {
371
+ return this.request(`/api/servers/${serverIdOrSlug}/apps/${encodeURIComponent(appKey)}`);
372
+ }
373
+ async deleteServerApp(serverIdOrSlug, appKey) {
374
+ return this.request(`/api/servers/${serverIdOrSlug}/apps/${encodeURIComponent(appKey)}`, {
375
+ method: "DELETE"
376
+ });
377
+ }
378
+ async grantServerAppToBuddy(serverIdOrSlug, appKey, data) {
379
+ return this.request(
380
+ `/api/servers/${serverIdOrSlug}/apps/${encodeURIComponent(appKey)}/grants`,
381
+ {
382
+ method: "POST",
383
+ body: JSON.stringify(data)
384
+ }
385
+ );
386
+ }
387
+ async getServerAppSkills(serverIdOrSlug, appKey) {
388
+ return this.request(`/api/servers/${serverIdOrSlug}/apps/${encodeURIComponent(appKey)}/skills`);
389
+ }
390
+ async createServerAppLaunch(serverIdOrSlug, appKey) {
391
+ return this.request(
392
+ `/api/servers/${serverIdOrSlug}/apps/${encodeURIComponent(appKey)}/launch`,
393
+ {
394
+ method: "POST"
395
+ }
396
+ );
397
+ }
398
+ async introspectServerAppToken(serverIdOrSlug, appKey, token) {
399
+ const url = `${this.baseUrl}/api/servers/${serverIdOrSlug}/apps/${encodeURIComponent(
400
+ appKey
401
+ )}/oauth/introspect`;
402
+ const res = await fetch(url, {
403
+ method: "POST",
404
+ headers: {
405
+ Authorization: `Bearer ${token}`,
406
+ "Content-Type": "application/json"
407
+ },
408
+ body: JSON.stringify({ token })
409
+ });
410
+ if (!res.ok) {
411
+ const body = await res.text().catch(() => "");
412
+ const message = sanitizeErrorBody(body);
413
+ throw new Error(`Shadow API POST /oauth/introspect failed (${res.status}): ${message}`);
414
+ }
415
+ return await res.json();
416
+ }
417
+ async callServerAppCommand(serverIdOrSlug, appKey, commandName, data) {
418
+ return this.request(
419
+ `/api/servers/${serverIdOrSlug}/apps/${encodeURIComponent(appKey)}/commands/${encodeURIComponent(
420
+ commandName
421
+ )}`,
422
+ {
423
+ method: "POST",
424
+ body: JSON.stringify(data ?? {})
425
+ }
426
+ );
427
+ }
428
+ async callServerAppCommandMultipart(serverIdOrSlug, appKey, commandName, data) {
429
+ const form = new FormData();
430
+ form.set("input", JSON.stringify(data.input ?? {}));
431
+ if (data.channelId) form.set("channelId", data.channelId);
432
+ form.set(data.field ?? "file", data.file, data.filename);
433
+ return this.request(
434
+ `/api/servers/${serverIdOrSlug}/apps/${encodeURIComponent(appKey)}/commands/${encodeURIComponent(
435
+ commandName
436
+ )}`,
437
+ {
438
+ method: "POST",
439
+ body: form
440
+ }
441
+ );
442
+ }
337
443
  async updateServer(serverIdOrSlug, data) {
338
444
  return this.request(`/api/servers/${serverIdOrSlug}`, {
339
445
  method: "PATCH",
340
446
  body: JSON.stringify(data)
341
447
  });
342
448
  }
343
- async updateServerHomepage(serverIdOrSlug, homepageHtml) {
344
- return this.updateServer(serverIdOrSlug, { homepageHtml });
345
- }
346
449
  async deleteServer(serverId) {
347
450
  return this.request(`/api/servers/${serverId}`, { method: "DELETE" });
348
451
  }
@@ -407,6 +510,14 @@ var ShadowClient = class {
407
510
  const ch = await this.request(`/api/channels/${channelId}`);
408
511
  return { ...ch, description: ch.topic };
409
512
  }
513
+ async getChannelBootstrap(channelId, options) {
514
+ const params = new URLSearchParams();
515
+ if (options?.messagesLimit) params.set("messagesLimit", String(options.messagesLimit));
516
+ const query = params.toString();
517
+ return this.request(
518
+ `/api/channels/${channelId}/bootstrap${query ? `?${query}` : ""}`
519
+ );
520
+ }
410
521
  async getChannelAccess(channelId) {
411
522
  return this.request(`/api/channels/${channelId}/access`);
412
523
  }
@@ -454,6 +565,43 @@ var ShadowClient = class {
454
565
  async removeChannelMember(channelId, userId) {
455
566
  return this.request(`/api/channels/${channelId}/members/${userId}`, { method: "DELETE" });
456
567
  }
568
+ async getVoiceState(channelId) {
569
+ return this.request(`/api/channels/${channelId}/voice/state`);
570
+ }
571
+ async joinVoiceChannel(channelId, options) {
572
+ return this.request(`/api/channels/${channelId}/voice/join`, {
573
+ method: "POST",
574
+ body: JSON.stringify(options ?? {})
575
+ });
576
+ }
577
+ async renewVoiceCredentials(channelId, options) {
578
+ return this.request(`/api/channels/${channelId}/voice/renew`, {
579
+ method: "POST",
580
+ body: JSON.stringify(options ?? {})
581
+ });
582
+ }
583
+ async leaveVoiceChannel(channelId, options) {
584
+ return this.request(`/api/channels/${channelId}/voice/leave`, {
585
+ method: "POST",
586
+ body: JSON.stringify(options ?? {})
587
+ });
588
+ }
589
+ async updateVoiceState(channelId, data) {
590
+ return this.request(`/api/channels/${channelId}/voice/state`, {
591
+ method: "PATCH",
592
+ body: JSON.stringify(data)
593
+ });
594
+ }
595
+ async getVoicePolicy(channelId, agentId) {
596
+ const params = new URLSearchParams({ agentId });
597
+ return this.request(`/api/channels/${channelId}/voice-policy?${params}`);
598
+ }
599
+ async updateVoicePolicy(channelId, data) {
600
+ return this.request(`/api/channels/${channelId}/voice-policy`, {
601
+ method: "PUT",
602
+ body: JSON.stringify(data)
603
+ });
604
+ }
457
605
  // ── Channel Buddy Policy ─────────────────────────────────────────────
458
606
  async setBuddyPolicy(channelId, agentId, data) {
459
607
  return this.request(`/api/channels/${channelId}/agents/${agentId}/policy`, {
@@ -670,9 +818,19 @@ var ShadowClient = class {
670
818
  return res.json();
671
819
  }
672
820
  async resolveAttachmentMediaUrl(attachmentId, options) {
673
- const disposition = options?.disposition ?? "inline";
821
+ const params = new URLSearchParams();
822
+ params.set("disposition", options?.disposition ?? "inline");
823
+ if (options?.variant) params.set("variant", options.variant);
674
824
  return this.request(
675
- `/api/attachments/${attachmentId}/media-url?disposition=${disposition}`
825
+ `/api/attachments/${attachmentId}/media-url?${params}`
826
+ );
827
+ }
828
+ async resolveWorkspaceMediaUrl(serverId, fileId, options) {
829
+ const params = new URLSearchParams();
830
+ params.set("disposition", options?.disposition ?? "inline");
831
+ if (options?.contentRef) params.set("contentRef", options.contentRef);
832
+ return this.request(
833
+ `/api/servers/${serverId}/workspace/files/${fileId}/media-url?${params}`
676
834
  );
677
835
  }
678
836
  /**
@@ -898,9 +1056,21 @@ var ShadowClient = class {
898
1056
  async listOAuthAccounts() {
899
1057
  return this.request("/api/auth/oauth/accounts");
900
1058
  }
1059
+ async createOAuthConnectUrl(provider, redirect) {
1060
+ return this.request(`/api/auth/oauth/${provider}/link`, {
1061
+ method: "POST",
1062
+ body: JSON.stringify({ redirect })
1063
+ });
1064
+ }
901
1065
  async unlinkOAuthAccount(accountId) {
902
1066
  return this.request(`/api/auth/oauth/accounts/${accountId}`, { method: "DELETE" });
903
1067
  }
1068
+ async listAuthSessions() {
1069
+ return this.request("/api/auth/sessions");
1070
+ }
1071
+ async revokeAuthSession(sessionId) {
1072
+ return this.request(`/api/auth/sessions/${sessionId}`, { method: "DELETE" });
1073
+ }
904
1074
  async changePassword(data) {
905
1075
  return this.request("/api/auth/password", {
906
1076
  method: "PUT",
@@ -1028,6 +1198,21 @@ var ShadowClient = class {
1028
1198
  body: JSON.stringify({ appId })
1029
1199
  });
1030
1200
  }
1201
+ async sendOAuthChannelMessage(channelId, content, opts) {
1202
+ return this.request(`/api/oauth/channels/${channelId}/messages`, {
1203
+ method: "POST",
1204
+ body: JSON.stringify({
1205
+ content,
1206
+ ...opts?.metadata ? { metadata: opts.metadata } : {}
1207
+ })
1208
+ });
1209
+ }
1210
+ async sendOAuthBuddyMessage(buddyId, data) {
1211
+ return this.request(`/api/oauth/buddies/${buddyId}/messages`, {
1212
+ method: "POST",
1213
+ body: JSON.stringify(data)
1214
+ });
1215
+ }
1031
1216
  // ── Marketplace / Rentals ─────────────────────────────────────────────
1032
1217
  async browseListings(params) {
1033
1218
  const qs = new URLSearchParams();
@@ -1135,6 +1320,9 @@ var ShadowClient = class {
1135
1320
  async getScopeNeutralProduct(productId) {
1136
1321
  return this.request(`/api/products/${productId}`);
1137
1322
  }
1323
+ async getCommerceProductContext(productId) {
1324
+ return this.request(`/api/commerce/products/${productId}/context`);
1325
+ }
1138
1326
  async getShopProduct(shopId, productId) {
1139
1327
  return this.request(`/api/shops/${shopId}/products/${productId}`);
1140
1328
  }
@@ -1325,6 +1513,11 @@ var ShadowClient = class {
1325
1513
  method: "POST"
1326
1514
  });
1327
1515
  }
1516
+ async completeOrder(serverId, orderId) {
1517
+ return this.request(`/api/servers/${serverId}/shop/orders/${orderId}/complete`, {
1518
+ method: "POST"
1519
+ });
1520
+ }
1328
1521
  async getProductReviews(serverId, productId) {
1329
1522
  return this.request(`/api/servers/${serverId}/shop/products/${productId}/reviews`);
1330
1523
  }
@@ -1560,6 +1753,23 @@ var ShadowClient = class {
1560
1753
  async getAllEntitlements() {
1561
1754
  return this.request("/api/entitlements");
1562
1755
  }
1756
+ async getEntitlement(entitlementId) {
1757
+ return this.request(`/api/entitlements/${entitlementId}`);
1758
+ }
1759
+ async getOAuthCommerceEntitlementAccess(params) {
1760
+ const qs = new URLSearchParams();
1761
+ if (params?.resourceType) qs.set("resourceType", params.resourceType);
1762
+ if (params?.resourceId) qs.set("resourceId", params.resourceId);
1763
+ if (params?.capability) qs.set("capability", params.capability);
1764
+ const query = qs.toString();
1765
+ return this.request(`/api/oauth/commerce/entitlements${query ? `?${query}` : ""}`);
1766
+ }
1767
+ async redeemOAuthCommerceEntitlement(data) {
1768
+ return this.request("/api/oauth/commerce/entitlements/redeem", {
1769
+ method: "POST",
1770
+ body: JSON.stringify(data)
1771
+ });
1772
+ }
1563
1773
  async verifyEntitlement(entitlementId) {
1564
1774
  return this.request(`/api/entitlements/${entitlementId}/verify`);
1565
1775
  }
@@ -1569,6 +1779,12 @@ var ShadowClient = class {
1569
1779
  body: JSON.stringify({ reason })
1570
1780
  });
1571
1781
  }
1782
+ async cancelEntitlementRenewal(entitlementId, reason) {
1783
+ return this.request(`/api/entitlements/${entitlementId}/cancel-renewal`, {
1784
+ method: "POST",
1785
+ body: JSON.stringify({ reason })
1786
+ });
1787
+ }
1572
1788
  // ── Task Center ───────────────────────────────────────────────────────
1573
1789
  async getTaskCenter() {
1574
1790
  return this.request("/api/tasks");
@@ -1609,6 +1825,16 @@ var ShadowClient = class {
1609
1825
  if (params?.limit) qs.set("limit", String(params.limit));
1610
1826
  return this.request(`/api/discover/search?${qs}`);
1611
1827
  }
1828
+ async discoverCommerce(params) {
1829
+ const qs = new URLSearchParams();
1830
+ if (params?.q) qs.set("q", params.q);
1831
+ if (params?.limit) qs.set("limit", String(params.limit));
1832
+ const suffix = qs.toString();
1833
+ return this.request(`/api/discover/business${suffix ? `?${suffix}` : ""}`);
1834
+ }
1835
+ async discoverBusinessHub(params) {
1836
+ return this.discoverCommerce(params);
1837
+ }
1612
1838
  // ── Voice Enhance ─────────────────────────────────────────────────────
1613
1839
  async enhanceVoice(data) {
1614
1840
  return this.request("/api/voice/enhance", {
@@ -1818,6 +2044,53 @@ var ShadowSocket = class {
1818
2044
  leaveChannel(channelId) {
1819
2045
  this.socket.emit("channel:leave", { channelId });
1820
2046
  }
2047
+ joinVoiceChannel(channelId, options) {
2048
+ return new Promise((resolve) => {
2049
+ this.socket.emit(
2050
+ "voice:join",
2051
+ { channelId, ...options },
2052
+ (res) => {
2053
+ resolve(res ?? { ok: false, error: "Voice join failed" });
2054
+ }
2055
+ );
2056
+ });
2057
+ }
2058
+ leaveVoiceChannel(channelId, options) {
2059
+ return new Promise((resolve) => {
2060
+ this.socket.emit(
2061
+ "voice:leave",
2062
+ { channelId, ...options },
2063
+ (res) => {
2064
+ resolve(res ?? { ok: true });
2065
+ }
2066
+ );
2067
+ });
2068
+ }
2069
+ renewVoiceCredentials(channelId, options) {
2070
+ return new Promise((resolve) => {
2071
+ this.socket.emit(
2072
+ "voice:token:renew",
2073
+ { channelId, ...options },
2074
+ (res) => {
2075
+ resolve(res ?? { ok: false, error: "Voice token renewal failed" });
2076
+ }
2077
+ );
2078
+ });
2079
+ }
2080
+ updateVoiceState(channelId, data) {
2081
+ return new Promise((resolve) => {
2082
+ this.socket.emit(
2083
+ "voice:state:update",
2084
+ { channelId, ...data },
2085
+ (res) => {
2086
+ resolve(res ?? { ok: true });
2087
+ }
2088
+ );
2089
+ });
2090
+ }
2091
+ sendVoiceHeartbeat(channelId, options) {
2092
+ this.socket.emit("voice:heartbeat", { channelId, ...options });
2093
+ }
1821
2094
  // ── Client actions ────────────────────────────────────────────────────
1822
2095
  /** Send a message via WebSocket (text-only; for file attachments use REST) */
1823
2096
  sendMessage(data) {
@@ -1836,12 +2109,199 @@ var ShadowSocket = class {
1836
2109
  this.socket.emit("presence:activity", { channelId, activity });
1837
2110
  }
1838
2111
  };
2112
+
2113
+ // src/voice.ts
2114
+ var cachedAgoraRTC = null;
2115
+ async function loadAgoraRTC() {
2116
+ if (cachedAgoraRTC) return cachedAgoraRTC;
2117
+ try {
2118
+ const module2 = await import("agora-rtc-sdk-ng");
2119
+ cachedAgoraRTC = module2.default;
2120
+ return cachedAgoraRTC;
2121
+ } catch (error) {
2122
+ throw new Error(
2123
+ `Agora RTC SDK is required for ShadowVoiceConsumer. Install agora-rtc-sdk-ng in this app to use browser voice media. ${error instanceof Error ? error.message : String(error)}`
2124
+ );
2125
+ }
2126
+ }
2127
+ function createVoiceClientId() {
2128
+ return `shadow-sdk-${globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`}`;
2129
+ }
2130
+ var ShadowVoiceConsumer = class {
2131
+ constructor(options) {
2132
+ this.options = options;
2133
+ this.clientId = options.clientId ?? createVoiceClientId();
2134
+ }
2135
+ rtc = null;
2136
+ screenRtc = null;
2137
+ audioTrack = null;
2138
+ screenTrack = null;
2139
+ session = null;
2140
+ clientId;
2141
+ tokenRenewTimer = null;
2142
+ get joinResult() {
2143
+ return this.session;
2144
+ }
2145
+ async join() {
2146
+ const AgoraRTC = await loadAgoraRTC();
2147
+ this.session = await this.options.client.joinVoiceChannel(this.options.channelId, {
2148
+ muted: this.options.muted,
2149
+ clientId: this.clientId
2150
+ });
2151
+ const { credentials } = this.session;
2152
+ const rtc = AgoraRTC.createClient({ mode: "rtc", codec: "vp8" });
2153
+ this.rtc = rtc;
2154
+ try {
2155
+ this.bindTokenRenewal(rtc);
2156
+ rtc.on("user-published", async (user, mediaType) => {
2157
+ await rtc.subscribe(user, mediaType);
2158
+ if (mediaType === "audio" && user.audioTrack) {
2159
+ this.options.onRemoteAudio?.({ uid: user.uid, track: user.audioTrack });
2160
+ }
2161
+ if (mediaType === "video" && user.videoTrack) {
2162
+ this.options.onRemoteScreen?.({ uid: user.uid, track: user.videoTrack });
2163
+ }
2164
+ });
2165
+ await rtc.join(
2166
+ credentials.appId,
2167
+ credentials.agoraChannelName,
2168
+ credentials.token,
2169
+ credentials.uid
2170
+ );
2171
+ this.audioTrack = await AgoraRTC.createMicrophoneAudioTrack();
2172
+ await this.audioTrack.setEnabled(!this.options.muted);
2173
+ await rtc.publish([this.audioTrack]);
2174
+ this.scheduleTokenRenewal();
2175
+ return this.session;
2176
+ } catch (error) {
2177
+ this.clearTokenRenewal();
2178
+ this.audioTrack?.stop();
2179
+ this.audioTrack?.close();
2180
+ this.audioTrack = null;
2181
+ await rtc.leave().catch(() => void 0);
2182
+ this.rtc = null;
2183
+ await this.options.client.leaveVoiceChannel(this.options.channelId, { clientId: this.clientId }).catch(() => void 0);
2184
+ this.session = null;
2185
+ throw error;
2186
+ }
2187
+ }
2188
+ async setMuted(muted) {
2189
+ await this.audioTrack?.setEnabled(!muted);
2190
+ await this.options.client.updateVoiceState(this.options.channelId, {
2191
+ clientId: this.clientId,
2192
+ muted
2193
+ });
2194
+ }
2195
+ async startScreenShare() {
2196
+ if (!this.session || this.screenRtc || this.screenTrack) return;
2197
+ const { credentials } = this.session;
2198
+ const AgoraRTC = await loadAgoraRTC();
2199
+ const screenRtc = AgoraRTC.createClient({ mode: "rtc", codec: "vp8" });
2200
+ this.screenRtc = screenRtc;
2201
+ try {
2202
+ this.bindTokenRenewal(screenRtc);
2203
+ await screenRtc.join(
2204
+ credentials.appId,
2205
+ credentials.agoraChannelName,
2206
+ credentials.screenToken,
2207
+ credentials.screenUid
2208
+ );
2209
+ const trackResult = await AgoraRTC.createScreenVideoTrack(
2210
+ { encoderConfig: "1080p_1" },
2211
+ "disable"
2212
+ );
2213
+ const screenTrack = Array.isArray(trackResult) ? trackResult[0] : trackResult;
2214
+ this.screenTrack = screenTrack;
2215
+ await screenRtc.publish([this.screenTrack]);
2216
+ await this.options.client.updateVoiceState(this.options.channelId, {
2217
+ clientId: this.clientId,
2218
+ screenSharing: true
2219
+ });
2220
+ } catch (error) {
2221
+ this.screenTrack?.stop();
2222
+ this.screenTrack?.close();
2223
+ this.screenTrack = null;
2224
+ await screenRtc.leave().catch(() => void 0);
2225
+ this.screenRtc = null;
2226
+ await this.options.client.updateVoiceState(this.options.channelId, {
2227
+ clientId: this.clientId,
2228
+ screenSharing: false
2229
+ }).catch(() => void 0);
2230
+ throw error;
2231
+ }
2232
+ }
2233
+ async stopScreenShare() {
2234
+ this.screenTrack?.stop();
2235
+ this.screenTrack?.close();
2236
+ this.screenTrack = null;
2237
+ await this.screenRtc?.leave();
2238
+ this.screenRtc = null;
2239
+ await this.options.client.updateVoiceState(this.options.channelId, {
2240
+ clientId: this.clientId,
2241
+ screenSharing: false
2242
+ });
2243
+ }
2244
+ async leave() {
2245
+ this.clearTokenRenewal();
2246
+ await this.stopScreenShare();
2247
+ this.audioTrack?.stop();
2248
+ this.audioTrack?.close();
2249
+ this.audioTrack = null;
2250
+ await this.rtc?.leave();
2251
+ this.rtc = null;
2252
+ await this.options.client.leaveVoiceChannel(this.options.channelId, { clientId: this.clientId });
2253
+ this.session = null;
2254
+ }
2255
+ bindTokenRenewal(rtc) {
2256
+ rtc.on("token-privilege-will-expire", () => {
2257
+ void this.renewTokens();
2258
+ });
2259
+ rtc.on("token-privilege-did-expire", () => {
2260
+ void this.renewTokens();
2261
+ });
2262
+ }
2263
+ scheduleTokenRenewal() {
2264
+ this.clearTokenRenewal();
2265
+ const expiresAt = this.session?.credentials.expiresAt;
2266
+ if (!expiresAt) return;
2267
+ const renewAt = new Date(expiresAt).getTime() - 5 * 6e4;
2268
+ const delay = Math.max(3e4, renewAt - Date.now());
2269
+ this.tokenRenewTimer = setTimeout(() => {
2270
+ void this.renewTokens();
2271
+ }, delay);
2272
+ }
2273
+ clearTokenRenewal() {
2274
+ if (this.tokenRenewTimer) {
2275
+ clearTimeout(this.tokenRenewTimer);
2276
+ this.tokenRenewTimer = null;
2277
+ }
2278
+ }
2279
+ async renewTokens() {
2280
+ if (!this.session) return;
2281
+ const result = await this.options.client.renewVoiceCredentials(this.options.channelId, {
2282
+ clientId: this.clientId
2283
+ });
2284
+ this.session = {
2285
+ ...this.session,
2286
+ credentials: result.credentials,
2287
+ state: result.state
2288
+ };
2289
+ if (result.credentials.token) {
2290
+ await this.rtc?.renewToken?.(result.credentials.token);
2291
+ }
2292
+ if (result.credentials.screenToken) {
2293
+ await this.screenRtc?.renewToken?.(result.credentials.screenToken);
2294
+ }
2295
+ this.scheduleTokenRenewal();
2296
+ }
2297
+ };
1839
2298
  // Annotate the CommonJS export names for ESM import in node:
1840
2299
  0 && (module.exports = {
1841
2300
  CLIENT_EVENTS,
1842
2301
  SERVER_EVENTS,
1843
2302
  ShadowClient,
1844
2303
  ShadowSocket,
2304
+ ShadowVoiceConsumer,
1845
2305
  channelRoom,
1846
2306
  threadRoom,
1847
2307
  userRoom