@shadowob/sdk 1.1.4 → 1.1.6-dev.311

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.js CHANGED
@@ -522,6 +522,43 @@ var ShadowClient = class {
522
522
  async removeChannelMember(channelId, userId) {
523
523
  return this.request(`/api/channels/${channelId}/members/${userId}`, { method: "DELETE" });
524
524
  }
525
+ async getVoiceState(channelId) {
526
+ return this.request(`/api/channels/${channelId}/voice/state`);
527
+ }
528
+ async joinVoiceChannel(channelId, options) {
529
+ return this.request(`/api/channels/${channelId}/voice/join`, {
530
+ method: "POST",
531
+ body: JSON.stringify(options ?? {})
532
+ });
533
+ }
534
+ async renewVoiceCredentials(channelId, options) {
535
+ return this.request(`/api/channels/${channelId}/voice/renew`, {
536
+ method: "POST",
537
+ body: JSON.stringify(options ?? {})
538
+ });
539
+ }
540
+ async leaveVoiceChannel(channelId, options) {
541
+ return this.request(`/api/channels/${channelId}/voice/leave`, {
542
+ method: "POST",
543
+ body: JSON.stringify(options ?? {})
544
+ });
545
+ }
546
+ async updateVoiceState(channelId, data) {
547
+ return this.request(`/api/channels/${channelId}/voice/state`, {
548
+ method: "PATCH",
549
+ body: JSON.stringify(data)
550
+ });
551
+ }
552
+ async getVoicePolicy(channelId, agentId) {
553
+ const params = new URLSearchParams({ agentId });
554
+ return this.request(`/api/channels/${channelId}/voice-policy?${params}`);
555
+ }
556
+ async updateVoicePolicy(channelId, data) {
557
+ return this.request(`/api/channels/${channelId}/voice-policy`, {
558
+ method: "PUT",
559
+ body: JSON.stringify(data)
560
+ });
561
+ }
525
562
  // ── Channel Buddy Policy ─────────────────────────────────────────────
526
563
  async setBuddyPolicy(channelId, agentId, data) {
527
564
  return this.request(`/api/channels/${channelId}/agents/${agentId}/policy`, {
@@ -1240,6 +1277,9 @@ var ShadowClient = class {
1240
1277
  async getScopeNeutralProduct(productId) {
1241
1278
  return this.request(`/api/products/${productId}`);
1242
1279
  }
1280
+ async getCommerceProductContext(productId) {
1281
+ return this.request(`/api/commerce/products/${productId}/context`);
1282
+ }
1243
1283
  async getShopProduct(shopId, productId) {
1244
1284
  return this.request(`/api/shops/${shopId}/products/${productId}`);
1245
1285
  }
@@ -1430,6 +1470,11 @@ var ShadowClient = class {
1430
1470
  method: "POST"
1431
1471
  });
1432
1472
  }
1473
+ async completeOrder(serverId, orderId) {
1474
+ return this.request(`/api/servers/${serverId}/shop/orders/${orderId}/complete`, {
1475
+ method: "POST"
1476
+ });
1477
+ }
1433
1478
  async getProductReviews(serverId, productId) {
1434
1479
  return this.request(`/api/servers/${serverId}/shop/products/${productId}/reviews`);
1435
1480
  }
@@ -1665,6 +1710,23 @@ var ShadowClient = class {
1665
1710
  async getAllEntitlements() {
1666
1711
  return this.request("/api/entitlements");
1667
1712
  }
1713
+ async getEntitlement(entitlementId) {
1714
+ return this.request(`/api/entitlements/${entitlementId}`);
1715
+ }
1716
+ async getOAuthCommerceEntitlementAccess(params) {
1717
+ const qs = new URLSearchParams();
1718
+ if (params?.resourceType) qs.set("resourceType", params.resourceType);
1719
+ if (params?.resourceId) qs.set("resourceId", params.resourceId);
1720
+ if (params?.capability) qs.set("capability", params.capability);
1721
+ const query = qs.toString();
1722
+ return this.request(`/api/oauth/commerce/entitlements${query ? `?${query}` : ""}`);
1723
+ }
1724
+ async redeemOAuthCommerceEntitlement(data) {
1725
+ return this.request("/api/oauth/commerce/entitlements/redeem", {
1726
+ method: "POST",
1727
+ body: JSON.stringify(data)
1728
+ });
1729
+ }
1668
1730
  async verifyEntitlement(entitlementId) {
1669
1731
  return this.request(`/api/entitlements/${entitlementId}/verify`);
1670
1732
  }
@@ -1674,6 +1736,12 @@ var ShadowClient = class {
1674
1736
  body: JSON.stringify({ reason })
1675
1737
  });
1676
1738
  }
1739
+ async cancelEntitlementRenewal(entitlementId, reason) {
1740
+ return this.request(`/api/entitlements/${entitlementId}/cancel-renewal`, {
1741
+ method: "POST",
1742
+ body: JSON.stringify({ reason })
1743
+ });
1744
+ }
1677
1745
  // ── Task Center ───────────────────────────────────────────────────────
1678
1746
  async getTaskCenter() {
1679
1747
  return this.request("/api/tasks");
@@ -1714,6 +1782,16 @@ var ShadowClient = class {
1714
1782
  if (params?.limit) qs.set("limit", String(params.limit));
1715
1783
  return this.request(`/api/discover/search?${qs}`);
1716
1784
  }
1785
+ async discoverCommerce(params) {
1786
+ const qs = new URLSearchParams();
1787
+ if (params?.q) qs.set("q", params.q);
1788
+ if (params?.limit) qs.set("limit", String(params.limit));
1789
+ const suffix = qs.toString();
1790
+ return this.request(`/api/discover/business${suffix ? `?${suffix}` : ""}`);
1791
+ }
1792
+ async discoverBusinessHub(params) {
1793
+ return this.discoverCommerce(params);
1794
+ }
1717
1795
  // ── Voice Enhance ─────────────────────────────────────────────────────
1718
1796
  async enhanceVoice(data) {
1719
1797
  return this.request("/api/voice/enhance", {
@@ -1923,6 +2001,53 @@ var ShadowSocket = class {
1923
2001
  leaveChannel(channelId) {
1924
2002
  this.socket.emit("channel:leave", { channelId });
1925
2003
  }
2004
+ joinVoiceChannel(channelId, options) {
2005
+ return new Promise((resolve) => {
2006
+ this.socket.emit(
2007
+ "voice:join",
2008
+ { channelId, ...options },
2009
+ (res) => {
2010
+ resolve(res ?? { ok: false, error: "Voice join failed" });
2011
+ }
2012
+ );
2013
+ });
2014
+ }
2015
+ leaveVoiceChannel(channelId, options) {
2016
+ return new Promise((resolve) => {
2017
+ this.socket.emit(
2018
+ "voice:leave",
2019
+ { channelId, ...options },
2020
+ (res) => {
2021
+ resolve(res ?? { ok: true });
2022
+ }
2023
+ );
2024
+ });
2025
+ }
2026
+ renewVoiceCredentials(channelId, options) {
2027
+ return new Promise((resolve) => {
2028
+ this.socket.emit(
2029
+ "voice:token:renew",
2030
+ { channelId, ...options },
2031
+ (res) => {
2032
+ resolve(res ?? { ok: false, error: "Voice token renewal failed" });
2033
+ }
2034
+ );
2035
+ });
2036
+ }
2037
+ updateVoiceState(channelId, data) {
2038
+ return new Promise((resolve) => {
2039
+ this.socket.emit(
2040
+ "voice:state:update",
2041
+ { channelId, ...data },
2042
+ (res) => {
2043
+ resolve(res ?? { ok: true });
2044
+ }
2045
+ );
2046
+ });
2047
+ }
2048
+ sendVoiceHeartbeat(channelId, options) {
2049
+ this.socket.emit("voice:heartbeat", { channelId, ...options });
2050
+ }
1926
2051
  // ── Client actions ────────────────────────────────────────────────────
1927
2052
  /** Send a message via WebSocket (text-only; for file attachments use REST) */
1928
2053
  sendMessage(data) {
@@ -1941,11 +2066,198 @@ var ShadowSocket = class {
1941
2066
  this.socket.emit("presence:activity", { channelId, activity });
1942
2067
  }
1943
2068
  };
2069
+
2070
+ // src/voice.ts
2071
+ var cachedAgoraRTC = null;
2072
+ async function loadAgoraRTC() {
2073
+ if (cachedAgoraRTC) return cachedAgoraRTC;
2074
+ try {
2075
+ const module = await import("agora-rtc-sdk-ng");
2076
+ cachedAgoraRTC = module.default;
2077
+ return cachedAgoraRTC;
2078
+ } catch (error) {
2079
+ throw new Error(
2080
+ `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)}`
2081
+ );
2082
+ }
2083
+ }
2084
+ function createVoiceClientId() {
2085
+ return `shadow-sdk-${globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`}`;
2086
+ }
2087
+ var ShadowVoiceConsumer = class {
2088
+ constructor(options) {
2089
+ this.options = options;
2090
+ this.clientId = options.clientId ?? createVoiceClientId();
2091
+ }
2092
+ rtc = null;
2093
+ screenRtc = null;
2094
+ audioTrack = null;
2095
+ screenTrack = null;
2096
+ session = null;
2097
+ clientId;
2098
+ tokenRenewTimer = null;
2099
+ get joinResult() {
2100
+ return this.session;
2101
+ }
2102
+ async join() {
2103
+ const AgoraRTC = await loadAgoraRTC();
2104
+ this.session = await this.options.client.joinVoiceChannel(this.options.channelId, {
2105
+ muted: this.options.muted,
2106
+ clientId: this.clientId
2107
+ });
2108
+ const { credentials } = this.session;
2109
+ const rtc = AgoraRTC.createClient({ mode: "rtc", codec: "vp8" });
2110
+ this.rtc = rtc;
2111
+ try {
2112
+ this.bindTokenRenewal(rtc);
2113
+ rtc.on("user-published", async (user, mediaType) => {
2114
+ await rtc.subscribe(user, mediaType);
2115
+ if (mediaType === "audio" && user.audioTrack) {
2116
+ this.options.onRemoteAudio?.({ uid: user.uid, track: user.audioTrack });
2117
+ }
2118
+ if (mediaType === "video" && user.videoTrack) {
2119
+ this.options.onRemoteScreen?.({ uid: user.uid, track: user.videoTrack });
2120
+ }
2121
+ });
2122
+ await rtc.join(
2123
+ credentials.appId,
2124
+ credentials.agoraChannelName,
2125
+ credentials.token,
2126
+ credentials.uid
2127
+ );
2128
+ this.audioTrack = await AgoraRTC.createMicrophoneAudioTrack();
2129
+ await this.audioTrack.setEnabled(!this.options.muted);
2130
+ await rtc.publish([this.audioTrack]);
2131
+ this.scheduleTokenRenewal();
2132
+ return this.session;
2133
+ } catch (error) {
2134
+ this.clearTokenRenewal();
2135
+ this.audioTrack?.stop();
2136
+ this.audioTrack?.close();
2137
+ this.audioTrack = null;
2138
+ await rtc.leave().catch(() => void 0);
2139
+ this.rtc = null;
2140
+ await this.options.client.leaveVoiceChannel(this.options.channelId, { clientId: this.clientId }).catch(() => void 0);
2141
+ this.session = null;
2142
+ throw error;
2143
+ }
2144
+ }
2145
+ async setMuted(muted) {
2146
+ await this.audioTrack?.setEnabled(!muted);
2147
+ await this.options.client.updateVoiceState(this.options.channelId, {
2148
+ clientId: this.clientId,
2149
+ muted
2150
+ });
2151
+ }
2152
+ async startScreenShare() {
2153
+ if (!this.session || this.screenRtc || this.screenTrack) return;
2154
+ const { credentials } = this.session;
2155
+ const AgoraRTC = await loadAgoraRTC();
2156
+ const screenRtc = AgoraRTC.createClient({ mode: "rtc", codec: "vp8" });
2157
+ this.screenRtc = screenRtc;
2158
+ try {
2159
+ this.bindTokenRenewal(screenRtc);
2160
+ await screenRtc.join(
2161
+ credentials.appId,
2162
+ credentials.agoraChannelName,
2163
+ credentials.screenToken,
2164
+ credentials.screenUid
2165
+ );
2166
+ const trackResult = await AgoraRTC.createScreenVideoTrack(
2167
+ { encoderConfig: "1080p_1" },
2168
+ "disable"
2169
+ );
2170
+ const screenTrack = Array.isArray(trackResult) ? trackResult[0] : trackResult;
2171
+ this.screenTrack = screenTrack;
2172
+ await screenRtc.publish([this.screenTrack]);
2173
+ await this.options.client.updateVoiceState(this.options.channelId, {
2174
+ clientId: this.clientId,
2175
+ screenSharing: true
2176
+ });
2177
+ } catch (error) {
2178
+ this.screenTrack?.stop();
2179
+ this.screenTrack?.close();
2180
+ this.screenTrack = null;
2181
+ await screenRtc.leave().catch(() => void 0);
2182
+ this.screenRtc = null;
2183
+ await this.options.client.updateVoiceState(this.options.channelId, {
2184
+ clientId: this.clientId,
2185
+ screenSharing: false
2186
+ }).catch(() => void 0);
2187
+ throw error;
2188
+ }
2189
+ }
2190
+ async stopScreenShare() {
2191
+ this.screenTrack?.stop();
2192
+ this.screenTrack?.close();
2193
+ this.screenTrack = null;
2194
+ await this.screenRtc?.leave();
2195
+ this.screenRtc = null;
2196
+ await this.options.client.updateVoiceState(this.options.channelId, {
2197
+ clientId: this.clientId,
2198
+ screenSharing: false
2199
+ });
2200
+ }
2201
+ async leave() {
2202
+ this.clearTokenRenewal();
2203
+ await this.stopScreenShare();
2204
+ this.audioTrack?.stop();
2205
+ this.audioTrack?.close();
2206
+ this.audioTrack = null;
2207
+ await this.rtc?.leave();
2208
+ this.rtc = null;
2209
+ await this.options.client.leaveVoiceChannel(this.options.channelId, { clientId: this.clientId });
2210
+ this.session = null;
2211
+ }
2212
+ bindTokenRenewal(rtc) {
2213
+ rtc.on("token-privilege-will-expire", () => {
2214
+ void this.renewTokens();
2215
+ });
2216
+ rtc.on("token-privilege-did-expire", () => {
2217
+ void this.renewTokens();
2218
+ });
2219
+ }
2220
+ scheduleTokenRenewal() {
2221
+ this.clearTokenRenewal();
2222
+ const expiresAt = this.session?.credentials.expiresAt;
2223
+ if (!expiresAt) return;
2224
+ const renewAt = new Date(expiresAt).getTime() - 5 * 6e4;
2225
+ const delay = Math.max(3e4, renewAt - Date.now());
2226
+ this.tokenRenewTimer = setTimeout(() => {
2227
+ void this.renewTokens();
2228
+ }, delay);
2229
+ }
2230
+ clearTokenRenewal() {
2231
+ if (this.tokenRenewTimer) {
2232
+ clearTimeout(this.tokenRenewTimer);
2233
+ this.tokenRenewTimer = null;
2234
+ }
2235
+ }
2236
+ async renewTokens() {
2237
+ if (!this.session) return;
2238
+ const result = await this.options.client.renewVoiceCredentials(this.options.channelId, {
2239
+ clientId: this.clientId
2240
+ });
2241
+ this.session = {
2242
+ ...this.session,
2243
+ credentials: result.credentials,
2244
+ state: result.state
2245
+ };
2246
+ if (result.credentials.token) {
2247
+ await this.rtc?.renewToken?.(result.credentials.token);
2248
+ }
2249
+ if (result.credentials.screenToken) {
2250
+ await this.screenRtc?.renewToken?.(result.credentials.screenToken);
2251
+ }
2252
+ this.scheduleTokenRenewal();
2253
+ }
2254
+ };
1944
2255
  export {
1945
2256
  CLIENT_EVENTS,
1946
2257
  SERVER_EVENTS,
1947
2258
  ShadowClient,
1948
2259
  ShadowSocket,
2260
+ ShadowVoiceConsumer,
1949
2261
  channelRoom,
1950
2262
  threadRoom,
1951
2263
  userRoom
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shadowob/sdk",
3
- "version": "1.1.4",
3
+ "version": "1.1.6-dev.311",
4
4
  "description": "Shadow SDK — typed REST client and real-time Socket.IO event listener for Shadow servers",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -22,9 +22,18 @@
22
22
  ],
23
23
  "dependencies": {
24
24
  "socket.io-client": "^4.8.1",
25
- "@shadowob/shared": "1.1.4"
25
+ "@shadowob/shared": "1.1.6-dev.311"
26
+ },
27
+ "peerDependencies": {
28
+ "agora-rtc-sdk-ng": "^4.24.3"
29
+ },
30
+ "peerDependenciesMeta": {
31
+ "agora-rtc-sdk-ng": {
32
+ "optional": true
33
+ }
26
34
  },
27
35
  "devDependencies": {
36
+ "agora-rtc-sdk-ng": "^4.24.3",
28
37
  "tsup": "^8.5.0",
29
38
  "typescript": "^5.9.3"
30
39
  },