@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.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
|