@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.cjs +313 -0
- package/dist/index.d.cts +442 -14
- package/dist/index.d.ts +442 -14
- package/dist/index.js +312 -0
- package/package.json +11 -2
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.
|
|
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.
|
|
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
|
},
|