@shadowob/sdk 1.1.4 → 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
@@ -564,6 +565,43 @@ var ShadowClient = class {
564
565
  async removeChannelMember(channelId, userId) {
565
566
  return this.request(`/api/channels/${channelId}/members/${userId}`, { method: "DELETE" });
566
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
+ }
567
605
  // ── Channel Buddy Policy ─────────────────────────────────────────────
568
606
  async setBuddyPolicy(channelId, agentId, data) {
569
607
  return this.request(`/api/channels/${channelId}/agents/${agentId}/policy`, {
@@ -1282,6 +1320,9 @@ var ShadowClient = class {
1282
1320
  async getScopeNeutralProduct(productId) {
1283
1321
  return this.request(`/api/products/${productId}`);
1284
1322
  }
1323
+ async getCommerceProductContext(productId) {
1324
+ return this.request(`/api/commerce/products/${productId}/context`);
1325
+ }
1285
1326
  async getShopProduct(shopId, productId) {
1286
1327
  return this.request(`/api/shops/${shopId}/products/${productId}`);
1287
1328
  }
@@ -1472,6 +1513,11 @@ var ShadowClient = class {
1472
1513
  method: "POST"
1473
1514
  });
1474
1515
  }
1516
+ async completeOrder(serverId, orderId) {
1517
+ return this.request(`/api/servers/${serverId}/shop/orders/${orderId}/complete`, {
1518
+ method: "POST"
1519
+ });
1520
+ }
1475
1521
  async getProductReviews(serverId, productId) {
1476
1522
  return this.request(`/api/servers/${serverId}/shop/products/${productId}/reviews`);
1477
1523
  }
@@ -1707,6 +1753,23 @@ var ShadowClient = class {
1707
1753
  async getAllEntitlements() {
1708
1754
  return this.request("/api/entitlements");
1709
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
+ }
1710
1773
  async verifyEntitlement(entitlementId) {
1711
1774
  return this.request(`/api/entitlements/${entitlementId}/verify`);
1712
1775
  }
@@ -1716,6 +1779,12 @@ var ShadowClient = class {
1716
1779
  body: JSON.stringify({ reason })
1717
1780
  });
1718
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
+ }
1719
1788
  // ── Task Center ───────────────────────────────────────────────────────
1720
1789
  async getTaskCenter() {
1721
1790
  return this.request("/api/tasks");
@@ -1756,6 +1825,16 @@ var ShadowClient = class {
1756
1825
  if (params?.limit) qs.set("limit", String(params.limit));
1757
1826
  return this.request(`/api/discover/search?${qs}`);
1758
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
+ }
1759
1838
  // ── Voice Enhance ─────────────────────────────────────────────────────
1760
1839
  async enhanceVoice(data) {
1761
1840
  return this.request("/api/voice/enhance", {
@@ -1965,6 +2044,53 @@ var ShadowSocket = class {
1965
2044
  leaveChannel(channelId) {
1966
2045
  this.socket.emit("channel:leave", { channelId });
1967
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
+ }
1968
2094
  // ── Client actions ────────────────────────────────────────────────────
1969
2095
  /** Send a message via WebSocket (text-only; for file attachments use REST) */
1970
2096
  sendMessage(data) {
@@ -1983,12 +2109,199 @@ var ShadowSocket = class {
1983
2109
  this.socket.emit("presence:activity", { channelId, activity });
1984
2110
  }
1985
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
+ };
1986
2298
  // Annotate the CommonJS export names for ESM import in node:
1987
2299
  0 && (module.exports = {
1988
2300
  CLIENT_EVENTS,
1989
2301
  SERVER_EVENTS,
1990
2302
  ShadowClient,
1991
2303
  ShadowSocket,
2304
+ ShadowVoiceConsumer,
1992
2305
  channelRoom,
1993
2306
  threadRoom,
1994
2307
  userRoom